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
_init(void)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
_fini(void)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
_info(struct modinfo * modinfop)221 _info(struct modinfo *modinfop)
222 {
223 return (mod_info(&modlinkage, modinfop));
224 }
225
226 static void
i2bsc_dodetach(dev_info_t * dip)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
i2bsc_doattach(dev_info_t * dip)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
i2bsc_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
i2bsc_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
i2bsc_open(dev_t * devp,int flag,int otyp,cred_t * cred_p)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
i2bsc_close(dev_t dev,int flag,int otyp,cred_t * cred_p)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
i2bsc_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)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
i2bsc_bus_ctl(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t op,void * arg,void * result)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
i2bsc_suspend(dev_info_t * dip)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
i2bsc_resume(dev_info_t * dip)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
i2bsc_acquire(i2bsc_t * i2c,dev_info_t * dip,i2c_transfer_t * tp)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
i2bsc_release(i2bsc_t * i2c)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
i2bsc_initchild(dev_info_t * dip,dev_info_t * cdip)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
i2bsc_uninitchild(dev_info_t * dip,dev_info_t * cdip)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
i2bsc_setup_regs(i2bsc_t * i2c)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
i2bsc_free_regs(i2bsc_t * i2c)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
i2bsc_reportdev(dev_info_t * dip,dev_info_t * rdip)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
i2bsc_bscbus_state(i2bsc_t * i2c)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
i2bsc_clear_acc_fault(i2bsc_t * i2c)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
i2bsc_start_session(i2bsc_t * i2c)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
i2bsc_fail_session(i2bsc_t * i2c)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
i2bsc_end_session(i2bsc_t * i2c)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
i2bsc_is_firmware_broken(i2bsc_t * i2c)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
i2bsc_put8(i2bsc_t * i2c,uint8_t space,uint8_t index,uint8_t value)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
i2bsc_get8(i2bsc_t * i2c,uint8_t space,uint8_t index)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
i2bsc_put8_once(i2bsc_t * i2c,uint8_t space,uint8_t index,uint8_t value)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
i2bsc_get8_once(i2bsc_t * i2c,uint8_t space,uint8_t index)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
i2bsc_notify_max_transfer_size(i2bsc_t * i2c)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
i2bsc_discover_capability(i2bsc_t * i2c)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
i2bsc_upload_preamble(i2bsc_t * i2c,i2c_transfer_t * tp)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
i2bsc_upload(i2bsc_t * i2c,i2c_transfer_t * tp)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
i2bsc_safe_upload(i2bsc_t * i2c,i2c_transfer_t * tp)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
i2bsc_transfer(dev_info_t * dip,i2c_transfer_t * tp)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
i2bsc_trace(i2bsc_t * ssp,char code,const char * caller,const char * fmt,...)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
i2bsc_trace(i2bsc_t * ssp,char code,const char * caller,const char * fmt,...)1253 i2bsc_trace(i2bsc_t *ssp, char code, const char *caller,
1254 const char *fmt, ...)
1255 {
1256 }
1257
1258 #endif /* DEBUG */
1259