1989f2807SJerry Jelinek /* 2989f2807SJerry Jelinek * Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com> 3989f2807SJerry Jelinek * All rights reserved. 4989f2807SJerry Jelinek * 5989f2807SJerry Jelinek * Redistribution and use in source and binary forms, with or without 6989f2807SJerry Jelinek * modification, are permitted provided that the following conditions 7989f2807SJerry Jelinek * are met: 8989f2807SJerry Jelinek * 1. Redistributions of source code must retain the above copyright 9989f2807SJerry Jelinek * notice, this list of conditions and the following disclaimer. 10989f2807SJerry Jelinek * 2. Redistributions in binary form must reproduce the above copyright 11989f2807SJerry Jelinek * notice, this list of conditions and the following disclaimer in the 12989f2807SJerry Jelinek * documentation and/or other materials provided with the distribution. 13989f2807SJerry Jelinek * 14989f2807SJerry Jelinek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15989f2807SJerry Jelinek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16989f2807SJerry Jelinek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17989f2807SJerry Jelinek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18989f2807SJerry Jelinek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19989f2807SJerry Jelinek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20989f2807SJerry Jelinek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21989f2807SJerry Jelinek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22989f2807SJerry Jelinek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23989f2807SJerry Jelinek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24989f2807SJerry Jelinek * SUCH DAMAGE. 25989f2807SJerry Jelinek */ 26989f2807SJerry Jelinek 27989f2807SJerry Jelinek /* $FreeBSD: src/sys/dev/ipmi/ipmi_kcs.c,v 1.3 2008/08/28 02:11:04 jhb */ 28989f2807SJerry Jelinek 29989f2807SJerry Jelinek /* 30*12950e8eSJerry Jelinek * Copyright 2013, Joyent, Inc. All rights reserved. 311e393477SMarcel Telka * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 32989f2807SJerry Jelinek */ 33989f2807SJerry Jelinek 34989f2807SJerry Jelinek #include <sys/param.h> 35989f2807SJerry Jelinek #include <sys/disp.h> 36989f2807SJerry Jelinek #include <sys/systm.h> 37989f2807SJerry Jelinek #include <sys/condvar.h> 38989f2807SJerry Jelinek #include <sys/cmn_err.h> 39989f2807SJerry Jelinek #include <sys/ddi.h> 40989f2807SJerry Jelinek #include <sys/sunddi.h> 41989f2807SJerry Jelinek 42989f2807SJerry Jelinek #include <sys/ipmi.h> 43989f2807SJerry Jelinek #include "ipmivars.h" 44989f2807SJerry Jelinek 45989f2807SJerry Jelinek static void kcs_clear_obf(struct ipmi_softc *, int); 46989f2807SJerry Jelinek static void kcs_error(struct ipmi_softc *); 47989f2807SJerry Jelinek static int kcs_wait_for_ibf(struct ipmi_softc *, int); 48989f2807SJerry Jelinek static int kcs_wait_for_obf(struct ipmi_softc *, int); 49989f2807SJerry Jelinek 50989f2807SJerry Jelinek #define RETRY_USECS 100 51989f2807SJerry Jelinek static clock_t timeout_usecs; 52989f2807SJerry Jelinek 53989f2807SJerry Jelinek static int 54989f2807SJerry Jelinek kcs_wait_for_ibf(struct ipmi_softc *sc, int state) 55989f2807SJerry Jelinek { 56989f2807SJerry Jelinek int status; 57989f2807SJerry Jelinek clock_t i; 58989f2807SJerry Jelinek 59989f2807SJerry Jelinek status = INB(sc, KCS_CTL_STS); 60989f2807SJerry Jelinek if (state == 0) { 61989f2807SJerry Jelinek /* WAIT FOR IBF = 0 */ 62989f2807SJerry Jelinek for (i = 0; i < timeout_usecs && status & KCS_STATUS_IBF; 63989f2807SJerry Jelinek i += RETRY_USECS) { 64989f2807SJerry Jelinek drv_usecwait(RETRY_USECS); 65989f2807SJerry Jelinek status = INB(sc, KCS_CTL_STS); 66989f2807SJerry Jelinek } 67989f2807SJerry Jelinek } else { 68989f2807SJerry Jelinek /* WAIT FOR IBF = 1 */ 69989f2807SJerry Jelinek for (i = 0; i < timeout_usecs && !(status & KCS_STATUS_IBF); 70989f2807SJerry Jelinek i += RETRY_USECS) { 71989f2807SJerry Jelinek drv_usecwait(RETRY_USECS); 72989f2807SJerry Jelinek status = INB(sc, KCS_CTL_STS); 73989f2807SJerry Jelinek } 74989f2807SJerry Jelinek } 75989f2807SJerry Jelinek return (status); 76989f2807SJerry Jelinek } 77989f2807SJerry Jelinek 78989f2807SJerry Jelinek static int 79989f2807SJerry Jelinek kcs_wait_for_obf(struct ipmi_softc *sc, int state) 80989f2807SJerry Jelinek { 81989f2807SJerry Jelinek int status; 82989f2807SJerry Jelinek clock_t i; 83989f2807SJerry Jelinek 84989f2807SJerry Jelinek status = INB(sc, KCS_CTL_STS); 85989f2807SJerry Jelinek if (state == 0) { 86989f2807SJerry Jelinek /* WAIT FOR OBF = 0 */ 87989f2807SJerry Jelinek for (i = 0; i < timeout_usecs && status & KCS_STATUS_OBF; 88989f2807SJerry Jelinek i += RETRY_USECS) { 89989f2807SJerry Jelinek drv_usecwait(RETRY_USECS); 90989f2807SJerry Jelinek status = INB(sc, KCS_CTL_STS); 91989f2807SJerry Jelinek } 92989f2807SJerry Jelinek } else { 93989f2807SJerry Jelinek /* WAIT FOR OBF = 1 */ 94989f2807SJerry Jelinek for (i = 0; i < timeout_usecs && !(status & KCS_STATUS_OBF); 95989f2807SJerry Jelinek i += RETRY_USECS) { 96989f2807SJerry Jelinek drv_usecwait(RETRY_USECS); 97989f2807SJerry Jelinek status = INB(sc, KCS_CTL_STS); 98989f2807SJerry Jelinek } 99989f2807SJerry Jelinek } 100989f2807SJerry Jelinek return (status); 101989f2807SJerry Jelinek } 102989f2807SJerry Jelinek 103989f2807SJerry Jelinek static void 104989f2807SJerry Jelinek kcs_clear_obf(struct ipmi_softc *sc, int status) 105989f2807SJerry Jelinek { 106989f2807SJerry Jelinek /* Clear OBF */ 107989f2807SJerry Jelinek if (status & KCS_STATUS_OBF) { 108989f2807SJerry Jelinek (void) INB(sc, KCS_DATA); 109989f2807SJerry Jelinek } 110989f2807SJerry Jelinek } 111989f2807SJerry Jelinek 112989f2807SJerry Jelinek static void 113989f2807SJerry Jelinek kcs_error(struct ipmi_softc *sc) 114989f2807SJerry Jelinek { 115989f2807SJerry Jelinek int retry, status; 116989f2807SJerry Jelinek uchar_t data; 117989f2807SJerry Jelinek 118989f2807SJerry Jelinek for (retry = 0; retry < 2; retry++) { 119989f2807SJerry Jelinek 120989f2807SJerry Jelinek /* Wait for IBF = 0 */ 121989f2807SJerry Jelinek status = kcs_wait_for_ibf(sc, 0); 122989f2807SJerry Jelinek 123989f2807SJerry Jelinek /* ABORT */ 124989f2807SJerry Jelinek OUTB(sc, KCS_CTL_STS, KCS_CONTROL_GET_STATUS_ABORT); 125989f2807SJerry Jelinek 126989f2807SJerry Jelinek /* Wait for IBF = 0 */ 127989f2807SJerry Jelinek status = kcs_wait_for_ibf(sc, 0); 128989f2807SJerry Jelinek 129989f2807SJerry Jelinek /* Clear OBF */ 130989f2807SJerry Jelinek kcs_clear_obf(sc, status); 131989f2807SJerry Jelinek 132989f2807SJerry Jelinek if (status & KCS_STATUS_OBF) { 133989f2807SJerry Jelinek data = INB(sc, KCS_DATA); 134989f2807SJerry Jelinek if (data != 0) 135989f2807SJerry Jelinek cmn_err(CE_WARN, 136989f2807SJerry Jelinek "KCS Error Data %02x", data); 137989f2807SJerry Jelinek } 138989f2807SJerry Jelinek 139989f2807SJerry Jelinek /* 0x00 to DATA_IN */ 140989f2807SJerry Jelinek OUTB(sc, KCS_DATA, 0x00); 141989f2807SJerry Jelinek 142989f2807SJerry Jelinek /* Wait for IBF = 0 */ 143989f2807SJerry Jelinek status = kcs_wait_for_ibf(sc, 0); 144989f2807SJerry Jelinek 145989f2807SJerry Jelinek if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_READ) { 146989f2807SJerry Jelinek 147989f2807SJerry Jelinek /* Wait for OBF = 1 */ 148989f2807SJerry Jelinek status = kcs_wait_for_obf(sc, 1); 149989f2807SJerry Jelinek 150989f2807SJerry Jelinek /* Read error status */ 151989f2807SJerry Jelinek data = INB(sc, KCS_DATA); 152989f2807SJerry Jelinek if (data != 0) 153989f2807SJerry Jelinek cmn_err(CE_WARN, "KCS error: %02x", data); 154989f2807SJerry Jelinek 155989f2807SJerry Jelinek /* Write READ into Data_in */ 156989f2807SJerry Jelinek OUTB(sc, KCS_DATA, KCS_DATA_IN_READ); 157989f2807SJerry Jelinek 158989f2807SJerry Jelinek /* Wait for IBF = 0 */ 159989f2807SJerry Jelinek status = kcs_wait_for_ibf(sc, 0); 160989f2807SJerry Jelinek } 161989f2807SJerry Jelinek 162989f2807SJerry Jelinek /* IDLE STATE */ 163989f2807SJerry Jelinek if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_IDLE) { 164989f2807SJerry Jelinek /* Wait for OBF = 1 */ 165989f2807SJerry Jelinek status = kcs_wait_for_obf(sc, 1); 166989f2807SJerry Jelinek 167989f2807SJerry Jelinek /* Clear OBF */ 168989f2807SJerry Jelinek kcs_clear_obf(sc, status); 169989f2807SJerry Jelinek return; 170989f2807SJerry Jelinek } 171989f2807SJerry Jelinek } 172989f2807SJerry Jelinek cmn_err(CE_WARN, "KCS: Error retry exhausted"); 173989f2807SJerry Jelinek } 174989f2807SJerry Jelinek 175989f2807SJerry Jelinek /* 176989f2807SJerry Jelinek * Start to write a request. Waits for IBF to clear and then sends the 177989f2807SJerry Jelinek * WR_START command. 178989f2807SJerry Jelinek */ 179989f2807SJerry Jelinek static int 180989f2807SJerry Jelinek kcs_start_write(struct ipmi_softc *sc) 181989f2807SJerry Jelinek { 182989f2807SJerry Jelinek int retry, status; 183989f2807SJerry Jelinek 184989f2807SJerry Jelinek for (retry = 0; retry < 10; retry++) { 185989f2807SJerry Jelinek /* Wait for IBF = 0 */ 186989f2807SJerry Jelinek status = kcs_wait_for_ibf(sc, 0); 187989f2807SJerry Jelinek 188989f2807SJerry Jelinek /* Clear OBF */ 189989f2807SJerry Jelinek kcs_clear_obf(sc, status); 190989f2807SJerry Jelinek 191989f2807SJerry Jelinek /* Write start to command */ 192989f2807SJerry Jelinek OUTB(sc, KCS_CTL_STS, KCS_CONTROL_WRITE_START); 193989f2807SJerry Jelinek 194989f2807SJerry Jelinek /* Wait for IBF = 0 */ 195989f2807SJerry Jelinek status = kcs_wait_for_ibf(sc, 0); 196989f2807SJerry Jelinek if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_WRITE) 197989f2807SJerry Jelinek break; 198*12950e8eSJerry Jelinek delay(drv_usectohz(1000000)); 199989f2807SJerry Jelinek } 200989f2807SJerry Jelinek 201989f2807SJerry Jelinek if (KCS_STATUS_STATE(status) != KCS_STATUS_STATE_WRITE) 202989f2807SJerry Jelinek /* error state */ 203989f2807SJerry Jelinek return (0); 204989f2807SJerry Jelinek 205989f2807SJerry Jelinek /* Clear OBF */ 206989f2807SJerry Jelinek kcs_clear_obf(sc, status); 207989f2807SJerry Jelinek 208989f2807SJerry Jelinek return (1); 209989f2807SJerry Jelinek } 210989f2807SJerry Jelinek 211989f2807SJerry Jelinek /* 212989f2807SJerry Jelinek * Write a byte of the request message, excluding the last byte of the 213989f2807SJerry Jelinek * message which requires special handling. 214989f2807SJerry Jelinek */ 215989f2807SJerry Jelinek static int 216989f2807SJerry Jelinek kcs_write_byte(struct ipmi_softc *sc, uchar_t data) 217989f2807SJerry Jelinek { 218989f2807SJerry Jelinek int status; 219989f2807SJerry Jelinek 220989f2807SJerry Jelinek /* Data to Data */ 221989f2807SJerry Jelinek OUTB(sc, KCS_DATA, data); 222989f2807SJerry Jelinek 223989f2807SJerry Jelinek /* Wait for IBF = 0 */ 224989f2807SJerry Jelinek status = kcs_wait_for_ibf(sc, 0); 225989f2807SJerry Jelinek 226989f2807SJerry Jelinek if (KCS_STATUS_STATE(status) != KCS_STATUS_STATE_WRITE) 227989f2807SJerry Jelinek return (0); 228989f2807SJerry Jelinek 229989f2807SJerry Jelinek /* Clear OBF */ 230989f2807SJerry Jelinek kcs_clear_obf(sc, status); 231989f2807SJerry Jelinek return (1); 232989f2807SJerry Jelinek } 233989f2807SJerry Jelinek 234989f2807SJerry Jelinek /* 235989f2807SJerry Jelinek * Write the last byte of a request message. 236989f2807SJerry Jelinek */ 237989f2807SJerry Jelinek static int 238989f2807SJerry Jelinek kcs_write_last_byte(struct ipmi_softc *sc, uchar_t data) 239989f2807SJerry Jelinek { 240989f2807SJerry Jelinek int status; 241989f2807SJerry Jelinek 242989f2807SJerry Jelinek /* Write end to command */ 243989f2807SJerry Jelinek OUTB(sc, KCS_CTL_STS, KCS_CONTROL_WRITE_END); 244989f2807SJerry Jelinek 245989f2807SJerry Jelinek /* Wait for IBF = 0 */ 246989f2807SJerry Jelinek status = kcs_wait_for_ibf(sc, 0); 247989f2807SJerry Jelinek 248989f2807SJerry Jelinek if (KCS_STATUS_STATE(status) != KCS_STATUS_STATE_WRITE) 249989f2807SJerry Jelinek /* error state */ 250989f2807SJerry Jelinek return (0); 251989f2807SJerry Jelinek 252989f2807SJerry Jelinek /* Clear OBF */ 253989f2807SJerry Jelinek kcs_clear_obf(sc, status); 254989f2807SJerry Jelinek 255989f2807SJerry Jelinek /* Send data byte to DATA. */ 256989f2807SJerry Jelinek OUTB(sc, KCS_DATA, data); 257989f2807SJerry Jelinek return (1); 258989f2807SJerry Jelinek } 259989f2807SJerry Jelinek 260989f2807SJerry Jelinek /* 261989f2807SJerry Jelinek * Read one byte of the reply message. 262989f2807SJerry Jelinek */ 263989f2807SJerry Jelinek static int 264989f2807SJerry Jelinek kcs_read_byte(struct ipmi_softc *sc, uchar_t *data) 265989f2807SJerry Jelinek { 266989f2807SJerry Jelinek int status; 267989f2807SJerry Jelinek 268989f2807SJerry Jelinek /* Wait for IBF = 0 */ 269989f2807SJerry Jelinek status = kcs_wait_for_ibf(sc, 0); 270989f2807SJerry Jelinek 271989f2807SJerry Jelinek /* Read State */ 272989f2807SJerry Jelinek if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_READ) { 273989f2807SJerry Jelinek 274989f2807SJerry Jelinek /* Wait for OBF = 1 */ 275989f2807SJerry Jelinek status = kcs_wait_for_obf(sc, 1); 276989f2807SJerry Jelinek 277989f2807SJerry Jelinek /* Read Data_out */ 278989f2807SJerry Jelinek *data = INB(sc, KCS_DATA); 279989f2807SJerry Jelinek 280989f2807SJerry Jelinek /* Write READ into Data_in */ 281989f2807SJerry Jelinek OUTB(sc, KCS_DATA, KCS_DATA_IN_READ); 282989f2807SJerry Jelinek return (1); 283989f2807SJerry Jelinek } 284989f2807SJerry Jelinek 285989f2807SJerry Jelinek /* Idle State */ 286989f2807SJerry Jelinek if (KCS_STATUS_STATE(status) == KCS_STATUS_STATE_IDLE) { 287989f2807SJerry Jelinek 288989f2807SJerry Jelinek /* Wait for OBF = 1 */ 289989f2807SJerry Jelinek status = kcs_wait_for_obf(sc, 1); 290989f2807SJerry Jelinek 291989f2807SJerry Jelinek /* Read Dummy */ 292989f2807SJerry Jelinek (void) INB(sc, KCS_DATA); 293989f2807SJerry Jelinek return (2); 294989f2807SJerry Jelinek } 295989f2807SJerry Jelinek 296989f2807SJerry Jelinek /* Error State */ 297989f2807SJerry Jelinek return (0); 298989f2807SJerry Jelinek } 299989f2807SJerry Jelinek 300989f2807SJerry Jelinek /* 301989f2807SJerry Jelinek * Send a request message and collect the reply. Returns true if we 302989f2807SJerry Jelinek * succeed. 303989f2807SJerry Jelinek */ 304989f2807SJerry Jelinek static int 305989f2807SJerry Jelinek kcs_polled_request(struct ipmi_softc *sc, struct ipmi_request *req) 306989f2807SJerry Jelinek { 307989f2807SJerry Jelinek uchar_t *cp, data; 308989f2807SJerry Jelinek int i, state; 309989f2807SJerry Jelinek 310989f2807SJerry Jelinek /* Send the request. */ 311989f2807SJerry Jelinek if (!kcs_start_write(sc)) { 312989f2807SJerry Jelinek cmn_err(CE_WARN, "KCS: Failed to start write"); 313989f2807SJerry Jelinek goto fail; 314989f2807SJerry Jelinek } 315989f2807SJerry Jelinek #ifdef KCS_DEBUG 316989f2807SJerry Jelinek cmn_err(CE_NOTE, "KCS: WRITE_START... ok"); 317989f2807SJerry Jelinek #endif 318989f2807SJerry Jelinek 319989f2807SJerry Jelinek if (!kcs_write_byte(sc, req->ir_addr)) { 320989f2807SJerry Jelinek cmn_err(CE_WARN, "KCS: Failed to write address"); 321989f2807SJerry Jelinek goto fail; 322989f2807SJerry Jelinek } 323989f2807SJerry Jelinek #ifdef KCS_DEBUG 324989f2807SJerry Jelinek cmn_err(CE_NOTE, "KCS: Wrote address: %02x", req->ir_addr); 325989f2807SJerry Jelinek #endif 326989f2807SJerry Jelinek 327989f2807SJerry Jelinek if (req->ir_requestlen == 0) { 328989f2807SJerry Jelinek if (!kcs_write_last_byte(sc, req->ir_command)) { 329989f2807SJerry Jelinek cmn_err(CE_WARN, 330989f2807SJerry Jelinek "KCS: Failed to write command"); 331989f2807SJerry Jelinek goto fail; 332989f2807SJerry Jelinek } 333989f2807SJerry Jelinek #ifdef KCS_DEBUG 334989f2807SJerry Jelinek cmn_err(CE_NOTE, "KCS: Wrote command: %02x", 335989f2807SJerry Jelinek req->ir_command); 336989f2807SJerry Jelinek #endif 337989f2807SJerry Jelinek } else { 338989f2807SJerry Jelinek if (!kcs_write_byte(sc, req->ir_command)) { 339989f2807SJerry Jelinek cmn_err(CE_WARN, 340989f2807SJerry Jelinek "KCS: Failed to write command"); 341989f2807SJerry Jelinek goto fail; 342989f2807SJerry Jelinek } 343989f2807SJerry Jelinek #ifdef KCS_DEBUG 344989f2807SJerry Jelinek cmn_err(CE_NOTE, "KCS: Wrote command: %02x", 345989f2807SJerry Jelinek req->ir_command); 346989f2807SJerry Jelinek #endif 347989f2807SJerry Jelinek 348989f2807SJerry Jelinek cp = req->ir_request; 349989f2807SJerry Jelinek for (i = 0; i < req->ir_requestlen - 1; i++) { 350989f2807SJerry Jelinek if (!kcs_write_byte(sc, *cp++)) { 351989f2807SJerry Jelinek cmn_err(CE_WARN, 352989f2807SJerry Jelinek "KCS: Failed to write data byte %d", 353989f2807SJerry Jelinek i + 1); 354989f2807SJerry Jelinek goto fail; 355989f2807SJerry Jelinek } 356989f2807SJerry Jelinek #ifdef KCS_DEBUG 357989f2807SJerry Jelinek cmn_err(CE_NOTE, "KCS: Wrote data: %02x", 358989f2807SJerry Jelinek cp[-1]); 359989f2807SJerry Jelinek #endif 360989f2807SJerry Jelinek } 361989f2807SJerry Jelinek 362989f2807SJerry Jelinek if (!kcs_write_last_byte(sc, *cp)) { 363989f2807SJerry Jelinek cmn_err(CE_WARN, 364989f2807SJerry Jelinek "KCS: Failed to write last dta byte"); 365989f2807SJerry Jelinek goto fail; 366989f2807SJerry Jelinek } 367989f2807SJerry Jelinek #ifdef KCS_DEBUG 368989f2807SJerry Jelinek cmn_err(CE_NOTE, "KCS: Wrote last data: %02x", 369989f2807SJerry Jelinek *cp); 370989f2807SJerry Jelinek #endif 371989f2807SJerry Jelinek } 372989f2807SJerry Jelinek 373989f2807SJerry Jelinek /* Read the reply. First, read the NetFn/LUN. */ 374989f2807SJerry Jelinek if (kcs_read_byte(sc, &data) != 1) { 375989f2807SJerry Jelinek cmn_err(CE_WARN, "KCS: Failed to read address"); 376989f2807SJerry Jelinek goto fail; 377989f2807SJerry Jelinek } 378989f2807SJerry Jelinek #ifdef KCS_DEBUG 379989f2807SJerry Jelinek cmn_err(CE_NOTE, "KCS: Read address: %02x", data); 380989f2807SJerry Jelinek #endif 381989f2807SJerry Jelinek if (data != IPMI_REPLY_ADDR(req->ir_addr)) { 382989f2807SJerry Jelinek cmn_err(CE_WARN, "KCS: Reply address mismatch"); 383989f2807SJerry Jelinek goto fail; 384989f2807SJerry Jelinek } 385989f2807SJerry Jelinek 386989f2807SJerry Jelinek /* Next we read the command. */ 387989f2807SJerry Jelinek if (kcs_read_byte(sc, &data) != 1) { 388989f2807SJerry Jelinek cmn_err(CE_WARN, "KCS: Failed to read command"); 389989f2807SJerry Jelinek goto fail; 390989f2807SJerry Jelinek } 391989f2807SJerry Jelinek #ifdef KCS_DEBUG 392989f2807SJerry Jelinek cmn_err(CE_NOTE, "KCS: Read command: %02x", data); 393989f2807SJerry Jelinek #endif 394989f2807SJerry Jelinek if (data != req->ir_command) { 395989f2807SJerry Jelinek cmn_err(CE_WARN, "KCS: Command mismatch"); 396989f2807SJerry Jelinek goto fail; 397989f2807SJerry Jelinek } 398989f2807SJerry Jelinek 399989f2807SJerry Jelinek /* Next we read the completion code. */ 400989f2807SJerry Jelinek if (kcs_read_byte(sc, &req->ir_compcode) != 1) { 401989f2807SJerry Jelinek cmn_err(CE_WARN, "KCS: Failed to read completion code"); 402989f2807SJerry Jelinek goto fail; 403989f2807SJerry Jelinek } 404989f2807SJerry Jelinek #ifdef KCS_DEBUG 405989f2807SJerry Jelinek cmn_err(CE_NOTE, "KCS: Read completion code: %02x", 406989f2807SJerry Jelinek req->ir_compcode); 407989f2807SJerry Jelinek #endif 408989f2807SJerry Jelinek 409989f2807SJerry Jelinek /* Finally, read the reply from the BMC. */ 410989f2807SJerry Jelinek i = 0; 411989f2807SJerry Jelinek for (;;) { 412989f2807SJerry Jelinek state = kcs_read_byte(sc, &data); 413989f2807SJerry Jelinek if (state == 0) { 414989f2807SJerry Jelinek cmn_err(CE_WARN, 415989f2807SJerry Jelinek "KCS: Read failed on byte %d", i + 1); 416989f2807SJerry Jelinek goto fail; 417989f2807SJerry Jelinek } 418989f2807SJerry Jelinek if (state == 2) 419989f2807SJerry Jelinek break; 420989f2807SJerry Jelinek if (i < req->ir_replybuflen) { 421989f2807SJerry Jelinek req->ir_reply[i] = data; 422989f2807SJerry Jelinek #ifdef KCS_DEBUG 423989f2807SJerry Jelinek cmn_err(CE_NOTE, "KCS: Read data %02x", 424989f2807SJerry Jelinek data); 425989f2807SJerry Jelinek } else { 426989f2807SJerry Jelinek cmn_err(CE_WARN, 427989f2807SJerry Jelinek "KCS: Read short %02x byte %d", data, i + 1); 428989f2807SJerry Jelinek #endif 429989f2807SJerry Jelinek } 430989f2807SJerry Jelinek i++; 431989f2807SJerry Jelinek } 432989f2807SJerry Jelinek req->ir_replylen = i; 433989f2807SJerry Jelinek #ifdef KCS_DEBUG 434989f2807SJerry Jelinek cmn_err(CE_NOTE, "KCS: READ finished (%d bytes)", i); 435989f2807SJerry Jelinek if (req->ir_replybuflen < i) 436989f2807SJerry Jelinek #else 437989f2807SJerry Jelinek if (req->ir_replybuflen < i && req->ir_replybuflen != 0) 438989f2807SJerry Jelinek #endif 439989f2807SJerry Jelinek cmn_err(CE_WARN, "KCS: Read short: %d buffer, %d actual", 440989f2807SJerry Jelinek (int)(req->ir_replybuflen), i); 441989f2807SJerry Jelinek return (1); 442989f2807SJerry Jelinek fail: 443989f2807SJerry Jelinek kcs_error(sc); 444989f2807SJerry Jelinek return (0); 445989f2807SJerry Jelinek } 446989f2807SJerry Jelinek 447989f2807SJerry Jelinek static void 448989f2807SJerry Jelinek kcs_loop(void *arg) 449989f2807SJerry Jelinek { 450989f2807SJerry Jelinek struct ipmi_softc *sc = arg; 451989f2807SJerry Jelinek struct ipmi_request *req; 452989f2807SJerry Jelinek int i, ok; 453989f2807SJerry Jelinek 454989f2807SJerry Jelinek IPMI_LOCK(sc); 455989f2807SJerry Jelinek while ((req = ipmi_dequeue_request(sc)) != NULL) { 4561e393477SMarcel Telka IPMI_UNLOCK(sc); 457989f2807SJerry Jelinek ok = 0; 458989f2807SJerry Jelinek for (i = 0; i < 3 && !ok; i++) 459989f2807SJerry Jelinek ok = kcs_polled_request(sc, req); 460989f2807SJerry Jelinek if (ok) 461989f2807SJerry Jelinek req->ir_error = 0; 462989f2807SJerry Jelinek else 463989f2807SJerry Jelinek req->ir_error = EIO; 4641e393477SMarcel Telka IPMI_LOCK(sc); 465989f2807SJerry Jelinek ipmi_complete_request(sc, req); 466989f2807SJerry Jelinek } 467989f2807SJerry Jelinek IPMI_UNLOCK(sc); 468989f2807SJerry Jelinek } 469989f2807SJerry Jelinek 470989f2807SJerry Jelinek static int 471989f2807SJerry Jelinek kcs_startup(struct ipmi_softc *sc) 472989f2807SJerry Jelinek { 473989f2807SJerry Jelinek sc->ipmi_kthread = taskq_create_proc("ipmi_kcs", 1, minclsyspri, 1, 1, 474989f2807SJerry Jelinek curzone->zone_zsched, TASKQ_PREPOPULATE); 475989f2807SJerry Jelinek 476989f2807SJerry Jelinek if (taskq_dispatch(sc->ipmi_kthread, kcs_loop, (void *) sc, 477989f2807SJerry Jelinek TQ_SLEEP) == NULL) { 478989f2807SJerry Jelinek taskq_destroy(sc->ipmi_kthread); 479989f2807SJerry Jelinek return (1); 480989f2807SJerry Jelinek } 481989f2807SJerry Jelinek 482989f2807SJerry Jelinek return (0); 483989f2807SJerry Jelinek } 484989f2807SJerry Jelinek 485989f2807SJerry Jelinek int 486989f2807SJerry Jelinek ipmi_kcs_attach(struct ipmi_softc *sc) 487989f2807SJerry Jelinek { 488989f2807SJerry Jelinek int status; 489989f2807SJerry Jelinek 490989f2807SJerry Jelinek /* Setup function pointers. */ 491989f2807SJerry Jelinek sc->ipmi_startup = kcs_startup; 492989f2807SJerry Jelinek sc->ipmi_enqueue_request = ipmi_polled_enqueue_request; 493989f2807SJerry Jelinek 494989f2807SJerry Jelinek /* See if we can talk to the controller. */ 495989f2807SJerry Jelinek status = INB(sc, KCS_CTL_STS); 496989f2807SJerry Jelinek if (status == 0xff) { 497989f2807SJerry Jelinek cmn_err(CE_CONT, "!KCS couldn't find it"); 498989f2807SJerry Jelinek return (ENXIO); 499989f2807SJerry Jelinek } 500989f2807SJerry Jelinek 501989f2807SJerry Jelinek timeout_usecs = drv_hztousec(MAX_TIMEOUT); 502989f2807SJerry Jelinek 503989f2807SJerry Jelinek #ifdef KCS_DEBUG 504989f2807SJerry Jelinek cmn_err(CE_NOTE, "KCS: initial state: %02x", status); 505989f2807SJerry Jelinek #endif 506989f2807SJerry Jelinek if (status & KCS_STATUS_OBF || 507989f2807SJerry Jelinek KCS_STATUS_STATE(status) != KCS_STATUS_STATE_IDLE) 508989f2807SJerry Jelinek kcs_error(sc); 509989f2807SJerry Jelinek 510989f2807SJerry Jelinek return (0); 511989f2807SJerry Jelinek } 512