xref: /titanic_44/usr/src/uts/common/io/bscbus.c (revision 1c42de6d020629af774dd9e9fc81be3f3ed9398e)
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", &regs, &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