XXXX introduce drv_sectohz

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