1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  *
  25  * The "bscbus" driver provides access to the LOMlite2 virtual registers,
  26  * so that its clients (children) need not be concerned with the details
  27  * of the access mechanism, which in this case is implemented via a
  28  * packet-based protocol over a Xbus (similar to ebus) parallel link to the
  29  * H8 host interface registers.
  30  *
  31  * On the other hand, this driver doesn't generally know what the virtual
  32  * registers signify - only the clients need this information.
  33  */
  34 
  35 
  36 #include <sys/note.h>
  37 #include <sys/types.h>
  38 #include <sys/conf.h>
  39 #include <sys/debug.h>
  40 #include <sys/errno.h>
  41 #include <sys/file.h>
  42 
  43 #if defined(__sparc)
  44 #include <sys/intr.h>
  45 #include <sys/membar.h>
  46 #endif
  47 
  48 #include <sys/kmem.h>
  49 #include <sys/modctl.h>
  50 #include <sys/note.h>
  51 #include <sys/open.h>
  52 #include <sys/poll.h>
  53 #include <sys/spl.h>
  54 #include <sys/stat.h>
  55 #include <sys/strlog.h>
  56 #include <sys/atomic.h>
  57 
  58 #include <sys/ddi.h>
  59 #include <sys/sunddi.h>
  60 #include <sys/sunndi.h>
  61 
  62 #include <sys/bscbus.h>
  63 
  64 #if     defined(NDI_ACC_HDL_V2)
  65 
  66 /*
  67  * Compiling for Solaris 10+ with access handle enhancements
  68  */
  69 #define HANDLE_TYPE             ndi_acc_handle_t
  70 #define HANDLE_ADDR(hdlp)       (hdlp->ah_addr)
  71 #define HANDLE_FAULT(hdlp)      (hdlp->ah_fault)
  72 #define HANDLE_MAPLEN(hdlp)     (hdlp->ah_len)
  73 #define HANDLE_PRIVATE(hdlp)    (hdlp->ah_bus_private)
  74 
  75 #else
  76 
  77 /*
  78  * Compatibility definitions for backport to Solaris 8/9
  79  */
  80 #define HANDLE_TYPE             ddi_acc_impl_t
  81 #define HANDLE_ADDR(hdlp)       (hdlp->ahi_common.ah_addr)
  82 #define HANDLE_FAULT(hdlp)      (hdlp->ahi_fault)
  83 #define HANDLE_MAPLEN(hdlp)     (hdlp->ahi_common.ah_len)
  84 #define HANDLE_PRIVATE(hdlp)    (hdlp->ahi_common.ah_bus_private)
  85 
  86 #define ddi_driver_major(dip)   ddi_name_to_major(ddi_binding_name(dip))
  87 
  88 #endif  /* NDI_ACC_HDL_V2 */
  89 
  90 
  91 /*
  92  * Local definitions
  93  */
  94 #define MYNAME                  "bscbus"
  95 #define NOMAJOR                 (~(major_t)0)
  96 #define DUMMY_VALUE             (~(int8_t)0)
  97 
  98 #define BSCBUS_INST_TO_MINOR(i) (i)
  99 #define BSCBUS_MINOR_TO_INST(m) (m)
 100 
 101 #define BSCBUS_MAX_CHANNELS     (4)
 102 
 103 #define BSCBUS_DUMMY_ADDRESS    ((caddr_t)0x0CADD1ED)
 104 #define ADDR_TO_OFFSET(a, hdlp) ((caddr_t)(a) - HANDLE_ADDR(hdlp))
 105 #define ADDR_TO_VREG(a)         ((caddr_t)(a) - BSCBUS_DUMMY_ADDRESS)
 106 #define VREG_TO_ADDR(v)         (BSCBUS_DUMMY_ADDRESS + (v))
 107 
 108 #ifdef DEBUG
 109 #define BSCBUS_LOGSTATUS
 110 #endif /* DEBUG */
 111 
 112 #ifdef BSCBUS_LOGSTATUS
 113 /*
 114  * BSC command logging routines.
 115  * Record the data passing to and from the BSC
 116  */
 117 
 118 typedef enum {
 119         BSC_CMD_BUSY = 1,               /* bsc reports busy     */
 120         BSC_CMD_CLEARING = 2,           /* clearing bsc busy    */
 121         BSC_CMD_CLEARED = 3,            /* cleared bsc busy     */
 122         BSC_CMD_SENDING = 4,            /* sending next byte    */
 123         BSC_CMD_SENT = 5,               /* sending last byte    */
 124         BSC_CMD_PENDING = 6,            /* got sent byte ack    */
 125         BSC_CMD_REPLY = 7,              /* got reply byte       */
 126         BSC_CMD_COMPLETE = 8,           /* command complete     */
 127         BSC_CMD_ERROR_SEQ = 9,          /* error status         */
 128         BSC_CMD_ERROR_STATUS = 10,      /* error status         */
 129         BSC_CMD_ERROR_OFLOW = 11,       /* error status         */
 130         BSC_CMD_ERROR_TOUT = 12,        /* error status         */
 131 
 132         BSC_CMD_PROCESS = 13,           /* async intr           */
 133         BSC_CMD_V1INTR = 14,            /* v1 intr              */
 134         BSC_CMD_V1INTRUNCL = 15,        /* v1 intr unclaim      */
 135         BSC_CMD_DOGPAT = 17             /* watchdog pat         */
 136 } bsc_cmd_stamp_t;
 137 
 138 typedef struct {
 139         hrtime_t        bcl_now;
 140         int             bcl_seq;
 141         bsc_cmd_stamp_t bcl_cat;
 142         uint8_t         bcl_chno;
 143         uint8_t         bcl_cmdstate;
 144         uint8_t         bcl_status;
 145         uint8_t         bcl_data;
 146 } bsc_cmd_log_t;
 147 
 148 uint32_t        bscbus_cmd_log_size = 1024;
 149 
 150 uint32_t        bscbus_cmd_log_flags = 0xffffffff;
 151 
 152 #endif /* BSCBUS_LOGSTATUS */
 153 
 154 /*
 155  * The following definitions are taken from the Hardware Manual for
 156  * the Hitachi H8S/2148 in conjunction with the hardware specification
 157  * for the Stiletto blade.
 158  *
 159  * Each instance of the host interface has 3 registers on the H8:
 160  * IDRn  - Input Data Register  - write-only for Solaris.
 161  *                                writes to this can be done via two
 162  *                                addresses - control and data.
 163  *                                The H8 can determine which address was
 164  *                                written by examining the C/D bit in
 165  *                                the status register.
 166  * ODRn  - Output Data Register - read-only for Solaris.
 167  *                                A read has the side effect of acknowledging
 168  *                                interrupts.
 169  * STRn  - Status Register      - read-only for Solaris.
 170  *
 171  *
 172  *
 173  * In terms of host access to this the Input and Output data registers are
 174  * mapped at the same address.
 175  */
 176 #define H8_IDRD 0
 177 #define H8_IDRC 1
 178 #define H8_ODR  0
 179 #define H8_STR  1
 180 
 181 #define H8_STR_OBF              0x01    /* data available in ODR */
 182 #define H8_STR_IBF              0x02    /* data for H8 in IDR */
 183 #define H8_STR_IDRC             0x08    /* last write to IDR was to IDRC */
 184                                         /* 0=data, 1=command */
 185 #define H8_STR_BUSY             0x04    /* H8 busy processing command */
 186 #define H8_STR_TOKENPROTOCOL    0x80    /* token-passing protocol */
 187 
 188 /*
 189  * Packet format ...
 190  */
 191 #define BSCBUS_MASK             0xc0    /* Byte-type bits               */
 192 #define BSCBUS_PARAM            0x00    /* Parameter byte: 0b0xxxxxxx   */
 193 #define BSCBUS_LAST             0x80    /* Last byte of packet          */
 194 #define BSCBUS_CMD              0x80    /* Command byte:   0b10###XWV   */
 195 #define BSCBUS_STATUS           0xc0    /* Status  byte:   0b11###AEV   */
 196 
 197 #define BSCBUS_SEQ              0x38    /* Sequence number bits         */
 198 #define BSCBUS_SEQ_LSB          0x08    /* Sequence number LSB          */
 199 #define BSCBUS_CMD_XADDR        0x04    /* Extended (2-byte) addressing */
 200 #define BSCBUS_CMD_WRITE        0x02    /* Write command                */
 201 #define BSCBUS_CMD_WMSB         0x01    /* Set MSB on Write             */
 202 #define BSCBUS_CMD_READ         0x01    /* Read command                 */
 203 #define BSCBUS_CMD_NOP          0x00    /* NOP command                  */
 204 
 205 #define BSCBUS_STATUS_ASYNC     0x04    /* Asynchronous event pending   */
 206 #define BSCBUS_STATUS_ERR       0x02    /* Error in command processing  */
 207 #define BSCBUS_STATUS_MSB       0x01    /* MSB of Value read            */
 208 
 209 #define BSCBUS_VREG_LO(x)       ((x) & ((1 << 7) - 1))
 210 #define BSCBUS_VREG_HI(x)       ((x) >> 7)
 211 
 212 #define BSCBUS_BUFSIZE          8
 213 
 214 #define BSCBUS_CHANNEL_TO_OFFSET(chno)  ((chno) * 2)    /* Register offset */
 215 
 216 /*
 217  * Time periods, in nanoseconds
 218  *
 219  * Note that LOMBUS_ONE_SEC and some other time
 220  * periods are defined in <sys/lombus.h>
 221  */
 222 #define BSCBUS_CMD_POLL                 (LOMBUS_ONE_SEC)
 223 #define BSCBUS_CMD_POLLNOINTS           (LOMBUS_ONE_SEC/20)
 224 #define BSCBUS_HWRESET_POLL             (LOMBUS_ONE_SEC/20)
 225 #define BSCBUS_HWRESET_TIMEOUT          (LOMBUS_ONE_SEC*2)
 226 
 227 #define BSCBUS_DOG_PAT_POLL_LIMIT       (1000)
 228 #define BSCBUS_DOG_PAT_POLL             (1)
 229 #define BSCBUS_PAT_RETRY_LIMIT  5
 230 
 231 /*
 232  * Local datatypes
 233  */
 234 enum bscbus_cmdstate {
 235         BSCBUS_CMDSTATE_IDLE,           /* No transaction in progress */
 236         BSCBUS_CMDSTATE_BUSY,           /* Setting up command */
 237         BSCBUS_CMDSTATE_CLEARING,       /* Clearing firmware busy status */
 238         BSCBUS_CMDSTATE_SENDING,        /* Waiting to send data to f/w */
 239         BSCBUS_CMDSTATE_PENDING,        /* Waiting for ack from f/w */
 240         BSCBUS_CMDSTATE_WAITING,        /* Waiting for status from f/w */
 241         BSCBUS_CMDSTATE_READY,          /* Status received/command done */
 242         BSCBUS_CMDSTATE_ERROR           /* Command failed with error */
 243 };
 244 
 245 struct bscbus_channel_state {
 246         /* Changes to these are protected by the instance ch_mutex mutex */
 247         struct bscbus_state     *ssp;
 248         uint8_t                 *ch_regs;
 249         ddi_acc_handle_t        ch_handle;  /* per channel access handle */
 250         unsigned int            chno;
 251         unsigned int            map_count; /* Number of mappings to channel */
 252         boolean_t               map_dog;   /* channel is mapped for watchdog */
 253 
 254         /*
 255          * Flag to indicate that we've incurred a hardware fault on
 256          * accesses to the H8; once this is set, we fake all further
 257          * accesses in order not to provoke additional bus errors.
 258          */
 259         boolean_t               xio_fault;
 260 
 261         /*
 262          * Data protected by the dog_mutex: the watchdog-patting
 263          * protocol data (since the dog can be patted from a high-level
 264          * cyclic), and the interrupt-enabled flag.
 265          */
 266         kmutex_t                dog_mutex[1];
 267         unsigned int            pat_retry_count;
 268         unsigned int            pat_fail_count;
 269 
 270         /*
 271          * Serial protocol state data, protected by lo_mutex
 272          * (which is initialised using <lo_iblk>)
 273          */
 274         kmutex_t                lo_mutex[1];
 275         ddi_iblock_cookie_t     lo_iblk;
 276         kcondvar_t              lo_cv[1];
 277         int                     unclaimed_count;
 278 
 279         volatile enum bscbus_cmdstate cmdstate;
 280         clock_t                 deadline;
 281         clock_t                 poll_hz;
 282         boolean_t               interrupt_failed;
 283         uint8_t                 cmdbuf[BSCBUS_BUFSIZE];
 284         uint8_t                 *cmdp;  /* Points to last tx'd in cmdbuf */
 285         uint8_t                 reply[BSCBUS_BUFSIZE];
 286         uint8_t                 async;
 287         uint8_t                 index;
 288         uint8_t                 result;
 289         uint8_t                 sequence;
 290         uint32_t                error;
 291 };
 292 
 293 #define BSCBUS_TX_PENDING(csp)          ((csp)->cmdp > (csp)->cmdbuf)
 294 
 295 /*
 296  * This driver's soft-state structure
 297  */
 298 
 299 struct bscbus_state {
 300         /*
 301          * Configuration data, set during attach
 302          */
 303         dev_info_t              *dip;
 304         major_t                 majornum;
 305         int                     instance;
 306 
 307         ddi_acc_handle_t        h8_handle;
 308         uint8_t                 *h8_regs;
 309 
 310         /*
 311          * Parameters derived from .conf properties
 312          */
 313         uint32_t                debug;
 314 
 315         /*
 316          * Flag to indicate that we are using per channel
 317          * mapping of the register sets and interrupts.
 318          * reg set 0 is chan 0
 319          * reg set 1 is chan 1 ...
 320          *
 321          * Interrupts are specified in that order but later
 322          * channels may not have interrupts.
 323          */
 324         boolean_t               per_channel_regs;
 325 
 326         /*
 327          * channel state data, protected by ch_mutex
 328          * channel claim/release requests are protected by this mutex.
 329          */
 330         kmutex_t                ch_mutex[1];
 331         struct bscbus_channel_state     channel[BSCBUS_MAX_CHANNELS];
 332 
 333 #ifdef BSCBUS_LOGSTATUS
 334         /*
 335          * Command logging buffer for recording transactions with the
 336          * BSC. This is useful for debugging failed transactions and other
 337          * such funnies.
 338          */
 339         bsc_cmd_log_t           *cmd_log;
 340         uint32_t                cmd_log_idx;
 341         uint32_t                cmd_log_size;
 342         uint32_t                cmd_log_flags;
 343 #endif /* BSCBUS_LOGSTATUS */
 344 };
 345 
 346 /*
 347  * The auxiliary structure attached to each child
 348  * (the child's parent-private-data points to this).
 349  */
 350 struct bscbus_child_info {
 351         lombus_regspec_t *rsp;
 352         int nregs;
 353 };
 354 
 355 #ifdef BSCBUS_LOGSTATUS
 356 void bscbus_cmd_log(struct bscbus_channel_state *, bsc_cmd_stamp_t,
 357     uint8_t, uint8_t);
 358 #else /* BSCBUS_LOGSTATUS */
 359 #define bscbus_cmd_log(state, stamp, status, data)
 360 #endif /* BSCBUS_LOGSTATUS */
 361 
 362 
 363 /*
 364  * Local data
 365  */
 366 
 367 static void *bscbus_statep;
 368 
 369 static major_t bscbus_major = NOMAJOR;
 370 
 371 static ddi_device_acc_attr_t bscbus_dev_acc_attr[1] = {
 372         DDI_DEVICE_ATTR_V0,
 373         DDI_STRUCTURE_LE_ACC,
 374         DDI_STRICTORDER_ACC
 375 };
 376 
 377 
 378 /*
 379  *  General utility routines ...
 380  */
 381 
 382 #ifdef DEBUG
 383 static void
 384 bscbus_trace(struct bscbus_channel_state *csp, char code, const char *caller,
 385         const char *fmt, ...)
 386 {
 387         char buf[256];
 388         char *p;
 389         va_list va;
 390 
 391         if (csp->ssp->debug & (1 << (code-'@'))) {
 392                 p = buf;
 393                 (void) snprintf(p, sizeof (buf) - (p - buf),
 394                     "%s/%s: ", MYNAME, caller);
 395                 p += strlen(p);
 396 
 397                 va_start(va, fmt);
 398                 (void) vsnprintf(p, sizeof (buf) - (p - buf), fmt, va);
 399                 va_end(va);
 400 
 401                 buf[sizeof (buf) - 1] = '\0';
 402                 (void) strlog(csp->ssp->majornum, csp->ssp->instance,
 403                     code, SL_TRACE, buf);
 404         }
 405 }
 406 #else /* DEBUG */
 407 #define bscbus_trace
 408 #endif /* DEBUG */
 409 
 410 static struct bscbus_state *
 411 bscbus_getstate(dev_info_t *dip, int instance, const char *caller)
 412 {
 413         struct bscbus_state *ssp = NULL;
 414         dev_info_t *sdip = NULL;
 415         major_t dmaj = NOMAJOR;
 416 
 417         if (dip != NULL) {
 418                 /*
 419                  * Use the instance number from the <dip>; also,
 420                  * check that it really corresponds to this driver
 421                  */
 422                 instance = ddi_get_instance(dip);
 423                 dmaj = ddi_driver_major(dip);
 424                 if (bscbus_major == NOMAJOR && dmaj != NOMAJOR)
 425                         bscbus_major = dmaj;
 426                 else if (dmaj != bscbus_major) {
 427                         cmn_err(CE_WARN,
 428                             "%s: major number mismatch (%d vs. %d) in %s(),"
 429                             "probably due to child misconfiguration",
 430                             MYNAME, bscbus_major, dmaj, caller);
 431                         instance = -1;
 432                 }
 433         }
 434 
 435         if (instance >= 0)
 436                 ssp = ddi_get_soft_state(bscbus_statep, instance);
 437         if (ssp != NULL) {
 438                 sdip = ssp->dip;
 439                 if (dip == NULL && sdip == NULL)
 440                         ssp = NULL;
 441                 else if (dip != NULL && sdip != NULL && sdip != dip) {
 442                         cmn_err(CE_WARN,
 443                             "%s: devinfo mismatch (%p vs. %p) in %s(), "
 444                             "probably due to child misconfiguration",
 445                             MYNAME, (void *)dip, (void *)sdip, caller);
 446                         ssp = NULL;
 447                 }
 448         }
 449 
 450         return (ssp);
 451 }
 452 
 453 /*
 454  * Lowest-level I/O register read/write
 455  */
 456 
 457 static void
 458 bscbus_put_reg(struct bscbus_channel_state *csp, uint_t reg, uint8_t val)
 459 {
 460         if (csp->ch_handle != NULL && !csp->xio_fault) {
 461                 ddi_put8(csp->ch_handle,
 462                     csp->ch_regs + reg, val);
 463         }
 464 }
 465 
 466 static uint8_t
 467 bscbus_get_reg(struct bscbus_channel_state *csp, uint_t reg)
 468 {
 469         uint8_t val;
 470 
 471         if (csp->ch_handle != NULL && !csp->xio_fault)
 472                 val = ddi_get8(csp->ch_handle,
 473                     csp->ch_regs + reg);
 474         else
 475                 val = DUMMY_VALUE;
 476 
 477         return (val);
 478 }
 479 
 480 static void
 481 bscbus_check_fault_status(struct bscbus_channel_state *csp)
 482 {
 483         csp->xio_fault =
 484             ddi_check_acc_handle(csp->ch_handle) != DDI_SUCCESS;
 485 }
 486 
 487 static boolean_t
 488 bscbus_faulty(struct bscbus_channel_state *csp)
 489 {
 490         if (!csp->xio_fault)
 491                 bscbus_check_fault_status(csp);
 492         return (csp->xio_fault);
 493 }
 494 
 495 /*
 496  * Write data into h8 registers
 497  */
 498 static void
 499 bscbus_pat_dog(struct bscbus_channel_state *csp, uint8_t val)
 500 {
 501         uint8_t status;
 502         uint32_t doglimit = BSCBUS_DOG_PAT_POLL_LIMIT;
 503 
 504         bscbus_trace(csp, 'W', "bscbus_pat_dog:", "");
 505 
 506         bscbus_cmd_log(csp, BSC_CMD_DOGPAT, 0, val);
 507         status = bscbus_get_reg(csp, H8_STR);
 508         while (status & H8_STR_IBF) {
 509                 if (csp->pat_retry_count > BSCBUS_PAT_RETRY_LIMIT) {
 510                         /*
 511                          * Previous attempts to contact BSC have failed.
 512                          * Do not bother waiting for it to eat previous
 513                          * data.
 514                          * Pat anyway just in case the BSC is really alive
 515                          * and the IBF bit is lying.
 516                          */
 517                         bscbus_put_reg(csp, H8_IDRC, val);
 518                         bscbus_trace(csp, 'W', "bscbus_pat_dog:",
 519                             "retry count exceeded");
 520                         return;
 521                 }
 522                 if (--doglimit == 0) {
 523                         /* The BSC is not responding - give up */
 524                         csp->pat_fail_count++;
 525                         csp->pat_retry_count++;
 526                         /* Pat anyway just in case the BSC is really alive */
 527                         bscbus_put_reg(csp, H8_IDRC, val);
 528                         bscbus_trace(csp, 'W', "bscbus_pat_dog:",
 529                             "poll limit exceeded");
 530                         return;
 531                 }
 532                 drv_usecwait(BSCBUS_DOG_PAT_POLL);
 533                 status = bscbus_get_reg(csp, H8_STR);
 534         }
 535         bscbus_put_reg(csp, H8_IDRC, val);
 536         csp->pat_retry_count = 0;
 537 }
 538 
 539 /*
 540  * State diagrams for how bscbus_process works.
 541  *      BSCBUS_CMDSTATE_IDLE            No transaction in progress
 542  *      BSCBUS_CMDSTATE_BUSY            Setting up command
 543  *      BSCBUS_CMDSTATE_CLEARING        Clearing firmware busy status
 544  *      BSCBUS_CMDSTATE_SENDING         Waiting to send data to f/w
 545  *      BSCBUS_CMDSTATE_PENDING         Waiting for ack from f/w
 546  *      BSCBUS_CMDSTATE_WAITING         Waiting for status from f/w
 547  *      BSCBUS_CMDSTATE_READY           Status received/command done
 548  *      BSCBUS_CMDSTATE_ERROR           Command failed with error
 549  *
 550  *      +----------+
 551  *      |          |
 552  *      | IDLE/BUSY|
 553  *      |   (0/1)  |  abnormal
 554  *      +----------+  state
 555  *          |     \   detected
 556  *          |      \------>------+  +----<---+
 557  *      bsc |                    |  |        |
 558  *      is  |                    V  V        |
 559  *     ready|                +----------+    |
 560  *          |                |          |    ^
 561  *          |                | CLEARING |    |
 562  *          |                |   (2)    |    |
 563  *          |                +----------+    |
 564  *          |            cleared /  | \      | more to clear
 565  *          |                   /   |  \-->--+
 566  *          |  +-------<-------/    V
 567  *          |  |                    |
 568  *          V  V                    |timeout
 569  *      +----------+ timeout        |
 570  *      |          |------>---------+--------+
 571  *      | SENDING  |                         |
 572  *      |   (3)    |------<-------+       |
 573  *      +----------+              |          V
 574  *      sent|    \ send           ^ack       |
 575  *      last|     \ next          |received  |
 576  *          |      \         +----------+    |
 577  *          |       \        |          |    |
 578  *          |        \------>| PENDING       |-->-+
 579  *          |                |   (4)    |    |
 580  *          |                +----------+    |timeout
 581  *          |    +---<----+               |
 582  *          |    |        |                  |
 583  *          V    V        |                  |
 584  *      +----------+      |                  |
 585  *      |          |      |                  |
 586  *      | WAITING  |      ^                  |
 587  *      |   (5)    |      |                  |
 588  *      +----------+      |                  |
 589  *          |  | |more    |                  |
 590  *          |  V |required|                  |
 591  *      done|  | +--->----+               |
 592  *          |  +--->--------------+  +---<---+
 593  *          |   error/timeout     |  |
 594  *          V                     V  V
 595  *      +----------+          +----------+
 596  *      |          |          |          |
 597  *      | READY    |          |  ERROR   |
 598  *      |   (7)    |          |   (6)    |
 599  *      +----------+          +----------+
 600  *          |                     |
 601  *          V                     V
 602  *          |                     |
 603  *          +------>---+---<------+
 604  *                     |
 605  *                     |
 606  *                   Back to
 607  *                    Idle
 608  */
 609 
 610 static void
 611 bscbus_process_sending(struct bscbus_channel_state *csp, uint8_t status)
 612 {
 613         /*
 614          * When we get here we actually expect H8_STR_IBF to
 615          * be clear but we check just in case of problems.
 616          */
 617         ASSERT(BSCBUS_TX_PENDING(csp));
 618         if (!(status & H8_STR_IBF)) {
 619                 bscbus_put_reg(csp, H8_IDRD, *--csp->cmdp);
 620                 bscbus_trace(csp, 'P', "bscbus_process_sending",
 621                     "state %d; val $%x",
 622                     csp->cmdstate, *csp->cmdp);
 623                 if (!BSCBUS_TX_PENDING(csp)) {
 624                         bscbus_cmd_log(csp, BSC_CMD_SENT,
 625                             status, *csp->cmdp);
 626                         /* No more pending - move to waiting state */
 627                         bscbus_trace(csp, 'P', "bscbus_process_sending",
 628                             "moving to waiting");
 629                         csp->cmdstate = BSCBUS_CMDSTATE_WAITING;
 630                         /* Extend deadline because time has moved on */
 631                         csp->deadline = ddi_get_lbolt() +
 632                             drv_usectohz(LOMBUS_CMD_TIMEOUT/1000);
 633                 } else {
 634                         /* Wait for ack of this byte */
 635                         bscbus_cmd_log(csp, BSC_CMD_SENDING,
 636                             status, *csp->cmdp);
 637                         csp->cmdstate = BSCBUS_CMDSTATE_PENDING;
 638                         bscbus_trace(csp, 'P', "bscbus_process_sending",
 639                             "moving to pending");
 640                 }
 641         }
 642 }
 643 
 644 static void
 645 bscbus_process_clearing(struct bscbus_channel_state *csp,
 646     uint8_t status, uint8_t data)
 647 {
 648         /*
 649          * We only enter this state if H8_STR_BUSY was set when
 650          * we started the transaction. We just ignore all received
 651          * data until we see OBF set AND BUSY cleared.
 652          * It is not good enough to see BUSY clear on its own
 653          */
 654         if ((status & H8_STR_OBF) && !(status & H8_STR_BUSY)) {
 655                 bscbus_cmd_log(csp, BSC_CMD_CLEARED, status, data);
 656                 csp->cmdstate = BSCBUS_CMDSTATE_SENDING;
 657                 /* Throw away any data received up until now */
 658                 bscbus_trace(csp, 'P', "bscbus_process_clearing",
 659                     "busy cleared");
 660                 /*
 661                  * Send the next byte immediately.
 662                  * At this stage we should clear the OBF flag because that
 663                  * data has been used. IBF is still valid so do not clear that.
 664                  */
 665                 status &= ~(H8_STR_OBF);
 666                 bscbus_process_sending(csp, status);
 667         } else {
 668                 if (status & H8_STR_OBF) {
 669                         bscbus_cmd_log(csp, BSC_CMD_CLEARING, status, data);
 670                 }
 671         }
 672 }
 673 
 674 static void
 675 bscbus_process_pending(struct bscbus_channel_state *csp, uint8_t status)
 676 {
 677         /* We are waiting for an acknowledgement of a byte */
 678         if (status & H8_STR_OBF) {
 679                 bscbus_cmd_log(csp, BSC_CMD_PENDING,
 680                     status, *csp->cmdp);
 681                 bscbus_trace(csp, 'P', "bscbus_process_pending",
 682                     "moving to sending");
 683                 csp->cmdstate = BSCBUS_CMDSTATE_SENDING;
 684                 /*
 685                  * Send the next byte immediately.
 686                  * At this stage we should clear the OBF flag because that
 687                  * data has been used. IBF is still valid so do not clear that.
 688                  */
 689                 status &= ~(H8_STR_OBF);
 690                 bscbus_process_sending(csp, status);
 691         }
 692 }
 693 
 694 static boolean_t
 695 bscbus_process_waiting(struct bscbus_channel_state *csp,
 696     uint8_t status, uint8_t data)
 697 {
 698         uint8_t rcvd = 0;
 699         boolean_t ready = B_FALSE;
 700         uint8_t tmp;
 701 
 702         if (status & H8_STR_OBF) {
 703                 csp->reply[rcvd = csp->index] = data;
 704                 if (++rcvd < BSCBUS_BUFSIZE)
 705                         csp->index = rcvd;
 706 
 707                 bscbus_trace(csp, 'D', "bscbus_process_waiting",
 708                     "rcvd %d: $%02x $%02x $%02x $%02x $%02x $%02x $%02x $%02x",
 709                     rcvd,
 710                     csp->reply[0], csp->reply[1],
 711                     csp->reply[2], csp->reply[3],
 712                     csp->reply[4], csp->reply[5],
 713                     csp->reply[6], csp->reply[7]);
 714         }
 715 
 716         if (rcvd == 0) {
 717                 /*
 718                  * No bytes received this time through (though there
 719                  * might be a partial packet sitting in the buffer).
 720                  */
 721                 /* EMPTY */
 722                 ;
 723         } else if (rcvd >= BSCBUS_BUFSIZE) {
 724                 /*
 725                  * Buffer overflow; discard the data & treat as an error
 726                  * (even if the last byte read did claim to terminate a
 727                  * packet, it can't be a valid one 'cos it's too long!)
 728                  */
 729                 bscbus_cmd_log(csp, BSC_CMD_ERROR_OFLOW, status, data);
 730                 csp->index = 0;
 731                 csp->cmdstate = BSCBUS_CMDSTATE_ERROR;
 732                 csp->error = LOMBUS_ERR_OFLOW;
 733                 ready = B_TRUE;
 734         } else if ((data & BSCBUS_LAST) == 0) {
 735                 /*
 736                  * Packet not yet complete; leave the partial packet in
 737                  * the buffer for later ...
 738                  */
 739                 bscbus_cmd_log(csp, BSC_CMD_REPLY, status, data);
 740         } else if ((data & BSCBUS_MASK) != BSCBUS_STATUS) {
 741                 /* Invalid "status" byte - maybe an echo of the command? */
 742                 bscbus_cmd_log(csp, BSC_CMD_ERROR_STATUS, status, data);
 743 
 744                 csp->cmdstate = BSCBUS_CMDSTATE_ERROR;
 745                 csp->error = LOMBUS_ERR_BADSTATUS;
 746                 ready = B_TRUE;
 747         } else if ((data & BSCBUS_SEQ) != csp->sequence) {
 748                 /* Wrong sequence number!  Flag this as an error */
 749                 bscbus_cmd_log(csp, BSC_CMD_ERROR_SEQ, status, data);
 750 
 751                 csp->cmdstate = BSCBUS_CMDSTATE_ERROR;
 752                 csp->error = LOMBUS_ERR_SEQUENCE;
 753                 ready = B_TRUE;
 754         } else {
 755                 /*
 756                  * Finally, we know that's it's a valid reply to our
 757                  * last command.  Update the ASYNC status, derive the
 758                  * reply parameter (if any), and check the ERROR bit
 759                  * to find out what the parameter means.
 760                  *
 761                  * Note that not all the values read/assigned here
 762                  * are meaningful, but it doesn't matter; the waiting
 763                  * thread will know which one(s) it should check.
 764                  */
 765                 bscbus_cmd_log(csp, BSC_CMD_COMPLETE, status, data);
 766                 csp->async = (data & BSCBUS_STATUS_ASYNC) ? 1 : 0;
 767 
 768                 tmp = ((data & BSCBUS_STATUS_MSB) ? 0x80 : 0) | csp->reply[0];
 769                 if (data & BSCBUS_STATUS_ERR) {
 770                         csp->cmdstate = BSCBUS_CMDSTATE_ERROR;
 771                         csp->error = tmp;
 772                 } else {
 773                         csp->cmdstate = BSCBUS_CMDSTATE_READY;
 774                         csp->result = tmp;
 775                 }
 776                 ready = B_TRUE;
 777         }
 778         return (ready);
 779 }
 780 
 781 /*
 782  * Packet receive handler
 783  *
 784  * This routine should be called from the low-level softint,
 785  * or bscbus_cmd() (for polled operation), with the
 786  * low-level mutex already held.
 787  */
 788 static void
 789 bscbus_process(struct bscbus_channel_state *csp,
 790     uint8_t status, uint8_t data)
 791 {
 792         boolean_t ready = B_FALSE;
 793 
 794         ASSERT(mutex_owned(csp->lo_mutex));
 795 
 796         if ((status & H8_STR_OBF) || (status & H8_STR_IBF)) {
 797                 bscbus_trace(csp, 'D', "bscbus_process",
 798                     "state %d; error $%x",
 799                     csp->cmdstate, csp->error);
 800         }
 801 
 802         switch (csp->cmdstate) {
 803         case BSCBUS_CMDSTATE_CLEARING:
 804                 bscbus_process_clearing(csp, status, data);
 805                 break;
 806         case BSCBUS_CMDSTATE_SENDING:
 807                 bscbus_process_sending(csp, status);
 808                 break;
 809         case BSCBUS_CMDSTATE_PENDING:
 810                 bscbus_process_pending(csp, status);
 811                 break;
 812         case BSCBUS_CMDSTATE_WAITING:
 813                 ready = bscbus_process_waiting(csp, status, data);
 814                 break;
 815         default:
 816                 /* Nothing to do */
 817                 break;
 818         }
 819 
 820         /*
 821          * Check for timeouts - but only if the command has not yet
 822          * completed (ready is true when command completes in this
 823          * call to bscbus_process OR cmdstate is READY or ERROR if
 824          * this is a spurious call to bscbus_process i.e. a spurious
 825          * interrupt)
 826          */
 827         if (!ready &&
 828             ((ddi_get_lbolt() - csp->deadline) > 0) &&
 829             csp->cmdstate != BSCBUS_CMDSTATE_READY &&
 830             csp->cmdstate != BSCBUS_CMDSTATE_ERROR) {
 831                 bscbus_trace(csp, 'P', "bscbus_process",
 832                     "timeout previous state %d; error $%x",
 833                     csp->cmdstate, csp->error);
 834                 bscbus_cmd_log(csp, BSC_CMD_ERROR_TOUT, status, data);
 835                 if (csp->cmdstate == BSCBUS_CMDSTATE_CLEARING) {
 836                         /* Move onto sending because busy might be stuck */
 837                         csp->cmdstate = BSCBUS_CMDSTATE_SENDING;
 838                         /* Extend timeout relative to original start time */
 839                         csp->deadline += drv_usectohz(LOMBUS_CMD_TIMEOUT/1000);
 840                 } else if (csp->cmdstate != BSCBUS_CMDSTATE_IDLE) {
 841                         csp->cmdstate = BSCBUS_CMDSTATE_ERROR;
 842                         csp->error = LOMBUS_ERR_TIMEOUT;
 843                 }
 844                 ready = B_TRUE;
 845         }
 846 
 847         if ((status & H8_STR_OBF) || (status & H8_STR_IBF) || ready) {
 848                 bscbus_trace(csp, 'D', "bscbus_process",
 849                     "last $%02x; state %d; error $%x; ready %d",
 850                     data, csp->cmdstate, csp->error, ready);
 851         }
 852         if (ready)
 853                 cv_broadcast(csp->lo_cv);
 854 }
 855 
 856 static uint_t
 857 bscbus_hwintr(caddr_t arg)
 858 {
 859         struct bscbus_channel_state *csp = (void *)arg;
 860 
 861         uint8_t status;
 862         uint8_t data = 0xb0 /* Dummy value */;
 863 
 864         mutex_enter(csp->lo_mutex);
 865         /*
 866          * Read the registers to ensure that the interrupt is cleared.
 867          * Status must be read first because reading data changes the
 868          * status.
 869          * We always read the data because that clears the interrupt down.
 870          * This is horrible hardware semantics but we have to do it!
 871          */
 872         status = bscbus_get_reg(csp, H8_STR);
 873         data = bscbus_get_reg(csp, H8_ODR);
 874         if (!(status & H8_STR_OBF)) {
 875                 bscbus_cmd_log(csp, BSC_CMD_V1INTRUNCL, status, data);
 876                 csp->unclaimed_count++;
 877         } else {
 878                 bscbus_cmd_log(csp, BSC_CMD_V1INTR, status, data);
 879         }
 880         if (status & H8_STR_TOKENPROTOCOL) {
 881                 bscbus_process(csp, status, data);
 882                 if (csp->interrupt_failed) {
 883                         bscbus_trace(csp, 'I', "bscbus_hwintr:",
 884                             "interrupt fault cleared channel %d", csp->chno);
 885                         csp->interrupt_failed = B_FALSE;
 886                         csp->poll_hz = drv_usectohz(BSCBUS_CMD_POLL / 1000);
 887                 }
 888         }
 889 
 890         mutex_exit(csp->lo_mutex);
 891         return (DDI_INTR_CLAIMED);
 892 }
 893 
 894 void
 895 bscbus_poll(struct bscbus_channel_state *csp)
 896 {
 897         /*
 898          * This routine is only called if we timeout in userland
 899          * waiting for an interrupt. This generally means that we have
 900          * lost interrupt capabilities or that something has gone
 901          * wrong.  In this case we are allowed to access the hardware
 902          * and read the data register if necessary.
 903          * If interrupts return then recovery actions should mend us!
 904          */
 905         uint8_t status;
 906         uint8_t data = 0xfa; /* Dummy value */
 907 
 908         ASSERT(mutex_owned(csp->lo_mutex));
 909 
 910         /* Should look for data to receive */
 911         status = bscbus_get_reg(csp, H8_STR);
 912         if (status & H8_STR_OBF) {
 913                 /* There is data available */
 914                 data = bscbus_get_reg(csp, H8_ODR);
 915                 bscbus_cmd_log(csp, BSC_CMD_PROCESS, status, data);
 916         }
 917         bscbus_process(csp, status, data);
 918 }
 919 
 920 /*
 921  * Serial protocol
 922  *
 923  * This routine builds a command and sets it in progress.
 924  */
 925 static uint8_t
 926 bscbus_cmd(HANDLE_TYPE *hdlp, ptrdiff_t vreg, uint_t val, uint_t cmd)
 927 {
 928         struct bscbus_channel_state *csp;
 929         clock_t start;
 930         uint8_t status;
 931 
 932         /*
 933          * First of all, wait for the interface to be available.
 934          *
 935          * NOTE: we blow through all the mutex/cv/state checking and
 936          * preempt any command in progress if the system is panicking!
 937          */
 938         csp = HANDLE_PRIVATE(hdlp);
 939         mutex_enter(csp->lo_mutex);
 940         while (csp->cmdstate != BSCBUS_CMDSTATE_IDLE && !ddi_in_panic())
 941                 cv_wait(csp->lo_cv, csp->lo_mutex);
 942 
 943         csp->cmdstate = BSCBUS_CMDSTATE_BUSY;
 944         csp->sequence = (csp->sequence + BSCBUS_SEQ_LSB) & BSCBUS_SEQ;
 945 
 946         /*
 947          * We have exclusive ownership, so assemble the command (backwards):
 948          *
 949          * [byte 0]     Command:        modified by XADDR and/or WMSB bits
 950          * [Optional] Parameter:        Value to write (low 7 bits)
 951          * [Optional] Parameter:        Register number (high 7 bits)
 952          * [Optional] Parameter:        Register number (low 7 bits)
 953          */
 954         csp->cmdp = &csp->cmdbuf[0];
 955         *csp->cmdp++ = BSCBUS_CMD | csp->sequence | cmd;
 956         switch (cmd) {
 957         case BSCBUS_CMD_WRITE:
 958                 *csp->cmdp++ = val & 0x7f;
 959                 if (val >= 0x80)
 960                         csp->cmdbuf[0] |= BSCBUS_CMD_WMSB;
 961                 /*FALLTHRU*/
 962         case BSCBUS_CMD_READ:
 963                 if (BSCBUS_VREG_HI(vreg) != 0) {
 964                         *csp->cmdp++ = BSCBUS_VREG_HI(vreg);
 965                         csp->cmdbuf[0] |= BSCBUS_CMD_XADDR;
 966                 }
 967                 *csp->cmdp++ = BSCBUS_VREG_LO(vreg);
 968                 /*FALLTHRU*/
 969         case BSCBUS_CMD_NOP:
 970                 break;
 971         }
 972 
 973         /*
 974          * Check and update the H8 h/w fault status before accessing
 975          * the chip registers.  If there's a (new or previous) fault,
 976          * we'll run through the protocol but won't really touch the
 977          * hardware and all commands will timeout.  If a previously
 978          * discovered fault has now gone away (!), then we can (try to)
 979          * proceed with the new command (probably a probe).
 980          */
 981         bscbus_check_fault_status(csp);
 982 
 983         /*
 984          * Prepare for the command (to be processed by the interrupt
 985          * handler and/or polling loop below), and wait for a response
 986          * or timeout.
 987          */
 988         start = ddi_get_lbolt();
 989         csp->deadline = start + drv_usectohz(LOMBUS_CMD_TIMEOUT/1000);
 990         csp->error = 0;
 991         csp->index = 0;
 992         csp->result = DUMMY_VALUE;
 993 
 994         status = bscbus_get_reg(csp, H8_STR);
 995         if (status & H8_STR_BUSY) {
 996                 bscbus_cmd_log(csp, BSC_CMD_BUSY, status, 0xfd);
 997                 /*
 998                  * Must ensure that the busy state has cleared before
 999                  * sending the command
1000                  */
1001                 csp->cmdstate = BSCBUS_CMDSTATE_CLEARING;
1002                 bscbus_trace(csp, 'P', "bscbus_cmd",
1003                     "h8 reporting status (%x) busy - clearing", status);
1004         } else {
1005                 /* It is clear to send the command immediately */
1006                 csp->cmdstate = BSCBUS_CMDSTATE_SENDING;
1007                 bscbus_trace(csp, 'P', "bscbus_cmd",
1008                     "sending first byte of command, status %x", status);
1009                 bscbus_poll(csp);
1010         }
1011 
1012         csp->poll_hz = drv_usectohz(
1013             (csp->interrupt_failed ?
1014             BSCBUS_CMD_POLLNOINTS : BSCBUS_CMD_POLL) / 1000);
1015 
1016         while ((csp->cmdstate != BSCBUS_CMDSTATE_READY) &&
1017             (csp->cmdstate != BSCBUS_CMDSTATE_ERROR)) {
1018                 ASSERT(csp->cmdstate != BSCBUS_CMDSTATE_IDLE);
1019 
1020                 if ((cv_reltimedwait(csp->lo_cv, csp->lo_mutex,
1021                     csp->poll_hz, TR_CLOCK_TICK) == -1) &&
1022                     csp->cmdstate != BSCBUS_CMDSTATE_READY &&
1023                     csp->cmdstate != BSCBUS_CMDSTATE_ERROR) {
1024                         if (!csp->interrupt_failed) {
1025                                 bscbus_trace(csp, 'I', "bscbus_cmd:",
1026                                     "interrupt_failed channel %d", csp->chno);
1027                                 csp->interrupt_failed = B_TRUE;
1028                                 csp->poll_hz = drv_usectohz(
1029                                     BSCBUS_CMD_POLLNOINTS / 1000);
1030                         }
1031                         bscbus_poll(csp);
1032                 }
1033         }
1034 
1035         /*
1036          * The return value may not be meaningful but retrieve it anyway
1037          */
1038         val = csp->result;
1039         if (bscbus_faulty(csp)) {
1040                 val = DUMMY_VALUE;
1041                 HANDLE_FAULT(hdlp) = LOMBUS_ERR_SIOHW;
1042         } else if (csp->cmdstate != BSCBUS_CMDSTATE_READY) {
1043                 /*
1044                  * Some problem here ... transfer the error code from
1045                  * the per-instance state to the per-handle fault flag.
1046                  * The error code shouldn't be zero!
1047                  */
1048                 if (csp->error != 0)
1049                         HANDLE_FAULT(hdlp) = csp->error;
1050                 else
1051                         HANDLE_FAULT(hdlp) = LOMBUS_ERR_BADERRCODE;
1052         }
1053 
1054         /*
1055          * All done now!
1056          */
1057         csp->index = 0;
1058         csp->cmdstate = BSCBUS_CMDSTATE_IDLE;
1059         cv_broadcast(csp->lo_cv);
1060         mutex_exit(csp->lo_mutex);
1061 
1062         return (val);
1063 }
1064 
1065 /*
1066  * Space 0 - LOM virtual register access
1067  * Only 8-bit accesses are supported.
1068  */
1069 static uint8_t
1070 bscbus_vreg_get8(HANDLE_TYPE *hdlp, uint8_t *addr)
1071 {
1072         ptrdiff_t offset;
1073 
1074         /*
1075          * Check the offset that the caller has added to the base address
1076          * against the length of the mapping originally requested.
1077          */
1078         offset = ADDR_TO_OFFSET(addr, hdlp);
1079         if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) {
1080                 /*
1081                  * Invalid access - flag a fault and return a dummy value
1082                  */
1083                 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
1084                 return (DUMMY_VALUE);
1085         }
1086 
1087         /*
1088          * Derive the virtual register number and run the command
1089          */
1090         return (bscbus_cmd(hdlp, ADDR_TO_VREG(addr), 0, BSCBUS_CMD_READ));
1091 }
1092 
1093 static void
1094 bscbus_vreg_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val)
1095 {
1096         ptrdiff_t offset;
1097 
1098         /*
1099          * Check the offset that the caller has added to the base address
1100          * against the length of the mapping originally requested.
1101          */
1102         offset = ADDR_TO_OFFSET(addr, hdlp);
1103         if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) {
1104                 /*
1105                  * Invalid access - flag a fault and return
1106                  */
1107                 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
1108                 return;
1109         }
1110 
1111         /*
1112          * Derive the virtual register number and run the command
1113          */
1114         (void) bscbus_cmd(hdlp, ADDR_TO_VREG(addr), val, BSCBUS_CMD_WRITE);
1115 }
1116 
1117 static void
1118 bscbus_vreg_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1119         uint8_t *dev_addr, size_t repcount, uint_t flags)
1120 {
1121         size_t inc;
1122 
1123         inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1124         for (; repcount--; dev_addr += inc)
1125                 *host_addr++ = bscbus_vreg_get8(hdlp, dev_addr);
1126 }
1127 
1128 static void
1129 bscbus_vreg_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1130         uint8_t *dev_addr, size_t repcount, uint_t flags)
1131 {
1132         size_t inc;
1133 
1134         inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1135         for (; repcount--; dev_addr += inc)
1136                 bscbus_vreg_put8(hdlp, dev_addr, *host_addr++);
1137 }
1138 
1139 
1140 /*
1141  * Space 1 - LOM watchdog pat register access
1142  * Only 8-bit accesses are supported.
1143  *
1144  * Reads have no effect and return 0.
1145  *
1146  * Multi-byte reads (using ddi_rep_get8(9F)) are a fairly inefficient
1147  * way of zeroing the destination area ;-) and still won't pat the dog.
1148  *
1149  * Multi-byte writes (using ddi_rep_put8(9F)) will almost certainly
1150  * only count as a single pat, no matter how many bytes the caller
1151  * says to write, as the inter-pat time is VERY long compared with
1152  * the time it will take to read the memory source area.
1153  */
1154 
1155 static uint8_t
1156 bscbus_pat_get8(HANDLE_TYPE *hdlp, uint8_t *addr)
1157 {
1158         ptrdiff_t offset;
1159 
1160         /*
1161          * Check the offset that the caller has added to the base address
1162          * against the length of the mapping originally requested.
1163          */
1164         offset = ADDR_TO_OFFSET(addr, hdlp);
1165         if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) {
1166                 /*
1167                  * Invalid access - flag a fault and return a dummy value
1168                  */
1169                 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
1170                 return (DUMMY_VALUE);
1171         }
1172 
1173         return (0);
1174 }
1175 
1176 static void
1177 bscbus_pat_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val)
1178 {
1179         struct bscbus_channel_state *csp;
1180         ptrdiff_t offset;
1181 
1182         /*
1183          * Check the offset that the caller has added to the base address
1184          * against the length of the mapping originally requested.
1185          */
1186         offset = ADDR_TO_OFFSET(addr, hdlp);
1187         if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) {
1188                 /*
1189                  * Invalid access - flag a fault and return
1190                  */
1191                 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
1192                 return;
1193         }
1194 
1195         csp = HANDLE_PRIVATE(hdlp);
1196         mutex_enter(csp->dog_mutex);
1197         bscbus_pat_dog(csp, val);
1198         mutex_exit(csp->dog_mutex);
1199 }
1200 
1201 static void
1202 bscbus_pat_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1203         uint8_t *dev_addr, size_t repcount, uint_t flags)
1204 {
1205         size_t inc;
1206 
1207         inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1208         for (; repcount--; dev_addr += inc)
1209                 *host_addr++ = bscbus_pat_get8(hdlp, dev_addr);
1210 }
1211 
1212 static void
1213 bscbus_pat_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1214         uint8_t *dev_addr, size_t repcount, uint_t flags)
1215 {
1216         size_t inc;
1217 
1218         inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1219         for (; repcount--; dev_addr += inc)
1220                 bscbus_pat_put8(hdlp, dev_addr, *host_addr++);
1221 }
1222 
1223 
1224 /*
1225  * Space 2 - LOM async event flag register access
1226  * Only 16-bit accesses are supported.
1227  */
1228 static uint16_t
1229 bscbus_event_get16(HANDLE_TYPE *hdlp, uint16_t *addr)
1230 {
1231         struct bscbus_channel_state *csp;
1232         ptrdiff_t offset;
1233 
1234         /*
1235          * Check the offset that the caller has added to the base address
1236          * against the length of the mapping orignally requested.
1237          */
1238         offset = ADDR_TO_OFFSET(addr, hdlp);
1239         if (offset < 0 || (offset%2) != 0 || offset >= HANDLE_MAPLEN(hdlp)) {
1240                 /*
1241                  * Invalid access - flag a fault and return a dummy value
1242                  */
1243                 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
1244                 return (DUMMY_VALUE);
1245         }
1246 
1247         /*
1248          * Return the value of the asynchronous-event-pending flag
1249          * as passed back by the LOM at the end of the last command.
1250          */
1251         csp = HANDLE_PRIVATE(hdlp);
1252         return (csp->async);
1253 }
1254 
1255 static void
1256 bscbus_event_put16(HANDLE_TYPE *hdlp, uint16_t *addr, uint16_t val)
1257 {
1258         ptrdiff_t offset;
1259 
1260         _NOTE(ARGUNUSED(val))
1261 
1262         /*
1263          * Check the offset that the caller has added to the base address
1264          * against the length of the mapping originally requested.
1265          */
1266         offset = ADDR_TO_OFFSET(addr, hdlp);
1267         if (offset < 0 || (offset%2) != 0 || offset >= HANDLE_MAPLEN(hdlp)) {
1268                 /*
1269                  * Invalid access - flag a fault and return
1270                  */
1271                 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
1272                 return;
1273         }
1274 
1275         /*
1276          * The user can't overwrite the asynchronous-event-pending flag!
1277          */
1278         HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_RO;
1279 }
1280 
1281 static void
1282 bscbus_event_rep_get16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
1283         uint16_t *dev_addr, size_t repcount, uint_t flags)
1284 {
1285         size_t inc;
1286 
1287         inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1288         for (; repcount--; dev_addr += inc)
1289                 *host_addr++ = bscbus_event_get16(hdlp, dev_addr);
1290 }
1291 
1292 static void
1293 bscbus_event_rep_put16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
1294         uint16_t *dev_addr, size_t repcount, uint_t flags)
1295 {
1296         size_t inc;
1297 
1298         inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1299         for (; repcount--; dev_addr += inc)
1300                 bscbus_event_put16(hdlp, dev_addr, *host_addr++);
1301 }
1302 
1303 
1304 /*
1305  * All spaces - access handle fault information
1306  * Only 32-bit accesses are supported.
1307  */
1308 static uint32_t
1309 bscbus_meta_get32(HANDLE_TYPE *hdlp, uint32_t *addr)
1310 {
1311         struct bscbus_channel_state *csp;
1312         ptrdiff_t offset;
1313 
1314         /*
1315          * Derive the offset that the caller has added to the base
1316          * address originally returned, and use it to determine
1317          * which meta-register is to be accessed ...
1318          */
1319         offset = ADDR_TO_OFFSET(addr, hdlp);
1320         switch (offset) {
1321         case LOMBUS_FAULT_REG:
1322                 /*
1323                  * This meta-register provides a code for the most
1324                  * recent virtual register access fault, if any.
1325                  */
1326                 return (HANDLE_FAULT(hdlp));
1327 
1328         case LOMBUS_PROBE_REG:
1329                 /*
1330                  * Reading this meta-register clears any existing fault
1331                  * (at the virtual, not the hardware access layer), then
1332                  * runs a NOP command and returns the fault code from that.
1333                  */
1334                 HANDLE_FAULT(hdlp) = 0;
1335                 (void) bscbus_cmd(hdlp, 0, 0, BSCBUS_CMD_NOP);
1336                 return (HANDLE_FAULT(hdlp));
1337 
1338         case LOMBUS_ASYNC_REG:
1339                 /*
1340                  * Obsolescent - but still supported for backwards
1341                  * compatibility.  This is an alias for the newer
1342                  * LOMBUS_EVENT_REG, but doesn't require a separate
1343                  * "reg" entry and ddi_regs_map_setup() call.
1344                  *
1345                  * It returns the value of the asynchronous-event-pending
1346                  * flag as passed back by the BSC at the end of the last
1347                  * completed command.
1348                  */
1349                 csp = HANDLE_PRIVATE(hdlp);
1350                 return (csp->async);
1351 
1352         default:
1353                 /*
1354                  * Invalid access - flag a fault and return a dummy value
1355                  */
1356                 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1357                 return (DUMMY_VALUE);
1358         }
1359 }
1360 
1361 static void
1362 bscbus_meta_put32(HANDLE_TYPE *hdlp, uint32_t *addr, uint32_t val)
1363 {
1364         ptrdiff_t offset;
1365 
1366         /*
1367          * Derive the offset that the caller has added to the base
1368          * address originally returned, and use it to determine
1369          * which meta-register is to be accessed ...
1370          */
1371         offset = ADDR_TO_OFFSET(addr, hdlp);
1372         switch (offset) {
1373         case LOMBUS_FAULT_REG:
1374                 /*
1375                  * This meta-register contains a code for the most
1376                  * recent virtual register access fault, if any.
1377                  * It can be cleared simply by writing 0 to it.
1378                  */
1379                 HANDLE_FAULT(hdlp) = val;
1380                 return;
1381 
1382         case LOMBUS_PROBE_REG:
1383                 /*
1384                  * Writing this meta-register clears any existing fault
1385                  * (at the virtual, not the hardware acess layer), then
1386                  * runs a NOP command.  The caller can check the fault
1387                  * code later if required.
1388                  */
1389                 HANDLE_FAULT(hdlp) = 0;
1390                 (void) bscbus_cmd(hdlp, 0, 0, BSCBUS_CMD_NOP);
1391                 return;
1392 
1393         default:
1394                 /*
1395                  * Invalid access - flag a fault
1396                  */
1397                 HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1398                 return;
1399         }
1400 }
1401 
1402 static void
1403 bscbus_meta_rep_get32(HANDLE_TYPE *hdlp, uint32_t *host_addr,
1404         uint32_t *dev_addr, size_t repcount, uint_t flags)
1405 {
1406         size_t inc;
1407 
1408         inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1409         for (; repcount--; dev_addr += inc)
1410                 *host_addr++ = bscbus_meta_get32(hdlp, dev_addr);
1411 }
1412 
1413 static void
1414 bscbus_meta_rep_put32(HANDLE_TYPE *hdlp, uint32_t *host_addr,
1415         uint32_t *dev_addr, size_t repcount, uint_t flags)
1416 {
1417         size_t inc;
1418 
1419         inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1420         for (; repcount--; dev_addr += inc)
1421                 bscbus_meta_put32(hdlp, dev_addr, *host_addr++);
1422 }
1423 
1424 
1425 /*
1426  * Finally, some dummy functions for all unsupported access
1427  * space/size/mode combinations ...
1428  */
1429 static uint8_t
1430 bscbus_no_get8(HANDLE_TYPE *hdlp, uint8_t *addr)
1431 {
1432         _NOTE(ARGUNUSED(addr))
1433 
1434         /*
1435          * Invalid access - flag a fault and return a dummy value
1436          */
1437         HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1438         return (DUMMY_VALUE);
1439 }
1440 
1441 static void
1442 bscbus_no_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val)
1443 {
1444         _NOTE(ARGUNUSED(addr, val))
1445 
1446         /*
1447          * Invalid access - flag a fault
1448          */
1449         HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1450 }
1451 
1452 static void
1453 bscbus_no_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1454                 uint8_t *dev_addr, size_t repcount, uint_t flags)
1455 {
1456         _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
1457 
1458         /*
1459          * Invalid access - flag a fault
1460          */
1461         HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1462 }
1463 
1464 static void
1465 bscbus_no_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1466         uint8_t *dev_addr, size_t repcount, uint_t flags)
1467 {
1468         _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
1469 
1470         /*
1471          * Invalid access - flag a fault
1472          */
1473         HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1474 }
1475 
1476 static uint16_t
1477 bscbus_no_get16(HANDLE_TYPE *hdlp, uint16_t *addr)
1478 {
1479         _NOTE(ARGUNUSED(addr))
1480 
1481         /*
1482          * Invalid access - flag a fault and return a dummy value
1483          */
1484         HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1485         return (DUMMY_VALUE);
1486 }
1487 
1488 static void
1489 bscbus_no_put16(HANDLE_TYPE *hdlp, uint16_t *addr, uint16_t val)
1490 {
1491         _NOTE(ARGUNUSED(addr, val))
1492 
1493         /*
1494          * Invalid access - flag a fault
1495          */
1496         HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1497 }
1498 
1499 static void
1500 bscbus_no_rep_get16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
1501                 uint16_t *dev_addr, size_t repcount, uint_t flags)
1502 {
1503         _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
1504 
1505         /*
1506          * Invalid access - flag a fault
1507          */
1508         HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1509 }
1510 
1511 static void
1512 bscbus_no_rep_put16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
1513         uint16_t *dev_addr, size_t repcount, uint_t flags)
1514 {
1515         _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
1516 
1517         /*
1518          * Invalid access - flag a fault
1519          */
1520         HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1521 }
1522 
1523 static uint64_t
1524 bscbus_no_get64(HANDLE_TYPE *hdlp, uint64_t *addr)
1525 {
1526         _NOTE(ARGUNUSED(addr))
1527 
1528         /*
1529          * Invalid access - flag a fault and return a dummy value
1530          */
1531         HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1532         return (DUMMY_VALUE);
1533 }
1534 
1535 static void
1536 bscbus_no_put64(HANDLE_TYPE *hdlp, uint64_t *addr, uint64_t val)
1537 {
1538         _NOTE(ARGUNUSED(addr, val))
1539 
1540         /*
1541          * Invalid access - flag a fault
1542          */
1543         HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1544 }
1545 
1546 static void
1547 bscbus_no_rep_get64(HANDLE_TYPE *hdlp, uint64_t *host_addr,
1548         uint64_t *dev_addr, size_t repcount, uint_t flags)
1549 {
1550         _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
1551 
1552         /*
1553          * Invalid access - flag a fault
1554          */
1555         HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1556 }
1557 
1558 static void
1559 bscbus_no_rep_put64(HANDLE_TYPE *hdlp, uint64_t *host_addr,
1560         uint64_t *dev_addr, size_t repcount, uint_t flags)
1561 {
1562         _NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
1563 
1564         /*
1565          * Invalid access - flag a fault
1566          */
1567         HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1568 }
1569 
1570 static int
1571 bscbus_acc_fault_check(HANDLE_TYPE *hdlp)
1572 {
1573         return (HANDLE_FAULT(hdlp) != 0);
1574 }
1575 
1576 /*
1577  * Hardware setup - ensure that there are no pending transactions and
1578  * hence no pending interrupts. We do this be ensuring that the BSC is
1579  * not reporting a busy condition and that it does not have any data
1580  * pending in its output buffer.
1581  * This is important because if we have pending interrupts at attach
1582  * time Solaris will hang due to bugs in ddi_get_iblock_cookie.
1583  */
1584 static void
1585 bscbus_hw_reset(struct bscbus_channel_state *csp)
1586 {
1587         int64_t timeout;
1588         uint8_t status;
1589 
1590         if (csp->map_count == 0) {
1591                 /* No-one using this instance - no need to reset hardware */
1592                 return;
1593         }
1594 
1595         bscbus_trace(csp, 'R', "bscbus_hw_reset",
1596             "resetting channel %d", csp->chno);
1597 
1598         status = bscbus_get_reg(csp, H8_STR);
1599         if (status & H8_STR_BUSY) {
1600                 /*
1601                  * Give the h8 time to complete a reply.
1602                  * In practice we should never worry about this
1603                  * because whenever we get here it will have been
1604                  * long enough for the h8 to complete a reply
1605                  */
1606                 bscbus_cmd_log(csp, BSC_CMD_BUSY, status, 0);
1607                 bscbus_trace(csp, 'R', "bscbus_hw_reset",
1608                     "h8 reporting status (%x) busy - waiting", status);
1609                 if (ddi_in_panic()) {
1610                         drv_usecwait(BSCBUS_HWRESET_POLL/1000);
1611                 } else {
1612                         delay(drv_usectohz(BSCBUS_HWRESET_POLL/1000));
1613                 }
1614         }
1615         /* Reply should be completed by now. Try to clear busy status */
1616         status = bscbus_get_reg(csp, H8_STR);
1617         if (status & (H8_STR_BUSY | H8_STR_OBF)) {
1618                 bscbus_trace(csp, 'R', "bscbus_hw_reset",
1619                     "clearing busy status for channel %d", csp->chno);
1620 
1621                 for (timeout = BSCBUS_HWRESET_TIMEOUT;
1622                     (timeout > 0);
1623                     timeout -= BSCBUS_HWRESET_POLL) {
1624                         if (status & H8_STR_OBF) {
1625                                 (void) bscbus_get_reg(csp, H8_ODR);
1626                                 if (!(status & H8_STR_BUSY)) {
1627                                         /* We are done */
1628                                         break;
1629                                 }
1630                         }
1631                         if (ddi_in_panic()) {
1632                                 drv_usecwait(BSCBUS_HWRESET_POLL/1000);
1633                         } else {
1634                                 delay(drv_usectohz(BSCBUS_HWRESET_POLL/1000));
1635                         }
1636                         status = bscbus_get_reg(csp, H8_STR);
1637                 }
1638                 if (timeout <= 0) {
1639                         cmn_err(CE_WARN, "bscbus_hw_reset: timed out "
1640                             "clearing busy status");
1641                 }
1642         }
1643         /*
1644          * We read ODR just in case there is a pending interrupt with
1645          * no data. This is potentially dangerous because we could get
1646          * out of sync due to race conditions BUT at this point the
1647          * channel should be idle so it is safe.
1648          */
1649         (void) bscbus_get_reg(csp, H8_ODR);
1650 }
1651 
1652 /*
1653  * Higher-level setup & teardown
1654  */
1655 
1656 static void
1657 bscbus_offline(struct bscbus_state *ssp)
1658 {
1659         if (ssp->h8_handle != NULL)
1660                 ddi_regs_map_free(&ssp->h8_handle);
1661         ssp->h8_handle = NULL;
1662         ssp->h8_regs = NULL;
1663 }
1664 
1665 static int
1666 bscbus_online(struct bscbus_state *ssp)
1667 {
1668         ddi_acc_handle_t h;
1669         caddr_t p;
1670         int nregs;
1671         int err;
1672 
1673         ssp->h8_handle = NULL;
1674         ssp->h8_regs = (void *)NULL;
1675         ssp->per_channel_regs = B_FALSE;
1676 
1677         if (ddi_dev_nregs(ssp->dip, &nregs) != DDI_SUCCESS)
1678                 nregs = 0;
1679 
1680         switch (nregs) {
1681         case 1:
1682                 /*
1683                  *  regset 0 represents the H8 interface registers
1684                  */
1685                 err = ddi_regs_map_setup(ssp->dip, 0, &p, 0, 0,
1686                     bscbus_dev_acc_attr, &h);
1687                 if (err != DDI_SUCCESS)
1688                         return (EIO);
1689 
1690                 ssp->h8_handle = h;
1691                 ssp->h8_regs = (void *)p;
1692                 break;
1693 
1694         case 0:
1695                 /*
1696                  *  If no registers are defined, succeed vacuously;
1697                  *  commands will be accepted, but we fake the accesses.
1698                  */
1699                 break;
1700 
1701         default:
1702                 /*
1703                  * Remember that we are using the new register scheme.
1704                  * reg set 0 is chan 0
1705                  * reg set 1 is chan 1 ...
1706                  * Interrupts are specified in that order but later
1707                  * channels may not have interrupts.
1708                  * We map the regs later on a per channel basis.
1709                  */
1710                 ssp->per_channel_regs = B_TRUE;
1711                 break;
1712         }
1713         return (0);
1714 }
1715 
1716 static int
1717 bscbus_claim_channel(struct bscbus_channel_state *csp, boolean_t map_dog)
1718 {
1719         int err;
1720 
1721         mutex_enter(csp->ssp->ch_mutex);
1722         csp->map_count++;
1723         bscbus_trace(csp, 'C', "bscbus_claim_channel",
1724             "claim channel for channel %d, count %d",
1725             csp->chno, csp->map_count);
1726 
1727         if (csp->map_count == 1) {
1728                 /* No-one is using this channel - initialise it */
1729                 bscbus_trace(csp, 'C', "bscbus_claim_channel",
1730                     "initialise channel %d, count %d",
1731                     csp->chno, csp->map_count);
1732 
1733                 mutex_init(csp->dog_mutex, NULL, MUTEX_DRIVER,
1734                     (void *)(uintptr_t)__ipltospl(SPL7 - 1));
1735                 csp->map_dog = map_dog;
1736                 csp->interrupt_failed = B_FALSE;
1737                 csp->cmdstate = BSCBUS_CMDSTATE_IDLE;
1738                 csp->pat_retry_count = 0;
1739                 csp->pat_fail_count = 0;
1740 
1741                 /* Map appropriate register set for this channel */
1742                 if (csp->ssp->per_channel_regs == B_TRUE) {
1743                         ddi_acc_handle_t h;
1744                         caddr_t p;
1745 
1746                         err = ddi_regs_map_setup(csp->ssp->dip, csp->chno,
1747                             &p, 0, 0, bscbus_dev_acc_attr, &h);
1748 
1749                         if (err != DDI_SUCCESS) {
1750                                 goto failed1;
1751                         }
1752 
1753                         csp->ch_handle = h;
1754                         csp->ch_regs = (void *)p;
1755 
1756                         bscbus_trace(csp, 'C', "bscbus_claim_channel",
1757                             "mapped chno=%d ch_handle=%d ch_regs=%p",
1758                             csp->chno, h, p);
1759                 } else {
1760                         /*
1761                          * if using the old reg property scheme use the
1762                          * common mapping.
1763                          */
1764                         csp->ch_handle = csp->ssp->h8_handle;
1765                         csp->ch_regs =
1766                             csp->ssp->h8_regs +
1767                             BSCBUS_CHANNEL_TO_OFFSET(csp->chno);
1768                 }
1769 
1770                 /* Ensure no interrupts pending prior to getting iblk cookie */
1771                 bscbus_hw_reset(csp);
1772 
1773                 if (csp->map_dog == 1) {
1774                         /*
1775                          * we don't want lo_mutex to be initialised
1776                          * with an iblock cookie if we are the wdog,
1777                          * because we don't use interrupts.
1778                          */
1779                         mutex_init(csp->lo_mutex, NULL,
1780                             MUTEX_DRIVER, NULL);
1781                         cv_init(csp->lo_cv, NULL,
1782                             CV_DRIVER, NULL);
1783                         csp->unclaimed_count = 0;
1784                 } else {
1785                         int ninterrupts;
1786 
1787                         /*
1788                          * check that there is an interrupt for this
1789                          * this channel. If we fail to setup interrupts we
1790                          * must unmap the registers and fail.
1791                          */
1792                         err = ddi_dev_nintrs(csp->ssp->dip, &ninterrupts);
1793 
1794                         if (err != DDI_SUCCESS) {
1795                                 ninterrupts = 0;
1796                         }
1797 
1798                         if (ninterrupts <= csp->chno) {
1799                                 cmn_err(CE_WARN,
1800                                     "no interrupt available for "
1801                                     "bscbus channel %d", csp->chno);
1802                                 goto failed2;
1803                         }
1804 
1805                         if (ddi_intr_hilevel(csp->ssp->dip, csp->chno) != 0) {
1806                                 cmn_err(CE_WARN,
1807                                     "bscbus interrupts are high "
1808                                     "level - channel not usable.");
1809                                 goto failed2;
1810                         } else {
1811                                 err = ddi_get_iblock_cookie(csp->ssp->dip,
1812                                     csp->chno, &csp->lo_iblk);
1813                                 if (err != DDI_SUCCESS) {
1814                                         goto failed2;
1815                                 }
1816 
1817                                 mutex_init(csp->lo_mutex, NULL,
1818                                     MUTEX_DRIVER, csp->lo_iblk);
1819                                 cv_init(csp->lo_cv, NULL,
1820                                     CV_DRIVER, NULL);
1821                                 csp->unclaimed_count = 0;
1822 
1823                                 err = ddi_add_intr(csp->ssp->dip, csp->chno,
1824                                     &csp->lo_iblk, NULL,
1825                                     bscbus_hwintr, (caddr_t)csp);
1826                                 if (err != DDI_SUCCESS) {
1827                                         cv_destroy(csp->lo_cv);
1828                                         mutex_destroy(csp->lo_mutex);
1829                                         goto failed2;
1830                                 }
1831                         }
1832                 }
1833                 /*
1834                  * The channel is now live and may
1835                  * receive interrupts
1836                  */
1837         } else if (csp->map_dog != map_dog) {
1838                 bscbus_trace(csp, 'C', "bscbus_claim_channel",
1839                     "request conflicts with previous mapping. old %x, new %x.",
1840                     csp->map_dog, map_dog);
1841                 goto failed1;
1842         }
1843         mutex_exit(csp->ssp->ch_mutex);
1844         return (1);
1845 
1846 failed2:
1847         /* unmap regs for failed channel */
1848         if (csp->ssp->per_channel_regs == B_TRUE) {
1849                 ddi_regs_map_free(&csp->ch_handle);
1850         }
1851         csp->ch_handle = NULL;
1852         csp->ch_regs = (void *)NULL;
1853 failed1:
1854         csp->map_count--;
1855         mutex_exit(csp->ssp->ch_mutex);
1856         return (0);
1857 }
1858 
1859 static void
1860 bscbus_release_channel(struct bscbus_channel_state *csp)
1861 {
1862         mutex_enter(csp->ssp->ch_mutex);
1863         if (csp->map_count == 1) {
1864                 /* No-one is now using this channel - shutdown channel */
1865                 bscbus_trace(csp, 'C', "bscbus_release_channel",
1866                     "shutdown channel %d, count %d",
1867                     csp->chno, csp->map_count);
1868 
1869                 if (csp->map_dog == 0) {
1870                         ASSERT(!ddi_intr_hilevel(csp->ssp->dip, csp->chno));
1871                         ddi_remove_intr(csp->ssp->dip, csp->chno, csp->lo_iblk);
1872                 }
1873                 cv_destroy(csp->lo_cv);
1874                 mutex_destroy(csp->lo_mutex);
1875                 mutex_destroy(csp->dog_mutex);
1876                 bscbus_hw_reset(csp);
1877 
1878                 /* unmap registers if using the new register scheme */
1879                 if (csp->ssp->per_channel_regs == B_TRUE) {
1880                         ddi_regs_map_free(&csp->ch_handle);
1881                 }
1882                 csp->ch_handle = NULL;
1883                 csp->ch_regs = (void *)NULL;
1884         }
1885         csp->map_count--;
1886         bscbus_trace(csp, 'C', "bscbus_release_channel",
1887             "release channel %d, count %d",
1888             csp->chno, csp->map_count);
1889         mutex_exit(csp->ssp->ch_mutex);
1890 }
1891 
1892 
1893 /*
1894  *  Nexus routines
1895  */
1896 
1897 #if     defined(NDI_ACC_HDL_V2)
1898 
1899 static const ndi_acc_fns_t bscbus_vreg_acc_fns = {
1900         NDI_ACC_FNS_CURRENT,
1901         NDI_ACC_FNS_V1,
1902 
1903         bscbus_vreg_get8,
1904         bscbus_vreg_put8,
1905         bscbus_vreg_rep_get8,
1906         bscbus_vreg_rep_put8,
1907 
1908         bscbus_no_get16,
1909         bscbus_no_put16,
1910         bscbus_no_rep_get16,
1911         bscbus_no_rep_put16,
1912 
1913         bscbus_meta_get32,
1914         bscbus_meta_put32,
1915         bscbus_meta_rep_get32,
1916         bscbus_meta_rep_put32,
1917 
1918         bscbus_no_get64,
1919         bscbus_no_put64,
1920         bscbus_no_rep_get64,
1921         bscbus_no_rep_put64,
1922 
1923         bscbus_acc_fault_check
1924 };
1925 
1926 static const ndi_acc_fns_t bscbus_pat_acc_fns = {
1927         NDI_ACC_FNS_CURRENT,
1928         NDI_ACC_FNS_V1,
1929 
1930         bscbus_pat_get8,
1931         bscbus_pat_put8,
1932         bscbus_pat_rep_get8,
1933         bscbus_pat_rep_put8,
1934 
1935         bscbus_no_get16,
1936         bscbus_no_put16,
1937         bscbus_no_rep_get16,
1938         bscbus_no_rep_put16,
1939 
1940         bscbus_meta_get32,
1941         bscbus_meta_put32,
1942         bscbus_meta_rep_get32,
1943         bscbus_meta_rep_put32,
1944 
1945         bscbus_no_get64,
1946         bscbus_no_put64,
1947         bscbus_no_rep_get64,
1948         bscbus_no_rep_put64,
1949 
1950         bscbus_acc_fault_check
1951 };
1952 
1953 static const ndi_acc_fns_t bscbus_event_acc_fns = {
1954         NDI_ACC_FNS_CURRENT,
1955         NDI_ACC_FNS_V1,
1956 
1957         bscbus_no_get8,
1958         bscbus_no_put8,
1959         bscbus_no_rep_get8,
1960         bscbus_no_rep_put8,
1961 
1962         bscbus_event_get16,
1963         bscbus_event_put16,
1964         bscbus_event_rep_get16,
1965         bscbus_event_rep_put16,
1966 
1967         bscbus_meta_get32,
1968         bscbus_meta_put32,
1969         bscbus_meta_rep_get32,
1970         bscbus_meta_rep_put32,
1971 
1972         bscbus_no_get64,
1973         bscbus_no_put64,
1974         bscbus_no_rep_get64,
1975         bscbus_no_rep_put64,
1976 
1977         bscbus_acc_fault_check
1978 };
1979 
1980 static int
1981 bscbus_map_handle(struct bscbus_channel_state *csp, ddi_map_op_t op,
1982         int space, caddr_t vaddr, off_t len,
1983         ndi_acc_handle_t *hdlp, caddr_t *addrp)
1984 {
1985         switch (op) {
1986         default:
1987                 return (DDI_ME_UNIMPLEMENTED);
1988 
1989         case DDI_MO_MAP_LOCKED:
1990                 if (bscbus_claim_channel(csp,
1991                     (space == LOMBUS_PAT_SPACE)) == 0) {
1992                         return (DDI_ME_GENERIC);
1993                 }
1994 
1995                 switch (space) {
1996                 default:
1997                         return (DDI_ME_REGSPEC_RANGE);
1998 
1999                 case LOMBUS_VREG_SPACE:
2000                         ndi_set_acc_fns(hdlp, &bscbus_vreg_acc_fns);
2001                         break;
2002 
2003                 case LOMBUS_PAT_SPACE:
2004                         ndi_set_acc_fns(hdlp, &bscbus_pat_acc_fns);
2005                         break;
2006 
2007                 case LOMBUS_EVENT_SPACE:
2008                         ndi_set_acc_fns(hdlp, &bscbus_event_acc_fns);
2009                         break;
2010                 }
2011                 hdlp->ah_addr = *addrp = vaddr;
2012                 hdlp->ah_len = len;
2013                 hdlp->ah_bus_private = csp;
2014                 return (DDI_SUCCESS);
2015 
2016         case DDI_MO_UNMAP:
2017                 *addrp = NULL;
2018                 hdlp->ah_bus_private = NULL;
2019                 bscbus_release_channel(csp);
2020                 return (DDI_SUCCESS);
2021         }
2022 }
2023 
2024 #else
2025 
2026 static int
2027 bscbus_map_handle(struct bscbus_channel_state *csp, ddi_map_op_t op,
2028         int space, caddr_t vaddr, off_t len,
2029         ddi_acc_hdl_t *hdlp, caddr_t *addrp)
2030 {
2031         ddi_acc_impl_t *aip = hdlp->ah_platform_private;
2032 
2033         switch (op) {
2034         default:
2035                 return (DDI_ME_UNIMPLEMENTED);
2036 
2037         case DDI_MO_MAP_LOCKED:
2038                 if (bscbus_claim_channel(csp,
2039                     (space == LOMBUS_PAT_SPACE)) == 0) {
2040                         return (DDI_ME_GENERIC);
2041                 }
2042 
2043                 switch (space) {
2044                 default:
2045                         return (DDI_ME_REGSPEC_RANGE);
2046 
2047                 case LOMBUS_VREG_SPACE:
2048                         aip->ahi_get8 = bscbus_vreg_get8;
2049                         aip->ahi_put8 = bscbus_vreg_put8;
2050                         aip->ahi_rep_get8 = bscbus_vreg_rep_get8;
2051                         aip->ahi_rep_put8 = bscbus_vreg_rep_put8;
2052 
2053                         aip->ahi_get16 = bscbus_no_get16;
2054                         aip->ahi_put16 = bscbus_no_put16;
2055                         aip->ahi_rep_get16 = bscbus_no_rep_get16;
2056                         aip->ahi_rep_put16 = bscbus_no_rep_put16;
2057 
2058                         aip->ahi_get32 = bscbus_meta_get32;
2059                         aip->ahi_put32 = bscbus_meta_put32;
2060                         aip->ahi_rep_get32 = bscbus_meta_rep_get32;
2061                         aip->ahi_rep_put32 = bscbus_meta_rep_put32;
2062 
2063                         aip->ahi_get64 = bscbus_no_get64;
2064                         aip->ahi_put64 = bscbus_no_put64;
2065                         aip->ahi_rep_get64 = bscbus_no_rep_get64;
2066                         aip->ahi_rep_put64 = bscbus_no_rep_put64;
2067 
2068                         aip->ahi_fault_check = bscbus_acc_fault_check;
2069                         break;
2070 
2071                 case LOMBUS_PAT_SPACE:
2072                         aip->ahi_get8 = bscbus_pat_get8;
2073                         aip->ahi_put8 = bscbus_pat_put8;
2074                         aip->ahi_rep_get8 = bscbus_pat_rep_get8;
2075                         aip->ahi_rep_put8 = bscbus_pat_rep_put8;
2076 
2077                         aip->ahi_get16 = bscbus_no_get16;
2078                         aip->ahi_put16 = bscbus_no_put16;
2079                         aip->ahi_rep_get16 = bscbus_no_rep_get16;
2080                         aip->ahi_rep_put16 = bscbus_no_rep_put16;
2081 
2082                         aip->ahi_get32 = bscbus_meta_get32;
2083                         aip->ahi_put32 = bscbus_meta_put32;
2084                         aip->ahi_rep_get32 = bscbus_meta_rep_get32;
2085                         aip->ahi_rep_put32 = bscbus_meta_rep_put32;
2086 
2087                         aip->ahi_get64 = bscbus_no_get64;
2088                         aip->ahi_put64 = bscbus_no_put64;
2089                         aip->ahi_rep_get64 = bscbus_no_rep_get64;
2090                         aip->ahi_rep_put64 = bscbus_no_rep_put64;
2091 
2092                         aip->ahi_fault_check = bscbus_acc_fault_check;
2093                         break;
2094 
2095                 case LOMBUS_EVENT_SPACE:
2096                         aip->ahi_get8 = bscbus_no_get8;
2097                         aip->ahi_put8 = bscbus_no_put8;
2098                         aip->ahi_rep_get8 = bscbus_no_rep_get8;
2099                         aip->ahi_rep_put8 = bscbus_no_rep_put8;
2100 
2101                         aip->ahi_get16 = bscbus_event_get16;
2102                         aip->ahi_put16 = bscbus_event_put16;
2103                         aip->ahi_rep_get16 = bscbus_event_rep_get16;
2104                         aip->ahi_rep_put16 = bscbus_event_rep_put16;
2105 
2106                         aip->ahi_get32 = bscbus_meta_get32;
2107                         aip->ahi_put32 = bscbus_meta_put32;
2108                         aip->ahi_rep_get32 = bscbus_meta_rep_get32;
2109                         aip->ahi_rep_put32 = bscbus_meta_rep_put32;
2110 
2111                         aip->ahi_get64 = bscbus_no_get64;
2112                         aip->ahi_put64 = bscbus_no_put64;
2113                         aip->ahi_rep_get64 = bscbus_no_rep_get64;
2114                         aip->ahi_rep_put64 = bscbus_no_rep_put64;
2115 
2116                         aip->ahi_fault_check = bscbus_acc_fault_check;
2117                         break;
2118                 }
2119                 hdlp->ah_addr = *addrp = vaddr;
2120                 hdlp->ah_len = len;
2121                 hdlp->ah_bus_private = csp;
2122                 return (DDI_SUCCESS);
2123 
2124         case DDI_MO_UNMAP:
2125                 *addrp = NULL;
2126                 hdlp->ah_bus_private = NULL;
2127                 bscbus_release_channel(csp);
2128                 return (DDI_SUCCESS);
2129         }
2130 }
2131 
2132 #endif  /* NDI_ACC_HDL_V2 */
2133 
2134 static int
2135 bscbus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
2136         off_t off, off_t len, caddr_t *addrp)
2137 {
2138         struct bscbus_child_info *lcip;
2139         struct bscbus_state *ssp;
2140         lombus_regspec_t *rsp;
2141 
2142         if ((ssp = bscbus_getstate(dip, -1, "bscbus_map")) == NULL)
2143                 return (DDI_FAILURE);   /* this "can't happen" */
2144 
2145         /*
2146          * Validate mapping request ...
2147          */
2148 
2149         if (mp->map_flags != DDI_MF_KERNEL_MAPPING)
2150                 return (DDI_ME_UNSUPPORTED);
2151         if (mp->map_handlep == NULL)
2152                 return (DDI_ME_UNSUPPORTED);
2153         if (mp->map_type != DDI_MT_RNUMBER)
2154                 return (DDI_ME_UNIMPLEMENTED);
2155         if ((lcip = ddi_get_parent_data(rdip)) == NULL)
2156                 return (DDI_ME_INVAL);
2157         if ((rsp = lcip->rsp) == NULL)
2158                 return (DDI_ME_INVAL);
2159         if (mp->map_obj.rnumber >= lcip->nregs)
2160                 return (DDI_ME_RNUMBER_RANGE);
2161         rsp += mp->map_obj.rnumber;
2162         if (off < 0 || off >= rsp->lombus_size)
2163                 return (DDI_ME_INVAL);
2164         if (len == 0)
2165                 len = rsp->lombus_size-off;
2166         if (len < 0)
2167                 return (DDI_ME_INVAL);
2168         if (off+len < 0 || off+len > rsp->lombus_size)
2169                 return (DDI_ME_INVAL);
2170 
2171         return (bscbus_map_handle(
2172             &ssp->channel[LOMBUS_SPACE_TO_CHANNEL(rsp->lombus_space)],
2173             mp->map_op, LOMBUS_SPACE_TO_REGSET(rsp->lombus_space),
2174             VREG_TO_ADDR(rsp->lombus_base+off), len, mp->map_handlep, addrp));
2175 }
2176 
2177 
2178 static int
2179 bscbus_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op,
2180         void *arg, void *result)
2181 {
2182         struct bscbus_child_info *lcip;
2183         lombus_regspec_t *rsp;
2184         dev_info_t *cdip;
2185         char addr[32];
2186         uint_t nregs;
2187         uint_t rnum;
2188         int *regs;
2189         int limit;
2190         int err;
2191         int i;
2192 
2193         if (bscbus_getstate(dip, -1, "bscbus_ctlops") == NULL)
2194                 return (DDI_FAILURE);   /* this "can't happen" */
2195 
2196         switch (op) {
2197         default:
2198                 break;
2199 
2200         case DDI_CTLOPS_INITCHILD:
2201                 /*
2202                  * First, look up and validate the "reg" property.
2203                  *
2204                  * It must be a non-empty integer array containing a set
2205                  * of triples.  Once we've verified that, we can treat it
2206                  * as an array of type lombus_regspec_t[], which defines
2207                  * the meaning of the elements of each triple:
2208                  * +  the first element of each triple must be a valid space
2209                  * +  the second and third elements (base, size) of each
2210                  *      triple must define a valid subrange of that space
2211                  * If it passes all the tests, we save it away for future
2212                  * reference in the child's parent-private-data field.
2213                  */
2214                 cdip = arg;
2215                 err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip,
2216                     DDI_PROP_DONTPASS, "reg", &regs, &nregs);
2217                 if (err != DDI_PROP_SUCCESS)
2218                         return (DDI_FAILURE);
2219 
2220                 err = (nregs <= 0 || (nregs % LOMBUS_REGSPEC_SIZE) != 0);
2221                 nregs /= LOMBUS_REGSPEC_SIZE;
2222                 rsp = (lombus_regspec_t *)regs;
2223                 for (i = 0; i < nregs && !err; ++i) {
2224                         switch (LOMBUS_SPACE_TO_REGSET(rsp[i].lombus_space)) {
2225                         default:
2226                                 limit = 0;
2227                                 err = 1;
2228                                 cmn_err(CE_WARN,
2229                                     "child(%p): unknown reg space %d",
2230                                     (void *)cdip, rsp[i].lombus_space);
2231                                 break;
2232 
2233                         case LOMBUS_VREG_SPACE:
2234                                 limit = LOMBUS_MAX_REG+1;
2235                                 break;
2236 
2237                         case LOMBUS_PAT_SPACE:
2238                                 limit = LOMBUS_PAT_REG+1;
2239                                 break;
2240 
2241                         case LOMBUS_EVENT_SPACE:
2242                                 limit = LOMBUS_EVENT_REG+1;
2243                                 break;
2244                         }
2245 
2246                         err |= (rsp[i].lombus_base < 0);
2247                         err |= (rsp[i].lombus_base >= limit);
2248 
2249                         if (rsp[i].lombus_size == 0)
2250                                 rsp[i].lombus_size = limit-rsp[i].lombus_base;
2251 
2252                         err |= (rsp[i].lombus_size < 0);
2253                         err |= (rsp[i].lombus_base+rsp[i].lombus_size < 0);
2254                         err |= (rsp[i].lombus_base+rsp[i].lombus_size > limit);
2255 
2256                         err |= (rsp[i].lombus_base+rsp[i].lombus_size > limit);
2257 
2258                 }
2259 
2260                 if (err) {
2261                         ddi_prop_free(regs);
2262                         return (DDI_FAILURE);
2263                 }
2264 
2265                 lcip = kmem_zalloc(sizeof (*lcip), KM_SLEEP);
2266                 lcip->nregs = nregs;
2267                 lcip->rsp = rsp;
2268                 ddi_set_parent_data(cdip, lcip);
2269 
2270                 (void) snprintf(addr, sizeof (addr),
2271                     "%x,%x", rsp[0].lombus_space, rsp[0].lombus_base);
2272                 ddi_set_name_addr(cdip, addr);
2273 
2274                 return (DDI_SUCCESS);
2275 
2276         case DDI_CTLOPS_UNINITCHILD:
2277                 cdip = arg;
2278                 ddi_set_name_addr(cdip, NULL);
2279                 lcip = ddi_get_parent_data(cdip);
2280                 ddi_set_parent_data(cdip, NULL);
2281                 ddi_prop_free(lcip->rsp);
2282                 kmem_free(lcip, sizeof (*lcip));
2283                 return (DDI_SUCCESS);
2284 
2285         case DDI_CTLOPS_REPORTDEV:
2286                 if (rdip == NULL)
2287                         return (DDI_FAILURE);
2288 
2289                 cmn_err(CE_CONT, "?BSC device: %s@%s, %s#%d\n",
2290                     ddi_node_name(rdip), ddi_get_name_addr(rdip),
2291                     ddi_driver_name(dip), ddi_get_instance(dip));
2292 
2293                 return (DDI_SUCCESS);
2294 
2295         case DDI_CTLOPS_REGSIZE:
2296                 if ((lcip = ddi_get_parent_data(rdip)) == NULL)
2297                         return (DDI_FAILURE);
2298                 if ((rnum = *(uint_t *)arg) >= lcip->nregs)
2299                         return (DDI_FAILURE);
2300                 *(off_t *)result = lcip->rsp[rnum].lombus_size;
2301                 return (DDI_SUCCESS);
2302 
2303         case DDI_CTLOPS_NREGS:
2304                 if ((lcip = ddi_get_parent_data(rdip)) == NULL)
2305                         return (DDI_FAILURE);
2306                 *(int *)result = lcip->nregs;
2307                 return (DDI_SUCCESS);
2308         }
2309 
2310         return (ddi_ctlops(dip, rdip, op, arg, result));
2311 }
2312 
2313 
2314 /*
2315  * This nexus does not support passing interrupts to leaf drivers, so
2316  * all the intrspec-related operations just fail as cleanly as possible.
2317  */
2318 
2319 /*ARGSUSED*/
2320 static int
2321 bscbus_intr_op(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op,
2322     ddi_intr_handle_impl_t *hdlp, void *result)
2323 {
2324 #if defined(__sparc)
2325         return (i_ddi_intr_ops(dip, rdip, op, hdlp, result));
2326 #else
2327         _NOTE(ARGUNUSED(dip, rdip, op, hdlp, result))
2328         return (DDI_FAILURE);
2329 #endif
2330 }
2331 
2332 /*
2333  *  Clean up on detach or failure of attach
2334  */
2335 static int
2336 bscbus_unattach(struct bscbus_state *ssp, int instance)
2337 {
2338         int chno;
2339 
2340         if (ssp != NULL) {
2341                 for (chno = 0; chno < BSCBUS_MAX_CHANNELS; chno++) {
2342                         ASSERT(ssp->channel[chno].map_count == 0);
2343                 }
2344                 bscbus_offline(ssp);
2345                 ddi_set_driver_private(ssp->dip, NULL);
2346                 mutex_destroy(ssp->ch_mutex);
2347         }
2348 #ifdef BSCBUS_LOGSTATUS
2349         if (ssp->cmd_log_size != 0) {
2350                 kmem_free(ssp->cmd_log,
2351                     ssp->cmd_log_size * sizeof (bsc_cmd_log_t));
2352         }
2353 #endif /* BSCBUS_LOGSTATUS */
2354 
2355 
2356         ddi_soft_state_free(bscbus_statep, instance);
2357         return (DDI_FAILURE);
2358 }
2359 
2360 /*
2361  *  Autoconfiguration routines
2362  */
2363 
2364 static int
2365 bscbus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2366 {
2367         struct bscbus_state *ssp = NULL;
2368         int chno;
2369         int instance;
2370         int err;
2371 
2372         switch (cmd) {
2373         default:
2374                 return (DDI_FAILURE);
2375 
2376         case DDI_ATTACH:
2377                 break;
2378         }
2379 
2380         /*
2381          *  Allocate the soft-state structure
2382          */
2383         instance = ddi_get_instance(dip);
2384         if (ddi_soft_state_zalloc(bscbus_statep, instance) != DDI_SUCCESS)
2385                 return (DDI_FAILURE);
2386         if ((ssp = bscbus_getstate(dip, instance, "bscbus_attach")) == NULL)
2387                 return (bscbus_unattach(ssp, instance));
2388         ddi_set_driver_private(dip, ssp);
2389 
2390         /*
2391          *  Initialise devinfo-related fields
2392          */
2393         ssp->dip = dip;
2394         ssp->majornum = ddi_driver_major(dip);
2395         ssp->instance = instance;
2396 
2397         /*
2398          *  Set various options from .conf properties
2399          */
2400         ssp->debug = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
2401             DDI_PROP_DONTPASS, "debug", 0);
2402 
2403         mutex_init(ssp->ch_mutex, NULL, MUTEX_DRIVER, NULL);
2404 
2405 #ifdef BSCBUS_LOGSTATUS
2406         ssp->cmd_log_size = bscbus_cmd_log_size;
2407         if (ssp->cmd_log_size != 0) {
2408                 ssp->cmd_log_idx = 0;
2409                 ssp->cmd_log = kmem_zalloc(ssp->cmd_log_size *
2410                     sizeof (bsc_cmd_log_t), KM_SLEEP);
2411         }
2412 #endif /* BSCBUS_LOGSTATUS */
2413 
2414         /*
2415          *  Online the hardware ...
2416          */
2417         err = bscbus_online(ssp);
2418         if (err != 0)
2419                 return (bscbus_unattach(ssp, instance));
2420 
2421         for (chno = 0; chno < BSCBUS_MAX_CHANNELS; chno++) {
2422                 struct bscbus_channel_state *csp = &ssp->channel[chno];
2423 
2424                 /*
2425                  * Initialise state
2426                  * The hardware/interrupts are setup at map time to
2427                  * avoid claiming hardware that OBP is using
2428                  */
2429                 csp->ssp = ssp;
2430                 csp->chno = chno;
2431                 csp->map_count = 0;
2432                 csp->map_dog = B_FALSE;
2433         }
2434 
2435         /*
2436          *  All done, report success
2437          */
2438         ddi_report_dev(dip);
2439         return (DDI_SUCCESS);
2440 }
2441 
2442 static int
2443 bscbus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2444 {
2445         struct bscbus_state *ssp;
2446         int instance;
2447 
2448         switch (cmd) {
2449         default:
2450                 return (DDI_FAILURE);
2451 
2452         case DDI_DETACH:
2453                 break;
2454         }
2455 
2456         instance = ddi_get_instance(dip);
2457         if ((ssp = bscbus_getstate(dip, instance, "bscbus_detach")) == NULL)
2458                 return (DDI_FAILURE);   /* this "can't happen" */
2459 
2460         (void) bscbus_unattach(ssp, instance);
2461         return (DDI_SUCCESS);
2462 }
2463 
2464 static int
2465 bscbus_reset(dev_info_t *dip, ddi_reset_cmd_t cmd)
2466 {
2467         struct bscbus_state *ssp;
2468         int chno;
2469 
2470         _NOTE(ARGUNUSED(cmd))
2471 
2472         if ((ssp = bscbus_getstate(dip, -1, "bscbus_reset")) == NULL)
2473                 return (DDI_FAILURE);
2474 
2475         for (chno = 0; chno < BSCBUS_MAX_CHANNELS; chno++) {
2476                 bscbus_hw_reset(&ssp->channel[chno]);
2477         }
2478         return (DDI_SUCCESS);
2479 }
2480 
2481 
2482 /*
2483  * System interface structures
2484  */
2485 
2486 static struct cb_ops bscbus_cb_ops =
2487 {
2488         nodev,                  /* b/c open     */
2489         nodev,                  /* b/c close    */
2490         nodev,                  /* b   strategy */
2491         nodev,                  /* b   print    */
2492         nodev,                  /* b   dump     */
2493         nodev,                  /* c   read     */
2494         nodev,                  /* c   write    */
2495         nodev,                  /* c   ioctl    */
2496         nodev,                  /* c   devmap   */
2497         nodev,                  /* c   mmap     */
2498         nodev,                  /* c   segmap   */
2499         nochpoll,               /* c   poll     */
2500         ddi_prop_op,            /* b/c prop_op  */
2501         NULL,                   /* c   streamtab */
2502         D_MP | D_NEW            /* b/c flags    */
2503 };
2504 
2505 static struct bus_ops bscbus_bus_ops =
2506 {
2507         BUSO_REV,                       /* revision             */
2508         bscbus_map,                     /* bus_map              */
2509         0,                              /* get_intrspec         */
2510         0,                              /* add_intrspec         */
2511         0,                              /* remove_intrspec      */
2512         i_ddi_map_fault,                /* map_fault            */
2513         ddi_no_dma_map,                 /* dma_map              */
2514         ddi_no_dma_allochdl,            /* allocate DMA handle  */
2515         ddi_no_dma_freehdl,             /* free DMA handle      */
2516         ddi_no_dma_bindhdl,             /* bind DMA handle      */
2517         ddi_no_dma_unbindhdl,           /* unbind DMA handle    */
2518         ddi_no_dma_flush,               /* flush DMA            */
2519         ddi_no_dma_win,                 /* move DMA window      */
2520         ddi_no_dma_mctl,                /* generic DMA control  */
2521         bscbus_ctlops,                  /* generic control      */
2522         ddi_bus_prop_op,                /* prop_op              */
2523         ndi_busop_get_eventcookie,      /* get_eventcookie      */
2524         ndi_busop_add_eventcall,        /* add_eventcall        */
2525         ndi_busop_remove_eventcall,     /* remove_eventcall     */
2526         ndi_post_event,                 /* post_event           */
2527         0,                              /* interrupt control    */
2528         0,                              /* bus_config           */
2529         0,                              /* bus_unconfig         */
2530         0,                              /* bus_fm_init          */
2531         0,                              /* bus_fm_fini          */
2532         0,                              /* bus_fm_access_enter  */
2533         0,                              /* bus_fm_access_exit   */
2534         0,                              /* bus_power            */
2535         bscbus_intr_op                  /* bus_intr_op          */
2536 };
2537 
2538 static struct dev_ops bscbus_dev_ops =
2539 {
2540         DEVO_REV,
2541         0,                              /* refcount             */
2542         ddi_no_info,                    /* getinfo              */
2543         nulldev,                        /* identify             */
2544         nulldev,                        /* probe                */
2545         bscbus_attach,                  /* attach               */
2546         bscbus_detach,                  /* detach               */
2547         bscbus_reset,                   /* reset                */
2548         &bscbus_cb_ops,                     /* driver operations    */
2549         &bscbus_bus_ops,            /* bus operations       */
2550         NULL,                           /* power                */
2551         ddi_quiesce_not_needed,                 /* quiesce              */
2552 };
2553 
2554 static struct modldrv modldrv =
2555 {
2556         &mod_driverops,
2557         "bscbus driver",
2558         &bscbus_dev_ops
2559 };
2560 
2561 static struct modlinkage modlinkage =
2562 {
2563         MODREV_1,
2564         {
2565                 &modldrv,
2566                 NULL
2567         }
2568 };
2569 
2570 
2571 /*
2572  *  Dynamic loader interface code
2573  */
2574 
2575 int
2576 _init(void)
2577 {
2578         int err;
2579 
2580         err = ddi_soft_state_init(&bscbus_statep,
2581             sizeof (struct bscbus_state), 0);
2582         if (err == DDI_SUCCESS)
2583                 if ((err = mod_install(&modlinkage)) != DDI_SUCCESS) {
2584                         ddi_soft_state_fini(&bscbus_statep);
2585                 }
2586 
2587         return (err);
2588 }
2589 
2590 int
2591 _info(struct modinfo *mip)
2592 {
2593         return (mod_info(&modlinkage, mip));
2594 }
2595 
2596 int
2597 _fini(void)
2598 {
2599         int err;
2600 
2601         if ((err = mod_remove(&modlinkage)) == DDI_SUCCESS) {
2602                 ddi_soft_state_fini(&bscbus_statep);
2603                 bscbus_major = NOMAJOR;
2604         }
2605 
2606         return (err);
2607 }
2608 
2609 #ifdef BSCBUS_LOGSTATUS
2610 void bscbus_cmd_log(struct bscbus_channel_state *csp, bsc_cmd_stamp_t cat,
2611     uint8_t status, uint8_t data)
2612 {
2613         int idx;
2614         bsc_cmd_log_t *logp;
2615         struct bscbus_state *ssp;
2616 
2617         if ((csp) == NULL)
2618                 return;
2619         if ((ssp = (csp)->ssp) == NULL)
2620                 return;
2621         if (ssp->cmd_log_size == 0)
2622                 return;
2623         if ((bscbus_cmd_log_flags & (1 << cat)) == 0)
2624                 return;
2625         idx = atomic_inc_32_nv(&ssp->cmd_log_idx);
2626         logp = &ssp->cmd_log[idx % ssp->cmd_log_size];
2627         logp->bcl_seq = idx;
2628         logp->bcl_cat = cat;
2629         logp->bcl_now = gethrtime();
2630         logp->bcl_chno = csp->chno;
2631         logp->bcl_cmdstate = csp->cmdstate;
2632         logp->bcl_status = status;
2633         logp->bcl_data = data;
2634 }
2635 #endif /* BSCBUS_LOGSTATUS */