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