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