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