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