xref: /titanic_51/usr/src/uts/sun4u/lw2plus/io/lombus.c (revision 6185db853e024a486ff8837e6784dd290d866112)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * The "lombus" driver provides access to the LOMlite2 virtual registers,
27  * so that its clients (children) need not be concerned with the details
28  * of the access mechanism, which in this case is implemented via a
29  * packet-based protocol over a serial link connected to one of the serial
30  * ports of the SuperIO (SIO) chip.
31  *
32  * On the other hand, this driver doesn't generally know what the virtual
33  * registers signify - only the clients need this information.
34  */
35 
36 #pragma ident	"%Z%%M%	%I%	%E% SMI"
37 
38 /*
39  *  Header files
40  */
41 
42 #include <sys/types.h>
43 #include <sys/conf.h>
44 #include <sys/cyclic.h>
45 #include <sys/debug.h>
46 #include <sys/errno.h>
47 #include <sys/file.h>
48 #include <sys/intr.h>
49 #include <sys/kmem.h>
50 #include <sys/membar.h>
51 #include <sys/modctl.h>
52 #include <sys/note.h>
53 #include <sys/open.h>
54 #include <sys/poll.h>
55 #include <sys/spl.h>
56 #include <sys/stat.h>
57 #include <sys/strlog.h>
58 
59 #include <sys/ddi.h>
60 #include <sys/sunddi.h>
61 #include <sys/sunndi.h>
62 
63 #include <sys/lombus.h>
64 
65 
66 #if	defined(NDI_ACC_HDL_V2)
67 
68 /*
69  * Compiling for Solaris 9+ with access handle enhancements
70  */
71 #define	HANDLE_TYPE		ndi_acc_handle_t
72 #define	HANDLE_ADDR(hdlp)	(hdlp->ah_addr)
73 #define	HANDLE_FAULT(hdlp)	(hdlp->ah_fault)
74 #define	HANDLE_MAPLEN(hdlp)	(hdlp->ah_len)
75 #define	HANDLE_PRIVATE(hdlp)	(hdlp->ah_bus_private)
76 
77 #else
78 
79 /*
80  * Compatibility definitions for backport to Solaris 8
81  */
82 #define	HANDLE_TYPE		ddi_acc_impl_t
83 #define	HANDLE_ADDR(hdlp)	(hdlp->ahi_common.ah_addr)
84 #define	HANDLE_FAULT(hdlp)	(hdlp->ahi_fault)
85 #define	HANDLE_MAPLEN(hdlp)	(hdlp->ahi_common.ah_len)
86 #define	HANDLE_PRIVATE(hdlp)	(hdlp->ahi_common.ah_bus_private)
87 
88 #define	ddi_driver_major(dip)	ddi_name_to_major(ddi_binding_name(dip))
89 
90 #endif	/* NDI_ACC_HDL_V2 */
91 
92 
93 /*
94  * Local definitions
95  */
96 #define	MYNAME			"lombus"
97 #define	NOMAJOR			(~(major_t)0)
98 #define	DUMMY_VALUE		(~(int8_t)0)
99 
100 #define	LOMBUS_INST_TO_MINOR(i)	(i)
101 #define	LOMBUS_MINOR_TO_INST(m)	(m)
102 
103 #define	LOMBUS_DUMMY_ADDRESS	((caddr_t)0x0CADD1ED)
104 #define	ADDR_TO_OFFSET(a, hdlp)	((caddr_t)(a) - HANDLE_ADDR(hdlp))
105 #define	ADDR_TO_VREG(a)		((caddr_t)(a) - LOMBUS_DUMMY_ADDRESS)
106 #define	VREG_TO_ADDR(v)		(LOMBUS_DUMMY_ADDRESS + (v))
107 
108 
109 /*
110  * The following definitions are taken from the datasheet
111  * for the National Semiconductor PC87317 (SuperIO) chip.
112  *
113  * This chip implements UART functionality as logical device 6.
114  * It provides all sorts of wierd modes and extensions, but we
115  * have chosen to use only the 16550-compatible features
116  * ("non-extended mode").
117  *
118  * Hardware: serial chip register numbers
119  */
120 #define	SIO_RXD			0	/* read		*/
121 #define	SIO_TXD			0	/* write	*/
122 #define	SIO_IER			1
123 #define	SIO_EIR			2	/* read		*/
124 #define	SIO_FCR			2	/* write	*/
125 #define	SIO_LCR			3
126 #define	SIO_BSR			3	/* wierd	*/
127 #define	SIO_MCR			4
128 #define	SIO_LSR			5
129 #define	SIO_MSR			6
130 #define	SIO_SCR			7
131 
132 #define	SIO_LBGDL		0	/* bank 1	*/
133 #define	SIO_LBGDH		1	/* bank 1	*/
134 
135 /*
136  * Hardware: serial chip register bits
137  */
138 #define	SIO_IER_RXHDL_IE	0x01
139 #define	SIO_IER_STD		0x00
140 
141 #define	SIO_EIR_IPF		0x01
142 #define	SIO_EIR_IPR0		0x02
143 #define	SIO_EIR_IPR1		0x04
144 #define	SIO_EIR_RXFT		0x08
145 #define	SIO_EIR_FEN0		0x40
146 #define	SIO_EIR_FEN1		0x80
147 
148 #define	SIO_FCR_FIFO_EN		0x01
149 #define	SIO_FCR_RXSR		0x02
150 #define	SIO_FCR_TXSR		0x04
151 #define	SIO_FCR_RXFTH0		0x40
152 #define	SIO_FCR_RXFTH1		0x80
153 #define	SIO_FCR_STD		(SIO_FCR_RXFTH0|SIO_FCR_FIFO_EN)
154 
155 #define	SIO_LCR_WLS0		0x01
156 #define	SIO_LCR_WLS1		0x02
157 #define	SIO_LCR_STB		0x04
158 #define	SIO_LCR_PEN		0x08
159 #define	SIO_LCR_EPS		0x10
160 #define	SIO_LCR_STKP		0x20
161 #define	SIO_LCR_SBRK		0x40
162 #define	SIO_LCR_BKSE		0x80
163 #define	SIO_LCR_8BIT		(SIO_LCR_WLS0|SIO_LCR_WLS1)
164 #define	SIO_LCR_EPAR		(SIO_LCR_PEN|SIO_LCR_EPS)
165 #define	SIO_LCR_STD		(SIO_LCR_8BIT|SIO_LCR_EPAR)
166 
167 #define	SIO_BSR_BANK0		(SIO_LCR_STD)
168 #define	SIO_BSR_BANK1		(SIO_LCR_BKSE|SIO_LCR_STD)
169 
170 #define	SIO_MCR_DTR		0x01
171 #define	SIO_MCR_RTS		0x02
172 #define	SIO_MCR_ISEN		0x08
173 #define	SIO_MCR_STD		(SIO_MCR_ISEN)
174 
175 #define	SIO_LSR_RXDA		0x01
176 #define	SIO_LSR_OE		0x02
177 #define	SIO_LSR_PE		0x04
178 #define	SIO_LSR_FE		0x08
179 #define	SIO_LSR_BRKE		0x10
180 #define	SIO_LSR_TXRDY		0x20
181 #define	SIO_LSR_TXEMP		0x40
182 #define	SIO_LSR_ER_INF		0x80
183 
184 #define	SIO_MSR_DCTS		0x01
185 #define	SIO_MSR_DDSR		0x02
186 #define	SIO_MSR_TERI		0x04
187 #define	SIO_MSR_DDCD		0x08
188 #define	SIO_MSR_CTS		0x10
189 #define	SIO_MSR_DSR		0x20
190 #define	SIO_MSR_RI		0x40
191 #define	SIO_MSR_DCD		0x80
192 
193 /*
194  * Min/max/default baud rates, and a macro to convert from a baud
195  * rate to the number (divisor) to put in the baud rate registers
196  */
197 #define	SIO_BAUD_MIN		50
198 #define	SIO_BAUD_MAX		115200
199 #define	SIO_BAUD_DEFAULT	38400
200 #define	SIO_BAUD_TO_DIVISOR(b)	(115200 / (b))
201 
202 
203 /*
204  * Packet format ...
205  */
206 #define	LOMBUS_MASK		0xc0	/* Byte-type bits		*/
207 #define	LOMBUS_PARAM		0x00	/* Parameter byte: 0b0xxxxxxx	*/
208 #define	LOMBUS_LAST		0x80	/* Last byte of packet		*/
209 #define	LOMBUS_CMD		0x80	/* Command byte:   0b10###XWV	*/
210 #define	LOMBUS_STATUS		0xc0	/* Status  byte:   0b11###AEV	*/
211 
212 #define	LOMBUS_SEQ		0x38	/* Sequence number bits		*/
213 #define	LOMBUS_SEQ_LSB		0x08	/* Sequence number LSB		*/
214 #define	LOMBUS_CMD_XADDR	0x04	/* Extended (2-byte) addressing	*/
215 #define	LOMBUS_CMD_WRITE	0x02	/* Write command		*/
216 #define	LOMBUS_CMD_WMSB		0x01	/* Set MSB on Write		*/
217 #define	LOMBUS_CMD_READ		0x01	/* Read command			*/
218 #define	LOMBUS_CMD_NOP		0x00	/* NOP command			*/
219 
220 #define	LOMBUS_STATUS_ASYNC	0x04	/* Asynchronous event pending	*/
221 #define	LOMBUS_STATUS_ERR	0x02	/* Error in command processing	*/
222 #define	LOMBUS_STATUS_MSB	0x01	/* MSB of Value read		*/
223 
224 #define	LOMBUS_VREG_LO(x)	((x) & ((1 << 7) - 1))
225 #define	LOMBUS_VREG_HI(x)	((x) >> 7)
226 
227 #define	LOMBUS_BUFSIZE		8
228 
229 
230 /*
231  * Time periods, in nanoseconds
232  *
233  * Note that LOMBUS_ONE_SEC and some other time
234  * periods are defined in <sys/lombus.h>
235  */
236 #define	LOMBUS_CMD_POLL		(LOMBUS_ONE_SEC/20)
237 #define	LOMBUS_CTS_POLL		(LOMBUS_ONE_SEC/20)
238 #define	LOMBUS_CTS_TIMEOUT	(LOMBUS_ONE_SEC*2)
239 
240 
241 /*
242  * Local datatypes
243  */
244 enum lombus_cmdstate {
245 	LOMBUS_CMDSTATE_IDLE,
246 	LOMBUS_CMDSTATE_BUSY,
247 	LOMBUS_CMDSTATE_WAITING,
248 	LOMBUS_CMDSTATE_READY,
249 	LOMBUS_CMDSTATE_ERROR
250 };
251 
252 
253 /*
254  * This driver's soft-state structure
255  */
256 
257 struct lombus_state {
258 	/*
259 	 * Configuration data, set during attach
260 	 */
261 	dev_info_t *dip;
262 	major_t majornum;
263 	int instance;
264 
265 	ddi_acc_handle_t sio_handle;
266 	uint8_t *sio_regs;
267 	ddi_softintr_t softid;
268 	cyclic_id_t cycid;
269 
270 	/*
271 	 * Parameters derived from .conf properties
272 	 */
273 	boolean_t allow_echo;
274 	int baud;
275 	uint32_t debug;
276 	boolean_t fake_cts;
277 
278 	/*
279 	 * Hardware mutex (initialised using <hw_iblk>),
280 	 * used to prevent retriggering the softint while
281 	 * it's still fetching data out of the chip FIFO.
282 	 */
283 	kmutex_t hw_mutex[1];
284 	ddi_iblock_cookie_t hw_iblk;
285 
286 	/*
287 	 * Data protected by the hardware mutex: the watchdog-patting
288 	 * protocol data (since the dog can be patted from a high-level
289 	 * cyclic), and the interrupt-enabled flag.
290 	 */
291 	hrtime_t hw_last_pat;
292 	boolean_t hw_int_enabled;
293 
294 	/*
295 	 * Flag to indicate that we've incurred a hardware fault on
296 	 * accesses to the SIO; once this is set, we fake all further
297 	 * accesses in order not to provoke additional bus errors.
298 	 */
299 	boolean_t sio_fault;
300 
301 	/*
302 	 * Serial protocol state data, protected by lo_mutex
303 	 * (which is initialised using <lo_iblk>)
304 	 */
305 	kmutex_t lo_mutex[1];
306 	ddi_iblock_cookie_t lo_iblk;
307 	kcondvar_t lo_cv[1];
308 
309 	volatile enum lombus_cmdstate cmdstate;
310 	clock_t deadline;
311 	uint8_t cmdbuf[LOMBUS_BUFSIZE];
312 	uint8_t reply[LOMBUS_BUFSIZE];
313 	uint8_t async;
314 	uint8_t index;
315 	uint8_t result;
316 	uint8_t sequence;
317 	uint32_t error;
318 };
319 
320 /*
321  * The auxiliary structure attached to each child
322  * (the child's parent-private-data points to this).
323  */
324 struct lombus_child_info {
325 	lombus_regspec_t *rsp;
326 	int nregs;
327 };
328 
329 
330 /*
331  * Local data
332  */
333 
334 static void *lombus_statep;
335 
336 static major_t lombus_major = NOMAJOR;
337 
338 static ddi_device_acc_attr_t lombus_dev_acc_attr[1] =
339 {
340 	DDI_DEVICE_ATTR_V0,
341 	DDI_STRUCTURE_LE_ACC,
342 	DDI_STRICTORDER_ACC
343 };
344 
345 
346 /*
347  *  General utility routines ...
348  */
349 
350 static void
351 lombus_trace(struct lombus_state *ssp, char code, const char *caller,
352 	const char *fmt, ...)
353 {
354 	char buf[256];
355 	char *p;
356 	va_list va;
357 
358 	if (ssp->debug & (1 << (code-'@'))) {
359 		p = buf;
360 		snprintf(p, sizeof (buf) - (p - buf),
361 			"%s/%s: ", MYNAME, caller);
362 		p += strlen(p);
363 
364 		va_start(va, fmt);
365 		vsnprintf(p, sizeof (buf) - (p - buf), fmt, va);
366 		va_end(va);
367 
368 		buf[sizeof (buf) - 1] = '\0';
369 		strlog(ssp->majornum, ssp->instance, code, SL_TRACE, buf);
370 	}
371 }
372 
373 static struct lombus_state *
374 lombus_getstate(dev_info_t *dip, int instance, const char *caller)
375 {
376 	struct lombus_state *ssp = NULL;
377 	dev_info_t *sdip = NULL;
378 	major_t dmaj = NOMAJOR;
379 
380 	if (dip != NULL) {
381 		/*
382 		 * Use the instance number from the <dip>; also,
383 		 * check that it really corresponds to this driver
384 		 */
385 		instance = ddi_get_instance(dip);
386 		dmaj = ddi_driver_major(dip);
387 		if (lombus_major == NOMAJOR && dmaj != NOMAJOR)
388 			lombus_major = dmaj;
389 		else if (dmaj != lombus_major) {
390 			cmn_err(CE_WARN,
391 			    "%s: major number mismatch (%d vs. %d) in %s(),"
392 			    "probably due to child misconfiguration",
393 			    MYNAME, lombus_major, dmaj, caller);
394 			instance = -1;
395 		}
396 	}
397 
398 	if (instance >= 0)
399 		ssp = ddi_get_soft_state(lombus_statep, instance);
400 	if (ssp != NULL) {
401 		sdip = ssp->dip;
402 		if (dip == NULL && sdip == NULL)
403 			ssp = NULL;
404 		else if (dip != NULL && sdip != NULL && sdip != dip) {
405 			cmn_err(CE_WARN,
406 			    "%s: devinfo mismatch (%p vs. %p) in %s(), "
407 			    "probably due to child misconfiguration",
408 			    MYNAME, (void *)dip, (void *)sdip, caller);
409 			ssp = NULL;
410 		}
411 	}
412 
413 	return (ssp);
414 }
415 
416 /*
417  * Lowest-level serial I/O chip register read/write
418  */
419 
420 static void
421 sio_put_reg(struct lombus_state *ssp, uint_t reg, uint8_t val)
422 {
423 	lombus_trace(ssp, 'P', "sio_put_reg", "REG[%d] <- $%02x", reg, val);
424 
425 	if (ssp->sio_handle != NULL && !ssp->sio_fault) {
426 		/*
427 		 * The chip is mapped as "I/O" (e.g. with the side-effect
428 		 * bit on SPARC), therefore accesses are required to be
429 		 * in-order, with no value cacheing.  However, there can
430 		 * still be write-behind buffering, so it is not guaranteed
431 		 * that a write actually reaches the chip in a given time.
432 		 *
433 		 * To force the access right through to the chip, we follow
434 		 * the write with another write (to the SCRATCH register)
435 		 * and a read (of the value just written to the SCRATCH
436 		 * register).  The SCRATCH register is specifically provided
437 		 * for temporary data and has no effect on the SIO's own
438 		 * operation, making it ideal as a synchronising mechanism.
439 		 *
440 		 * If we didn't do this, it would be possible that the new
441 		 * value wouldn't reach the chip (and have the *intended*
442 		 * side-effects, such as disabling interrupts), for such a
443 		 * long time that the processor could execute a *lot* of
444 		 * instructions - including exiting the interrupt service
445 		 * routine and re-enabling interrupts.  This effect was
446 		 * observed to lead to spurious (unclaimed) interrupts in
447 		 * some circumstances.
448 		 *
449 		 * This will no longer be needed once "synchronous" access
450 		 * handles are available (see PSARC/2000/269 and 2000/531).
451 		 */
452 		ddi_put8(ssp->sio_handle, ssp->sio_regs + reg, val);
453 		ddi_put8(ssp->sio_handle, ssp->sio_regs + SIO_SCR, val);
454 		membar_sync();
455 		(void) ddi_get8(ssp->sio_handle, ssp->sio_regs + SIO_SCR);
456 	}
457 }
458 
459 static uint8_t
460 sio_get_reg(struct lombus_state *ssp, uint_t reg)
461 {
462 	uint8_t val;
463 
464 	if (ssp->sio_handle && !ssp->sio_fault)
465 		val = ddi_get8(ssp->sio_handle, ssp->sio_regs + reg);
466 	else
467 		val = DUMMY_VALUE;
468 
469 	lombus_trace(ssp, 'G', "sio_get_reg", "$%02x <- REG[%d]", val, reg);
470 
471 	return (val);
472 }
473 
474 static void
475 sio_check_fault_status(struct lombus_state *ssp)
476 {
477 	ssp->sio_fault = ddi_check_acc_handle(ssp->sio_handle) != DDI_SUCCESS;
478 }
479 
480 static boolean_t
481 sio_faulty(struct lombus_state *ssp)
482 {
483 	if (!ssp->sio_fault)
484 		sio_check_fault_status(ssp);
485 	return (ssp->sio_fault);
486 }
487 
488 
489 /*
490  * Check for data ready.
491  */
492 static boolean_t
493 sio_data_ready(struct lombus_state *ssp)
494 {
495 	uint8_t status;
496 
497 	/*
498 	 * Data is available if the RXDA bit in the LSR is nonzero
499 	 * (if reading it didn't incur a fault).
500 	 */
501 	status = sio_get_reg(ssp, SIO_LSR);
502 	return ((status & SIO_LSR_RXDA) != 0 && !sio_faulty(ssp));
503 }
504 
505 /*
506  * Check for LOM ready
507  */
508 static boolean_t
509 sio_lom_ready(struct lombus_state *ssp)
510 {
511 	uint8_t status;
512 	boolean_t rslt;
513 
514 	/*
515 	 * The LOM is ready if the CTS bit in the MSR is 1, meaning
516 	 * that the /CTS signal is being asserted (driven LOW) -
517 	 * unless we incurred a fault in trying to read the MSR!
518 	 *
519 	 * For debugging, we force the result to TRUE if the FAKE flag is set
520 	 */
521 	status = sio_get_reg(ssp, SIO_MSR);
522 	rslt = (status & SIO_MSR_CTS) != 0 && !sio_faulty(ssp);
523 
524 	lombus_trace(ssp, 'R', "sio_lom_ready", "S $%02x R %d F %d",
525 		status, rslt, ssp->fake_cts);
526 
527 	return (rslt || ssp->fake_cts);
528 }
529 
530 #if	0
531 /*
532  * Check for interrupt pending
533  */
534 static boolean_t
535 sio_irq_pending(struct lombus_state *ssp)
536 {
537 	uint8_t status;
538 	boolean_t rslt;
539 
540 	/*
541 	 * An interrupt is pending if the IPF bit in the EIR is 0,
542 	 * assuming we didn't incur a fault in trying to ready it.
543 	 *
544 	 * Note: we expect that every time we read this register
545 	 * (which is only done from the interrupt service routine),
546 	 * we will see $11001100 (RX FIFO timeout interrupt pending).
547 	 */
548 	status = sio_get_reg(ssp, SIO_EIR);
549 
550 	rslt = (status & SIO_EIR_IPF) == 0 && !sio_faulty(ssp);
551 	lombus_trace(ssp, 'I', "sio_irq_pending", "S $%02x R %d",
552 		status, rslt);
553 
554 	/*
555 	 * To investigate whether we're getting any abnormal interrupts
556 	 * this code checks that the status value is as expected, and that
557 	 * chip-level interrupts are supposed to be enabled at this time.
558 	 * This will cause a PANIC (on a driver compiled with DEBUG) if
559 	 * all is not as expected ...
560 	 */
561 	ASSERT(status == 0xCC);
562 	ASSERT(ssp->hw_int_enabled);
563 
564 	return (rslt);
565 }
566 #endif	/* 0 */
567 
568 /*
569  * Enable/disable interrupts
570  */
571 static void
572 lombus_set_irq(struct lombus_state *ssp, boolean_t newstate)
573 {
574 	uint8_t val;
575 
576 	val = newstate ? SIO_IER_RXHDL_IE : 0;
577 	sio_put_reg(ssp, SIO_IER, SIO_IER_STD | val);
578 	ssp->hw_int_enabled = newstate;
579 }
580 
581 /*
582  * Assert/deassert RTS
583  */
584 static void
585 lombus_toggle_rts(struct lombus_state *ssp)
586 {
587 	uint8_t val;
588 
589 	val = sio_get_reg(ssp, SIO_MCR);
590 	val &= SIO_MCR_RTS;
591 	val ^= SIO_MCR_RTS;
592 	val |= SIO_MCR_STD;
593 	sio_put_reg(ssp, SIO_MCR, val);
594 }
595 
596 
597 /*
598  * High-level interrupt handler:
599  *	Checks whether initialisation is complete (to avoid a race
600  *	with mutex_init()), and whether chip interrupts are enabled.
601  *	If not, the interrupt's not for us, so just return UNCLAIMED.
602  *	Otherwise, disable the interrupt, trigger a softint, and return
603  *	CLAIMED.  The softint handler will then do all the real work.
604  *
605  *	NOTE: the chip interrupt capability is only re-enabled once the
606  *	receive code has run, but that can be called from a poll loop
607  *	or cyclic callback as well as from the softint.  So it's *not*
608  *	guaranteed that there really is a chip interrupt pending here,
609  *	'cos the work may already have been done and the reason for the
610  *	interrupt gone away before we get here.
611  *
612  *	OTOH, if we come through here twice without the receive code
613  *	having run in between, that's definitely wrong.  In such an
614  *	event, we would notice that chip interrupts haven't yet been
615  *	re-enabled and return UNCLAIMED, allowing the system's jabber
616  *	protect code (if any) to do its job.
617  */
618 static uint_t
619 lombus_hi_intr(caddr_t arg)
620 {
621 	struct lombus_state *ssp = (void *)arg;
622 	uint_t claim;
623 
624 	claim = DDI_INTR_UNCLAIMED;
625 	if (ssp->cycid != CYCLIC_NONE) {
626 		mutex_enter(ssp->hw_mutex);
627 		if (ssp->hw_int_enabled) {
628 			lombus_set_irq(ssp, B_FALSE);
629 			ddi_trigger_softintr(ssp->softid);
630 			claim = DDI_INTR_CLAIMED;
631 		}
632 		mutex_exit(ssp->hw_mutex);
633 	}
634 
635 	return (claim);
636 }
637 
638 /*
639  * Packet receive handler
640  *
641  * This routine should be called from the low-level softint, or the
642  * cyclic callback, or lombus_cmd() (for polled operation), with the
643  * low-level mutex already held.
644  */
645 static void
646 lombus_receive(struct lombus_state *ssp)
647 {
648 	boolean_t ready = B_FALSE;
649 	uint8_t data = 0;
650 	uint8_t rcvd = 0;
651 	uint8_t tmp;
652 
653 	lombus_trace(ssp, 'S', "lombus_receive",
654 		"state %d; error $%x",
655 		ssp->cmdstate, ssp->error);
656 
657 	/*
658 	 * Check for access faults before starting the receive
659 	 * loop (we don't want to cause bus errors or suchlike
660 	 * unpleasantness in the event that the SIO has died).
661 	 */
662 	if (!sio_faulty(ssp)) {
663 		/*
664 		 * Read bytes from the FIFO until they're all gone,
665 		 * or we find the 'END OF PACKET' set on one, or
666 		 * our buffer overflows (which must be an error)
667 		 */
668 		mutex_enter(ssp->hw_mutex);
669 		while (sio_data_ready(ssp)) {
670 			data = sio_get_reg(ssp, SIO_RXD);
671 			ssp->reply[rcvd = ssp->index] = data;
672 			if (++rcvd >= LOMBUS_BUFSIZE)
673 				break;
674 			ssp->index = rcvd;
675 			if (data & LOMBUS_LAST)
676 				break;
677 		}
678 		lombus_set_irq(ssp, B_TRUE);
679 		mutex_exit(ssp->hw_mutex);
680 	}
681 
682 	lombus_trace(ssp, 'S', "lombus_receive",
683 		"rcvd %d: $%02x $%02x $%02x $%02x $%02x $%02x $%02x $%02x",
684 		rcvd,
685 		ssp->reply[0], ssp->reply[1],
686 		ssp->reply[2], ssp->reply[3],
687 		ssp->reply[4], ssp->reply[5],
688 		ssp->reply[6], ssp->reply[7]);
689 
690 	if (ssp->cmdstate != LOMBUS_CMDSTATE_WAITING) {
691 		/*
692 		 * We're not expecting any data in this state, so if
693 		 * we DID receive any data, we just throw it away by
694 		 * resetting the buffer index to 0.
695 		 */
696 		ssp->index = 0;
697 	} else if (rcvd == 0) {
698 		/*
699 		 * No bytes received this time through (though there
700 		 * might be a partial packet sitting in the buffer).
701 		 * If it seems the LOM is taking too long to respond,
702 		 * we'll assume it's died and return an error.
703 		 */
704 		if (ddi_get_lbolt() > ssp->deadline) {
705 			ssp->cmdstate = LOMBUS_CMDSTATE_ERROR;
706 			ssp->error = LOMBUS_ERR_TIMEOUT;
707 			ready = B_TRUE;
708 		}
709 	} else if (rcvd >= LOMBUS_BUFSIZE) {
710 		/*
711 		 * Buffer overflow; discard the data & treat as an error
712 		 * (even if the last byte read did claim to terminate a
713 		 * packet, it can't be a valid one 'cos it's too long!)
714 		 */
715 		ssp->index = 0;
716 		ssp->cmdstate = LOMBUS_CMDSTATE_ERROR;
717 		ssp->error = LOMBUS_ERR_OFLOW;
718 		ready = B_TRUE;
719 	} else if ((data & LOMBUS_LAST) == 0) {
720 		/*
721 		 * Packet not yet complete; leave the partial packet in
722 		 * the buffer for later ...
723 		 */
724 		_NOTE(EMPTY)
725 		;
726 	} else if ((data & LOMBUS_MASK) != LOMBUS_STATUS) {
727 		/*
728 		 * Invalid "status" byte - maybe an echo of the command?
729 		 *
730 		 * As a debugging feature, we allow for this, assuming
731 		 * that if the LOM has echoed the command byte, it has
732 		 * also echoed all the parameter bytes before starting
733 		 * command processing.  So, we dump out the buffer and
734 		 * then clear it, so we can go back to looking for the
735 		 * real reply.
736 		 *
737 		 * Otherwise, we just drop the data & flag an error.
738 		 */
739 		if (ssp->allow_echo) {
740 			lombus_trace(ssp, 'E', "lombus_receive",
741 				"echo $%02x $%02x $%02x $%02x "
742 				"$%02x $%02x $%02x $%02x",
743 				ssp->reply[0], ssp->reply[1],
744 				ssp->reply[2], ssp->reply[3],
745 				ssp->reply[4], ssp->reply[5],
746 				ssp->reply[6], ssp->reply[7]);
747 			ssp->index = 0;
748 		} else {
749 			ssp->cmdstate = LOMBUS_CMDSTATE_ERROR;
750 			ssp->error = LOMBUS_ERR_BADSTATUS;
751 			ready = B_TRUE;
752 		}
753 	} else if ((data & LOMBUS_SEQ) != ssp->sequence) {
754 		/*
755 		 * Wrong sequence number!  Flag this as an error
756 		 */
757 		ssp->cmdstate = LOMBUS_CMDSTATE_ERROR;
758 		ssp->error = LOMBUS_ERR_SEQUENCE;
759 		ready = B_TRUE;
760 	} else {
761 		/*
762 		 * Finally, we know that's it's a valid reply to our
763 		 * last command.  Update the ASYNC status, derive the
764 		 * reply parameter (if any), and check the ERROR bit
765 		 * to find out what the parameter means.
766 		 *
767 		 * Note that not all the values read/assigned here
768 		 * are meaningful, but it doesn't matter; the waiting
769 		 * thread will know which one(s) it should check.
770 		 */
771 		ssp->async = (data & LOMBUS_STATUS_ASYNC) ? 1 : 0;
772 		tmp = ((data & LOMBUS_STATUS_MSB) ? 0x80 : 0) | ssp->reply[0];
773 		if (data & LOMBUS_STATUS_ERR) {
774 			ssp->cmdstate = LOMBUS_CMDSTATE_ERROR;
775 			ssp->error = tmp;
776 		} else {
777 			ssp->cmdstate = LOMBUS_CMDSTATE_READY;
778 			ssp->result = tmp;
779 		}
780 		ready = B_TRUE;
781 	}
782 
783 	lombus_trace(ssp, 'T', "lombus_receive",
784 		"rcvd %d; last $%02x; state %d; error $%x; ready %d",
785 			rcvd, data, ssp->cmdstate, ssp->error, ready);
786 
787 	if (ready)
788 		cv_broadcast(ssp->lo_cv);
789 }
790 
791 /*
792  * Low-level softint handler
793  *
794  * This routine should be triggered whenever there's a byte to be read
795  */
796 static uint_t
797 lombus_softint(caddr_t arg)
798 {
799 	struct lombus_state *ssp = (void *)arg;
800 
801 	mutex_enter(ssp->lo_mutex);
802 	lombus_receive(ssp);
803 	mutex_exit(ssp->lo_mutex);
804 
805 	return (DDI_INTR_CLAIMED);
806 }
807 
808 /*
809  * Cyclic handler: just calls the receive routine, in case interrupts
810  * are not being delivered and in order to handle command timeout
811  */
812 static void
813 lombus_cyclic(void *arg)
814 {
815 	struct lombus_state *ssp = (void *)arg;
816 
817 	mutex_enter(ssp->lo_mutex);
818 	lombus_receive(ssp);
819 	mutex_exit(ssp->lo_mutex);
820 }
821 
822 
823 /*
824  * Serial protocol
825  *
826  * This routine builds a command and sets it in progress.
827  */
828 static uint8_t
829 lombus_cmd(HANDLE_TYPE *hdlp, ptrdiff_t vreg, uint_t val, uint_t cmd)
830 {
831 	struct lombus_state *ssp;
832 	clock_t start;
833 	clock_t tick;
834 	uint8_t *p;
835 
836 	/*
837 	 * First of all, wait for the interface to be available.
838 	 *
839 	 * NOTE: we blow through all the mutex/cv/state checking and
840 	 * preempt any command in progress if the system is panicking!
841 	 */
842 	ssp = HANDLE_PRIVATE(hdlp);
843 	mutex_enter(ssp->lo_mutex);
844 	while (ssp->cmdstate != LOMBUS_CMDSTATE_IDLE && !panicstr)
845 		cv_wait(ssp->lo_cv, ssp->lo_mutex);
846 
847 	ssp->cmdstate = LOMBUS_CMDSTATE_BUSY;
848 	ssp->sequence = (ssp->sequence + LOMBUS_SEQ_LSB) & LOMBUS_SEQ;
849 
850 	/*
851 	 * We have exclusive ownership, so assemble the command (backwards):
852 	 *
853 	 * [byte 0]	Command:	modified by XADDR and/or WMSB bits
854 	 * [Optional] Parameter: 	Value to write (low 7 bits)
855 	 * [Optional] Parameter: 	Register number (high 7 bits)
856 	 * [Optional] Parameter: 	Register number (low 7 bits)
857 	 */
858 	p = &ssp->cmdbuf[0];
859 	*p++ = LOMBUS_CMD | ssp->sequence | cmd;
860 	switch (cmd) {
861 	case LOMBUS_CMD_WRITE:
862 		*p++ = val & 0x7f;
863 		if (val >= 0x80)
864 			ssp->cmdbuf[0] |= LOMBUS_CMD_WMSB;
865 		/*FALLTHRU*/
866 	case LOMBUS_CMD_READ:
867 		if (LOMBUS_VREG_HI(vreg) != 0) {
868 			*p++ = LOMBUS_VREG_HI(vreg);
869 			ssp->cmdbuf[0] |= LOMBUS_CMD_XADDR;
870 		}
871 		*p++ = LOMBUS_VREG_LO(vreg);
872 		/*FALLTHRU*/
873 	case LOMBUS_CMD_NOP:
874 		break;
875 	}
876 
877 	/*
878 	 * Check and update the SIO h/w fault status before accessing
879 	 * the chip registers.  If there's a (new or previous) fault,
880 	 * we'll run through the protocol but won't really touch the
881 	 * hardware and all commands will timeout.  If a previously
882 	 * discovered fault has now gone away (!), then we can (try to)
883 	 * proceed with the new command (probably a probe).
884 	 */
885 	sio_check_fault_status(ssp);
886 
887 	/*
888 	 * Wait up to LOMBUS_CTS_TIMEOUT (2 seconds) for the LOM to tell
889 	 * us that it's ready for the next command.  If it doesn't, though,
890 	 * we'll send it anyway, on the basis that the CTS signal might be
891 	 * open- or short-circuited (or the LOM firmware forgot to set it,
892 	 * or the LOM just got reset, or whatever ...)
893 	 */
894 	start = ddi_get_lbolt();
895 	ssp->deadline = start + drv_usectohz(LOMBUS_CTS_TIMEOUT/1000);
896 	while (!sio_lom_ready(ssp)) {
897 		if ((tick = ddi_get_lbolt()) > ssp->deadline)
898 			break;
899 		tick += drv_usectohz(LOMBUS_CTS_POLL/1000);
900 		cv_timedwait(ssp->lo_cv, ssp->lo_mutex, tick);
901 	}
902 
903 	/*
904 	 * Either the LOM is ready, or we timed out waiting for CTS.
905 	 * In either case, we're going to send the command now by
906 	 * stuffing the packet into the Tx FIFO, reversing it as we go.
907 	 * We call lombus_receive() first to ensure there isn't any
908 	 * garbage left in the Rx FIFO from an earlier command that
909 	 * timed out (or was pre-empted by a PANIC!).  This also makes
910 	 * sure that SIO interrupts are enabled so we'll see the reply
911 	 * more quickly (the poll loop below will still work even if
912 	 * interrupts aren't enabled, but it will take longer).
913 	 */
914 	lombus_receive(ssp);
915 	mutex_enter(ssp->hw_mutex);
916 	while (p > ssp->cmdbuf)
917 		sio_put_reg(ssp, SIO_TXD, *--p);
918 	mutex_exit(ssp->hw_mutex);
919 
920 	/*
921 	 * Prepare for the reply (to be processed by the interrupt/cyclic
922 	 * handler and/or polling loop below), then wait for a response
923 	 * or timeout.
924 	 */
925 	start = ddi_get_lbolt();
926 	ssp->deadline = start + drv_usectohz(LOMBUS_CMD_TIMEOUT/1000);
927 	ssp->error = 0;
928 	ssp->index = 0;
929 	ssp->result = DUMMY_VALUE;
930 	ssp->cmdstate = LOMBUS_CMDSTATE_WAITING;
931 	while (ssp->cmdstate == LOMBUS_CMDSTATE_WAITING) {
932 		tick = ddi_get_lbolt() + drv_usectohz(LOMBUS_CMD_POLL/1000);
933 		if (cv_timedwait(ssp->lo_cv, ssp->lo_mutex, tick) == -1)
934 			lombus_receive(ssp);
935 	}
936 
937 	/*
938 	 * The return value may not be meaningful but retrieve it anyway
939 	 */
940 	val = ssp->result;
941 	if (sio_faulty(ssp)) {
942 		val = DUMMY_VALUE;
943 		HANDLE_FAULT(hdlp) = LOMBUS_ERR_SIOHW;
944 	} else if (ssp->cmdstate != LOMBUS_CMDSTATE_READY) {
945 		/*
946 		 * Some problem here ... transfer the error code from
947 		 * the per-instance state to the per-handle fault flag.
948 		 * The error code shouldn't be zero!
949 		 */
950 		if (ssp->error != 0)
951 			HANDLE_FAULT(hdlp) = ssp->error;
952 		else
953 			HANDLE_FAULT(hdlp) = LOMBUS_ERR_BADERRCODE;
954 	}
955 
956 	/*
957 	 * All done now!
958 	 */
959 	ssp->index = 0;
960 	ssp->cmdstate = LOMBUS_CMDSTATE_IDLE;
961 	cv_broadcast(ssp->lo_cv);
962 	mutex_exit(ssp->lo_mutex);
963 
964 	return (val);
965 }
966 
967 
968 /*
969  * Space 0 - LOM virtual register access
970  * Only 8-bit accesses are supported.
971  */
972 static uint8_t
973 lombus_vreg_get8(HANDLE_TYPE *hdlp, uint8_t *addr)
974 {
975 	ptrdiff_t offset;
976 
977 	/*
978 	 * Check the offset that the caller has added to the base address
979 	 * against the length of the mapping originally requested.
980 	 */
981 	offset = ADDR_TO_OFFSET(addr, hdlp);
982 	if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) {
983 		/*
984 		 * Invalid access - flag a fault and return a dummy value
985 		 */
986 		HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
987 		return (DUMMY_VALUE);
988 	}
989 
990 	/*
991 	 * Derive the virtual register number and run the command
992 	 */
993 	return (lombus_cmd(hdlp, ADDR_TO_VREG(addr), 0, LOMBUS_CMD_READ));
994 }
995 
996 static void
997 lombus_vreg_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val)
998 {
999 	ptrdiff_t offset;
1000 
1001 	/*
1002 	 * Check the offset that the caller has added to the base address
1003 	 * against the length of the mapping originally requested.
1004 	 */
1005 	offset = ADDR_TO_OFFSET(addr, hdlp);
1006 	if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) {
1007 		/*
1008 		 * Invalid access - flag a fault and return
1009 		 */
1010 		HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
1011 		return;
1012 	}
1013 
1014 	/*
1015 	 * Derive the virtual register number and run the command
1016 	 */
1017 	(void) lombus_cmd(hdlp, ADDR_TO_VREG(addr), val, LOMBUS_CMD_WRITE);
1018 }
1019 
1020 static void
1021 lombus_vreg_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1022 	uint8_t *dev_addr, size_t repcount, uint_t flags)
1023 {
1024 	size_t inc;
1025 
1026 	inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1027 	for (; repcount--; dev_addr += inc)
1028 		*host_addr++ = lombus_vreg_get8(hdlp, dev_addr);
1029 }
1030 
1031 static void
1032 lombus_vreg_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1033 	uint8_t *dev_addr, size_t repcount, uint_t flags)
1034 {
1035 	size_t inc;
1036 
1037 	inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1038 	for (; repcount--; dev_addr += inc)
1039 		lombus_vreg_put8(hdlp, dev_addr, *host_addr++);
1040 }
1041 
1042 
1043 /*
1044  * Space 1 - LOM watchdog pat register access
1045  * Only 8-bit accesses are supported.
1046  *
1047  * Reads have no effect and return 0.
1048  *
1049  * Writes pat the dog by toggling the RTS line iff enough time has
1050  * elapsed since last time we toggled it.
1051  *
1052  * Multi-byte reads (using ddi_rep_get8(9F)) are a fairly inefficient
1053  * way of zeroing the destination area ;-) and still won't pat the dog.
1054  *
1055  * Multi-byte writes (using ddi_rep_put8(9F)) will almost certainly
1056  * only count as a single pat, no matter how many bytes the caller
1057  * says to write, as the inter-pat time is VERY long compared with
1058  * the time it will take to read the memory source area.
1059  */
1060 
1061 static uint8_t
1062 lombus_pat_get8(HANDLE_TYPE *hdlp, uint8_t *addr)
1063 {
1064 	ptrdiff_t offset;
1065 
1066 	/*
1067 	 * Check the offset that the caller has added to the base address
1068 	 * against the length of the mapping originally requested.
1069 	 */
1070 	offset = ADDR_TO_OFFSET(addr, hdlp);
1071 	if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) {
1072 		/*
1073 		 * Invalid access - flag a fault and return a dummy value
1074 		 */
1075 		HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
1076 		return (DUMMY_VALUE);
1077 	}
1078 
1079 	return (0);
1080 }
1081 
1082 static void
1083 lombus_pat_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val)
1084 {
1085 	struct lombus_state *ssp;
1086 	ptrdiff_t offset;
1087 	hrtime_t now;
1088 
1089 	_NOTE(ARGUNUSED(val))
1090 
1091 	/*
1092 	 * Check the offset that the caller has added to the base address
1093 	 * against the length of the mapping originally requested.
1094 	 */
1095 	offset = ADDR_TO_OFFSET(addr, hdlp);
1096 	if (offset < 0 || offset >= HANDLE_MAPLEN(hdlp)) {
1097 		/*
1098 		 * Invalid access - flag a fault and return
1099 		 */
1100 		HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
1101 		return;
1102 	}
1103 
1104 	ssp = HANDLE_PRIVATE(hdlp);
1105 	mutex_enter(ssp->hw_mutex);
1106 	now = gethrtime();
1107 	if ((now - ssp->hw_last_pat) >= LOMBUS_MIN_PAT) {
1108 		lombus_toggle_rts(ssp);
1109 		ssp->hw_last_pat = now;
1110 	}
1111 	mutex_exit(ssp->hw_mutex);
1112 }
1113 
1114 static void
1115 lombus_pat_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1116 	uint8_t *dev_addr, size_t repcount, uint_t flags)
1117 {
1118 	size_t inc;
1119 
1120 	inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1121 	for (; repcount--; dev_addr += inc)
1122 		*host_addr++ = lombus_pat_get8(hdlp, dev_addr);
1123 }
1124 
1125 static void
1126 lombus_pat_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1127 	uint8_t *dev_addr, size_t repcount, uint_t flags)
1128 {
1129 	size_t inc;
1130 
1131 	inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1132 	for (; repcount--; dev_addr += inc)
1133 		lombus_pat_put8(hdlp, dev_addr, *host_addr++);
1134 }
1135 
1136 
1137 /*
1138  * Space 2 - LOM async event flag register access
1139  * Only 16-bit accesses are supported.
1140  */
1141 static uint16_t
1142 lombus_event_get16(HANDLE_TYPE *hdlp, uint16_t *addr)
1143 {
1144 	struct lombus_state *ssp;
1145 	ptrdiff_t offset;
1146 
1147 	/*
1148 	 * Check the offset that the caller has added to the base address
1149 	 * against the length of the mapping orignally requested.
1150 	 */
1151 	offset = ADDR_TO_OFFSET(addr, hdlp);
1152 	if (offset < 0 || (offset%2) != 0 || offset >= HANDLE_MAPLEN(hdlp)) {
1153 		/*
1154 		 * Invalid access - flag a fault and return a dummy value
1155 		 */
1156 		HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
1157 		return (DUMMY_VALUE);
1158 	}
1159 
1160 	/*
1161 	 * Return the value of the asynchronous-event-pending flag
1162 	 * as passed back by the LOM at the end of the last command.
1163 	 */
1164 	ssp = HANDLE_PRIVATE(hdlp);
1165 	return (ssp->async);
1166 }
1167 
1168 static void
1169 lombus_event_put16(HANDLE_TYPE *hdlp, uint16_t *addr, uint16_t val)
1170 {
1171 	ptrdiff_t offset;
1172 
1173 	_NOTE(ARGUNUSED(val))
1174 
1175 	/*
1176 	 * Check the offset that the caller has added to the base address
1177 	 * against the length of the mapping originally requested.
1178 	 */
1179 	offset = ADDR_TO_OFFSET(addr, hdlp);
1180 	if (offset < 0 || (offset%2) != 0 || offset >= HANDLE_MAPLEN(hdlp)) {
1181 		/*
1182 		 * Invalid access - flag a fault and return
1183 		 */
1184 		HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_NUM;
1185 		return;
1186 	}
1187 
1188 	/*
1189 	 * The user can't overwrite the asynchronous-event-pending flag!
1190 	 */
1191 	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_RO;
1192 }
1193 
1194 static void
1195 lombus_event_rep_get16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
1196 	uint16_t *dev_addr, size_t repcount, uint_t flags)
1197 {
1198 	size_t inc;
1199 
1200 	inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1201 	for (; repcount--; dev_addr += inc)
1202 		*host_addr++ = lombus_event_get16(hdlp, dev_addr);
1203 }
1204 
1205 static void
1206 lombus_event_rep_put16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
1207 	uint16_t *dev_addr, size_t repcount, uint_t flags)
1208 {
1209 	size_t inc;
1210 
1211 	inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1212 	for (; repcount--; dev_addr += inc)
1213 		lombus_event_put16(hdlp, dev_addr, *host_addr++);
1214 }
1215 
1216 
1217 /*
1218  * All spaces - access handle fault information
1219  * Only 32-bit accesses are supported.
1220  */
1221 static uint32_t
1222 lombus_meta_get32(HANDLE_TYPE *hdlp, uint32_t *addr)
1223 {
1224 	struct lombus_state *ssp;
1225 	ptrdiff_t offset;
1226 
1227 	/*
1228 	 * Derive the offset that the caller has added to the base
1229 	 * address originally returned, and use it to determine
1230 	 * which meta-register is to be accessed ...
1231 	 */
1232 	offset = ADDR_TO_OFFSET(addr, hdlp);
1233 	switch (offset) {
1234 	case LOMBUS_FAULT_REG:
1235 		/*
1236 		 * This meta-register provides a code for the most
1237 		 * recent virtual register access fault, if any.
1238 		 */
1239 		return (HANDLE_FAULT(hdlp));
1240 
1241 	case LOMBUS_PROBE_REG:
1242 		/*
1243 		 * Reading this meta-register clears any existing fault
1244 		 * (at the virtual, not the hardware access layer), then
1245 		 * runs a NOP command and returns the fault code from that.
1246 		 */
1247 		HANDLE_FAULT(hdlp) = 0;
1248 		lombus_cmd(hdlp, 0, 0, LOMBUS_CMD_NOP);
1249 		return (HANDLE_FAULT(hdlp));
1250 
1251 	case LOMBUS_ASYNC_REG:
1252 		/*
1253 		 * Obsolescent - but still supported for backwards
1254 		 * compatibility.  This is an alias for the newer
1255 		 * LOMBUS_EVENT_REG, but doesn't require a separate
1256 		 * "reg" entry and ddi_regs_map_setup() call.
1257 		 *
1258 		 * It returns the value of the asynchronous-event-pending
1259 		 * flag as passed back by the LOM at the end of the last
1260 		 * completed command.
1261 		 */
1262 		ssp = HANDLE_PRIVATE(hdlp);
1263 		return (ssp->async);
1264 
1265 	default:
1266 		/*
1267 		 * Invalid access - flag a fault and return a dummy value
1268 		 */
1269 		HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1270 		return (DUMMY_VALUE);
1271 	}
1272 }
1273 
1274 static void
1275 lombus_meta_put32(HANDLE_TYPE *hdlp, uint32_t *addr, uint32_t val)
1276 {
1277 	ptrdiff_t offset;
1278 
1279 	/*
1280 	 * Derive the offset that the caller has added to the base
1281 	 * address originally returned, and use it to determine
1282 	 * which meta-register is to be accessed ...
1283 	 */
1284 	offset = ADDR_TO_OFFSET(addr, hdlp);
1285 	switch (offset) {
1286 	case LOMBUS_FAULT_REG:
1287 		/*
1288 		 * This meta-register contains a code for the most
1289 		 * recent virtual register access fault, if any.
1290 		 * It can be cleared simply by writing 0 to it.
1291 		 */
1292 		HANDLE_FAULT(hdlp) = val;
1293 		return;
1294 
1295 	case LOMBUS_PROBE_REG:
1296 		/*
1297 		 * Writing this meta-register clears any existing fault
1298 		 * (at the virtual, not the hardware acess layer), then
1299 		 * runs a NOP command.  The caller can check the fault
1300 		 * code later if required.
1301 		 */
1302 		HANDLE_FAULT(hdlp) = 0;
1303 		lombus_cmd(hdlp, 0, 0, LOMBUS_CMD_NOP);
1304 		return;
1305 
1306 	default:
1307 		/*
1308 		 * Invalid access - flag a fault
1309 		 */
1310 		HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1311 		return;
1312 	}
1313 }
1314 
1315 static void
1316 lombus_meta_rep_get32(HANDLE_TYPE *hdlp, uint32_t *host_addr,
1317 	uint32_t *dev_addr, size_t repcount, uint_t flags)
1318 {
1319 	size_t inc;
1320 
1321 	inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1322 	for (; repcount--; dev_addr += inc)
1323 		*host_addr++ = lombus_meta_get32(hdlp, dev_addr);
1324 }
1325 
1326 static void
1327 lombus_meta_rep_put32(HANDLE_TYPE *hdlp, uint32_t *host_addr,
1328 	uint32_t *dev_addr, size_t repcount, uint_t flags)
1329 {
1330 	size_t inc;
1331 
1332 	inc = (flags & DDI_DEV_AUTOINCR) ? 1 : 0;
1333 	for (; repcount--; dev_addr += inc)
1334 		lombus_meta_put32(hdlp, dev_addr, *host_addr++);
1335 }
1336 
1337 
1338 /*
1339  * Finally, some dummy functions for all unsupported access
1340  * space/size/mode combinations ...
1341  */
1342 static uint8_t
1343 lombus_no_get8(HANDLE_TYPE *hdlp, uint8_t *addr)
1344 {
1345 	_NOTE(ARGUNUSED(addr))
1346 
1347 	/*
1348 	 * Invalid access - flag a fault and return a dummy value
1349 	 */
1350 	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1351 	return (DUMMY_VALUE);
1352 }
1353 
1354 static void
1355 lombus_no_put8(HANDLE_TYPE *hdlp, uint8_t *addr, uint8_t val)
1356 {
1357 	_NOTE(ARGUNUSED(addr, val))
1358 
1359 	/*
1360 	 * Invalid access - flag a fault
1361 	 */
1362 	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1363 }
1364 
1365 static void
1366 lombus_no_rep_get8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1367 		uint8_t *dev_addr, size_t repcount, uint_t flags)
1368 {
1369 	_NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
1370 
1371 	/*
1372 	 * Invalid access - flag a fault
1373 	 */
1374 	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1375 }
1376 
1377 static void
1378 lombus_no_rep_put8(HANDLE_TYPE *hdlp, uint8_t *host_addr,
1379 	uint8_t *dev_addr, size_t repcount, uint_t flags)
1380 {
1381 	_NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
1382 
1383 	/*
1384 	 * Invalid access - flag a fault
1385 	 */
1386 	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1387 }
1388 
1389 static uint16_t
1390 lombus_no_get16(HANDLE_TYPE *hdlp, uint16_t *addr)
1391 {
1392 	_NOTE(ARGUNUSED(addr))
1393 
1394 	/*
1395 	 * Invalid access - flag a fault and return a dummy value
1396 	 */
1397 	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1398 	return (DUMMY_VALUE);
1399 }
1400 
1401 static void
1402 lombus_no_put16(HANDLE_TYPE *hdlp, uint16_t *addr, uint16_t val)
1403 {
1404 	_NOTE(ARGUNUSED(addr, val))
1405 
1406 	/*
1407 	 * Invalid access - flag a fault
1408 	 */
1409 	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1410 }
1411 
1412 static void
1413 lombus_no_rep_get16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
1414 		uint16_t *dev_addr, size_t repcount, uint_t flags)
1415 {
1416 	_NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
1417 
1418 	/*
1419 	 * Invalid access - flag a fault
1420 	 */
1421 	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1422 }
1423 
1424 static void
1425 lombus_no_rep_put16(HANDLE_TYPE *hdlp, uint16_t *host_addr,
1426 	uint16_t *dev_addr, size_t repcount, uint_t flags)
1427 {
1428 	_NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
1429 
1430 	/*
1431 	 * Invalid access - flag a fault
1432 	 */
1433 	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1434 }
1435 
1436 static uint64_t
1437 lombus_no_get64(HANDLE_TYPE *hdlp, uint64_t *addr)
1438 {
1439 	_NOTE(ARGUNUSED(addr))
1440 
1441 	/*
1442 	 * Invalid access - flag a fault and return a dummy value
1443 	 */
1444 	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1445 	return (DUMMY_VALUE);
1446 }
1447 
1448 static void
1449 lombus_no_put64(HANDLE_TYPE *hdlp, uint64_t *addr, uint64_t val)
1450 {
1451 	_NOTE(ARGUNUSED(addr, val))
1452 
1453 	/*
1454 	 * Invalid access - flag a fault
1455 	 */
1456 	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1457 }
1458 
1459 static void
1460 lombus_no_rep_get64(HANDLE_TYPE *hdlp, uint64_t *host_addr,
1461 	uint64_t *dev_addr, size_t repcount, uint_t flags)
1462 {
1463 	_NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
1464 
1465 	/*
1466 	 * Invalid access - flag a fault
1467 	 */
1468 	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1469 }
1470 
1471 static void
1472 lombus_no_rep_put64(HANDLE_TYPE *hdlp, uint64_t *host_addr,
1473 	uint64_t *dev_addr, size_t repcount, uint_t flags)
1474 {
1475 	_NOTE(ARGUNUSED(host_addr, dev_addr, repcount, flags))
1476 
1477 	/*
1478 	 * Invalid access - flag a fault
1479 	 */
1480 	HANDLE_FAULT(hdlp) = LOMBUS_ERR_REG_SIZE;
1481 }
1482 
1483 static int
1484 lombus_acc_fault_check(HANDLE_TYPE *hdlp)
1485 {
1486 	return (HANDLE_FAULT(hdlp) != 0);
1487 }
1488 
1489 
1490 /*
1491  * Hardware setup - put the SIO chip in the required operational
1492  * state,  with all our favourite parameters programmed correctly.
1493  * This routine leaves all SIO interrupts disabled.
1494  */
1495 
1496 static void
1497 lombus_hw_reset(struct lombus_state *ssp)
1498 {
1499 	uint16_t divisor;
1500 
1501 	/*
1502 	 * Disable interrupts, soft reset Tx and Rx circuitry,
1503 	 * reselect standard modes (bits/char, parity, etc).
1504 	 */
1505 	lombus_set_irq(ssp, B_FALSE);
1506 	sio_put_reg(ssp, SIO_FCR, SIO_FCR_RXSR | SIO_FCR_TXSR);
1507 	sio_put_reg(ssp, SIO_LCR, SIO_LCR_STD);
1508 
1509 	/*
1510 	 * Select the proper baud rate; if the value is invalid
1511 	 * (presumably 0, i.e. not specified, but also if the
1512 	 * "baud" property is set to some silly value), we assume
1513 	 * the default.
1514 	 */
1515 	if (ssp->baud < SIO_BAUD_MIN || ssp->baud > SIO_BAUD_MAX)
1516 		divisor = SIO_BAUD_TO_DIVISOR(SIO_BAUD_DEFAULT);
1517 	else
1518 		divisor = SIO_BAUD_TO_DIVISOR(ssp->baud);
1519 
1520 	/*
1521 	 * According to the datasheet, it is forbidden for the divisor
1522 	 * register to be zero.  So when loading the register in two
1523 	 * steps, we have to make sure that the temporary value formed
1524 	 * between loads is nonzero.  However, we can't rely on either
1525 	 * half already having a nonzero value, as the datasheet also
1526 	 * says that these registers are indeterminate after a reset!
1527 	 * So, we explicitly set the low byte to a non-zero value first;
1528 	 * then we can safely load the high byte, and then the correct
1529 	 * value for the low byte, without the result ever being zero.
1530 	 */
1531 	sio_put_reg(ssp, SIO_BSR, SIO_BSR_BANK1);
1532 	sio_put_reg(ssp, SIO_LBGDL, 0xff);
1533 	sio_put_reg(ssp, SIO_LBGDH, divisor >> 8);
1534 	sio_put_reg(ssp, SIO_LBGDL, divisor & 0xff);
1535 	sio_put_reg(ssp, SIO_BSR, SIO_BSR_BANK0);
1536 
1537 	/*
1538 	 * Program the remaining device registers as required
1539 	 */
1540 	sio_put_reg(ssp, SIO_MCR, SIO_MCR_STD);
1541 	sio_put_reg(ssp, SIO_FCR, SIO_FCR_STD);
1542 }
1543 
1544 
1545 /*
1546  * Higher-level setup & teardown
1547  */
1548 
1549 static void
1550 lombus_offline(struct lombus_state *ssp)
1551 {
1552 	if (ssp->sio_handle != NULL)
1553 		ddi_regs_map_free(&ssp->sio_handle);
1554 	ssp->sio_handle = NULL;
1555 	ssp->sio_regs = NULL;
1556 }
1557 
1558 static int
1559 lombus_online(struct lombus_state *ssp)
1560 {
1561 	ddi_acc_handle_t h;
1562 	caddr_t p;
1563 	int nregs;
1564 	int err;
1565 
1566 	if (ddi_dev_nregs(ssp->dip, &nregs) != DDI_SUCCESS)
1567 		nregs = 0;
1568 
1569 	switch (nregs) {
1570 	default:
1571 	case 1:
1572 		/*
1573 		 *  regset 0 represents the SIO operating registers
1574 		 */
1575 		err = ddi_regs_map_setup(ssp->dip, 0, &p, 0, 0,
1576 		    lombus_dev_acc_attr, &h);
1577 		lombus_trace(ssp, 'O', "online",
1578 		    "regmap 0 status %d addr $%p", err, p);
1579 		if (err != DDI_SUCCESS)
1580 			return (EIO);
1581 
1582 		ssp->sio_handle = h;
1583 		ssp->sio_regs = (void *)p;
1584 		break;
1585 
1586 	case 0:
1587 		/*
1588 		 *  If no registers are defined, succeed vacuously;
1589 		 *  commands will be accepted, but we fake the accesses.
1590 		 */
1591 		break;
1592 	}
1593 
1594 	/*
1595 	 * Now that the registers are mapped, we can initialise the SIO h/w
1596 	 */
1597 	lombus_hw_reset(ssp);
1598 	return (0);
1599 }
1600 
1601 
1602 /*
1603  *  Nexus routines
1604  */
1605 
1606 #if	defined(NDI_ACC_HDL_V2)
1607 
1608 static const ndi_acc_fns_t lombus_vreg_acc_fns = {
1609 	NDI_ACC_FNS_CURRENT,
1610 	NDI_ACC_FNS_V1,
1611 
1612 	lombus_vreg_get8,
1613 	lombus_vreg_put8,
1614 	lombus_vreg_rep_get8,
1615 	lombus_vreg_rep_put8,
1616 
1617 	lombus_no_get16,
1618 	lombus_no_put16,
1619 	lombus_no_rep_get16,
1620 	lombus_no_rep_put16,
1621 
1622 	lombus_meta_get32,
1623 	lombus_meta_put32,
1624 	lombus_meta_rep_get32,
1625 	lombus_meta_rep_put32,
1626 
1627 	lombus_no_get64,
1628 	lombus_no_put64,
1629 	lombus_no_rep_get64,
1630 	lombus_no_rep_put64,
1631 
1632 	lombus_acc_fault_check
1633 };
1634 
1635 static const ndi_acc_fns_t lombus_pat_acc_fns = {
1636 	NDI_ACC_FNS_CURRENT,
1637 	NDI_ACC_FNS_V1,
1638 
1639 	lombus_pat_get8,
1640 	lombus_pat_put8,
1641 	lombus_pat_rep_get8,
1642 	lombus_pat_rep_put8,
1643 
1644 	lombus_no_get16,
1645 	lombus_no_put16,
1646 	lombus_no_rep_get16,
1647 	lombus_no_rep_put16,
1648 
1649 	lombus_meta_get32,
1650 	lombus_meta_put32,
1651 	lombus_meta_rep_get32,
1652 	lombus_meta_rep_put32,
1653 
1654 	lombus_no_get64,
1655 	lombus_no_put64,
1656 	lombus_no_rep_get64,
1657 	lombus_no_rep_put64,
1658 
1659 	lombus_acc_fault_check
1660 };
1661 
1662 static const ndi_acc_fns_t lombus_event_acc_fns = {
1663 	NDI_ACC_FNS_CURRENT,
1664 	NDI_ACC_FNS_V1,
1665 
1666 	lombus_no_get8,
1667 	lombus_no_put8,
1668 	lombus_no_rep_get8,
1669 	lombus_no_rep_put8,
1670 
1671 	lombus_event_get16,
1672 	lombus_event_put16,
1673 	lombus_event_rep_get16,
1674 	lombus_event_rep_put16,
1675 
1676 	lombus_meta_get32,
1677 	lombus_meta_put32,
1678 	lombus_meta_rep_get32,
1679 	lombus_meta_rep_put32,
1680 
1681 	lombus_no_get64,
1682 	lombus_no_put64,
1683 	lombus_no_rep_get64,
1684 	lombus_no_rep_put64,
1685 
1686 	lombus_acc_fault_check
1687 };
1688 
1689 static int
1690 lombus_map_handle(struct lombus_state *ssp, ddi_map_op_t op,
1691 	int space, caddr_t vaddr, off_t len,
1692 	ndi_acc_handle_t *hdlp, caddr_t *addrp)
1693 {
1694 	switch (op) {
1695 	default:
1696 		return (DDI_ME_UNIMPLEMENTED);
1697 
1698 	case DDI_MO_MAP_LOCKED:
1699 		switch (space) {
1700 		default:
1701 			return (DDI_ME_REGSPEC_RANGE);
1702 
1703 		case LOMBUS_VREG_SPACE:
1704 			ndi_set_acc_fns(hdlp, &lombus_vreg_acc_fns);
1705 			break;
1706 
1707 		case LOMBUS_PAT_SPACE:
1708 			ndi_set_acc_fns(hdlp, &lombus_pat_acc_fns);
1709 			break;
1710 
1711 		case LOMBUS_EVENT_SPACE:
1712 			ndi_set_acc_fns(hdlp, &lombus_event_acc_fns);
1713 			break;
1714 		}
1715 		hdlp->ah_addr = *addrp = vaddr;
1716 		hdlp->ah_len = len;
1717 		hdlp->ah_bus_private = ssp;
1718 		return (DDI_SUCCESS);
1719 
1720 	case DDI_MO_UNMAP:
1721 		*addrp = NULL;
1722 		hdlp->ah_bus_private = NULL;
1723 		return (DDI_SUCCESS);
1724 	}
1725 }
1726 
1727 #else
1728 
1729 static int
1730 lombus_map_handle(struct lombus_state *ssp, ddi_map_op_t op,
1731 	int space, caddr_t vaddr, off_t len,
1732 	ddi_acc_hdl_t *hdlp, caddr_t *addrp)
1733 {
1734 	ddi_acc_impl_t *aip = hdlp->ah_platform_private;
1735 
1736 	switch (op) {
1737 	default:
1738 		return (DDI_ME_UNIMPLEMENTED);
1739 
1740 	case DDI_MO_MAP_LOCKED:
1741 		switch (space) {
1742 		default:
1743 			return (DDI_ME_REGSPEC_RANGE);
1744 
1745 		case LOMBUS_VREG_SPACE:
1746 			aip->ahi_get8 = lombus_vreg_get8;
1747 			aip->ahi_put8 = lombus_vreg_put8;
1748 			aip->ahi_rep_get8 = lombus_vreg_rep_get8;
1749 			aip->ahi_rep_put8 = lombus_vreg_rep_put8;
1750 
1751 			aip->ahi_get16 = lombus_no_get16;
1752 			aip->ahi_put16 = lombus_no_put16;
1753 			aip->ahi_rep_get16 = lombus_no_rep_get16;
1754 			aip->ahi_rep_put16 = lombus_no_rep_put16;
1755 
1756 			aip->ahi_get32 = lombus_meta_get32;
1757 			aip->ahi_put32 = lombus_meta_put32;
1758 			aip->ahi_rep_get32 = lombus_meta_rep_get32;
1759 			aip->ahi_rep_put32 = lombus_meta_rep_put32;
1760 
1761 			aip->ahi_get64 = lombus_no_get64;
1762 			aip->ahi_put64 = lombus_no_put64;
1763 			aip->ahi_rep_get64 = lombus_no_rep_get64;
1764 			aip->ahi_rep_put64 = lombus_no_rep_put64;
1765 
1766 			aip->ahi_fault_check = lombus_acc_fault_check;
1767 			break;
1768 
1769 		case LOMBUS_PAT_SPACE:
1770 			aip->ahi_get8 = lombus_pat_get8;
1771 			aip->ahi_put8 = lombus_pat_put8;
1772 			aip->ahi_rep_get8 = lombus_pat_rep_get8;
1773 			aip->ahi_rep_put8 = lombus_pat_rep_put8;
1774 
1775 			aip->ahi_get16 = lombus_no_get16;
1776 			aip->ahi_put16 = lombus_no_put16;
1777 			aip->ahi_rep_get16 = lombus_no_rep_get16;
1778 			aip->ahi_rep_put16 = lombus_no_rep_put16;
1779 
1780 			aip->ahi_get32 = lombus_meta_get32;
1781 			aip->ahi_put32 = lombus_meta_put32;
1782 			aip->ahi_rep_get32 = lombus_meta_rep_get32;
1783 			aip->ahi_rep_put32 = lombus_meta_rep_put32;
1784 
1785 			aip->ahi_get64 = lombus_no_get64;
1786 			aip->ahi_put64 = lombus_no_put64;
1787 			aip->ahi_rep_get64 = lombus_no_rep_get64;
1788 			aip->ahi_rep_put64 = lombus_no_rep_put64;
1789 
1790 			aip->ahi_fault_check = lombus_acc_fault_check;
1791 			break;
1792 
1793 		case LOMBUS_EVENT_SPACE:
1794 			aip->ahi_get8 = lombus_no_get8;
1795 			aip->ahi_put8 = lombus_no_put8;
1796 			aip->ahi_rep_get8 = lombus_no_rep_get8;
1797 			aip->ahi_rep_put8 = lombus_no_rep_put8;
1798 
1799 			aip->ahi_get16 = lombus_event_get16;
1800 			aip->ahi_put16 = lombus_event_put16;
1801 			aip->ahi_rep_get16 = lombus_event_rep_get16;
1802 			aip->ahi_rep_put16 = lombus_event_rep_put16;
1803 
1804 			aip->ahi_get32 = lombus_meta_get32;
1805 			aip->ahi_put32 = lombus_meta_put32;
1806 			aip->ahi_rep_get32 = lombus_meta_rep_get32;
1807 			aip->ahi_rep_put32 = lombus_meta_rep_put32;
1808 
1809 			aip->ahi_get64 = lombus_no_get64;
1810 			aip->ahi_put64 = lombus_no_put64;
1811 			aip->ahi_rep_get64 = lombus_no_rep_get64;
1812 			aip->ahi_rep_put64 = lombus_no_rep_put64;
1813 
1814 			aip->ahi_fault_check = lombus_acc_fault_check;
1815 			break;
1816 		}
1817 		hdlp->ah_addr = *addrp = vaddr;
1818 		hdlp->ah_len = len;
1819 		hdlp->ah_bus_private = ssp;
1820 		return (DDI_SUCCESS);
1821 
1822 	case DDI_MO_UNMAP:
1823 		*addrp = NULL;
1824 		hdlp->ah_bus_private = NULL;
1825 		return (DDI_SUCCESS);
1826 	}
1827 }
1828 
1829 #endif	/* NDI_ACC_HDL_V2 */
1830 
1831 static int
1832 lombus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
1833 	off_t off, off_t len, caddr_t *addrp)
1834 {
1835 	struct lombus_child_info *lcip;
1836 	struct lombus_state *ssp;
1837 	lombus_regspec_t *rsp;
1838 
1839 	if ((ssp = lombus_getstate(dip, -1, "lombus_map")) == NULL)
1840 		return (DDI_FAILURE);	/* this "can't happen" */
1841 
1842 	/*
1843 	 * Validate mapping request ...
1844 	 */
1845 
1846 	if (mp->map_flags != DDI_MF_KERNEL_MAPPING)
1847 		return (DDI_ME_UNSUPPORTED);
1848 	if (mp->map_handlep == NULL)
1849 		return (DDI_ME_UNSUPPORTED);
1850 	if (mp->map_type != DDI_MT_RNUMBER)
1851 		return (DDI_ME_UNIMPLEMENTED);
1852 	if ((lcip = ddi_get_parent_data(rdip)) == NULL)
1853 		return (DDI_ME_INVAL);
1854 	if ((rsp = lcip->rsp) == NULL)
1855 		return (DDI_ME_INVAL);
1856 	if (mp->map_obj.rnumber >= lcip->nregs)
1857 		return (DDI_ME_RNUMBER_RANGE);
1858 	rsp += mp->map_obj.rnumber;
1859 	if (off < 0 || off >= rsp->lombus_size)
1860 		return (DDI_ME_INVAL);
1861 	if (len == 0)
1862 		len = rsp->lombus_size-off;
1863 	if (len < 0)
1864 		return (DDI_ME_INVAL);
1865 	if (off+len < 0 || off+len > rsp->lombus_size)
1866 		return (DDI_ME_INVAL);
1867 
1868 	return (lombus_map_handle(ssp, mp->map_op,
1869 		rsp->lombus_space, VREG_TO_ADDR(rsp->lombus_base+off), len,
1870 		mp->map_handlep, addrp));
1871 }
1872 
1873 static int
1874 lombus_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op,
1875 	void *arg, void *result)
1876 {
1877 	struct lombus_child_info *lcip;
1878 	struct lombus_state *ssp;
1879 	lombus_regspec_t *rsp;
1880 	dev_info_t *cdip;
1881 	char addr[32];
1882 	uint_t nregs;
1883 	uint_t rnum;
1884 	int *regs;
1885 	int limit;
1886 	int err;
1887 	int i;
1888 
1889 	if ((ssp = lombus_getstate(dip, -1, "lombus_ctlops")) == NULL)
1890 		return (DDI_FAILURE);	/* this "can't happen" */
1891 
1892 	switch (op) {
1893 	default:
1894 		break;
1895 
1896 	case DDI_CTLOPS_INITCHILD:
1897 		/*
1898 		 * First, look up and validate the "reg" property.
1899 		 *
1900 		 * It must be a non-empty integer array containing a set
1901 		 * of triples.  Once we've verified that, we can treat it
1902 		 * as an array of type lombus_regspec_t[], which defines
1903 		 * the meaning of the elements of each triple:
1904 		 * +  the first element of each triple must be a valid space
1905 		 * +  the second and third elements (base, size) of each
1906 		 *	triple must define a valid subrange of that space
1907 		 * If it passes all the tests, we save it away for future
1908 		 * reference in the child's parent-private-data field.
1909 		 */
1910 		cdip = arg;
1911 		err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip,
1912 			DDI_PROP_DONTPASS, "reg", &regs, &nregs);
1913 		lombus_trace(ssp, 'C', "initchild",
1914 		    "prop status %d size %d", err, nregs);
1915 		if (err != DDI_PROP_SUCCESS)
1916 			return (DDI_FAILURE);
1917 
1918 		err = (nregs <= 0 || (nregs % LOMBUS_REGSPEC_SIZE) != 0);
1919 		nregs /= LOMBUS_REGSPEC_SIZE;
1920 		rsp = (lombus_regspec_t *)regs;
1921 		for (i = 0; i < nregs && !err; ++i) {
1922 			switch (rsp[i].lombus_space) {
1923 			default:
1924 				limit = 0;
1925 				err = 1;
1926 				break;
1927 
1928 			case LOMBUS_VREG_SPACE:
1929 				limit = LOMBUS_MAX_REG+1;
1930 				break;
1931 
1932 			case LOMBUS_PAT_SPACE:
1933 				limit = LOMBUS_PAT_REG+1;
1934 				break;
1935 
1936 			case LOMBUS_EVENT_SPACE:
1937 				limit = LOMBUS_EVENT_REG+1;
1938 				break;
1939 			}
1940 
1941 			err |= (rsp[i].lombus_base < 0);
1942 			err |= (rsp[i].lombus_base >= limit);
1943 
1944 			if (rsp[i].lombus_size == 0)
1945 				rsp[i].lombus_size = limit-rsp[i].lombus_base;
1946 			err |= (rsp[i].lombus_size < 0);
1947 
1948 			err |= (rsp[i].lombus_base+rsp[i].lombus_size < 0);
1949 			err |= (rsp[i].lombus_base+rsp[i].lombus_size > limit);
1950 		}
1951 
1952 		if (err) {
1953 			ddi_prop_free(regs);
1954 			return (DDI_FAILURE);
1955 		}
1956 
1957 		lcip = kmem_zalloc(sizeof (*lcip), KM_SLEEP);
1958 		lcip->nregs = nregs;
1959 		lcip->rsp = rsp;
1960 		ddi_set_parent_data(cdip, lcip);
1961 
1962 		(void) snprintf(addr, sizeof (addr),
1963 			"%x,%x", rsp[0].lombus_space, rsp[0].lombus_base);
1964 		ddi_set_name_addr(cdip, addr);
1965 
1966 		return (DDI_SUCCESS);
1967 
1968 	case DDI_CTLOPS_UNINITCHILD:
1969 		cdip = arg;
1970 		ddi_set_name_addr(cdip, NULL);
1971 		lcip = ddi_get_parent_data(cdip);
1972 		ddi_set_parent_data(cdip, NULL);
1973 		ddi_prop_free(lcip->rsp);
1974 		kmem_free(lcip, sizeof (*lcip));
1975 		return (DDI_SUCCESS);
1976 
1977 	case DDI_CTLOPS_REPORTDEV:
1978 		if (rdip == NULL)
1979 			return (DDI_FAILURE);
1980 
1981 		cmn_err(CE_CONT, "?LOM device: %s@%s, %s#%d\n",
1982 			ddi_node_name(rdip), ddi_get_name_addr(rdip),
1983 			ddi_driver_name(dip), ddi_get_instance(dip));
1984 
1985 		return (DDI_SUCCESS);
1986 
1987 	case DDI_CTLOPS_REGSIZE:
1988 		if ((lcip = ddi_get_parent_data(rdip)) == NULL)
1989 			return (DDI_FAILURE);
1990 		if ((rnum = *(uint_t *)arg) >= lcip->nregs)
1991 			return (DDI_FAILURE);
1992 		*(off_t *)result = lcip->rsp[rnum].lombus_size;
1993 		return (DDI_SUCCESS);
1994 
1995 	case DDI_CTLOPS_NREGS:
1996 		if ((lcip = ddi_get_parent_data(rdip)) == NULL)
1997 			return (DDI_FAILURE);
1998 		*(int *)result = lcip->nregs;
1999 		return (DDI_SUCCESS);
2000 	}
2001 
2002 	return (ddi_ctlops(dip, rdip, op, arg, result));
2003 }
2004 
2005 
2006 /*
2007  *  Clean up on detach or failure of attach
2008  */
2009 static int
2010 lombus_unattach(struct lombus_state *ssp, int instance)
2011 {
2012 	if (ssp != NULL) {
2013 		lombus_hw_reset(ssp);
2014 		if (ssp->cycid != CYCLIC_NONE) {
2015 			mutex_enter(&cpu_lock);
2016 			cyclic_remove(ssp->cycid);
2017 			mutex_exit(&cpu_lock);
2018 			if (ssp->sio_handle != NULL)
2019 				ddi_remove_intr(ssp->dip, 0, ssp->hw_iblk);
2020 			ddi_remove_softintr(ssp->softid);
2021 			cv_destroy(ssp->lo_cv);
2022 			mutex_destroy(ssp->lo_mutex);
2023 			mutex_destroy(ssp->hw_mutex);
2024 		}
2025 		lombus_offline(ssp);
2026 		ddi_set_driver_private(ssp->dip, NULL);
2027 	}
2028 
2029 	ddi_soft_state_free(lombus_statep, instance);
2030 	return (DDI_FAILURE);
2031 }
2032 
2033 /*
2034  *  Autoconfiguration routines
2035  */
2036 
2037 static int
2038 lombus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2039 {
2040 	struct lombus_state *ssp = NULL;
2041 	cyc_handler_t cychand;
2042 	cyc_time_t cyctime;
2043 	int instance;
2044 	int err;
2045 
2046 	switch (cmd) {
2047 	default:
2048 		return (DDI_FAILURE);
2049 
2050 	case DDI_ATTACH:
2051 		break;
2052 	}
2053 
2054 	/*
2055 	 *  Allocate the soft-state structure
2056 	 */
2057 	instance = ddi_get_instance(dip);
2058 	if (ddi_soft_state_zalloc(lombus_statep, instance) != DDI_SUCCESS)
2059 		return (DDI_FAILURE);
2060 	if ((ssp = lombus_getstate(dip, instance, "lombus_attach")) == NULL)
2061 		return (lombus_unattach(ssp, instance));
2062 	ddi_set_driver_private(dip, ssp);
2063 
2064 	/*
2065 	 *  Initialise devinfo-related fields
2066 	 */
2067 	ssp->dip = dip;
2068 	ssp->majornum = ddi_driver_major(dip);
2069 	ssp->instance = instance;
2070 
2071 	/*
2072 	 *  Set various options from .conf properties
2073 	 */
2074 	ssp->allow_echo = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
2075 			DDI_PROP_DONTPASS, "allow-lom-echo", 0) != 0;
2076 	ssp->baud = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
2077 			DDI_PROP_DONTPASS, "baud-rate", 0);
2078 	ssp->debug = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
2079 			DDI_PROP_DONTPASS, "debug", 0);
2080 	ssp->fake_cts = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
2081 			DDI_PROP_DONTPASS, "fake-cts", 0) != 0;
2082 
2083 	/*
2084 	 * Initialise current state & time
2085 	 */
2086 	ssp->cmdstate = LOMBUS_CMDSTATE_IDLE;
2087 	ssp->hw_last_pat = gethrtime();
2088 	ssp->cycid = CYCLIC_NONE;
2089 
2090 	/*
2091 	 *  Online the hardware ...
2092 	 */
2093 	err = lombus_online(ssp);
2094 	if (err != 0)
2095 		return (lombus_unattach(ssp, instance));
2096 
2097 	/*
2098 	 * Install soft and hard interrupt handler(s)
2099 	 * Initialise mutexes and cv
2100 	 * Start cyclic callbacks
2101 	 * Enable interrupts
2102 	 */
2103 	err = ddi_add_softintr(dip, DDI_SOFTINT_LOW, &ssp->softid,
2104 		&ssp->lo_iblk, NULL, lombus_softint, (caddr_t)ssp);
2105 	if (err != DDI_SUCCESS)
2106 		return (lombus_unattach(ssp, instance));
2107 
2108 	if (ssp->sio_handle != NULL)
2109 		err = ddi_add_intr(dip, 0, &ssp->hw_iblk, NULL,
2110 			lombus_hi_intr, (caddr_t)ssp);
2111 
2112 	mutex_init(ssp->hw_mutex, NULL, MUTEX_DRIVER, ssp->hw_iblk);
2113 	mutex_init(ssp->lo_mutex, NULL, MUTEX_DRIVER, ssp->lo_iblk);
2114 	cv_init(ssp->lo_cv, NULL, CV_DRIVER, NULL);
2115 
2116 	cychand.cyh_func = lombus_cyclic;
2117 	cychand.cyh_arg = ssp;
2118 	cychand.cyh_level = CY_LOW_LEVEL;
2119 	cyctime.cyt_when = 0;			/* from the next second	*/
2120 	cyctime.cyt_interval = LOMBUS_ONE_SEC;	/* call at 1s intervals	*/
2121 	mutex_enter(&cpu_lock);
2122 	ssp->cycid = cyclic_add(&cychand, &cyctime);
2123 	mutex_exit(&cpu_lock);
2124 
2125 	/*
2126 	 * Final check before enabling h/w interrupts - did
2127 	 * we successfully install the h/w interrupt handler?
2128 	 */
2129 	if (err != DDI_SUCCESS)
2130 		return (lombus_unattach(ssp, instance));
2131 
2132 	lombus_set_irq(ssp, B_TRUE);
2133 
2134 	/*
2135 	 *  All done, report success
2136 	 */
2137 	ddi_report_dev(dip);
2138 	return (DDI_SUCCESS);
2139 }
2140 
2141 
2142 static int
2143 lombus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2144 {
2145 	struct lombus_state *ssp;
2146 	int instance;
2147 
2148 	switch (cmd) {
2149 	default:
2150 		return (DDI_FAILURE);
2151 
2152 	case DDI_DETACH:
2153 		break;
2154 	}
2155 
2156 	instance = ddi_get_instance(dip);
2157 	if ((ssp = lombus_getstate(dip, instance, "lombus_detach")) == NULL)
2158 		return (DDI_FAILURE);	/* this "can't happen" */
2159 
2160 	(void) lombus_unattach(ssp, instance);
2161 	return (DDI_SUCCESS);
2162 }
2163 
2164 static int
2165 lombus_reset(dev_info_t *dip, ddi_reset_cmd_t cmd)
2166 {
2167 	struct lombus_state *ssp;
2168 
2169 	_NOTE(ARGUNUSED(cmd))
2170 
2171 	if ((ssp = lombus_getstate(dip, -1, "lombus_reset")) == NULL)
2172 		return (DDI_FAILURE);
2173 
2174 	lombus_hw_reset(ssp);
2175 	return (DDI_SUCCESS);
2176 }
2177 
2178 
2179 /*
2180  * System interface structures
2181  */
2182 
2183 static struct cb_ops lombus_cb_ops =
2184 {
2185 	nodev,			/* b/c open	*/
2186 	nodev,			/* b/c close	*/
2187 	nodev,			/* b   strategy	*/
2188 	nodev,			/* b   print	*/
2189 	nodev,			/* b   dump 	*/
2190 	nodev,			/* c   read	*/
2191 	nodev,			/* c   write	*/
2192 	nodev,			/* c   ioctl	*/
2193 	nodev,			/* c   devmap	*/
2194 	nodev,			/* c   mmap	*/
2195 	nodev,			/* c   segmap	*/
2196 	nochpoll,		/* c   poll	*/
2197 	ddi_prop_op,		/* b/c prop_op	*/
2198 	NULL,			/* c   streamtab */
2199 	D_MP | D_NEW		/* b/c flags	*/
2200 };
2201 
2202 static struct bus_ops lombus_bus_ops =
2203 {
2204 	BUSO_REV,			/* revision		*/
2205 	lombus_map,			/* bus_map		*/
2206 	0,				/* get_intrspec		*/
2207 	0,				/* add_intrspec		*/
2208 	0,				/* remove_intrspec	*/
2209 	i_ddi_map_fault,		/* map_fault		*/
2210 	ddi_no_dma_map,			/* dma_map		*/
2211 	ddi_no_dma_allochdl,		/* allocate DMA handle	*/
2212 	ddi_no_dma_freehdl,		/* free DMA handle	*/
2213 	ddi_no_dma_bindhdl,		/* bind DMA handle	*/
2214 	ddi_no_dma_unbindhdl,		/* unbind DMA handle	*/
2215 	ddi_no_dma_flush,		/* flush DMA		*/
2216 	ddi_no_dma_win,			/* move DMA window	*/
2217 	ddi_no_dma_mctl,		/* generic DMA control	*/
2218 	lombus_ctlops,			/* generic control	*/
2219 	ddi_bus_prop_op,		/* prop_op		*/
2220 	ndi_busop_get_eventcookie,	/* get_eventcookie	*/
2221 	ndi_busop_add_eventcall,	/* add_eventcall	*/
2222 	ndi_busop_remove_eventcall,	/* remove_eventcall	*/
2223 	ndi_post_event,			/* post_event		*/
2224 	0,				/* interrupt control	*/
2225 	0,				/* bus_config		*/
2226 	0,				/* bus_unconfig		*/
2227 	0,				/* bus_fm_init		*/
2228 	0,				/* bus_fm_fini		*/
2229 	0,				/* bus_fm_access_enter	*/
2230 	0,				/* bus_fm_access_exit	*/
2231 	0,				/* bus_power		*/
2232 	i_ddi_intr_ops			/* bus_intr_op		*/
2233 };
2234 
2235 static struct dev_ops lombus_dev_ops =
2236 {
2237 	DEVO_REV,
2238 	0,				/* refcount		*/
2239 	ddi_no_info,			/* getinfo		*/
2240 	nulldev,			/* identify		*/
2241 	nulldev,			/* probe		*/
2242 	lombus_attach,			/* attach		*/
2243 	lombus_detach,			/* detach		*/
2244 	lombus_reset,			/* reset		*/
2245 	&lombus_cb_ops,			/* driver operations	*/
2246 	&lombus_bus_ops			/* bus operations	*/
2247 };
2248 
2249 static struct modldrv modldrv =
2250 {
2251 	&mod_driverops,
2252 	"lombus driver, v%I%",
2253 	&lombus_dev_ops
2254 };
2255 
2256 static struct modlinkage modlinkage =
2257 {
2258 	MODREV_1,
2259 	{
2260 		&modldrv,
2261 		NULL
2262 	}
2263 };
2264 
2265 
2266 /*
2267  *  Dynamic loader interface code
2268  */
2269 
2270 int
2271 _init(void)
2272 {
2273 	int err;
2274 
2275 	err = ddi_soft_state_init(&lombus_statep,
2276 		sizeof (struct lombus_state), 0);
2277 	if (err == DDI_SUCCESS)
2278 		if ((err = mod_install(&modlinkage)) != 0) {
2279 			ddi_soft_state_fini(&lombus_statep);
2280 		}
2281 
2282 	return (err);
2283 }
2284 
2285 int
2286 _info(struct modinfo *mip)
2287 {
2288 	return (mod_info(&modlinkage, mip));
2289 }
2290 
2291 int
2292 _fini(void)
2293 {
2294 	int err;
2295 
2296 	if ((err = mod_remove(&modlinkage)) == 0) {
2297 		ddi_soft_state_fini(&lombus_statep);
2298 		lombus_major = NOMAJOR;
2299 	}
2300 
2301 	return (err);
2302 }
2303