xref: /titanic_44/usr/src/uts/sun4u/io/i2c/nexus/i2bsc.c (revision 0f509175c7fa701d6edf3f65789303587905b1bd)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 /*
28  * i2bsc.c is the nexus driver i2c traffic against devices hidden behind the
29  * Blade Support Chip (BSC).  It supports both interrupt and polled
30  * mode operation, but defaults to interrupt.
31  */
32 
33 #include <sys/types.h>
34 #include <sys/conf.h>
35 #include <sys/file.h>
36 #include <sys/open.h>
37 #include <sys/ddi.h>
38 #include <sys/sunddi.h>
39 #include <sys/sunndi.h>
40 #include <sys/modctl.h>
41 #include <sys/stat.h>
42 #include <sys/kmem.h>
43 #include <sys/platform_module.h>
44 #include <sys/stream.h>
45 #include <sys/strlog.h>
46 #include <sys/log.h>
47 #include <sys/debug.h>
48 #include <sys/note.h>
49 
50 #include <sys/bscbus.h>
51 #include <sys/lom_ebuscodes.h>
52 
53 #include <sys/i2c/clients/i2c_client.h>
54 #include <sys/i2c/misc/i2c_svc.h>
55 #include <sys/i2c/misc/i2c_svc_impl.h>
56 #include <sys/i2c/nexus/i2bsc_impl.h>
57 
58 /*
59  * static function declarations
60  */
61 static void i2bsc_resume(dev_info_t *dip);
62 static void i2bsc_suspend(dev_info_t *dip);
63 static int i2bsc_bus_ctl(dev_info_t *dip, dev_info_t *rdip,
64 	ddi_ctl_enum_t op, void *arg, void *result);
65 static  void i2bsc_acquire(i2bsc_t *, dev_info_t *dip,
66 	i2c_transfer_t *tp);
67 static  void i2bsc_release(i2bsc_t *);
68 static int i2bsc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
69 static int i2bsc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
70 static int i2bsc_open(dev_t *devp, int flag, int otyp,
71     cred_t *cred_p);
72 static int i2bsc_close(dev_t dev, int flag, int otyp,
73     cred_t *cred_p);
74 static int i2bsc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
75 static int i2bsc_initchild(dev_info_t *dip, dev_info_t *cdip);
76 static int i2bsc_uninitchild(dev_info_t *dip, dev_info_t *cdip);
77 static int i2bsc_setup_regs(i2bsc_t *);
78 static void i2bsc_start_session(i2bsc_t *);
79 static void i2bsc_fail_session(i2bsc_t *);
80 static int i2bsc_end_session(i2bsc_t *);
81 static void i2bsc_free_regs(i2bsc_t *);
82 static int i2bsc_reportdev(dev_info_t *dip, dev_info_t *rdip);
83 int i2bsc_transfer(dev_info_t *dip, i2c_transfer_t *tp);
84 static void i2bsc_trace(i2bsc_t *, char, const char *,
85     const char *, ...);
86 static int i2bsc_notify_max_transfer_size(i2bsc_t *);
87 static int i2bsc_discover_capability(i2bsc_t *);
88 static void i2bsc_put8(i2bsc_t *, uint8_t, uint8_t, uint8_t);
89 static uint8_t i2bsc_get8(i2bsc_t *, uint8_t, uint8_t);
90 static int i2bsc_safe_upload(i2bsc_t *, i2c_transfer_t *);
91 static boolean_t i2bsc_is_firmware_broken(i2bsc_t *);
92 
93 static struct bus_ops i2bsc_busops = {
94 	BUSO_REV,
95 	nullbusmap,			/* bus_map */
96 	NULL,				/* bus_get_intrspec */
97 	NULL,				/* bus_add_intrspec */
98 	NULL,				/* bus_remove_intrspec */
99 	NULL,				/* bus_map_fault */
100 	ddi_no_dma_map,			/* bus_dma_map */
101 	ddi_no_dma_allochdl,		/* bus_dma_allochdl */
102 	ddi_no_dma_freehdl,		/* bus_dma_freehdl */
103 	ddi_no_dma_bindhdl,		/* bus_dma_bindhdl */
104 	ddi_no_dma_unbindhdl,		/* bus_unbindhdl */
105 	ddi_no_dma_flush,		/* bus_dma_flush */
106 	ddi_no_dma_win,			/* bus_dma_win */
107 	ddi_no_dma_mctl,		/* bus_dma_ctl */
108 	i2bsc_bus_ctl,			/* bus_ctl */
109 	ddi_bus_prop_op,		/* bus_prop_op */
110 	NULL,				/* bus_get_eventcookie */
111 	NULL,				/* bus_add_eventcall */
112 	NULL,				/* bus_remove_eventcall */
113 	NULL,				/* bus_post_event */
114 	0,				/* bus_intr_ctl */
115 	0,				/* bus_config		*/
116 	0,				/* bus_unconfig		*/
117 	0,				/* bus_fm_init		*/
118 	0,				/* bus_fm_fini		*/
119 	0,				/* bus_fm_access_enter	*/
120 	0,				/* bus_fm_access_exit	*/
121 	0,				/* bus_power		*/
122 	i_ddi_intr_ops			/* bus_intr_op		*/
123 
124 };
125 
126 struct cb_ops i2bsc_cb_ops = {
127 	i2bsc_open,		/* open */
128 	i2bsc_close,		/* close */
129 	nodev,			/* strategy */
130 	nodev,			/* print */
131 	nodev,			/* dump */
132 	nodev,			/* read */
133 	nodev,			/* write */
134 	i2bsc_ioctl,		/* ioctl */
135 	nodev,			/* devmap */
136 	nodev,			/* mmap */
137 	nodev,			/* segmap */
138 	nochpoll,		/* poll */
139 	ddi_prop_op,		/* cb_prop_op */
140 	0,			/* streamtab  */
141 	D_MP | D_NEW		/* Driver compatibility flag */
142 };
143 
144 static struct dev_ops i2bsc_ops = {
145 	DEVO_REV,
146 	0,
147 	ddi_getinfo_1to1,
148 	nulldev,
149 	nulldev,
150 	i2bsc_attach,
151 	i2bsc_detach,
152 	nodev,
153 	&i2bsc_cb_ops,
154 	&i2bsc_busops,
155 	NULL,
156 	ddi_quiesce_not_supported,	/* devo_quiesce */
157 };
158 
159 #ifdef DEBUG
160 #define	I2BSC_VERSION_STRING "i2bsc driver - Debug"
161 #else
162 #define	I2BSC_VERSION_STRING "i2bsc driver"
163 #endif
164 
165 static struct modldrv modldrv = {
166 	&mod_driverops, /* Type of module. This one is a driver */
167 	I2BSC_VERSION_STRING,	/* Name of the module. */
168 	&i2bsc_ops,		/* driver ops */
169 };
170 
171 static struct modlinkage modlinkage = {
172 	MODREV_1,
173 	&modldrv,
174 	NULL
175 };
176 
177 /*
178  * i2bsc soft state
179  */
180 static void	*i2bsc_state;
181 
182 i2c_nexus_reg_t i2bsc_regvec = {
183 	I2C_NEXUS_REV,
184 	i2bsc_transfer,
185 };
186 
187 int
188 _init(void)
189 {
190 	int status;
191 
192 	status = ddi_soft_state_init(&i2bsc_state, sizeof (i2bsc_t),
193 	    I2BSC_INITIAL_SOFT_SPACE);
194 	if (status != 0) {
195 		return (status);
196 	}
197 
198 	if ((status = mod_install(&modlinkage)) != 0) {
199 		ddi_soft_state_fini(&i2bsc_state);
200 	}
201 
202 	return (status);
203 }
204 
205 int
206 _fini(void)
207 {
208 	int status;
209 
210 	if ((status = mod_remove(&modlinkage)) == 0) {
211 		ddi_soft_state_fini(&i2bsc_state);
212 	}
213 
214 	return (status);
215 }
216 
217 /*
218  * The loadable-module _info(9E) entry point
219  */
220 int
221 _info(struct modinfo *modinfop)
222 {
223 	return (mod_info(&modlinkage, modinfop));
224 }
225 
226 static void
227 i2bsc_dodetach(dev_info_t *dip)
228 {
229 	i2bsc_t *i2c;
230 	int instance = ddi_get_instance(dip);
231 
232 	i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
233 
234 	if ((i2c->i2bsc_attachflags & IMUTEX) != 0) {
235 		mutex_destroy(&i2c->i2bsc_imutex);
236 		cv_destroy(&i2c->i2bsc_icv);
237 	}
238 	if ((i2c->i2bsc_attachflags & SETUP_REGS) != 0) {
239 		i2bsc_free_regs(i2c);
240 	}
241 	if ((i2c->i2bsc_attachflags & NEXUS_REGISTER) != 0) {
242 		i2c_nexus_unregister(dip);
243 	}
244 	if ((i2c->i2bsc_attachflags & MINOR_NODE) != 0) {
245 		ddi_remove_minor_node(dip, NULL);
246 	}
247 
248 	ddi_soft_state_free(i2bsc_state, instance);
249 }
250 
251 static int
252 i2bsc_doattach(dev_info_t *dip)
253 {
254 	i2bsc_t *i2c;
255 	int instance = ddi_get_instance(dip);
256 
257 	/*
258 	 * Allocate soft state structure.
259 	 */
260 	if (ddi_soft_state_zalloc(i2bsc_state, instance) != DDI_SUCCESS) {
261 		return (DDI_FAILURE);
262 	}
263 
264 	i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
265 
266 	i2c->majornum = ddi_driver_major(dip);
267 	i2c->minornum = instance;
268 	i2c->i2bsc_dip = dip;
269 	i2c->debug = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
270 	    DDI_PROP_DONTPASS, "debug", 0);
271 
272 	(void) snprintf(i2c->i2bsc_name, sizeof (i2c->i2bsc_name),
273 	    "%s_%d", ddi_node_name(dip), instance);
274 
275 	if (i2bsc_setup_regs(i2c) != DDI_SUCCESS) {
276 		goto bad;
277 	}
278 
279 	i2c->i2bsc_attachflags |= SETUP_REGS;
280 
281 	mutex_init(&i2c->i2bsc_imutex, NULL, MUTEX_DRIVER,
282 	    (void *) 0);
283 	cv_init(&i2c->i2bsc_icv, NULL, CV_DRIVER, NULL);
284 	i2c->i2bsc_attachflags |= IMUTEX;
285 
286 	i2c_nexus_register(dip, &i2bsc_regvec);
287 	i2c->i2bsc_attachflags |= NEXUS_REGISTER;
288 
289 	if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance,
290 	    DDI_NT_NEXUS, 0) == DDI_FAILURE) {
291 		cmn_err(CE_WARN, "%s ddi_create_minor_node failed",
292 		    i2c->i2bsc_name);
293 		goto bad;
294 	}
295 
296 	i2c->i2bsc_attachflags |= MINOR_NODE;
297 
298 	/*
299 	 * Now actually start talking to the microcontroller.  The first
300 	 * thing to check is whether the firmware is broken.
301 	 */
302 	if (i2bsc_is_firmware_broken(i2c)) {
303 		cmn_err(CE_WARN, "Underlying BSC hardware not communicating;"
304 		    " shutting down my i2c services");
305 		goto bad;
306 	}
307 
308 	i2c->i2bsc_attachflags |= FIRMWARE_ALIVE;
309 
310 	/*
311 	 * Now see if the BSC chip supports the i2c service we rely upon.
312 	 */
313 	(void) i2bsc_discover_capability(i2c);
314 
315 	if (i2bsc_notify_max_transfer_size(i2c) == DDI_SUCCESS)
316 		i2c->i2bsc_attachflags |= TRANSFER_SZ;
317 
318 	i2bsc_trace(i2c, 'A', "i2bsc_doattach", "attachflags %d",
319 	    i2c->i2bsc_attachflags);
320 
321 	return (DDI_SUCCESS);
322 
323 bad:
324 	i2bsc_dodetach(dip);
325 
326 	return (DDI_FAILURE);
327 }
328 
329 static int
330 i2bsc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
331 {
332 	switch (cmd) {
333 		case DDI_ATTACH:
334 		return (i2bsc_doattach(dip));
335 
336 		case DDI_RESUME:
337 		i2bsc_resume(dip);
338 		return (DDI_SUCCESS);
339 
340 		default:
341 		return (DDI_FAILURE);
342 	}
343 }
344 
345 static int
346 i2bsc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
347 {
348 	switch (cmd) {
349 	case DDI_DETACH:
350 		i2bsc_dodetach(dip);
351 		return (DDI_SUCCESS);
352 
353 	case DDI_SUSPEND:
354 		i2bsc_suspend(dip);
355 		return (DDI_SUCCESS);
356 
357 	default:
358 		return (DDI_FAILURE);
359 	}
360 }
361 
362 /*ARGSUSED*/
363 static int
364 i2bsc_open(dev_t  *devp,  int  flag,  int  otyp,  cred_t *cred_p)
365 {
366 	int instance;
367 	i2bsc_t *i2c;
368 
369 	/*
370 	 * Make sure the open is for the right file type
371 	 */
372 	if (otyp != OTYP_CHR)
373 		return (EINVAL);
374 
375 	instance = getminor(*devp);
376 	i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
377 	if (i2c == NULL)
378 		return (ENXIO);
379 
380 	/*
381 	 * Enforce exclusive access
382 	 */
383 	mutex_enter(&i2c->i2bsc_imutex);
384 	if (i2c->i2bsc_open) {
385 		mutex_exit(&i2c->i2bsc_imutex);
386 		return (EBUSY);
387 	} else
388 		i2c->i2bsc_open = 1;
389 
390 	mutex_exit(&i2c->i2bsc_imutex);
391 
392 	return (0);
393 }
394 
395 /*ARGSUSED*/
396 static int
397 i2bsc_close(dev_t  dev,  int  flag,  int  otyp,  cred_t *cred_p)
398 {
399 	int instance;
400 	i2bsc_t *i2c;
401 
402 	/*
403 	 * Make sure the close is for the right file type
404 	 */
405 	if (otyp != OTYP_CHR)
406 		return (EINVAL);
407 
408 	instance = getminor(dev);
409 	i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
410 	if (i2c == NULL)
411 		return (ENXIO);
412 
413 	mutex_enter(&i2c->i2bsc_imutex);
414 	i2c->i2bsc_open = 0;
415 	mutex_exit(&i2c->i2bsc_imutex);
416 
417 	return (0);
418 }
419 
420 /*ARGSUSED*/
421 static int
422 i2bsc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
423 	int *rvalp)
424 {
425 	i2bsc_t *i2c;
426 	dev_info_t *self;
427 	dev_info_t *child;
428 	struct devctl_iocdata *dcp;
429 	int rv;
430 
431 	i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, getminor(dev));
432 
433 	if (i2c == NULL)
434 		return (ENXIO);
435 
436 	self = (dev_info_t *)i2c->i2bsc_dip;
437 
438 	/*
439 	 * read devctl ioctl data
440 	 */
441 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) {
442 		return (EFAULT);
443 	}
444 
445 	switch (cmd) {
446 		case DEVCTL_BUS_DEV_CREATE:
447 		rv = ndi_dc_devi_create(dcp, self, 0, NULL);
448 		break;
449 
450 		case DEVCTL_DEVICE_REMOVE:
451 		if (ndi_dc_getname(dcp) == NULL ||
452 		    ndi_dc_getaddr(dcp) == NULL) {
453 			rv = EINVAL;
454 			break;
455 		}
456 
457 		/*
458 		 * lookup and hold child device
459 		 */
460 		child = ndi_devi_find(self,
461 		    ndi_dc_getname(dcp), ndi_dc_getaddr(dcp));
462 		if (child == NULL) {
463 			rv = ENXIO;
464 			break;
465 		}
466 
467 		if ((rv = ndi_devi_offline(child, NDI_DEVI_REMOVE)) !=
468 		    NDI_SUCCESS) {
469 			rv = (rv == NDI_BUSY) ? EBUSY : EIO;
470 		}
471 
472 		break;
473 
474 		default:
475 		rv = ENOTSUP;
476 	}
477 
478 	ndi_dc_freehdl(dcp);
479 
480 	return (rv);
481 }
482 
483 static int
484 i2bsc_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op,
485     void *arg, void *result)
486 {
487 	i2bsc_t	*i2c;
488 	int instance = ddi_get_instance(dip);
489 
490 	i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
491 
492 	i2bsc_trace(i2c, 'A', "i2bsc_bus_ctl", "dip/rdip,op/arg"
493 	    " %p/%p,%d/%p", dip, rdip, (int)op, arg);
494 
495 	switch (op) {
496 		case DDI_CTLOPS_INITCHILD:
497 		return (i2bsc_initchild(dip, (dev_info_t *)arg));
498 
499 		case DDI_CTLOPS_UNINITCHILD:
500 		return (i2bsc_uninitchild(dip, (dev_info_t *)arg));
501 
502 		case DDI_CTLOPS_REPORTDEV:
503 		return (i2bsc_reportdev(dip, rdip));
504 
505 		case DDI_CTLOPS_DMAPMAPC:
506 		case DDI_CTLOPS_POKE:
507 		case DDI_CTLOPS_PEEK:
508 		case DDI_CTLOPS_IOMIN:
509 		case DDI_CTLOPS_REPORTINT:
510 		case DDI_CTLOPS_SIDDEV:
511 		case DDI_CTLOPS_SLAVEONLY:
512 		case DDI_CTLOPS_AFFINITY:
513 		case DDI_CTLOPS_PTOB:
514 		case DDI_CTLOPS_BTOP:
515 		case DDI_CTLOPS_BTOPR:
516 		case DDI_CTLOPS_DVMAPAGESIZE:
517 		return (DDI_FAILURE);
518 
519 		default:
520 		return (ddi_ctlops(dip, rdip, op, arg, result));
521 	}
522 }
523 
524 /*
525  * i2bsc_suspend() is called before the system suspends.  Existing
526  * transfer in progress or waiting will complete, but new transfers are
527  * effectively blocked by "acquiring" the bus.
528  */
529 static void
530 i2bsc_suspend(dev_info_t *dip)
531 {
532 	i2bsc_t *i2c;
533 	int instance;
534 
535 	instance = ddi_get_instance(dip);
536 	i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
537 
538 	i2bsc_acquire(i2c, NULL, NULL);
539 }
540 
541 /*
542  * i2bsc_resume() is called when the system resumes from CPR.  It releases
543  * the hold that was placed on the i2c bus, which allows any real
544  * transfers to continue.
545  */
546 static void
547 i2bsc_resume(dev_info_t *dip)
548 {
549 	i2bsc_t *i2c;
550 	int instance;
551 
552 	instance = ddi_get_instance(dip);
553 	i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
554 
555 	i2bsc_release(i2c);
556 }
557 
558 /*
559  * i2bsc_acquire() is called by a thread wishing to "own" the I2C bus.
560  * It should not be held across multiple transfers.
561  */
562 static void
563 i2bsc_acquire(i2bsc_t *i2c, dev_info_t *dip, i2c_transfer_t *tp)
564 {
565 	mutex_enter(&i2c->i2bsc_imutex);
566 	while (i2c->i2bsc_busy) {
567 		cv_wait(&i2c->i2bsc_icv, &i2c->i2bsc_imutex);
568 	}
569 	i2c->i2bsc_busy = 1;
570 	i2c->i2bsc_cur_tran = tp;
571 	i2c->i2bsc_cur_dip = dip;
572 	mutex_exit(&i2c->i2bsc_imutex);
573 }
574 
575 /*
576  * i2bsc_release() is called to release a hold made by i2bsc_acquire().
577  */
578 static void
579 i2bsc_release(i2bsc_t *i2c)
580 {
581 	mutex_enter(&i2c->i2bsc_imutex);
582 	i2c->i2bsc_busy = 0;
583 	i2c->i2bsc_cur_tran = NULL;
584 	cv_signal(&i2c->i2bsc_icv);
585 	mutex_exit(&i2c->i2bsc_imutex);
586 }
587 
588 static int
589 i2bsc_initchild(dev_info_t *dip, dev_info_t *cdip)
590 {
591 	i2bsc_t *i2c;
592 	int32_t address_cells;
593 	int len;
594 	int32_t regs[3];
595 	int err;
596 	i2bsc_ppvt_t *ppvt;
597 	char name[30];
598 
599 	i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, ddi_get_instance(dip));
600 
601 	i2bsc_trace(i2c, 'A', "i2bsc_initchild", "dip/cdip %p/%p", dip, cdip);
602 
603 	ppvt = kmem_alloc(sizeof (i2bsc_ppvt_t), KM_SLEEP);
604 
605 	len = sizeof (address_cells);
606 
607 	err = ddi_getlongprop_buf(DDI_DEV_T_ANY, cdip,
608 	    DDI_PROP_CANSLEEP, "#address-cells",
609 	    (caddr_t)&address_cells, &len);
610 	if (err != DDI_PROP_SUCCESS || len != sizeof (address_cells)) {
611 		return (DDI_FAILURE);
612 	}
613 
614 	len = sizeof (regs);
615 	err = ddi_getlongprop_buf(DDI_DEV_T_ANY, cdip,
616 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP,
617 	    "reg", (caddr_t)regs, &len);
618 	if (err != DDI_PROP_SUCCESS)
619 		return (DDI_FAILURE);
620 
621 	if (address_cells == 1) {
622 		ppvt->i2bsc_ppvt_bus = I2BSC_DEFAULT_BUS;
623 		ppvt->i2bsc_ppvt_addr = regs[0];
624 		(void) sprintf(name, "%x", regs[0]);
625 		i2bsc_trace(i2c, 'A', "i2bsc_initchild", "#address-cells = 1"
626 		    " regs[0] = %d", regs[0]);
627 	} else if (address_cells == 2) {
628 		ppvt->i2bsc_ppvt_bus = regs[0];
629 		ppvt->i2bsc_ppvt_addr = regs[1];
630 		(void) sprintf(name, "%x,%x", regs[0], regs[1]);
631 		i2bsc_trace(i2c, 'A', "i2bsc_initchild", "#address-cells = 2"
632 		    " regs[0] = %d, regs[1] = %d", regs[0], regs[1]);
633 	} else {
634 		return (DDI_FAILURE);
635 	}
636 
637 	/*
638 	 * Attach the parent's private data structure to the child's devinfo
639 	 * node, and store the child's address on the nexus in the child's
640 	 * devinfo node.
641 	 */
642 	ddi_set_parent_data(cdip, ppvt);
643 	ddi_set_name_addr(cdip, name);
644 
645 	i2bsc_trace(i2c, 'A', "i2bsc_initchild", "success(%s)",
646 	    ddi_node_name(cdip));
647 
648 	return (DDI_SUCCESS);
649 }
650 
651 static int
652 i2bsc_uninitchild(dev_info_t *dip, dev_info_t *cdip)
653 {
654 	i2bsc_t *i2c;
655 	i2bsc_ppvt_t *ppvt;
656 
657 	i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, ddi_get_instance(dip));
658 
659 	i2bsc_trace(i2c, 'D', "i2bsc_uninitchild", "dip/cdip %p/%p", dip, cdip);
660 
661 	ppvt = ddi_get_parent_data(cdip);
662 	kmem_free(ppvt, sizeof (i2bsc_ppvt_t));
663 
664 	ddi_set_parent_data(cdip, NULL);
665 	ddi_set_name_addr(cdip, NULL);
666 
667 	i2bsc_trace(i2c, 'D', "i2bsc_uninitchild", "success(%s)",
668 	    ddi_node_name(cdip));
669 
670 	return (DDI_SUCCESS);
671 }
672 
673 /*
674  * i2bsc_setup_regs() is called to map in registers specific to
675  * the i2bsc.
676  */
677 static int
678 i2bsc_setup_regs(i2bsc_t *i2c)
679 {
680 	int nregs;
681 
682 	i2c->bscbus_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
683 	i2c->bscbus_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
684 	i2c->bscbus_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
685 
686 	if (ddi_dev_nregs(i2c->i2bsc_dip, &nregs) != DDI_SUCCESS) {
687 		return (DDI_FAILURE);
688 	}
689 
690 	if (nregs < 1) {
691 		return (DDI_FAILURE);
692 	}
693 
694 	if (ddi_regs_map_setup(i2c->i2bsc_dip, 0,
695 	    (caddr_t *)&i2c->bscbus_regs, 0, 0, &i2c->bscbus_attr,
696 	    &i2c->bscbus_handle) != DDI_SUCCESS) {
697 		return (DDI_FAILURE);
698 	}
699 
700 	return (DDI_SUCCESS);
701 }
702 
703 /*
704  * i2bsc_free_regs() frees any registers previously
705  * allocated.
706  */
707 static void
708 i2bsc_free_regs(i2bsc_t *i2c)
709 {
710 	if (i2c->bscbus_regs != NULL) {
711 		ddi_regs_map_free(&i2c->bscbus_handle);
712 	}
713 }
714 
715 /*ARGSUSED*/
716 static int
717 i2bsc_reportdev(dev_info_t *dip, dev_info_t *rdip)
718 {
719 	if (rdip == (dev_info_t *)0)
720 		return (DDI_FAILURE);
721 
722 	cmn_err(CE_CONT, "?i2bsc-device: %s@%s, %s%d\n",
723 	    ddi_node_name(rdip), ddi_get_name_addr(rdip), ddi_driver_name(rdip),
724 	    ddi_get_instance(rdip));
725 
726 	return (DDI_SUCCESS);
727 }
728 
729 /*
730  * I/O Functions
731  *
732  * i2bsc_{put,get}8_once are wrapper functions to ddi_{get,put}8.
733  * i2bsc_{put,get}8 are equivalent functions but with retry code.
734  * i2bsc_bscbus_state determines underlying bus error status.
735  * i2bsc_clear_acc_fault clears the underlying bus error status.
736  *
737  * I/O Flags
738  *
739  * bscbus_fault	   -	Error register in underlying bus for last IO operation.
740  * session_failure - 	Set by any failed IO command.  This is a sticky flag
741  * 			reset explicitly using i2bsc_start_session
742  *
743  * Session Management
744  *
745  * i2bsc_{start,end}_session need to be used to detect an error across multiple
746  * gets/puts rather than having to test for an error on each get/put.
747  */
748 
749 static int i2bsc_bscbus_state(i2bsc_t *i2c)
750 {
751 	uint32_t retval;
752 
753 	retval = ddi_get32(i2c->bscbus_handle,
754 	    (uint32_t *)I2BSC_NEXUS_ADDR(i2c, EBUS_CMD_SPACE_GENERIC,
755 	    LOMBUS_FAULT_REG));
756 	i2c->bscbus_fault = retval;
757 
758 	return ((retval == 0) ? DDI_SUCCESS : DDI_FAILURE);
759 }
760 
761 static void i2bsc_clear_acc_fault(i2bsc_t *i2c)
762 {
763 	i2bsc_trace(i2c, '@', "i2bsc_clear_acc_fault", "clearing acc fault");
764 	ddi_put32(i2c->bscbus_handle,
765 	    (uint32_t *)I2BSC_NEXUS_ADDR(i2c, EBUS_CMD_SPACE_GENERIC,
766 	    LOMBUS_FAULT_REG), 0);
767 }
768 
769 static void
770 i2bsc_start_session(i2bsc_t *i2c)
771 {
772 	i2bsc_trace(i2c, 'S', "i2bsc_start_session", "session started");
773 	i2c->bscbus_session_failure = 0;
774 }
775 
776 static void
777 i2bsc_fail_session(i2bsc_t *i2c)
778 {
779 	i2bsc_trace(i2c, 'S', "i2bsc_fail_session", "session failed");
780 	i2c->bscbus_session_failure = 1;
781 }
782 
783 static int
784 i2bsc_end_session(i2bsc_t *i2c)
785 {
786 	/*
787 	 * The ONLY way to get the session status is to end the session.
788 	 * If clients of the session interface ever wanted the status mid-way
789 	 * then they are really working with multiple contigious sessions.
790 	 */
791 	i2bsc_trace(i2c, 'S', "i2bsc_end_session", "session ended with %d",
792 	    i2c->bscbus_session_failure);
793 	return ((i2c->bscbus_session_failure) ? DDI_FAILURE : DDI_SUCCESS);
794 }
795 
796 static boolean_t
797 i2bsc_is_firmware_broken(i2bsc_t *i2c)
798 {
799 	int i;
800 	int niterations = I2BSC_SHORT_RETRY_LIMIT;
801 
802 	i2bsc_trace(i2c, 'A', "i2bsc_is_firmware_broken", "called");
803 
804 	for (i = 0; i < niterations; i++) {
805 		(void) ddi_get8(i2c->bscbus_handle,
806 		    I2BSC_NEXUS_ADDR(i2c, EBUS_CMD_SPACE_I2C,
807 		    EBUS_IDX12_RESULT));
808 		if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS) {
809 			i2bsc_clear_acc_fault(i2c);
810 			continue;
811 		} else {
812 			/*
813 			 * Firmware communication succeeded.
814 			 */
815 			i2bsc_trace(i2c, 'A', "i2bsc_is_firmware_broken",
816 			    "firmware communications okay");
817 			return (B_FALSE);
818 		}
819 	}
820 
821 	/*
822 	 * Firmware is not communicative.  Some possible causes :
823 	 *	Broken hardware
824 	 *	BSC held in reset
825 	 *	Corrupt BSC image
826 	 *	OBP incompatiblity preventing drivers loading properly
827 	 */
828 	i2bsc_trace(i2c, 'A', "i2bsc_is_firmware_broken", "%d read fails",
829 	    niterations);
830 	return (B_TRUE);
831 }
832 
833 static void
834 i2bsc_put8(i2bsc_t *i2c, uint8_t space, uint8_t index, uint8_t value)
835 {
836 	int retryable = I2BSC_RETRY_LIMIT;
837 
838 	i2bsc_trace(i2c, '@', "i2bsc_put8", "(space,index)<-val (%d,%d)<-%d",
839 	    space, index, value);
840 
841 	i2bsc_clear_acc_fault(i2c);
842 
843 	/*
844 	 * If a session failure has already occurred, reduce the level of
845 	 * retries to a minimum.  This is a optimization of the failure
846 	 * recovery strategy.
847 	 */
848 	if (i2c->bscbus_session_failure)
849 		retryable = 1;
850 
851 	while (retryable--) {
852 		ddi_put8(i2c->bscbus_handle,
853 		    I2BSC_NEXUS_ADDR(i2c, space, index), value);
854 		if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS) {
855 			i2bsc_clear_acc_fault(i2c);
856 		} else
857 			break;
858 	}
859 
860 	if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS)
861 		i2bsc_fail_session(i2c);
862 
863 	i2bsc_trace(i2c, '@', "i2bsc_put8", "tried %d time(s)",
864 	    I2BSC_RETRY_LIMIT - retryable);
865 }
866 
867 static uint8_t
868 i2bsc_get8(i2bsc_t *i2c, uint8_t space, uint8_t index)
869 {
870 	uint8_t value;
871 	int retryable = I2BSC_RETRY_LIMIT;
872 
873 	i2bsc_clear_acc_fault(i2c);
874 
875 	/*
876 	 * If a session failure has already occurred, reduce the level of
877 	 * retries to a minimum.  This is a optimization of the failure
878 	 * recovery strategy.
879 	 */
880 	if (i2c->bscbus_session_failure)
881 		retryable = 1;
882 
883 	while (retryable--) {
884 		value = ddi_get8(i2c->bscbus_handle,
885 		    I2BSC_NEXUS_ADDR(i2c, space, index));
886 		if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS) {
887 			i2bsc_clear_acc_fault(i2c);
888 		} else
889 			break;
890 	}
891 
892 	if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS)
893 		i2bsc_fail_session(i2c);
894 
895 	i2bsc_trace(i2c, '@', "i2bsc_get8", "tried %d time(s)",
896 	    I2BSC_RETRY_LIMIT - retryable);
897 
898 	i2bsc_trace(i2c, '@', "i2bsc_get8", "(space,index)->val (%d,%d)->%d",
899 	    space, index, value);
900 	return (value);
901 }
902 
903 static void
904 i2bsc_put8_once(i2bsc_t *i2c, uint8_t space, uint8_t index, uint8_t value)
905 {
906 	i2bsc_trace(i2c, '@', "i2bsc_put8_once",
907 	    "(space,index)<-val (%d,%d)<-%d", space, index, value);
908 
909 	i2bsc_clear_acc_fault(i2c);
910 
911 	ddi_put8(i2c->bscbus_handle,
912 	    I2BSC_NEXUS_ADDR(i2c, space, index), value);
913 
914 	if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS)
915 		i2bsc_fail_session(i2c);
916 }
917 
918 static uint8_t
919 i2bsc_get8_once(i2bsc_t *i2c, uint8_t space, uint8_t index)
920 {
921 	uint8_t value;
922 
923 	i2bsc_clear_acc_fault(i2c);
924 
925 	value = ddi_get8(i2c->bscbus_handle,
926 	    I2BSC_NEXUS_ADDR(i2c, space, index));
927 
928 	if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS)
929 		i2bsc_fail_session(i2c);
930 
931 	i2bsc_trace(i2c, '@', "i2bsc_get8_once",
932 	    "(space,index)->val (%d,%d)->%d", space, index, value);
933 
934 	return (value);
935 }
936 
937 static int
938 i2bsc_notify_max_transfer_size(i2bsc_t *i2c)
939 {
940 	/*
941 	 * If the underlying hardware does not support the i2c service and
942 	 * we are not running in fake_mode, then we cannot set the
943 	 * MAX_TRANSFER_SZ.
944 	 */
945 	if (i2c->i2c_proxy_support == 0)
946 		return (DDI_FAILURE);
947 
948 	i2bsc_start_session(i2c);
949 
950 	i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_MAX_TRANSFER_SZ,
951 	    I2BSC_MAX_TRANSFER_SZ);
952 
953 	if (i2bsc_end_session(i2c) != DDI_SUCCESS)
954 		return (DDI_FAILURE);
955 
956 	return (DDI_SUCCESS);
957 }
958 
959 /*
960  * Discover if the microcontroller implements the I2C Proxy Service this
961  * driver requires.  If it does not, i2c transactions will abort with
962  * I2C_FAILURE, unless fake_mode is being used.
963  */
964 static int
965 i2bsc_discover_capability(i2bsc_t *i2c)
966 {
967 	i2bsc_start_session(i2c);
968 
969 	i2c->i2c_proxy_support = i2bsc_get8(i2c, EBUS_CMD_SPACE_GENERIC,
970 	    EBUS_IDX_CAP0);
971 	i2c->i2c_proxy_support &= EBUS_CAP0_I2C_PROXY;
972 
973 	if (i2bsc_end_session(i2c) != DDI_SUCCESS)
974 		return (DDI_FAILURE);
975 
976 	return (DDI_SUCCESS);
977 }
978 
979 static int
980 i2bsc_upload_preamble(i2bsc_t *i2c, i2c_transfer_t *tp)
981 {
982 	i2bsc_ppvt_t *ppvt;
983 	int wr_rd;
984 
985 	ppvt = ddi_get_parent_data(i2c->i2bsc_cur_dip);
986 
987 	/* Get a lock on the i2c devices owned by the microcontroller */
988 	i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_TRANSACTION_LOCK, 1);
989 	if (!i2bsc_get8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_TRANSACTION_LOCK)) {
990 		/*
991 		 * i2c client driver must timeout retry, NOT this nexus
992 		 */
993 		tp->i2c_result = I2C_INCOMPLETE;
994 		i2bsc_trace(i2c, 'U', "i2bsc_upload_preamble",
995 		    "Couldn't get transaction lock");
996 		return (tp->i2c_result);
997 	}
998 
999 	i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_BUS_ADDRESS,
1000 	    ppvt->i2bsc_ppvt_bus);
1001 
1002 	/*
1003 	 * The Solaris architecture for I2C uses 10-bit I2C addresses where
1004 	 * bit-0 is zero (the read/write bit).  The microcontroller uses 7 bit
1005 	 * I2C addresses (read/write bit excluded).  Hence we need to convert
1006 	 * the address by bit-shifting.
1007 	 */
1008 	i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_CLIENT_ADDRESS,
1009 	    ppvt->i2bsc_ppvt_addr >> 1);
1010 
1011 	i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_TRANSFER_TYPE,
1012 	    tp->i2c_flags);
1013 
1014 	/*
1015 	 * We have only one register used for data input and output.  When
1016 	 * a WR_RD is issued, this means we want to do a Random-Access-Read.
1017 	 * First a series of bytes are written which define the address to
1018 	 * read from.  In hardware this sets an address pointer.  Then a series
1019 	 * of bytes are read.  The read/write boundary tells you how many
1020 	 * bytes are to be written before reads will be issued.
1021 	 */
1022 	if (tp->i2c_flags == I2C_WR_RD)
1023 		wr_rd = tp->i2c_wlen;
1024 	else
1025 		wr_rd = 0;
1026 
1027 	i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_WR_RD_BOUNDARY, wr_rd);
1028 
1029 	return (I2C_SUCCESS);
1030 }
1031 
1032 /*
1033  * Function	i2bsc_upload
1034  *
1035  * Description	This function runs the i2c transfer protocol down to the
1036  *		microcontroller.  Its goal is to be as reliable as possible.
1037  *		This is achieved by making all the state-less aspects
1038  *		re-tryable.  For stateful aspects, we take care to ensure the
1039  *		counters are decremented only when data transfer has been
1040  *		successful.
1041  */
1042 static int
1043 i2bsc_upload(i2bsc_t *i2c, i2c_transfer_t *tp)
1044 {
1045 	int quota = I2BSC_MAX_TRANSFER_SZ;
1046 	uint8_t res;
1047 	int residual;
1048 
1049 	/*
1050 	 * Total amount of data outstanding
1051 	 */
1052 	residual = tp->i2c_w_resid + tp->i2c_r_resid;
1053 
1054 	/*
1055 	 * Anything in this session *could* be re-tried without side-effects.
1056 	 * Therefore, error exit codes are I2C_INCOMPLETE rather than
1057 	 * I2C_FAILURE.
1058 	 */
1059 	i2bsc_start_session(i2c);
1060 	if (i2bsc_upload_preamble(i2c, tp) != I2C_SUCCESS)
1061 		return (I2C_INCOMPLETE);
1062 	if (i2bsc_end_session(i2c) != DDI_SUCCESS)
1063 		return (I2C_INCOMPLETE);
1064 
1065 	/* The writes done here are not retryable */
1066 	while (tp->i2c_w_resid && quota) {
1067 		i2bsc_put8_once(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_DATA_INOUT,
1068 		    tp->i2c_wbuf[tp->i2c_wlen - tp->i2c_w_resid]);
1069 		if (i2bsc_bscbus_state(i2c) == DDI_SUCCESS) {
1070 			tp->i2c_w_resid--;
1071 			quota--;
1072 			residual--;
1073 		} else {
1074 			i2bsc_trace(i2c, 'T', "i2bsc_upload", "write failed");
1075 			return (tp->i2c_result = I2C_INCOMPLETE);
1076 		}
1077 	}
1078 
1079 	/* The reads done here are not retryable */
1080 	while (tp->i2c_r_resid && quota) {
1081 		tp->i2c_rbuf[tp->i2c_rlen - tp->i2c_r_resid] =
1082 		    i2bsc_get8_once(i2c, EBUS_CMD_SPACE_I2C,
1083 		    EBUS_IDX12_DATA_INOUT);
1084 		if (i2bsc_bscbus_state(i2c) == DDI_SUCCESS) {
1085 			tp->i2c_r_resid--;
1086 			quota--;
1087 			residual--;
1088 		} else {
1089 			i2bsc_trace(i2c, 'T', "i2bsc_upload", "read failed");
1090 			return (tp->i2c_result = I2C_INCOMPLETE);
1091 		}
1092 	}
1093 
1094 	i2bsc_start_session(i2c);
1095 
1096 	/*
1097 	 * A possible future enhancement would be to allow early breakout of the
1098 	 * loops seen above.  In such circumstances, "residual" would be non-
1099 	 * zero.  This may be useful if we want to support the interruption of
1100 	 * transfer part way through an i2c_transfer_t.
1101 	 */
1102 	i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_RESIDUAL_DATA, residual);
1103 	res = i2bsc_get8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_RESULT);
1104 	if (i2bsc_end_session(i2c) != DDI_SUCCESS)
1105 		return (tp->i2c_result = I2C_INCOMPLETE);
1106 
1107 	switch (res) {
1108 		case EBUS_I2C_SUCCESS:
1109 		tp->i2c_result = I2C_SUCCESS;
1110 		break;
1111 		case EBUS_I2C_FAILURE:
1112 		/*
1113 		 * This is rare but possible.  A retry may still fix this
1114 		 * so lets allow that by returning I2C_INCOMPLETE.
1115 		 * "hifTxRing still contains 1 bytes" is reported by the
1116 		 * microcontroller when this return value is seen.
1117 		 */
1118 		i2bsc_trace(i2c, 'T', "i2bsc_upload", "EBUS_I2C_FAILURE"
1119 		    " but returning I2C_INCOMPLETE for possible re-try");
1120 		tp->i2c_result = I2C_INCOMPLETE;
1121 		break;
1122 		case EBUS_I2C_INCOMPLETE:
1123 		tp->i2c_result = I2C_INCOMPLETE;
1124 		break;
1125 		default:
1126 		tp->i2c_result = I2C_FAILURE;
1127 	}
1128 
1129 	return (tp->i2c_result);
1130 }
1131 
1132 /*
1133  * Function	i2bsc_safe_upload
1134  *
1135  * Description	This function is called "safe"-upload because it attempts to
1136  *		do transaction re-tries for cases where state is not spoiled
1137  *		by a transaction-level retry.
1138  */
1139 static int
1140 i2bsc_safe_upload(i2bsc_t *i2c, i2c_transfer_t *tp)
1141 {
1142 	int retryable = I2BSC_RETRY_LIMIT;
1143 	int result;
1144 
1145 	i2bsc_trace(i2c, 'T', "i2bsc_safe_upload", "Transaction %s",
1146 	    (tp->i2c_flags == I2C_WR_RD) ? "retryable" : "single-shot");
1147 
1148 	/*
1149 	 * The only re-tryable transaction type is I2C_WR_RD.  If we don't
1150 	 * have this we can only use session-based recovery offered by
1151 	 * i2bsc_upload.
1152 	 */
1153 	if (tp->i2c_flags != I2C_WR_RD)
1154 		return (i2bsc_upload(i2c, tp));
1155 
1156 	while (retryable--) {
1157 		result = i2bsc_upload(i2c, tp);
1158 		if (result == I2C_INCOMPLETE) {
1159 			/* Have another go */
1160 			tp->i2c_r_resid = tp->i2c_rlen;
1161 			tp->i2c_w_resid = tp->i2c_wlen;
1162 			tp->i2c_result = I2C_SUCCESS;
1163 			i2bsc_trace(i2c, 'T', "i2bsc_safe_upload",
1164 			    "Retried (%d)", I2BSC_RETRY_LIMIT - retryable);
1165 			continue;
1166 		} else {
1167 			i2bsc_trace(i2c, 'T', "i2bsc_safe_upload",
1168 			    "Exiting while loop on result %d", result);
1169 			return (result);
1170 		}
1171 	}
1172 
1173 	i2bsc_trace(i2c, 'T', "i2bsc_safe_upload", "Exiting on %d", result);
1174 	return (result);
1175 }
1176 
1177 /*
1178  * Function	i2bsc_transfer
1179  *
1180  * Description	This is the entry-point that clients use via the Solaris i2c
1181  *		framework.  It kicks off the servicing of i2c transfer requests.
1182  */
1183 int
1184 i2bsc_transfer(dev_info_t *dip, i2c_transfer_t *tp)
1185 {
1186 	i2bsc_t *i2c;
1187 
1188 	i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state,
1189 	    ddi_get_instance(ddi_get_parent(dip)));
1190 
1191 	i2bsc_acquire(i2c, dip, tp);
1192 
1193 	tp->i2c_r_resid = tp->i2c_rlen;
1194 	tp->i2c_w_resid = tp->i2c_wlen;
1195 	tp->i2c_result = I2C_SUCCESS;
1196 
1197 	i2bsc_trace(i2c, 'T', "i2bsc_transfer", "Transaction i2c_version/flags"
1198 	    " %d/%d", tp->i2c_version, tp->i2c_flags);
1199 	i2bsc_trace(i2c, 'T', "i2bsc_transfer", "Transaction buffer rlen/wlen"
1200 	    " %d/%d", tp->i2c_rlen, tp->i2c_wlen);
1201 	i2bsc_trace(i2c, 'T', "i2bsc_transfer", "Transaction ptrs wbuf/rbuf"
1202 	    " %p/%p", tp->i2c_wbuf, tp->i2c_rbuf);
1203 
1204 	if (i2c->i2c_proxy_support)
1205 		(void) i2bsc_safe_upload(i2c, tp);
1206 	else
1207 		tp->i2c_result = I2C_FAILURE;
1208 
1209 	i2bsc_trace(i2c, 'T', "i2bsc_transfer", "Residual writes/reads"
1210 	    " %d/%d", tp->i2c_w_resid, tp->i2c_r_resid);
1211 	i2bsc_trace(i2c, 'T', "i2bsc_transfer", "i2c_result"
1212 	    " %d", tp->i2c_result);
1213 
1214 	i2bsc_release(i2c);
1215 
1216 	return (tp->i2c_result);
1217 }
1218 
1219 /*
1220  *  General utility routines ...
1221  */
1222 
1223 #ifdef DEBUG
1224 
1225 static void
1226 i2bsc_trace(i2bsc_t *ssp, char code, const char *caller,
1227 	const char *fmt, ...)
1228 {
1229 	char buf[256];
1230 	char *p;
1231 	va_list va;
1232 
1233 	if (ssp->debug & (1 << (code-'@'))) {
1234 		p = buf;
1235 		(void) snprintf(p, sizeof (buf) - (p - buf),
1236 		    "%s/%s: ", ssp->i2bsc_name, caller);
1237 		p += strlen(p);
1238 
1239 		va_start(va, fmt);
1240 		(void) vsnprintf(p, sizeof (buf) - (p - buf), fmt, va);
1241 		va_end(va);
1242 
1243 		buf[sizeof (buf) - 1] = '\0';
1244 		(void) strlog(ssp->majornum, ssp->minornum, code, SL_TRACE,
1245 		    buf);
1246 	}
1247 }
1248 
1249 #else /* DEBUG */
1250 
1251 _NOTE(ARGSUSED(0))
1252 static void
1253 i2bsc_trace(i2bsc_t *ssp, char code, const char *caller,
1254 	const char *fmt, ...)
1255 {
1256 }
1257 
1258 #endif /* DEBUG */
1259