xref: /illumos-gate/usr/src/uts/sun4u/daktari/io/hpc3130_dak.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Daktari platform specific hotplug controller. This
29  * driver exports the same interfaces to user space
30  * as the generic hpc3130 driver.  It adds specific
31  * functionality found on Daktari, such as slot button
32  * and platform specific LED displays.  Placed in
33  * the daktari specific platform directory, it will
34  * be loaded instead of the generic module.
35  */
36 
37 #pragma ident	"%Z%%M%	%I%	%E% SMI"
38 
39 #include <sys/types.h>
40 #include <sys/cmn_err.h>
41 #include <sys/kmem.h>
42 #include <sys/errno.h>
43 #include <sys/cpuvar.h>
44 #include <sys/open.h>
45 #include <sys/stat.h>
46 #include <sys/conf.h>
47 #include <sys/ddi.h>
48 #include <sys/sunddi.h>
49 #include <sys/modctl.h>
50 #include <sys/note.h>
51 #include <sys/hotplug/hpctrl.h>
52 #include <sys/hotplug/hpcsvc.h>
53 #include <sys/i2c/clients/hpc3130.h>
54 #include <sys/hpc3130_events.h>
55 #include <sys/daktari.h>
56 #include <sys/hpc3130_dak.h>
57 
58 #ifdef DEBUG
59 static int hpc3130debug = 0;
60 
61 #define	D1CMN_ERR(ARGS) if (hpc3130debug & 0x1) cmn_err ARGS;
62 #define	D2CMN_ERR(ARGS) if (hpc3130debug & 0x2) cmn_err ARGS;
63 
64 #else
65 
66 #define	D1CMN_ERR(ARGS)
67 #define	D2CMN_ERR(ARGS)
68 
69 #endif /* DEBUG */
70 
71 #define	HPC3130_REG(offset, slot) ((offset) + ((slot)*8))
72 #define	HPC3130_PIL	1
73 struct tuple {
74 	uint8_t reg;
75 	uint8_t val;
76 };
77 
78 struct connect_command {
79 	boolean_t set_bit;
80 	uint8_t value;
81 };
82 
83 struct tuple pci_sequence [] =
84 {
85 	{HPC3130_GCR, HPC3130_AUTO2_SEQ},
86 	{HPC3130_INTERRUPT, HPC3130_PWRGOOD |
87 		HPC3130_DETECT0 | HPC3130_PRSNT1 | HPC3130_PRSNT2},
88 	{HPC3130_EVENT_STATUS, 0xff},
89 	{HPC3130_NO_REGISTER, 0},
90 };
91 
92 struct tuple cpu_sequence [] =
93 {
94 	{HPC3130_INTERRUPT,
95 		HPC3130_PRSNT1 | HPC3130_DETECT0},
96 	{HPC3130_EVENT_STATUS, 0xff},
97 	{HPC3130_NO_REGISTER, 0},
98 };
99 
100 struct connect_command connect_sequence [] =
101 {
102 	{B_TRUE,  HPC3130_SLOTREQ64},
103 	{B_FALSE, HPC3130_SLOTRST},
104 	{B_FALSE, HPC3130_CLKON},
105 	{B_FALSE, HPC3130_REQ64},
106 	{B_FALSE, HPC3130_SLOTREQ64},
107 	{B_TRUE,  HPC3130_SLOTRST},
108 	{B_FALSE, HPC3130_BUS_CTL},
109 };
110 
111 #define	HPC3130_CONNECT_SEQ_COUNT (sizeof (connect_sequence)/ \
112 	sizeof (struct connect_command))
113 
114 struct xlate_entry {
115 	char	*nexus;
116 	int	pcidev;
117 };
118 /*
119  * The order here is significant.  Its the order
120  * of appearance of slots from bottom to top
121  * on a Sun-Fire-880
122  */
123 static struct xlate_entry slot_translate[] =
124 {
125 	{"/pci@8,700000", 5},	/* PCI0 */
126 	{"/pci@8,700000", 4},	/* PCI1 */
127 	{"/pci@8,700000", 3},	/* PCI2 */
128 	{"/pci@8,700000", 2},	/* PCI3 */
129 
130 	{"/pci@9,700000", 4},	/* PCI4 */
131 	{"/pci@9,700000", 3},	/* PCI5 */
132 	{"/pci@9,700000", 2},	/* PCI6 */
133 
134 	{"/pci@9,600000", 2},	/* PCI7 */
135 	{"/pci@9,600000", 1}	/* PCI8 */
136 };
137 
138 #define	HPC3130_LOOKUP_SLOTS (sizeof (slot_translate)/ \
139 	sizeof (struct xlate_entry))
140 
141 static int control_slot_control = HPC3130_SLOT_CONTROL_ENABLE;
142 
143 hpc3130_unit_t *hpc3130soft_statep;
144 
145 static int hpc3130_atoi(const char *);
146 int hpc3130_lookup_slot(char *, int);
147 
148 static int hpc3130_init(dev_info_t *, struct tuple *);
149 static uint_t hpc3130_hard_intr(caddr_t);
150 
151 static int hpc3130_cpu_init(hpc3130_unit_t *, int, i2c_client_hdl_t);
152 static int hpc3130_debounce_status(i2c_client_hdl_t, int, uint8_t *);
153 static int hpc3130_read(i2c_client_hdl_t, uint8_t, uint8_t, uint8_t *);
154 static int hpc3130_write(i2c_client_hdl_t, uint8_t, uint8_t, uint8_t);
155 static int hpc3130_rw(i2c_client_hdl_t, uint8_t, boolean_t, uint8_t *);
156 
157 static int hpc3130_do_attach(dev_info_t *);
158 static int hpc3130_do_detach(dev_info_t *);
159 static int hpc3130_do_resume(void);
160 static int hpc3130_do_suspend();
161 static int hpc3130_get(intptr_t, int, hpc3130_unit_t *, int);
162 static int hpc3130_set(intptr_t, int, hpc3130_unit_t *, int);
163 
164 static int hpc3130_slot_connect(caddr_t, hpc_slot_t, void *, uint_t);
165 static int hpc3130_slot_disconnect(caddr_t, hpc_slot_t, void *, uint_t);
166 static int hpc3130_verify_slot_power(hpc3130_unit_t *, i2c_client_hdl_t,
167 					uint8_t, char *, boolean_t);
168 static int hpc3130_slot_insert(caddr_t, hpc_slot_t, void *, uint_t);
169 static int hpc3130_slot_remove(caddr_t, hpc_slot_t, void *, uint_t);
170 static int hpc3130_slot_control(caddr_t, hpc_slot_t, int, caddr_t);
171 /*
172  * cb ops
173  */
174 static int hpc3130_open(dev_t *, int, int, cred_t *);
175 static int hpc3130_close(dev_t, int, int, cred_t *);
176 static int hpc3130_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
177 static int hpc3130_poll(dev_t dev, short events, int anyyet,  short
178 			*reventsp, struct pollhead **phpp);
179 
180 static struct cb_ops hpc3130_cbops = {
181 	hpc3130_open,			/* open  */
182 	hpc3130_close,			/* close */
183 	nodev,				/* strategy */
184 	nodev,				/* print */
185 	nodev,				/* dump */
186 	nodev,				/* read */
187 	nodev,				/* write */
188 	hpc3130_ioctl,			/* ioctl */
189 	nodev,				/* devmap */
190 	nodev,				/* mmap */
191 	nodev,				/* segmap */
192 	hpc3130_poll,			/* poll */
193 	ddi_prop_op,			/* cb_prop_op */
194 	NULL,				/* streamtab */
195 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
196 	CB_REV,				/* rev */
197 	nodev,				/* int (*cb_aread)() */
198 	nodev				/* int (*cb_awrite)() */
199 };
200 
201 /*
202  * dev ops
203  */
204 static int hpc3130_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
205 		void **result);
206 static int hpc3130_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
207 static int hpc3130_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
208 
209 static struct dev_ops hpc3130_ops = {
210 	DEVO_REV,
211 	0,
212 	hpc3130_info,
213 	nulldev,
214 	nulldev,
215 	hpc3130_attach,
216 	hpc3130_detach,
217 	nodev,
218 	&hpc3130_cbops,
219 	NULL
220 };
221 
222 extern struct mod_ops mod_driverops;
223 
224 static struct modldrv hpc3130_modldrv = {
225 	&mod_driverops,			/* type of module - driver */
226 	"Hotplug controller driver %I%",
227 	&hpc3130_ops
228 };
229 
230 static struct modlinkage hpc3130_modlinkage = {
231 	MODREV_1,
232 	&hpc3130_modldrv,
233 	0
234 };
235 
236 int
237 _init(void)
238 {
239 	int error;
240 
241 	error = mod_install(&hpc3130_modlinkage);
242 
243 	if (!error)
244 		(void) ddi_soft_state_init((void *)&hpc3130soft_statep,
245 			sizeof (hpc3130_unit_t), 4);
246 	return (error);
247 }
248 
249 int
250 _fini(void)
251 {
252 	int error;
253 
254 	error = mod_remove(&hpc3130_modlinkage);
255 	if (!error)
256 		ddi_soft_state_fini((void *)&hpc3130soft_statep);
257 
258 	return (error);
259 }
260 
261 int
262 _info(struct modinfo *modinfop)
263 {
264 	return (mod_info(&hpc3130_modlinkage, modinfop));
265 }
266 
267 static int
268 hpc3130_open(dev_t *devp, int flags, int otyp, cred_t *credp)
269 {
270 	_NOTE(ARGUNUSED(credp))
271 	hpc3130_unit_t *unitp;
272 	int instance;
273 	int error = 0;
274 
275 	if (otyp != OTYP_CHR) {
276 		return (EINVAL);
277 	}
278 
279 	instance = MINOR_TO_INST(getminor(*devp));
280 
281 	unitp = (hpc3130_unit_t *)
282 		ddi_get_soft_state(hpc3130soft_statep, instance);
283 
284 	if (unitp == NULL) {
285 		return (ENXIO);
286 	}
287 
288 	mutex_enter(&unitp->hpc3130_mutex);
289 
290 	if (flags & FEXCL) {
291 		if (unitp->hpc3130_oflag != 0) {
292 			error = EBUSY;
293 		} else {
294 			unitp->hpc3130_oflag = FEXCL;
295 		}
296 	} else {
297 		if (unitp->hpc3130_oflag == FEXCL) {
298 			error = EBUSY;
299 		} else {
300 			unitp->hpc3130_oflag = FOPEN;
301 		}
302 	}
303 
304 	mutex_exit(&unitp->hpc3130_mutex);
305 
306 	return (error);
307 }
308 
309 static int
310 hpc3130_close(dev_t dev, int flags, int otyp, cred_t *credp)
311 {
312 	_NOTE(ARGUNUSED(flags, otyp, credp))
313 	hpc3130_unit_t *unitp;
314 	int instance;
315 
316 	instance = MINOR_TO_INST(getminor(dev));
317 
318 	unitp = (hpc3130_unit_t *)
319 		ddi_get_soft_state(hpc3130soft_statep, instance);
320 
321 	if (unitp == NULL) {
322 		return (ENXIO);
323 	}
324 
325 	mutex_enter(&unitp->hpc3130_mutex);
326 
327 	unitp->hpc3130_oflag = 0;
328 
329 	mutex_exit(&unitp->hpc3130_mutex);
330 	return (DDI_SUCCESS);
331 }
332 
333 static int
334 hpc3130_get(intptr_t arg, int reg, hpc3130_unit_t *unitp, int mode)
335 {
336 	i2c_transfer_t		*i2c_tran_pointer;
337 	int err = DDI_SUCCESS;
338 
339 	if (arg == NULL) {
340 		D2CMN_ERR((CE_WARN, "ioctl: arg passed in to "
341 		    "ioctl = NULL"));
342 		return (EINVAL);
343 	}
344 	(void) i2c_transfer_alloc(unitp->hpc3130_hdl, &i2c_tran_pointer,
345 			1, 1, I2C_SLEEP);
346 	if (i2c_tran_pointer == NULL) {
347 		D2CMN_ERR((CE_WARN, "Failed in HPC3130_GET_STATUS"
348 		    " i2c_tran_pointer not allocated"));
349 		return (ENOMEM);
350 	}
351 
352 	i2c_tran_pointer->i2c_flags = I2C_WR_RD;
353 	i2c_tran_pointer->i2c_wbuf[0] = (uchar_t)reg;
354 
355 	err = i2c_transfer(unitp->hpc3130_hdl, i2c_tran_pointer);
356 	if (err) {
357 		D2CMN_ERR((CE_WARN, "Failed in HPC3130_GET_STATUS"
358 		    " i2c_trasfer routine"));
359 		i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer);
360 		return (err);
361 	}
362 	D1CMN_ERR((CE_NOTE, "The i2c_rbuf contains %x",
363 		i2c_tran_pointer->i2c_rbuf[0]));
364 
365 	if (ddi_copyout((caddr_t)i2c_tran_pointer->i2c_rbuf,
366 			(caddr_t)arg,
367 			sizeof (uint8_t), mode) != DDI_SUCCESS) {
368 		D2CMN_ERR((CE_WARN, "Failed in HPC3130_GET_STATUS"
369 		    " ddi_copyout routine"));
370 		err = EFAULT;
371 	}
372 	i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer);
373 	return (err);
374 }
375 
376 static int
377 hpc3130_set(intptr_t arg, int reg, hpc3130_unit_t *unitp, int mode)
378 {
379 	i2c_transfer_t		*i2c_tran_pointer;
380 	int err = DDI_SUCCESS;
381 	uint8_t passin_byte;
382 
383 	if (arg == NULL) {
384 		D2CMN_ERR((CE_WARN, "ioctl: arg passed in to "
385 		    "ioctl = NULL"));
386 		return (EINVAL);
387 	}
388 	if (ddi_copyin((caddr_t)arg, (caddr_t)&passin_byte,
389 			sizeof (uint8_t), mode) != DDI_SUCCESS) {
390 		D2CMN_ERR((CE_WARN, "Failed in HPC3130_SET_CONTROL "
391 		    "ddi_copyin routine"));
392 
393 		return (EFAULT);
394 	}
395 	(void) i2c_transfer_alloc(unitp->hpc3130_hdl, &i2c_tran_pointer,
396 				2, 0, I2C_SLEEP);
397 	if (i2c_tran_pointer == NULL) {
398 		D2CMN_ERR((CE_WARN, "Failed in "
399 		    "HPC3130_SET_CONTROL i2c_tran_pointer not allocated"));
400 
401 		return (ENOMEM);
402 	}
403 
404 	i2c_tran_pointer->i2c_flags = I2C_WR;
405 	i2c_tran_pointer->i2c_wbuf[0] = (uchar_t)reg;
406 	i2c_tran_pointer->i2c_wbuf[1] = passin_byte;
407 
408 	err = i2c_transfer(unitp->hpc3130_hdl, i2c_tran_pointer);
409 	i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer);
410 
411 	return (err);
412 }
413 
414 static int
415 hpc3130_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
416 		int *rvalp)
417 {
418 	_NOTE(ARGUNUSED(credp, rvalp))
419 	hpc3130_unit_t		*unitp;
420 	int 			err = DDI_SUCCESS;
421 	i2c_transfer_t		*i2c_tran_pointer;
422 	i2c_reg_t		ioctl_reg;
423 	int port = MINOR_TO_PORT(getminor(dev));
424 	int instance = MINOR_TO_INST(getminor(dev));
425 	hpc3130_slot_table_entry_t *ste;
426 
427 	if (!(port >= 0 && port < HPC3130_MAX_SLOT)) {
428 		return (EINVAL);
429 	}
430 
431 	unitp = (hpc3130_unit_t *)
432 		ddi_get_soft_state(hpc3130soft_statep, instance);
433 
434 	if (unitp == NULL) {
435 		D1CMN_ERR((CE_WARN, "unitp not filled"));
436 		return (ENOMEM);
437 	}
438 
439 	mutex_enter(&unitp->hpc3130_mutex);
440 
441 	ste = &unitp->hpc3130_slot_table[port];
442 
443 	D2CMN_ERR((CE_NOTE, "ioctl: port = %d  instance = %d",
444 		port, instance));
445 
446 	switch (cmd) {
447 	case HPC3130_GET_STATUS:
448 		err = hpc3130_get(arg, HPC3130_HP_STATUS_REG(port), unitp,
449 			mode);
450 		break;
451 
452 	case HPC3130_GET_CONTROL:
453 		err = hpc3130_get(arg, HPC3130_HP_CONTROL_REG(port), unitp,
454 			mode);
455 		break;
456 
457 	case HPC3130_SET_CONTROL:
458 		if (control_slot_control == HPC3130_SLOT_CONTROL_DISABLE) {
459 			cmn_err(CE_WARN, "Cannot change control register.");
460 			err = EINVAL;
461 			break;
462 		}
463 		err = hpc3130_set(arg, HPC3130_HP_CONTROL_REG(port), unitp,
464 			mode);
465 		break;
466 
467 	case HPC3130_GET_EVENT_STATUS:
468 		err = hpc3130_get(arg, HPC3130_INTERRUPT_STATUS_REG(port),
469 			unitp, mode);
470 		break;
471 
472 	case HPC3130_SET_EVENT_STATUS:
473 		err = hpc3130_set(arg, HPC3130_INTERRUPT_STATUS_REG(port),
474 			unitp, mode);
475 		break;
476 
477 	case HPC3130_GET_GENERAL_CONFIG:
478 		err = hpc3130_get(arg, HPC3130_GENERAL_CONFIG_REG(port),
479 			unitp, mode);
480 		break;
481 
482 	case HPC3130_SET_GENERAL_CONFIG:
483 		err = hpc3130_set(arg, HPC3130_GENERAL_CONFIG_REG(port),
484 			unitp, mode);
485 		break;
486 
487 	case HPC3130_GET_INDICATOR_CONTROL:
488 		err = hpc3130_get(arg, HPC3130_ATTENTION_INDICATOR(port),
489 			unitp, mode);
490 		break;
491 
492 	case HPC3130_SET_INDICATOR_CONTROL:
493 		err = hpc3130_set(arg, HPC3130_ATTENTION_INDICATOR(port),
494 			unitp, mode);
495 		break;
496 
497 	case HPC3130_GET_EVENT_ENABLE:
498 		err = hpc3130_get(arg, HPC3130_INTERRUPT_ENABLE_REG(port),
499 			unitp, mode);
500 		break;
501 
502 	case HPC3130_SET_EVENT_ENABLE:
503 		err = hpc3130_set(arg, HPC3130_INTERRUPT_ENABLE_REG(port),
504 			unitp, mode);
505 		break;
506 
507 	case HPC3130_ENABLE_SLOT_CONTROL:
508 		control_slot_control = HPC3130_SLOT_CONTROL_ENABLE;
509 		D2CMN_ERR((CE_NOTE, "Set the control_slot_control variable to"
510 		    "HPC3130_SLOT_CONTROL_ENABLE"));
511 		break;
512 
513 	case HPC3130_DISABLE_SLOT_CONTROL:
514 		control_slot_control = HPC3130_SLOT_CONTROL_DISABLE;
515 		D2CMN_ERR((CE_NOTE, "Set the control_slot_control variable to"
516 		    "HPC3130_SLOT_CONTROL_DISABLE"));
517 		break;
518 
519 	case I2C_GET_REG:
520 		if (arg == NULL) {
521 			D2CMN_ERR((CE_WARN, "ioctl: arg passed in to "
522 			    "ioctl = NULL"));
523 			err = EINVAL;
524 			break;
525 		}
526 		if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_reg,
527 			sizeof (i2c_reg_t), mode) != DDI_SUCCESS) {
528 			D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG "
529 			    "ddi_copyin routine"));
530 			err = EFAULT;
531 			break;
532 		}
533 		(void) i2c_transfer_alloc(unitp->hpc3130_hdl, &i2c_tran_pointer,
534 			1, 1, I2C_SLEEP);
535 		if (i2c_tran_pointer == NULL) {
536 			D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG "
537 			    "i2c_tran_pointer not allocated"));
538 			err = ENOMEM;
539 			break;
540 		}
541 
542 		i2c_tran_pointer->i2c_flags = I2C_WR_RD;
543 		i2c_tran_pointer->i2c_wbuf[0] = ioctl_reg.reg_num;
544 
545 		err = i2c_transfer(unitp->hpc3130_hdl, i2c_tran_pointer);
546 		if (err) {
547 			D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG "
548 			    "i2c_transfer routine"));
549 			i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer);
550 			break;
551 		}
552 		ioctl_reg.reg_value = i2c_tran_pointer->i2c_rbuf[0];
553 		if (ddi_copyout((caddr_t)&ioctl_reg, (caddr_t)arg,
554 			sizeof (i2c_reg_t), mode) != DDI_SUCCESS) {
555 			D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG "
556 			    "ddi_copyout routine"));
557 			err = EFAULT;
558 		}
559 
560 		i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer);
561 		break;
562 
563 	case I2C_SET_REG:
564 		if (arg == NULL) {
565 			D2CMN_ERR((CE_WARN, "ioctl: arg passed in to "
566 			    "ioctl = NULL"));
567 			err = EINVAL;
568 			break;
569 		}
570 		if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_reg,
571 			sizeof (i2c_reg_t), mode) != DDI_SUCCESS) {
572 			D2CMN_ERR((CE_WARN, "Failed in I2C_SET_REG "
573 			    "ddi_copyin routine"));
574 			err = EFAULT;
575 			break;
576 		}
577 		(void) i2c_transfer_alloc(unitp->hpc3130_hdl, &i2c_tran_pointer,
578 			2, 0, I2C_SLEEP);
579 	if (i2c_tran_pointer == NULL) {
580 			D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG "
581 			    "i2c_tran_pointer not allocated"));
582 			err = ENOMEM;
583 			break;
584 		}
585 
586 		i2c_tran_pointer->i2c_flags = I2C_WR;
587 		i2c_tran_pointer->i2c_wbuf[0] = ioctl_reg.reg_num;
588 		i2c_tran_pointer->i2c_wbuf[1] = (uchar_t)ioctl_reg.reg_value;
589 
590 		err = i2c_transfer(unitp->hpc3130_hdl, i2c_tran_pointer);
591 		if (err) {
592 			D2CMN_ERR((CE_WARN, "Failed in I2C_SET_REG "
593 			    "i2c_transfer routine"));
594 			i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer);
595 			break;
596 		}
597 
598 		i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer);
599 		break;
600 
601 	case HPC3130_GET_EVENT: {
602 		struct hpc3130_event ev;
603 
604 		bzero(&ev, sizeof (struct hpc3130_event));
605 
606 		if (unitp->slots_are == HPC3130_SLOT_TYPE_SBD) {
607 			DAK_GET_SBD_APID(ev.name, sizeof (ev.name), port);
608 		} else {
609 			snprintf(ev.name, HPC3130_NAME_MAX,
610 				"/devices%s:", ste->nexus);
611 			ASSERT(strlen(ev.name) < HPC3130_NAME_MAX - 1);
612 			DAK_GET_PCI_APID(ev.name + strlen(ev.name),
613 				HPC3130_NAME_MAX - strlen(ev.name),
614 				hpc3130_lookup_slot(ste->nexus,
615 				ste->hpc3130_slot_info.pci_dev_num));
616 		}
617 
618 		if (unitp->events[port] & HPC3130_IEVENT_OCCUPANCY) {
619 			unitp->events[port] &= ~HPC3130_IEVENT_OCCUPANCY;
620 			ev.id = (unitp->present[port] == B_FALSE ?
621 				HPC3130_EVENT_REMOVAL :
622 				HPC3130_EVENT_INSERTION);
623 		} else if (unitp->events[port] & HPC3130_IEVENT_POWER) {
624 			unitp->events[port] &= ~HPC3130_IEVENT_POWER;
625 			ev.id = (unitp->power[port] == B_TRUE ?
626 				HPC3130_EVENT_POWERON :
627 				HPC3130_EVENT_POWEROFF);
628 		} else if (unitp->events[port] & HPC3130_IEVENT_BUTTON) {
629 			unitp->events[port] &= ~HPC3130_IEVENT_BUTTON;
630 			ev.id = HPC3130_EVENT_BUTTON;
631 		} else if (unitp->events[port] & HPC3130_IEVENT_FAULT) {
632 			unitp->events[port] &= ~HPC3130_IEVENT_FAULT;
633 			ev.id = (unitp->fault_led[port] == HPC3130_ATTN_ON ?
634 			    HPC3130_LED_FAULT_ON :
635 			    HPC3130_LED_FAULT_OFF);
636 		} else if (unitp->events[port] & HPC3130_IEVENT_OK2REM) {
637 			unitp->events[port] &= ~HPC3130_IEVENT_OK2REM;
638 			ev.id = (unitp->ok2rem_led[port] == HPC3130_ATTN_ON ?
639 			    HPC3130_LED_REMOVABLE_ON :
640 			    HPC3130_LED_REMOVABLE_OFF);
641 		}
642 
643 		D1CMN_ERR((CE_NOTE,
644 		    "sending EVENT: ap_id=%s, event=%d", ev.name, ev.id));
645 
646 		if (ddi_copyout((caddr_t)&ev, (caddr_t)arg,
647 			sizeof (struct hpc3130_event), mode) != DDI_SUCCESS) {
648 			D1CMN_ERR((CE_WARN, "Failed in hpc3130_ioctl"
649 			    " ddi_copyout routine"));
650 			err = EFAULT;
651 		}
652 		break;
653 	}
654 	case HPC3130_CONF_DR: {
655 		uint8_t offset;
656 		int dr_conf;
657 
658 		if (ddi_copyin((caddr_t)arg, (caddr_t)&dr_conf,
659 				sizeof (int), mode) != DDI_SUCCESS) {
660 			D2CMN_ERR((CE_WARN, "Failed in HPC3130_CONF_DR "
661 				"ddi_copyin routine"))
662 			err = EFAULT;
663 			break;
664 		}
665 
666 		offset = ste->callback_info.offset;
667 
668 		unitp->enabled[offset] =
669 		    (dr_conf == HPC3130_DR_DISABLE ? B_FALSE : B_TRUE);
670 
671 		break;
672 	}
673 	default:
674 		D2CMN_ERR((CE_WARN, "Invalid IOCTL cmd: %x", cmd));
675 		err = EINVAL;
676 	}
677 
678 	mutex_exit(&unitp->hpc3130_mutex);
679 	return (err);
680 }
681 
682 static int
683 hpc3130_poll(dev_t dev, short events, int anyyet,  short
684 	*reventsp, struct pollhead **phpp)
685 {
686 	_NOTE(ARGUNUSED(events))
687 	hpc3130_unit_t 	*unitp;
688 	int port = MINOR_TO_PORT(getminor(dev));
689 	int instance = MINOR_TO_INST(getminor(dev));
690 
691 	if (!(port >= 0 && port < HPC3130_MAX_SLOT)) {
692 		return (EINVAL);
693 	}
694 	unitp = (hpc3130_unit_t *)
695 		ddi_get_soft_state(hpc3130soft_statep, instance);
696 
697 	mutex_enter(&unitp->hpc3130_mutex);
698 	if (unitp->events[port]) {
699 		*reventsp = POLLIN;
700 	} else {
701 		*reventsp = 0;
702 		if (!anyyet)
703 			*phpp = &unitp->pollhead[port];
704 	}
705 	mutex_exit(&unitp->hpc3130_mutex);
706 	return (0);
707 }
708 
709 /* ARGSUSED */
710 static int
711 hpc3130_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
712 {
713 	dev_t	dev;
714 	int	instance;
715 
716 	if (infocmd == DDI_INFO_DEVT2INSTANCE) {
717 		dev = (dev_t)arg;
718 		instance = MINOR_TO_INST(getminor(dev));
719 		*result = (void *)(uintptr_t)instance;
720 		return (DDI_SUCCESS);
721 	}
722 	return (DDI_FAILURE);
723 }
724 
725 static int
726 hpc3130_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
727 {
728 	switch (cmd) {
729 	case DDI_ATTACH:
730 		return (hpc3130_do_attach(dip));
731 	case DDI_RESUME:
732 		return (hpc3130_do_resume());
733 	default:
734 		return (DDI_FAILURE);
735 	}
736 }
737 
738 static int
739 hpc3130_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
740 {
741 	switch (cmd) {
742 	case DDI_DETACH:
743 		return (hpc3130_do_detach(dip));
744 	case DDI_SUSPEND:
745 		return (hpc3130_do_suspend());
746 	default:
747 		return (DDI_FAILURE);
748 	}
749 }
750 
751 static int
752 hpc3130_do_attach(dev_info_t *dip)
753 {
754 	hpc3130_unit_t	*hpc3130_p;
755 	char		*s;
756 	char		*nexus;
757 	char		*pcidev;
758 	char		*reg_offset;
759 	int		r, i, n, j;
760 	char		name[MAXNAMELEN];
761 	minor_t		minor_number;
762 	int		hpc3130_pil = HPC3130_PIL;
763 	int		instance = ddi_get_instance(dip);
764 
765 	/*
766 	 * Allocate the soft state structure for this instance.
767 	 */
768 	r = ddi_soft_state_zalloc(hpc3130soft_statep, instance);
769 	if (r != DDI_SUCCESS) {
770 		return (DDI_FAILURE);
771 	}
772 
773 	hpc3130_p =
774 	    (hpc3130_unit_t *)ddi_get_soft_state(hpc3130soft_statep, instance);
775 	ASSERT(hpc3130_p);
776 
777 	if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
778 		"interrupt-priorities", (caddr_t)&hpc3130_pil,
779 		sizeof (hpc3130_pil)) != DDI_PROP_SUCCESS) {
780 		goto failout0;
781 	}
782 
783 	if (ddi_intr_hilevel(dip, 0)) {
784 		cmn_err(CE_WARN, "High level interrupt not supported");
785 		goto failout0;
786 	}
787 
788 	/*
789 	 * Get the "slot-table" property which defines the list of
790 	 * hot-pluggable slots for this controller along with the
791 	 * corresponding bus nexus node and device identification
792 	 * for each slot.
793 	 */
794 	r = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
795 		"slot-table", (caddr_t)&hpc3130_p->hpc3130_slot_table_data,
796 		&hpc3130_p->hpc3130_slot_table_size);
797 
798 	switch (r) {
799 	case DDI_PROP_SUCCESS:
800 		break;
801 	case DDI_PROP_NOT_FOUND:
802 		cmn_err(CE_WARN,
803 		    "couldn't find slot-table property");
804 		return (DDI_FAILURE);
805 	case DDI_PROP_UNDEFINED:
806 		cmn_err(CE_WARN,
807 		    "slot-table undefined");
808 		return (DDI_FAILURE);
809 	case DDI_PROP_NO_MEMORY:
810 		cmn_err(CE_WARN,
811 		    "can't allocate memory for slot-table");
812 		return (DDI_FAILURE);
813 	}
814 
815 	/*
816 	 * Determine the size of the slot table from the OBP property and
817 	 * allocate the slot table arrary..
818 	 */
819 	for (i = 0, n = 0; i < hpc3130_p->hpc3130_slot_table_size; i++) {
820 		if (hpc3130_p->hpc3130_slot_table_data[i] == 0) {
821 			n++;
822 		}
823 	}
824 
825 	D1CMN_ERR((CE_NOTE, "hpc3130_attach(): slot table has %d entries", n));
826 
827 	/*
828 	 * There should be HPC3130_TABLE_COLUMNS elements per entry
829 	 */
830 	if (n % HPC3130_TABLE_COLUMNS) {
831 		cmn_err(CE_WARN, "bad format in slot-table");
832 		goto failout1;
833 	}
834 
835 	hpc3130_p->dip = dip;
836 	hpc3130_p->hpc3130_slot_table_length = n / HPC3130_TABLE_COLUMNS;
837 
838 	if (ddi_get_iblock_cookie(dip, 0, &hpc3130_p->ic_trap_cookie) !=
839 	    DDI_SUCCESS)  {
840 		cmn_err(CE_WARN, "ddi_get_iblock_cookie FAILED");
841 		goto failout1;
842 	}
843 
844 	mutex_init(&hpc3130_p->hpc3130_mutex, NULL, MUTEX_DRIVER,
845 		(void *)hpc3130_p->ic_trap_cookie);
846 	/*
847 	 * Create enough space for each slot table entry
848 	 * based on how many entries in the property
849 	 */
850 	hpc3130_p->hpc3130_slot_table = (hpc3130_slot_table_entry_t *)
851 		kmem_zalloc(hpc3130_p->hpc3130_slot_table_length *
852 			sizeof (hpc3130_slot_table_entry_t), KM_SLEEP);
853 
854 	/*
855 	 * Setup to talk to the i2c nexus
856 	 */
857 	if (i2c_client_register(dip, &hpc3130_p->hpc3130_hdl) != I2C_SUCCESS) {
858 		cmn_err(CE_WARN, "failed to register as i2c client");
859 		goto failout2;
860 	}
861 
862 	s = hpc3130_p->hpc3130_slot_table_data;
863 	for (i = 0; i < hpc3130_p->hpc3130_slot_table_length; i++) {
864 		hpc3130_slot_table_entry_t *ste;
865 
866 		/* Pick off pointer to nexus path */
867 		nexus = s;
868 		s = s + strlen(s) + 1;
869 
870 		/* Pick off pointer to 3130 register offset */
871 		reg_offset = s;
872 		s = s + strlen(s) + 1;
873 
874 		/* Pick off pointer to the device number */
875 		pcidev = s;
876 
877 		s = s + strlen(s) + 1;
878 
879 		j = hpc3130_atoi(reg_offset);
880 
881 		if (j < 0 || j >= HPC3130_MAX_SLOT) {
882 			cmn_err(CE_WARN,
883 			    "invalid register offset value");
884 			goto failout3;
885 		}
886 
887 		ste = &hpc3130_p->hpc3130_slot_table[j];
888 
889 		strcpy(ste->nexus, nexus);
890 
891 		if (strncmp(ste->nexus, "/pci", 4) == 0) {
892 
893 			ste->hpc3130_slot_info.pci_dev_num =
894 				hpc3130_atoi(pcidev);
895 
896 			DAK_GET_PCI_APID(ste->hpc3130_slot_info.pci_slot_name,
897 				PCI_SLOT_NAME_LEN,
898 				hpc3130_lookup_slot(ste->nexus,
899 				hpc3130_atoi(pcidev)));
900 
901 			ste->hpc3130_slot_info.slot_type = HPC_SLOT_TYPE_PCI;
902 			ste->hpc3130_slot_info.slot_flags =
903 				HPC_SLOT_CREATE_DEVLINK;
904 			hpc3130_p->slots_are = HPC3130_SLOT_TYPE_PCI;
905 
906 		} else {
907 
908 			ste->hpc3130_slot_info.sbd_slot_num =
909 				hpc3130_atoi(reg_offset);
910 
911 			ste->hpc3130_slot_info.slot_type = HPC_SLOT_TYPE_SBD;
912 
913 			hpc3130_p->slots_are = HPC3130_SLOT_TYPE_SBD;
914 		}
915 
916 		hpc3130_p->present[j] = B_FALSE;
917 		hpc3130_p->enabled[j] = B_TRUE;
918 
919 		/*
920 		 * The "callback_info" structure of the slot_table is what gets
921 		 * passed back in the callback routines.  All that is needed
922 		 * at that point is the device handle  and the register offset
923 		 * within it the chip it represents.
924 		 */
925 		ste->callback_info.handle = (caddr_t)hpc3130_p->hpc3130_hdl;
926 
927 		ste->callback_info.offset = hpc3130_atoi(reg_offset);
928 
929 		ste->callback_info.statep = (caddr_t)hpc3130_p;
930 	}
931 
932 	hpc3130_p->hpc3130_slot_ops = hpc_alloc_slot_ops(KM_SLEEP);
933 	hpc3130_p->hpc3130_slot_ops->hpc_version = 0;
934 
935 	hpc3130_p->hpc3130_slot_ops->hpc_op_connect = hpc3130_slot_connect;
936 	hpc3130_p->hpc3130_slot_ops->hpc_op_disconnect =
937 		hpc3130_slot_disconnect;
938 	hpc3130_p->hpc3130_slot_ops->hpc_op_insert = hpc3130_slot_insert;
939 	hpc3130_p->hpc3130_slot_ops->hpc_op_remove = hpc3130_slot_remove;
940 	hpc3130_p->hpc3130_slot_ops->hpc_op_control = hpc3130_slot_control;
941 
942 	cv_init(&hpc3130_p->hpc3130_cond, NULL, CV_DEFAULT, NULL);
943 
944 	if (hpc3130_init(dip, (hpc3130_p->slots_are == HPC3130_SLOT_TYPE_SBD) ?
945 		cpu_sequence : pci_sequence) != DDI_SUCCESS) {
946 			goto failout4;
947 	}
948 
949 	if (ddi_add_intr(dip, 0, &hpc3130_p->ic_trap_cookie,
950 		NULL, hpc3130_hard_intr,
951 		(caddr_t)hpc3130_p) != DDI_SUCCESS) {
952 		cmn_err(CE_WARN, "failed to add interrupt");
953 		goto failout4;
954 	}
955 
956 	/*
957 	 * Register with the "services" module
958 	 */
959 	for (i = 0; i < hpc3130_p->hpc3130_slot_table_length; i++) {
960 		hpc3130_slot_table_entry_t *ste =
961 		    &hpc3130_p->hpc3130_slot_table[i];
962 		hpc3130_p->power[i] = B_TRUE;
963 		if (ste->callback_info.handle != NULL) {
964 			hpc_slot_register(dip, ste->nexus,
965 				&ste->hpc3130_slot_info,
966 				&ste->hpc3130_slot_handle,
967 				hpc3130_p->hpc3130_slot_ops,
968 				(caddr_t)&ste->callback_info, 0);
969 		}
970 	}
971 
972 	(void) snprintf(hpc3130_p->hpc3130_name,
973 		sizeof (hpc3130_p->hpc3130_name),
974 			"%s%d", ddi_node_name(dip), instance);
975 
976 	for (i = 0; i < HPC3130_MAX_SLOT; i++) {
977 		(void) snprintf(name, MAXNAMELEN, "port_%d", i);
978 		minor_number = INST_TO_MINOR(instance) |
979 			PORT_TO_MINOR(I2C_PORT(i));
980 		if (ddi_create_minor_node(dip, name, S_IFCHR, minor_number,
981 				"ddi_i2c:controller", NULL) == DDI_FAILURE) {
982 			D1CMN_ERR((CE_WARN, "ddi_create_minor_node failed "
983 				"for %s", name));
984 			ddi_remove_intr(dip, 0u,
985 				hpc3130_p->ic_trap_cookie);
986 			goto failout4;
987 		}
988 	}
989 
990 	return (DDI_SUCCESS);
991 
992 failout4:
993 	hpc_free_slot_ops(hpc3130_p->hpc3130_slot_ops);
994 failout3:
995 	i2c_client_unregister(hpc3130_p->hpc3130_hdl);
996 failout2:
997 	mutex_destroy(&hpc3130_p->hpc3130_mutex);
998 	kmem_free(hpc3130_p->hpc3130_slot_table,
999 		hpc3130_p->hpc3130_slot_table_length *
1000 		sizeof (hpc3130_slot_table_entry_t));
1001 failout1:
1002 	kmem_free(hpc3130_p->hpc3130_slot_table_data,
1003 		hpc3130_p->hpc3130_slot_table_size);
1004 failout0:
1005 	ddi_soft_state_free(hpc3130soft_statep, instance);
1006 
1007 	return (DDI_FAILURE);
1008 }
1009 
1010 static int
1011 hpc3130_do_resume()
1012 {
1013 	return (DDI_SUCCESS);
1014 }
1015 
1016 static int
1017 hpc3130_do_suspend()
1018 {
1019 	return (DDI_SUCCESS);
1020 }
1021 
1022 static int
1023 hpc3130_do_detach(dev_info_t *dip)
1024 {
1025 	int i;
1026 	int instance = ddi_get_instance(dip);
1027 	hpc3130_unit_t *hpc3130_p;
1028 
1029 	hpc3130_p = (hpc3130_unit_t *)ddi_get_soft_state(hpc3130soft_statep,
1030 		instance);
1031 	if (hpc3130_p == NULL)
1032 		return (ENXIO);
1033 
1034 	i2c_client_unregister(hpc3130_p->hpc3130_hdl);
1035 
1036 	ddi_remove_intr(dip, 0u, hpc3130_p->ic_trap_cookie);
1037 
1038 	cv_destroy(&hpc3130_p->hpc3130_cond);
1039 
1040 	for (i = 0; i < hpc3130_p->hpc3130_slot_table_length; i++) {
1041 		hpc_slot_unregister(
1042 			&hpc3130_p->hpc3130_slot_table[i].hpc3130_slot_handle);
1043 	}
1044 
1045 	kmem_free(hpc3130_p->hpc3130_slot_table,
1046 	    hpc3130_p->hpc3130_slot_table_length *
1047 	    sizeof (hpc3130_slot_table_entry_t));
1048 
1049 	kmem_free(hpc3130_p->hpc3130_slot_table_data,
1050 		hpc3130_p->hpc3130_slot_table_size);
1051 
1052 	hpc_free_slot_ops(hpc3130_p->hpc3130_slot_ops);
1053 
1054 	mutex_destroy(&hpc3130_p->hpc3130_mutex);
1055 
1056 	ddi_soft_state_free(hpc3130soft_statep, instance);
1057 
1058 	return (DDI_SUCCESS);
1059 }
1060 
1061 int
1062 hpc3130_set_led(hpc3130_unit_t *unitp, int slot, int led, uint8_t value)
1063 {
1064 	i2c_client_hdl_t handle = unitp->hpc3130_hdl;
1065 	uint8_t old;
1066 	uint8_t	new;
1067 
1068 	if (hpc3130_read(handle, HPC3130_ATTEN, slot, &old) != DDI_SUCCESS) {
1069 		return (DDI_FAILURE);
1070 	}
1071 	new = (old & ~HPC3130_ATTN_MASK(led)) |
1072 		value << HPC3130_ATTN_SHIFT(led);
1073 
1074 	D1CMN_ERR((CE_NOTE, "setting led %d to %x", led, value));
1075 
1076 	if (hpc3130_write(handle, HPC3130_ATTEN, slot, new) != DDI_SUCCESS) {
1077 		return (DDI_FAILURE);
1078 	}
1079 
1080 	if ((value == HPC3130_ATTN_OFF || value == HPC3130_ATTN_ON) &&
1081 	    ((old & HPC3130_ATTN_MASK(led)) !=
1082 		(new & HPC3130_ATTN_MASK(led)))) {
1083 		/*
1084 		 * We're turning a LED on or off (i.e., not blinking), and
1085 		 * the value actually did change.
1086 		 */
1087 		if (led == HPC3130_LED_OK2REM) {
1088 			unitp->events[slot] |= HPC3130_IEVENT_OK2REM;
1089 			unitp->ok2rem_led[slot] = value;
1090 			D1CMN_ERR((CE_NOTE,
1091 			    "recording IEVENT_OK2REM slot=%d, val=%d",
1092 			    slot, value));
1093 		} else {
1094 			unitp->events[slot] |= HPC3130_IEVENT_FAULT;
1095 			unitp->fault_led[slot] = value;
1096 			D1CMN_ERR((CE_NOTE,
1097 			    "recording IEVENT_FAULT slot=%d, val=%d",
1098 			    slot, value));
1099 		}
1100 		ASSERT(MUTEX_HELD(&unitp->hpc3130_mutex));
1101 		mutex_exit(&unitp->hpc3130_mutex);
1102 		pollwakeup(&unitp->pollhead[slot], POLLIN);
1103 		mutex_enter(&unitp->hpc3130_mutex);
1104 	}
1105 	return (DDI_SUCCESS);
1106 }
1107 
1108 int
1109 hpc3130_get_led(i2c_client_hdl_t handle, int slot,
1110 	int led, uint8_t *value)
1111 {
1112 	uint8_t	temp;
1113 
1114 	if (hpc3130_read(handle, HPC3130_ATTEN, slot, &temp) != DDI_SUCCESS) {
1115 		return (DDI_FAILURE);
1116 	}
1117 
1118 	*value = (temp & HPC3130_ATTN_MASK(led)) >> HPC3130_ATTN_SHIFT(led);
1119 	return (DDI_SUCCESS);
1120 }
1121 
1122 static int
1123 hpc3130_write(i2c_client_hdl_t handle, uint8_t offset,
1124 	uint8_t port, uint8_t data)
1125 {
1126 	ASSERT(port >= 0 && port < HPC3130_MAX_SLOT);
1127 	ASSERT(handle);
1128 
1129 	return (hpc3130_rw(handle,
1130 	    HPC3130_REG(offset, port), B_TRUE, &data));
1131 }
1132 
1133 static int
1134 hpc3130_read(i2c_client_hdl_t handle, uint8_t offset,
1135 	uint8_t port, uint8_t *data)
1136 {
1137 	ASSERT(port >= 0 && port < HPC3130_MAX_SLOT);
1138 	ASSERT(handle);
1139 
1140 	return (hpc3130_rw(handle,
1141 	    HPC3130_REG(offset, port), B_FALSE, data));
1142 }
1143 
1144 static int
1145 hpc3130_rw(i2c_client_hdl_t handle, uint8_t reg,
1146 	boolean_t write, uint8_t *data)
1147 {
1148 	i2c_transfer_t	*i2c_tran_pointer;
1149 	int		err;
1150 	int		rlen;
1151 	int		wlen;
1152 
1153 	if (write == B_TRUE) {
1154 		wlen = 2;
1155 		rlen = 0;
1156 	} else {
1157 		wlen = 1;
1158 		rlen = 1;
1159 	}
1160 
1161 	(void) i2c_transfer_alloc(handle,
1162 		&i2c_tran_pointer, wlen, rlen, I2C_SLEEP);
1163 
1164 	if (i2c_tran_pointer == NULL) {
1165 		D1CMN_ERR((CE_WARN, "Failed in hpc3130_rw: "
1166 		    "no transfer structure 0x%x", reg));
1167 		return (DDI_FAILURE);
1168 	}
1169 	i2c_tran_pointer->i2c_wbuf[0] = reg;
1170 	if (write == B_TRUE) {
1171 		i2c_tran_pointer->i2c_flags = I2C_WR;
1172 		i2c_tran_pointer->i2c_wbuf[1] = *data;
1173 	} else {
1174 		i2c_tran_pointer->i2c_flags = I2C_WR_RD;
1175 	}
1176 
1177 	err = i2c_transfer(handle, i2c_tran_pointer);
1178 	if (err) {
1179 		D1CMN_ERR((CE_WARN, "Failed in hpc3130_rw: "
1180 		    "no I2C data transfered 0x%x", reg));
1181 		(void) i2c_transfer_free(handle, i2c_tran_pointer);
1182 		return (DDI_FAILURE);
1183 	}
1184 
1185 	if (write == B_FALSE)
1186 		*data = i2c_tran_pointer->i2c_rbuf[0];
1187 
1188 	(void) i2c_transfer_free(handle, i2c_tran_pointer);
1189 
1190 	return (DDI_SUCCESS);
1191 }
1192 
1193 /*
1194  * Put the hot plug controller(s) in proper mode for further
1195  * operations.
1196  */
1197 static int
1198 hpc3130_init(dev_info_t *dip,
1199 	struct tuple *init_sequence)
1200 {
1201 
1202 	int			slot;
1203 	i2c_client_hdl_t	handle;
1204 	hpc3130_unit_t		*hpc3130_p;
1205 	int			instance = ddi_get_instance(dip);
1206 	int			error = DDI_FAILURE;
1207 	struct tuple		*tp;
1208 
1209 	hpc3130_p =
1210 	    (hpc3130_unit_t *)ddi_get_soft_state(hpc3130soft_statep,
1211 	    instance);
1212 	ASSERT(hpc3130_p);
1213 
1214 	mutex_enter(&hpc3130_p->hpc3130_mutex);
1215 
1216 	handle = hpc3130_p->hpc3130_hdl;
1217 
1218 	for (slot = 0; slot < HPC3130_MAX_SLOT; slot++) {
1219 		tp = init_sequence;
1220 		while (tp->reg != HPC3130_NO_REGISTER) {
1221 			if (hpc3130_write(handle, tp->reg, slot,
1222 				tp->val) != DDI_SUCCESS) {
1223 				goto out;
1224 			}
1225 			tp++;
1226 		}
1227 		/*
1228 		 * CPU slots need some special initialization
1229 		 * attention.
1230 		 */
1231 		if (hpc3130_p->slots_are == HPC3130_SLOT_TYPE_SBD) {
1232 			if (hpc3130_cpu_init(hpc3130_p, slot, handle)
1233 			    != DDI_SUCCESS) {
1234 				goto out;
1235 			}
1236 		}
1237 	}
1238 	error = DDI_SUCCESS;
1239 out:
1240 	mutex_exit(&hpc3130_p->hpc3130_mutex);
1241 
1242 	return (error);
1243 }
1244 
1245 /*
1246  * When the TI 3130 produces an interrupt,
1247  * this routine is called to sort it out.
1248  */
1249 static uint_t
1250 hpc3130_hard_intr(caddr_t arg)
1251 {
1252 	uint8_t			interrupt;
1253 	uint8_t			status;
1254 	uint8_t			slot;
1255 	i2c_client_hdl_t	handle;
1256 	hpc3130_slot_type_t	slot_type;
1257 	uint_t			rc = DDI_INTR_UNCLAIMED;
1258 
1259 	hpc3130_unit_t		*hpc3130_p = (hpc3130_unit_t *)arg;
1260 	ASSERT(hpc3130_p);
1261 
1262 	mutex_enter(&hpc3130_p->hpc3130_mutex);
1263 
1264 	slot_type = hpc3130_p->slots_are;
1265 	handle = hpc3130_p->hpc3130_hdl;
1266 
1267 	for (slot = 0; slot < HPC3130_MAX_SLOT; slot++) {
1268 
1269 		/*
1270 		 * Read the interrupt event register - see
1271 		 * which event(s) took place.
1272 		 */
1273 		if (hpc3130_read(handle, HPC3130_EVENT_STATUS, slot,
1274 			&interrupt)) {
1275 			continue;
1276 		}
1277 
1278 		if (interrupt == 0)
1279 			continue;
1280 
1281 		rc = DDI_INTR_CLAIMED;
1282 
1283 		if (hpc3130_debounce_status(handle,
1284 			slot, &status) != DDI_SUCCESS) {
1285 			continue;
1286 		}
1287 
1288 		if (interrupt & HPC3130_PWRGOOD) {
1289 			hpc3130_p->power[slot] = B_FALSE;
1290 			if (!(status & HPC3130_PWRGOOD)) {
1291 				hpc3130_p->power[slot] = B_TRUE;
1292 			}
1293 			cv_signal(&hpc3130_p->hpc3130_cond);
1294 			hpc3130_p->events[slot] |= HPC3130_IEVENT_POWER;
1295 		}
1296 
1297 		if (interrupt & HPC3130_DETECT0) {
1298 			if (slot_type == HPC3130_SLOT_TYPE_SBD) {
1299 				boolean_t present = !(status&HPC3130_DETECT0);
1300 
1301 				/* Turn ON/OFF OK-to-remove LED */
1302 				(void) hpc3130_set_led(hpc3130_p,
1303 					slot,
1304 					HPC3130_LED_OK2REM,
1305 					(present ? HPC3130_ATTN_ON :
1306 					    HPC3130_ATTN_OFF));
1307 				if (!present) {
1308 					/* Clear the FAULT LED on removal */
1309 					(void) hpc3130_set_led(hpc3130_p,
1310 						slot,
1311 						HPC3130_LED_FAULT,
1312 						HPC3130_ATTN_OFF);
1313 				}
1314 
1315 				hpc3130_p->present[slot] = present;
1316 				hpc3130_p->events[slot] |=
1317 					HPC3130_IEVENT_OCCUPANCY;
1318 			} else {
1319 				ASSERT(slot_type == HPC3130_SLOT_TYPE_PCI);
1320 
1321 				if (!(status & HPC3130_DETECT0)) {
1322 					/*
1323 					 * Event on the downward
1324 					 * stroke of the button.
1325 					 */
1326 					hpc3130_p->events[slot] |=
1327 						HPC3130_IEVENT_BUTTON;
1328 				}
1329 			}
1330 		}
1331 
1332 		if (interrupt & (HPC3130_PRSNT1 | HPC3130_PRSNT2)) {
1333 			if (slot_type == HPC3130_SLOT_TYPE_SBD) {
1334 				if (!(status & HPC3130_PRSNT1)) {
1335 					/*
1336 					 * Event only on the downward
1337 					 * stroke of the button.
1338 					 */
1339 					hpc3130_p->events[slot] |=
1340 						HPC3130_IEVENT_BUTTON;
1341 				}
1342 			} else {
1343 				ASSERT(slot_type == HPC3130_SLOT_TYPE_PCI);
1344 				if ((status & (HPC3130_PRSNT1 |
1345 					HPC3130_PRSNT2)) ==
1346 					(HPC3130_PRSNT1 | HPC3130_PRSNT2)) {
1347 
1348 					hpc3130_p->present[slot] = B_FALSE;
1349 
1350 					/* Turn OFF Fault LED */
1351 					(void) hpc3130_set_led(hpc3130_p,
1352 						slot,
1353 						HPC3130_LED_FAULT,
1354 						HPC3130_ATTN_OFF);
1355 					/* Turn OFF OK-to-remove LED */
1356 					(void) hpc3130_set_led(hpc3130_p,
1357 						slot,
1358 						HPC3130_LED_OK2REM,
1359 						HPC3130_ATTN_OFF);
1360 				} else {
1361 
1362 					hpc3130_p->present[slot] = B_TRUE;
1363 
1364 					/* Turn ON OK-to-remove LED */
1365 					(void) hpc3130_set_led(hpc3130_p,
1366 						slot,
1367 						HPC3130_LED_OK2REM,
1368 						HPC3130_ATTN_ON);
1369 				}
1370 
1371 				hpc3130_p->events[slot] |=
1372 					HPC3130_IEVENT_OCCUPANCY;
1373 			}
1374 		}
1375 		if (hpc3130_p->events[slot] &&
1376 			(hpc3130_p->present[slot] == B_TRUE)) {
1377 			mutex_exit(&hpc3130_p->hpc3130_mutex);
1378 			pollwakeup(&hpc3130_p->pollhead[slot], POLLIN);
1379 			mutex_enter(&hpc3130_p->hpc3130_mutex);
1380 		}
1381 		(void) hpc3130_write(handle, HPC3130_EVENT_STATUS,
1382 			slot, interrupt);
1383 	}
1384 
1385 	mutex_exit(&hpc3130_p->hpc3130_mutex);
1386 
1387 	return (rc);
1388 }
1389 
1390 static int
1391 hpc3130_cpu_init(hpc3130_unit_t *hpc3130_p, int slot, i2c_client_hdl_t handle)
1392 {
1393 	uint8_t	slot_status;
1394 	uint8_t	control_reg;
1395 
1396 	int	result = HPC_ERR_FAILED;
1397 
1398 	if (hpc3130_read(handle, HPC3130_STATUS, slot,
1399 		&slot_status)) {
1400 		goto out;
1401 	}
1402 
1403 	if (hpc3130_read(handle, HPC3130_CONTROL, slot,
1404 		&control_reg)) {
1405 		goto out;
1406 	}
1407 
1408 	/*
1409 	 * For the CPU slots, the DETECT[0] pin on the HPC3130
1410 	 * goes low when a CPU module is in the slot. Pulled
1411 	 * high otherwise.
1412 	 */
1413 	if (slot_status & HPC3130_DETECT0) {
1414 		D1CMN_ERR((CE_NOTE, "hpc3130_cpu_init(): "
1415 		    "[0x%x]Power off....[%d]",
1416 		    slot_status, slot));
1417 		control_reg = control_reg & ~HPC3130_SLTPWRCTL;
1418 	} else {
1419 		D1CMN_ERR((CE_NOTE, "hpc3130_cpu_init(): "
1420 		    "[0x%x]Power LEFT on!!!....[%d]",
1421 		    slot_status, slot));
1422 		hpc3130_p->present[slot] = B_TRUE;
1423 		control_reg = control_reg | HPC3130_SLTPWRCTL;
1424 
1425 	}
1426 
1427 	/*
1428 	 * Set the control register accordingly
1429 	 */
1430 	if (hpc3130_write(handle, HPC3130_CONTROL,
1431 		slot, control_reg) != DDI_SUCCESS) {
1432 		goto out;
1433 	}
1434 
1435 	result = DDI_SUCCESS;
1436 out:
1437 
1438 	return (result);
1439 }
1440 
1441 static int
1442 hpc3130_debounce_status(i2c_client_hdl_t handle,
1443 	int slot, uint8_t *status)
1444 {
1445 	int	count, limit;
1446 	uint8_t	old;
1447 
1448 	ASSERT(status);
1449 
1450 	/*
1451 	 * Get HPC3130_DEBOUNCE_COUNT consecutive equal
1452 	 * readings from the status register
1453 	 */
1454 
1455 	count = 0; limit = 0; old = 0xff;
1456 	do {
1457 		if (hpc3130_read(handle, HPC3130_STATUS,
1458 			slot, status)) {
1459 			return (DDI_FAILURE);
1460 		}
1461 		if (old != *status) {
1462 			count = 0;
1463 		} else {
1464 			count += 1;
1465 		}
1466 
1467 		limit += 1;
1468 		old = *status;
1469 
1470 	} while (count < HPC3130_DEBOUNCE_COUNT &&
1471 		limit < HPC3130_DEBOUNCE_LIMIT);
1472 
1473 	if (limit == HPC3130_DEBOUNCE_LIMIT) {
1474 		return (DDI_FAILURE);
1475 	}
1476 
1477 	return (DDI_SUCCESS);
1478 }
1479 
1480 static int
1481 hpc3130_slot_connect(caddr_t ops_arg, hpc_slot_t slot_hdl,
1482 		void *data, uint_t flags)
1483 {
1484 	_NOTE(ARGUNUSED(slot_hdl, data, flags))
1485 	uint8_t			control;
1486 	uint8_t			offset;
1487 	uint8_t			config;
1488 	uint8_t			status;
1489 	hpc3130_unit_t		*hpc3130_p;
1490 	i2c_client_hdl_t	handle;
1491 	int			i;
1492 	int			result = HPC_ERR_FAILED;
1493 	hpc3130_slot_type_t	slot_type;
1494 	hpc3130_slot_table_entry_t *ste;
1495 	char			phys_slot[MAXPATHLEN];
1496 	boolean_t		needs_to_be_powered_off = B_FALSE;
1497 
1498 	hpc3130_callback_arg_t	*info_p = (hpc3130_callback_arg_t *)ops_arg;
1499 
1500 	/*
1501 	 * Callback parameter has specific device handle and offset
1502 	 * information in it.
1503 	 */
1504 
1505 	hpc3130_p = (hpc3130_unit_t *)info_p->statep;
1506 	ASSERT(hpc3130_p);
1507 
1508 	mutex_enter(&hpc3130_p->hpc3130_mutex);
1509 
1510 	handle = (i2c_client_hdl_t)info_p->handle;
1511 	offset = info_p->offset;
1512 
1513 	ste = &hpc3130_p->hpc3130_slot_table[offset];
1514 
1515 	if (hpc3130_p->slots_are == HPC3130_SLOT_TYPE_SBD) {
1516 		DAK_GET_SBD_APID(phys_slot, MAXPATHLEN, offset);
1517 	} else {
1518 		DAK_GET_PCI_APID(phys_slot, MAXPATHLEN,
1519 			hpc3130_lookup_slot(ste->nexus,
1520 			ste->hpc3130_slot_info.pci_dev_num));
1521 	}
1522 
1523 	ASSERT(ste->hpc3130_slot_handle != NULL);
1524 
1525 	slot_type = hpc3130_p->slots_are;
1526 
1527 	if (hpc3130_p->enabled[offset] == B_FALSE) {
1528 		cmn_err(CE_WARN, "hot-plug disabled on %s", phys_slot);
1529 		goto out;
1530 	}
1531 
1532 	/* Return (do nothing) if power already applied */
1533 	if (hpc3130_p->power[offset] == B_TRUE) {
1534 		D1CMN_ERR((CE_NOTE, "Slot power already on %s", phys_slot));
1535 		mutex_exit(&hpc3130_p->hpc3130_mutex);
1536 		return (HPC_SUCCESS);
1537 	}
1538 
1539 	if (hpc3130_read(handle, HPC3130_STATUS, offset,
1540 		&status)) {
1541 		goto out;
1542 	}
1543 
1544 	/* Read the slot control register to get current value */
1545 	if (hpc3130_read(handle, HPC3130_CONTROL, offset,
1546 		&control)) {
1547 		goto out;
1548 	}
1549 
1550 	if (slot_type == HPC3130_SLOT_TYPE_SBD) {
1551 
1552 		D1CMN_ERR((CE_NOTE, "CPU connect %d control=%x status=%x",
1553 		    offset, control, status));
1554 
1555 		control = control | HPC3130_SLTPWRCTL;
1556 		if (hpc3130_write(handle, HPC3130_CONTROL, offset,
1557 		    control) != DDI_SUCCESS) {
1558 			goto out;
1559 		}
1560 
1561 	} else {
1562 
1563 		D1CMN_ERR((CE_NOTE, "PCI connect %d", offset));
1564 
1565 		/*
1566 		 * PCI needs special sequencing of the control signals.
1567 		 */
1568 
1569 		if (hpc3130_read(handle, HPC3130_GCR, offset,
1570 			&config)) {
1571 			goto out;
1572 		}
1573 
1574 		/* Assert RST to comply with PCI spec. */
1575 		control &= ~HPC3130_SLOTRST;
1576 		if (hpc3130_write(handle, HPC3130_CONTROL, offset,
1577 		    control) != DDI_SUCCESS) {
1578 			goto out;
1579 		}
1580 		drv_usecwait(HPC3130_ADEQUATE_PAUSE);
1581 
1582 		/* Send the power on signal and verify the result */
1583 		control = control | HPC3130_SLTPWRCTL;
1584 		if ((hpc3130_write(handle, HPC3130_CONTROL, offset,
1585 		    control) != DDI_SUCCESS) ||
1586 		    (hpc3130_verify_slot_power(hpc3130_p, handle, offset,
1587 		    phys_slot, B_TRUE) == HPC_ERR_FAILED)) {
1588 			goto out;
1589 		}
1590 
1591 		/* The slot is now powered on. */
1592 
1593 		drv_usecwait(HPC3130_ADEQUATE_PAUSE);
1594 
1595 		/* Extinguish the "OK-to-remove" indicator */
1596 		(void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_OK2REM,
1597 		    HPC3130_ATTN_OFF);
1598 
1599 		/*
1600 		 * Perform bus/card speed check functions.
1601 		 */
1602 		if (hpc3130_read(handle, HPC3130_STATUS, offset, &status)) {
1603 			goto out;
1604 		}
1605 		if ((config & HPC3130_SYSM66STAT) &&
1606 		    !(status & HPC3130_M66EN)) {
1607 			cmn_err(CE_WARN, "66Mhz bus can't accept "
1608 			    "33Mhz card in %s", phys_slot);
1609 			needs_to_be_powered_off = B_TRUE;
1610 			goto out;
1611 		}
1612 		if (!(config & HPC3130_SYSM66STAT) &&
1613 		    (status & HPC3130_M66EN)) {
1614 			cmn_err(CE_NOTE, "66Mhz capable card throttled "
1615 			    "back to 33Mhz in %s", phys_slot);
1616 		}
1617 
1618 		/*
1619 		 * Send the connect sequence (see struct connect_sequence)
1620 		 */
1621 		for (i = 0; i < HPC3130_CONNECT_SEQ_COUNT; i++) {
1622 			if (connect_sequence[i].set_bit == B_TRUE) {
1623 				control |= connect_sequence[i].value;
1624 			} else {
1625 				control &= ~connect_sequence[i].value;
1626 			}
1627 			if (hpc3130_write(handle, HPC3130_CONTROL, offset,
1628 			    control) != DDI_SUCCESS) {
1629 				goto out;
1630 			}
1631 			drv_usecwait(HPC3130_ADEQUATE_PAUSE);
1632 		}
1633 	}
1634 
1635 	hpc_slot_event_notify(ste->hpc3130_slot_handle,
1636 		HPC_EVENT_SLOT_POWER_ON, 0);
1637 
1638 	/* Flash the "fault" indicator */
1639 	(void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_FAULT,
1640 		HPC3130_ATTN_SLO);
1641 
1642 	result = HPC_SUCCESS;
1643 
1644 out:
1645 	if (needs_to_be_powered_off == B_TRUE) {
1646 		/*
1647 		 * We are in an error state where the slot is powered on, and
1648 		 * it must be powered off.
1649 		 */
1650 
1651 		/* Send the power off signal and verify the result */
1652 		control = control & ~HPC3130_SLTPWRCTL;
1653 		if ((hpc3130_write(handle, HPC3130_CONTROL, offset,
1654 		    control) == DDI_SUCCESS) &&
1655 		    (hpc3130_verify_slot_power(hpc3130_p, handle, offset,
1656 		    phys_slot, B_FALSE) == HPC_SUCCESS)) {
1657 			/* Re-light "OK-to-remove" LED */
1658 			(void) hpc3130_set_led(hpc3130_p, offset,
1659 			    HPC3130_LED_OK2REM, HPC3130_ATTN_ON);
1660 		}
1661 	}
1662 
1663 	mutex_exit(&hpc3130_p->hpc3130_mutex);
1664 
1665 	return (result);
1666 }
1667 
1668 
1669 static int
1670 hpc3130_slot_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl,
1671 	void *data, uint_t flags)
1672 {
1673 	_NOTE(ARGUNUSED(slot_hdl, data, flags))
1674 	uint8_t			control;
1675 	uint8_t			offset;
1676 	i2c_client_hdl_t	handle;
1677 	hpc3130_unit_t		*hpc3130_p;
1678 	int			result = HPC_ERR_FAILED;
1679 	hpc3130_slot_type_t	slot_type;
1680 	hpc3130_slot_table_entry_t *ste;
1681 	char			phys_slot[MAXPATHLEN];
1682 
1683 	hpc3130_callback_arg_t	*info_p = (hpc3130_callback_arg_t *)ops_arg;
1684 
1685 	/*
1686 	 * Callback parameter has specific device handle and offset
1687 	 * information in it.
1688 	 */
1689 	hpc3130_p = (hpc3130_unit_t *)info_p->statep;
1690 	ASSERT(hpc3130_p);
1691 
1692 	mutex_enter(&hpc3130_p->hpc3130_mutex);
1693 
1694 	handle = (i2c_client_hdl_t)info_p->handle;
1695 	offset = info_p->offset;
1696 
1697 	ASSERT(handle == hpc3130_p->hpc3130_hdl);
1698 
1699 	ste = &hpc3130_p->hpc3130_slot_table[offset];
1700 
1701 	if (hpc3130_p->slots_are == HPC3130_SLOT_TYPE_SBD) {
1702 		DAK_GET_SBD_APID(phys_slot, MAXPATHLEN, offset);
1703 	} else {
1704 		DAK_GET_PCI_APID(phys_slot, MAXPATHLEN,
1705 			hpc3130_lookup_slot(ste->nexus,
1706 			ste->hpc3130_slot_info.pci_dev_num));
1707 	}
1708 
1709 	ASSERT(ste->hpc3130_slot_handle != NULL);
1710 
1711 	slot_type = hpc3130_p->slots_are;
1712 
1713 	/*
1714 	 * Read the slot control register to get current value
1715 	 */
1716 	if (hpc3130_read(handle, HPC3130_CONTROL, offset,
1717 		&control)) {
1718 		goto out;
1719 	}
1720 
1721 	if (slot_type == HPC3130_SLOT_TYPE_SBD) {
1722 
1723 		D1CMN_ERR((CE_NOTE, "CPU disconnect %d", offset));
1724 
1725 		control = control & ~HPC3130_SLTPWRCTL;
1726 		/*
1727 		 * Write out the modified control register
1728 		 */
1729 		if (hpc3130_write(handle, HPC3130_CONTROL, offset,
1730 			control) != DDI_SUCCESS) {
1731 			goto out;
1732 		}
1733 	} else {
1734 
1735 		D1CMN_ERR((CE_NOTE, "PCI disconnect %d", offset));
1736 
1737 		control &= ~HPC3130_SLOTRST;
1738 		if (hpc3130_write(handle, HPC3130_CONTROL, offset,
1739 			control) != DDI_SUCCESS) {
1740 			goto out;
1741 		}
1742 
1743 		control |= HPC3130_BUS_CTL;
1744 		if (hpc3130_write(handle, HPC3130_CONTROL, offset,
1745 			control) != DDI_SUCCESS) {
1746 			goto out;
1747 		}
1748 	}
1749 
1750 	D1CMN_ERR((CE_WARN, "disconnect present[%d]==%d",
1751 	    offset, hpc3130_p->present[offset]));
1752 
1753 	if (hpc3130_verify_slot_power(hpc3130_p, handle, offset,
1754 	    phys_slot, B_FALSE) == HPC_ERR_FAILED) {
1755 		goto out;
1756 	}
1757 
1758 	hpc_slot_event_notify(ste->hpc3130_slot_handle,
1759 		HPC_EVENT_SLOT_POWER_OFF, 0);
1760 
1761 	if (hpc3130_p->present[offset] == B_TRUE) {
1762 		/*
1763 		 * Illuminate the "OK-to-remove" indicator
1764 		 * if there is a card in the slot.
1765 		 */
1766 
1767 		(void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_OK2REM,
1768 			HPC3130_ATTN_ON);
1769 
1770 		/*
1771 		 * Turn off the "fault" indicator
1772 		 */
1773 		(void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_FAULT,
1774 			HPC3130_ATTN_OFF);
1775 	} else {
1776 		/*
1777 		 * If the slot is being powered off with
1778 		 * no cards in there, its at "boot time",
1779 		 * put the LEDs in a sane state
1780 		 */
1781 		if (slot_type == HPC3130_SLOT_TYPE_PCI) {
1782 			(void) hpc3130_set_led(hpc3130_p, offset,
1783 				HPC3130_LED_FAULT, HPC3130_ATTN_OFF);
1784 			(void) hpc3130_set_led(hpc3130_p, offset,
1785 				HPC3130_LED_OK2REM, HPC3130_ATTN_OFF);
1786 		}
1787 	}
1788 
1789 	result = HPC_SUCCESS;
1790 out:
1791 	mutex_exit(&hpc3130_p->hpc3130_mutex);
1792 
1793 	return (result);
1794 }
1795 
1796 static int
1797 hpc3130_verify_slot_power(hpc3130_unit_t *hpc3130_p, i2c_client_hdl_t handle,
1798 	uint8_t offset, char *phys_slot, boolean_t slot_target_state)
1799 {
1800 	uint8_t			tries = 0;
1801 	uint8_t			status;
1802 	int			result = HPC_SUCCESS;
1803 	clock_t			tm, timeleft;
1804 	boolean_t		slot_actual_state;
1805 	boolean_t		failure = B_FALSE;
1806 	hpc3130_slot_table_entry_t *ste;
1807 
1808 	/* This function is called while holding the hpc3130 mutex. */
1809 
1810 	/*
1811 	 * For slot_target_state and slot_actual_state:
1812 	 *    B_TRUE  == the slot is powered on
1813 	 *    B_FALSE == the slot is powered off
1814 	 */
1815 
1816 	ste = &hpc3130_p->hpc3130_slot_table[offset];
1817 	slot_actual_state = hpc3130_p->power[offset];
1818 
1819 	while ((slot_actual_state != slot_target_state) &&
1820 	    (failure != B_TRUE)) {
1821 		tm = ddi_get_lbolt();
1822 		tm += drv_usectohz(300000);
1823 		timeleft = cv_timedwait(&hpc3130_p->hpc3130_cond,
1824 		    &hpc3130_p->hpc3130_mutex, tm);
1825 		if (timeleft == -1) {
1826 			if (tries++ < HPC3130_POWER_TRIES) {
1827 				/*
1828 				 * The interrupt was missed - explicitly
1829 				 * check the status.
1830 				 */
1831 				if (hpc3130_read(handle,
1832 				    HPC3130_STATUS, offset, &status)) {
1833 					failure = B_TRUE;
1834 					continue;
1835 				}
1836 				if (status & HPC3130_PWRGOOD) {
1837 					slot_actual_state = B_FALSE;
1838 				} else {
1839 					slot_actual_state = B_TRUE;
1840 				}
1841 				hpc3130_p->power[offset] = slot_actual_state;
1842 			} else {
1843 				/* Too many tries.  We failed. */
1844 				failure = B_TRUE;
1845 			}
1846 		}
1847 	}
1848 
1849 	if (failure == B_TRUE) {
1850 		result = HPC_ERR_FAILED;
1851 		if (slot_target_state == B_TRUE) {
1852 			cmn_err(CE_WARN,
1853 			    "Could not power on slot %s", phys_slot);
1854 		} else {
1855 			cmn_err(CE_WARN,
1856 			    "Could not power off slot %s", phys_slot);
1857 		}
1858 		(void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_FAULT,
1859 		    HPC3130_ATTN_ON);
1860 		hpc_slot_event_notify(ste->hpc3130_slot_handle,
1861 		    HPC_EVENT_SLOT_NOT_HEALTHY, 0);
1862 	}
1863 
1864 	return (result);
1865 }
1866 
1867 static int
1868 hpc3130_slot_insert(caddr_t ops_arg, hpc_slot_t slot_hdl,
1869 		void *data, uint_t flags)
1870 {
1871 	_NOTE(ARGUNUSED(ops_arg, slot_hdl, data, flags))
1872 	return (HPC_ERR_NOTSUPPORTED);
1873 }
1874 
1875 static int
1876 hpc3130_slot_remove(caddr_t ops_arg, hpc_slot_t slot_hdl,
1877 		void *data, uint_t flags)
1878 {
1879 	_NOTE(ARGUNUSED(ops_arg, slot_hdl, data, flags))
1880 	return (HPC_ERR_NOTSUPPORTED);
1881 }
1882 
1883 static int
1884 hpc3130_slot_control(caddr_t ops_arg, hpc_slot_t slot_hdl,
1885 		int request, caddr_t arg)
1886 {
1887 	_NOTE(ARGUNUSED(slot_hdl))
1888 	i2c_client_hdl_t	handle;
1889 	uint8_t			offset;
1890 	uint8_t			state;
1891 	hpc_led_info_t		*led_info;
1892 	hpc3130_unit_t		*hpc3130_p;
1893 	hpc3130_slot_type_t	slot_type;
1894 
1895 	hpc3130_callback_arg_t	*info_p = (hpc3130_callback_arg_t *)ops_arg;
1896 
1897 	/*
1898 	 * Callback parameter has specific device handle and offset
1899 	 * information in it.
1900 	 */
1901 
1902 	hpc3130_p = (hpc3130_unit_t *)info_p->statep;
1903 	ASSERT(hpc3130_p);
1904 
1905 	mutex_enter(&hpc3130_p->hpc3130_mutex);
1906 
1907 	handle = (i2c_client_hdl_t)info_p->handle;
1908 	offset = info_p->offset;
1909 
1910 	ASSERT(handle == hpc3130_p->hpc3130_hdl);
1911 
1912 	slot_type = hpc3130_p->slots_are;
1913 
1914 	switch (request) {
1915 		case HPC_CTRL_GET_LED_STATE: {
1916 			int led;
1917 
1918 			led_info = (hpc_led_info_t *)arg;
1919 			if (led_info->led != HPC_FAULT_LED &&
1920 				led_info->led != HPC_ATTN_LED) {
1921 				D1CMN_ERR((CE_WARN,
1922 				    "Only FAULT and ATTN leds allowed"));
1923 				mutex_exit(&hpc3130_p->hpc3130_mutex);
1924 				return (HPC_ERR_INVALID);
1925 			}
1926 
1927 			if (led_info->led == HPC_FAULT_LED)
1928 				led = HPC3130_LED_FAULT;
1929 			else
1930 				led = HPC3130_LED_OK2REM;
1931 
1932 			if (hpc3130_get_led(handle, offset, led, &state) !=
1933 			    DDI_SUCCESS) {
1934 				mutex_exit(&hpc3130_p->hpc3130_mutex);
1935 				return (HPC_ERR_FAILED);
1936 			}
1937 
1938 			/* Make sure that no one broke the conversion macros */
1939 			ASSERT(state < sizeof (hpc3130_to_hpc_led_map));
1940 			ASSERT(state ==
1941 			    HPC3130_FROM_HPC_LED(HPC3130_TO_HPC_LED(state)));
1942 
1943 			led_info->state = HPC3130_TO_HPC_LED(state);
1944 		}
1945 		break;
1946 		case HPC_CTRL_SET_LED_STATE: {
1947 			int led;
1948 
1949 			/*
1950 			 * The HPC3130 support modifications to the Fault and
1951 			 * Ok-to-remove LEDs.
1952 			 */
1953 			led_info = (hpc_led_info_t *)arg;
1954 			if (led_info->led != HPC_FAULT_LED &&
1955 				led_info->led != HPC_ATTN_LED) {
1956 				D1CMN_ERR((CE_WARN,
1957 				    "Only FAULT and ATTN leds allowed"));
1958 				mutex_exit(&hpc3130_p->hpc3130_mutex);
1959 				return (HPC_ERR_INVALID);
1960 			}
1961 
1962 			if (led_info->led == HPC_FAULT_LED)
1963 				led = HPC3130_LED_FAULT;
1964 			else
1965 				led = HPC3130_LED_OK2REM;
1966 
1967 			state = led_info->state;
1968 			if (state >= sizeof (hpc3130_from_hpc_led_map) ||
1969 			    (state != HPC3130_TO_HPC_LED(
1970 				    HPC3130_FROM_HPC_LED(state)))) {
1971 				D1CMN_ERR((CE_WARN,
1972 				    "Improper LED value: %d %d", state,
1973 				    HPC3130_TO_HPC_LED(
1974 				    HPC3130_FROM_HPC_LED(state))));
1975 				mutex_exit(&hpc3130_p->hpc3130_mutex);
1976 				return (HPC_ERR_INVALID);
1977 			}
1978 
1979 			(void) hpc3130_set_led(hpc3130_p, offset, led,
1980 				HPC3130_FROM_HPC_LED(state));
1981 		}
1982 		break;
1983 		case HPC_CTRL_GET_SLOT_STATE: {
1984 			if (hpc3130_p->power[offset] == B_FALSE) {
1985 				if (hpc3130_p->present[offset] == B_FALSE) {
1986 					*(ap_rstate_t *)arg =
1987 						AP_RSTATE_EMPTY;
1988 				} else {
1989 					*(ap_rstate_t *)arg =
1990 						AP_RSTATE_DISCONNECTED;
1991 				}
1992 			} else {
1993 				*(ap_rstate_t *)arg =
1994 					AP_RSTATE_CONNECTED;
1995 			}
1996 		}
1997 		break;
1998 		case HPC_CTRL_GET_BOARD_TYPE: {
1999 			*(hpc_board_type_t *)arg =
2000 				(slot_type == HPC3130_SLOT_TYPE_SBD ?
2001 				HPC_BOARD_UNKNOWN : HPC_BOARD_PCI_HOTPLUG);
2002 		}
2003 		break;
2004 		case HPC_CTRL_DEV_CONFIG_START:
2005 		case HPC_CTRL_DEV_UNCONFIG_START:
2006 			hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_FAULT,
2007 				HPC3130_ATTN_SLO);
2008 		break;
2009 		case HPC_CTRL_DEV_CONFIG_FAILURE:
2010 			hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_FAULT,
2011 				HPC3130_ATTN_ON);
2012 		break;
2013 		case HPC_CTRL_DEV_CONFIGURED:
2014 			hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_FAULT,
2015 				HPC3130_ATTN_OFF);
2016 			hpc3130_p->present[offset] = B_TRUE;
2017 		break;
2018 		case HPC_CTRL_DEV_UNCONFIGURED:
2019 			if (hpc3130_p->power[offset] == B_TRUE) {
2020 				hpc3130_set_led(hpc3130_p, offset,
2021 					HPC3130_LED_FAULT, HPC3130_ATTN_SLO);
2022 			} else {
2023 				hpc3130_set_led(hpc3130_p, offset,
2024 					HPC3130_LED_FAULT, HPC3130_ATTN_OFF);
2025 			}
2026 		break;
2027 		case HPC_CTRL_DISABLE_SLOT: {
2028 			hpc3130_p->enabled[offset] = B_FALSE;
2029 		}
2030 		break;
2031 		case HPC_CTRL_ENABLE_SLOT: {
2032 			hpc3130_p->enabled[offset] = B_TRUE;
2033 		}
2034 		break;
2035 		default:
2036 			mutex_exit(&hpc3130_p->hpc3130_mutex);
2037 			return (HPC_ERR_FAILED);
2038 	}
2039 	mutex_exit(&hpc3130_p->hpc3130_mutex);
2040 	return (HPC_SUCCESS);
2041 }
2042 
2043 int
2044 hpc3130_lookup_slot(char *nexus, int pcidev)
2045 {
2046 	int	i = 0;
2047 
2048 	while ((slot_translate[i].pcidev != pcidev ||
2049 		strcmp(nexus, slot_translate[i].nexus) != 0) &&
2050 			i < HPC3130_LOOKUP_SLOTS) i++;
2051 	ASSERT(i != HPC3130_LOOKUP_SLOTS);
2052 	return (i);
2053 }
2054 
2055 /*
2056  * A routine to convert a number (represented as a string) to
2057  * the integer value it represents.
2058  */
2059 
2060 static int
2061 isdigit(int ch)
2062 {
2063 	return (ch >= '0' && ch <= '9');
2064 }
2065 
2066 #define	isspace(c)	((c) == ' ' || (c) == '\t' || (c) == '\n')
2067 #define	bad(val)	(val == NULL || !isdigit(*val))
2068 
2069 static int
2070 hpc3130_atoi(const char *p)
2071 {
2072 	int n;
2073 	int c, neg = 0;
2074 
2075 	if (!isdigit(c = *p)) {
2076 		while (isspace(c))
2077 			c = *++p;
2078 		switch (c) {
2079 		case '-':
2080 			neg++;
2081 			/* FALLTHROUGH */
2082 		case '+':
2083 			c = *++p;
2084 		}
2085 		if (!isdigit(c))
2086 			return (0);
2087 	}
2088 	for (n = '0' - c; isdigit(c = *++p); ) {
2089 		n *= 10; /* two steps to avoid unnecessary overflow */
2090 		n += '0' - c; /* accum neg to avoid surprises at MAX */
2091 	}
2092 	return (neg ? n : -n);
2093 }
2094