xref: /titanic_44/usr/src/uts/sun4u/montecarlo/io/hsc.c (revision 2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1f)
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 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * MonteCarlo HotSwap Controller functionality
31  */
32 
33 #include	<sys/types.h>
34 #include	<sys/stropts.h>
35 #include	<sys/stream.h>
36 #include	<sys/strsun.h>
37 #include	<sys/kmem.h>
38 #include	<sys/cmn_err.h>
39 #include	<sys/errno.h>
40 #include	<sys/cpuvar.h>
41 #include	<sys/open.h>
42 #include	<sys/stat.h>
43 #include	<sys/conf.h>
44 #include	<sys/ddi.h>
45 #include	<sys/sunddi.h>
46 #include	<sys/modctl.h>
47 #include	<sys/promif.h>
48 #include	<sys/hotplug/hpcsvc.h>
49 
50 #include	<sys/hscimpl.h>
51 #include	<sys/hsc.h>
52 
53 #include	<sys/mct_topology.h>
54 #include	<sys/scsbioctl.h>
55 #include	<sys/scsb.h>
56 
57 #define	HOTSWAP_MODE_PROP	"hotswap-mode"
58 #define	ALARM_CARD_ON_SLOT	1
59 #define	SCSB_HSC_FORCE_REMOVE	1	/* force remove enum intr handler */
60 
61 /* TUNABLE PARAMETERS. Some are Debug Only. Please take care when using. */
62 
63 /*
64  * Set this flag to 1, to enable full hotswap mode at boot time.
65  * Since HPS is threaded, it is not recommended that we set this flag
66  * to 1 because enabling full hotswap interrupt can invoke the ENUM
67  * event handler accessing the slot data structure which may have not
68  * been initialized in the hotplug framework since the HPS may not yet
69  * have called the slot registration function with the bus nexus.
70  */
71 static int	scsb_hsc_enable_fhs = 0;
72 
73 /*
74  * Every time  a slot is registered with the hotswap framework, the
75  * framework calls back. This variable keeps a count on how many
76  * callbacks are done.
77  */
78 static int scsb_hsc_numReg = 0;
79 /*
80  * When this flag is set, the board is taken offline (put in reset) after
81  * a unconfigure operation, in Basic Hotswap mode.
82  */
83 static int	scsb_hsc_bhs_slot_reset = 1;
84 /*
85  * When this flag is set, we take the board to reset after unconfigure
86  * operation when operating in full hotswap mode.
87  */
88 static int	scsb_hsc_fhs_slot_reset = 1;
89 /*
90  * Implementation of this counter will work only on Montecarlo since
91  * the ENUM# Interrupt line is not shared with other interrupts.
92  * When the hardware routing changes, then there may be need to remove
93  * or change this functionality.
94  * This functionality is provided so that a bad or non friendly full hotswap
95  * board does not hang the system in full hotswap mode. Atleast the
96  * intent is that! Eventually Solaris kernel will provide similar support
97  * for recovering from a stuck interrupt line. Till then, lets do this.
98  */
99 static int	scsb_hsc_max_intr_count = 8;
100 /*
101  * Since the hardware does not support enabling/disabling ENUM#, the
102  * following flag can be used for imitating that behaviour.
103  * Currently we can set this flag and use the remove op to remove the
104  * interrupt handler from the system. Care must be taken when using this
105  * function since trying to remove the interrupt handler when the interrupts
106  * are pending may hang the system permanently.
107  * Since the hardware does not support this functionality, we adopt this
108  * approach for debugs.
109  */
110 static int	scsb_hsc_enum_switch = 0;
111 
112 /*
113  * When the board loses Healthy# at runtime (with the board being configured),
114  * cPCI specs states that a Reset has to be asserted immediately.
115  * We dont do this currently, until satellite processor support is given
116  * and the implications of such a act is fully understood.
117  * To adopt the cPCI specs recommendation, set this flag to 1.
118  */
119 static	int	scsb_hsc_healthy_reset = 0;
120 
121 /*
122  * According to PCI 2.2 specification, once a board comes out of PCI_RST#,
123  * it may take upto 2^25 clock cycles to respond to config cycles. For
124  * montecarlo using a 33MHz cPCI bus, it's around 1.024 s. The variable
125  * will specify the time in ms to wait before attempting config access.
126  */
127 static	int scsb_connect_delay = 1025;
128 
129 /*
130  * slot map property for MC should be
131  *
132  *	hsc-slot-map="/pci@1f,0/pci@1/pci@1","15","2",
133  *               "/pci@1f,0/pci@1/pci@1","14","3",
134  *               "/pci@1f,0/pci@1/pci@1","13","4",
135  *               "/pci@1f,0/pci@1/pci@1","12","5"
136  *               "/pci@1f,0/pci@1/pci@1","11","6"
137  *               "/pci@1f,0/pci@1/pci@1","10","7"
138  *               "/pci@1f,0/pci@1/pci@1","8","8";
139  *
140  * slot map property for Tonga should be
141  *	hsc-slot-map="/pci@1f,0/pci@1/pci@1","8","1"
142  *		"/pci@1f,0/pci@1/pci@1", "15", "2"
143  *		"/pci@1f,0/pci@1/pci@1", "14", "4"
144  *		"/pci@1f,0/pci@1/pci@1", "13", "5"
145  *
146  * Please note that the CPU slot number is 3 for Tonga.
147  */
148 
149 /*
150  * Services we require from the SCSB
151  */
152 extern int	scsb_get_slot_state(void *, int, int *);
153 extern int	scsb_read_bhealthy(scsb_state_t *scsb);
154 extern int	scsb_read_slot_health(scsb_state_t *scsb, int pslotnum);
155 extern int	scsb_connect_slot(void *, int, int);
156 extern int	scsb_disconnect_slot(void *, int, int);
157 
158 static void	*hsc_state;
159 
160 static uint_t	hsc_enum_intr(char *);
161 static hsc_slot_t *hsc_get_slot_info(hsc_state_t *, int);
162 static int	scsb_enable_enum(hsc_state_t *);
163 static int	scsb_disable_enum(hsc_state_t *, int);
164 static int	atoi(const char *);
165 static int	isdigit(int);
166 static hsc_slot_t *hsc_find_slot(int);
167 static void	hsc_led_op(hsc_slot_t *, int, hpc_led_t, hpc_led_state_t);
168 static int	hsc_led_state(hsc_slot_t *, int, hpc_led_info_t *);
169 static int	scsb_hsc_disable_slot(hsc_slot_t *);
170 static int	scsb_hsc_enable_slot(hsc_slot_t *);
171 #ifndef	lint
172 static int hsc_clear_all_enum(hsc_state_t *);
173 #endif
174 static int	hsc_slot_register(hsc_state_t *, char *, uint16_t, uint_t,
175 					boolean_t);
176 static int	hsc_slot_unregister(int);
177 static int	scsb_hsc_init_slot_state(hsc_state_t *, hsc_slot_t *);
178 static int	hsc_slot_autoconnect(hsc_slot_t *);
179 
180 static hpc_slot_ops_t	*hsc_slotops;
181 static hsc_slot_t	*hsc_slot_list;		/* linked list of slots */
182 
183 /*
184  * This mutex protects the following variables:
185  *	hsc_slot_list
186  */
187 static kmutex_t		hsc_mutex;
188 
189 
190 /* ARGSUSED */
191 static int
192 hsc_connect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags)
193 {
194 	hsc_slot_t *hsp = (hsc_slot_t *)ops_arg;
195 	int rc, rstate;
196 	hsc_state_t	*hsc;
197 
198 	DEBUG2("hsc_connect: slot %d, healthy %d", hsp->hs_slot_number,
199 						hsp->hs_board_healthy);
200 
201 	if (!(hsp->hs_flags & (HSC_ENABLED|HSC_SLOT_ENABLED)))
202 		return (HPC_ERR_FAILED);
203 	/* if SCB hotswapped, do not allow connect operations */
204 	if (hsp->hs_flags & HSC_SCB_HOTSWAPPED)
205 		return (HPC_ERR_FAILED);
206 	/*
207 	 * if previous occupant stayed configured, do not allow another
208 	 * occupant to be connected.
209 	 * This behaviour is an indication that the slot state
210 	 * is not clean.
211 	 */
212 	if (hsp->hs_flags & HSC_SLOT_BAD_STATE) {
213 		/*
214 		 * In the current implementation, we turn both fault
215 		 * and active LEDs to ON state in this situation.
216 		 */
217 		hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
218 							HPC_LED_ON);
219 		return (HPC_ERR_FAILED);
220 	}
221 	/*
222 	 * Get the actual status from the i2c bus
223 	 */
224 	rc = scsb_get_slot_state(hsp->hs_hpchandle, hsp->hs_slot_number,
225 								&rstate);
226 	if (rc != DDI_SUCCESS)
227 		return (HPC_ERR_FAILED);
228 
229 	hsp->hs_slot_state = rstate;
230 	if (hsp->hs_slot_state == HPC_SLOT_EMPTY) {
231 #ifdef DEBUG
232 		cmn_err(CE_CONT,
233 			"?hsc_connect: slot %d is empty\n",
234 			hsp->hs_slot_number);
235 #endif
236 		return (HPC_ERR_FAILED);
237 	}
238 
239 	if (hsp->hs_slot_state == HPC_SLOT_CONNECTED)
240 		return (HPC_SUCCESS);
241 
242 	rc = HPC_SUCCESS;
243 	/*
244 	 * call scsb to connect the slot. This also makes sure board is healthy
245 	 */
246 	if (scsb_connect_slot(hsp->hs_hpchandle, hsp->hs_slot_number,
247 				hsp->hs_board_healthy) != DDI_SUCCESS) {
248 		DEBUG1("hsc_connect: slot %d connection failed",
249 				hsp->hs_slot_number);
250 		rc = HPC_ERR_FAILED;
251 	} else {
252 		if (hsp->hs_slot_state != HPC_SLOT_CONNECTED) {
253 			if (hsp->hs_board_healthy == B_FALSE) {
254 				cmn_err(CE_NOTE, "HEALTHY# not asserted on "
255 					" slot %d", hsp->hs_slot_number);
256 				return (HPC_ERR_FAILED);
257 			}
258 			hsc = hsp->hsc;
259 			hsc->hsp_last = hsp;
260 			if (scsb_reset_slot(hsp->hs_hpchandle,
261 				hsp->hs_slot_number, SCSB_UNRESET_SLOT) != 0) {
262 
263 				return (HPC_ERR_FAILED);
264 			}
265 			/*
266 			 * Unresetting a board may have caused an interrupt
267 			 * burst in case of non friendly boards. So it is
268 			 * important to make sure that the ISR has not
269 			 * put this board back to disconnect state.
270 			 */
271 			delay(1);
272 			if (hsp->hs_flags & HSC_ENUM_FAILED) {
273 				hsp->hs_flags &= ~HSC_ENUM_FAILED;
274 				return (HPC_ERR_FAILED);
275 			}
276 			DEBUG1("hsc_connect: slot %d connected",
277 						hsp->hs_slot_number);
278 			rc = HPC_SUCCESS;
279 			hsp->hs_slot_state = HPC_SLOT_CONNECTED;
280 			(void) hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
281 				HPC_FAULT_LED, HPC_LED_OFF);
282 		}
283 	}
284 
285 	/*
286 	 * PCI 2.2 specs recommend that the probe software wait
287 	 * for upto 2^25 PCI clock cycles after deassertion of
288 	 * PCI_RST# before the board is able to respond to config
289 	 * cycles. So, before we return, we wait for ~1 sec.
290 	 */
291 	delay(drv_usectohz(scsb_connect_delay * 1000));
292 	return (rc);
293 }
294 
295 
296 /* ARGSUSED */
297 static int
298 hsc_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags)
299 {
300 	hsc_slot_t		*hsp = (hsc_slot_t *)ops_arg;
301 	hsc_state_t		*hsc;
302 #ifdef	DEBUG
303 	static const char	func[] = "hsc_disconnect";
304 #endif
305 
306 	DEBUG1("hsc_disconnect: slot %d", hsp->hs_slot_number);
307 
308 	if (hsp->hs_board_configured) {
309 #ifdef	DEBUG
310 		cmn_err(CE_NOTE,
311 			"%s: cannot disconnect configured board in slot %d",
312 			func, hsp->hs_slot_number);
313 #endif
314 		return (HPC_ERR_FAILED);
315 	}
316 
317 	if (hsp->hs_slot_state == HPC_SLOT_EMPTY) {
318 #ifdef	DEBUG
319 		cmn_err(CE_NOTE, "%s: slot %d is empty",
320 			func, hsp->hs_slot_number);
321 #endif
322 		return (HPC_SUCCESS);
323 	}
324 
325 	if (hsp->hs_slot_state == HPC_SLOT_DISCONNECTED) {
326 		/*
327 		 * if already disconnected, just return success
328 		 * Duplicate disconnect messages should not be failed!
329 		 */
330 		return (HPC_SUCCESS);
331 	}
332 	/* if SCB hotswapped, do not allow disconnect operations */
333 	if (hsp->hs_flags & HSC_SCB_HOTSWAPPED)
334 		return (HPC_ERR_FAILED);
335 
336 	/* call scsb to disconnect the slot */
337 	if (scsb_disconnect_slot(hsp->hs_hpchandle, B_TRUE, hsp->hs_slot_number)
338 			!= DDI_SUCCESS)
339 		return (HPC_ERR_FAILED);
340 	hsc = hsp->hsc;
341 	if (hsc->hsp_last == hsp)
342 		hsc->hsp_last = NULL;
343 
344 	return (HPC_SUCCESS);
345 }
346 
347 
348 /*
349  * In the cPCI world, this operation is not applicable.
350  * However, we use this function to enable full hotswap mode in debug mode.
351  */
352 /* ARGSUSED */
353 static int
354 hsc_insert(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags)
355 {
356 	hsc_slot_t		*hsp = (hsc_slot_t *)ops_arg;
357 
358 	if (scsb_hsc_enum_switch &&
359 			(scsb_enable_enum(hsp->hsc) == DDI_SUCCESS)) {
360 		return (HPC_SUCCESS);
361 	}
362 	return (HPC_ERR_NOTSUPPORTED);
363 }
364 
365 
366 /*
367  * In the cPCI world, this operation is not applicable.
368  * However, we use this function to disable full hotswap mode in debug mode.
369  */
370 /* ARGSUSED */
371 static int
372 hsc_remove(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags)
373 {
374 	hsc_slot_t		*hsp = (hsc_slot_t *)ops_arg;
375 
376 	if (scsb_hsc_enum_switch &&
377 			(scsb_disable_enum(hsp->hsc, SCSB_HSC_FORCE_REMOVE)
378 					== DDI_SUCCESS)) {
379 		hsp->hs_flags &= ~HSC_ENUM_FAILED;
380 		return (HPC_SUCCESS);
381 	}
382 	return (HPC_ERR_NOTSUPPORTED);
383 }
384 
385 static void
386 hsc_led_op(hsc_slot_t *hsp, int cmd, hpc_led_t led, hpc_led_state_t led_state)
387 {
388 	hpc_led_info_t	ledinfo;
389 
390 	ledinfo.led = led;
391 	ledinfo.state = led_state;
392 	(void) hsc_led_state(hsp, cmd, &ledinfo);
393 }
394 
395 static int
396 hsc_led_state(hsc_slot_t *hsp, int cmd, hpc_led_info_t *hlip)
397 {
398 	hpc_led_state_t	*hlsp;
399 	scsb_uinfo_t	sunit;
400 	int		res;
401 
402 	DEBUG3("hsc_led_state: slot %d, led %x, state %x",
403 		hsp->hs_slot_number, hlip->led, hlip->state);
404 
405 	sunit.unit_type = SLOT;
406 	sunit.unit_number = hsp->hs_slot_number;
407 	/*
408 	 * We ignore operations on LEDs that we don't support
409 	 */
410 	switch (hlip->led) {
411 		case HPC_FAULT_LED:
412 			sunit.led_type = NOK;
413 			hlsp = &hsp->hs_fault_led_state;
414 			break;
415 		case HPC_ACTIVE_LED:
416 			sunit.led_type = OK;
417 			hlsp = &hsp->hs_active_led_state;
418 			break;
419 		default:
420 			return (HPC_ERR_NOTSUPPORTED);
421 	}
422 
423 	switch (hlip->state) {
424 		case HPC_LED_BLINK:
425 			sunit.unit_state = BLINK;
426 			if (hlip->led != HPC_ACTIVE_LED)
427 				return (HPC_ERR_NOTSUPPORTED);
428 			break;
429 		case HPC_LED_ON:
430 			sunit.unit_state = ON;
431 			break;
432 		case HPC_LED_OFF:
433 			sunit.unit_state = OFF;
434 			break;
435 		default:
436 			break;
437 	}
438 
439 	switch (cmd) {
440 	case HPC_CTRL_SET_LED_STATE:
441 		res = scsb_led_set(hsp->hs_hpchandle, &sunit, sunit.led_type);
442 		if (res != 0)
443 			return (HPC_ERR_FAILED);
444 		*hlsp = (hpc_led_state_t)sunit.unit_state;
445 		break;
446 
447 	case HPC_CTRL_GET_LED_STATE:
448 		res = scsb_led_get(hsp->hs_hpchandle, &sunit, sunit.led_type);
449 		if (res)
450 			return (HPC_ERR_FAILED);
451 		/* hlip->state = sunit.unit_state; */
452 		break;
453 
454 	default:
455 		return (HPC_ERR_INVALID);
456 	}
457 
458 	return (HPC_SUCCESS);
459 
460 }
461 
462 
463 static int
464 hsc_get_slot_state(hsc_slot_t *hsp, hpc_slot_state_t *hssp)
465 {
466 	int rstate = 0;
467 	int rc;
468 #ifdef	DEBUG
469 	int orstate;	/* original rstate */
470 #endif
471 
472 	DEBUG1("hsc_get_slot_state: slot %d", hsp->hs_slot_number);
473 	rc = scsb_get_slot_state(hsp->hs_hpchandle, hsp->hs_slot_number,
474 								&rstate);
475 	if (rc != DDI_SUCCESS)
476 		return (HPC_ERR_FAILED);
477 #ifdef	DEBUG
478 	orstate = hsp->hs_slot_state;
479 #endif
480 	hsp->hs_slot_state = rstate;
481 	switch (hsp->hs_slot_state) {
482 	case HPC_SLOT_EMPTY:
483 		DEBUG0("empty");
484 		break;
485 	case HPC_SLOT_CONNECTED:
486 		DEBUG0("connected");
487 		break;
488 	case HPC_SLOT_DISCONNECTED:
489 		DEBUG0("disconnected");
490 		break;
491 	}
492 
493 	*hssp = hsp->hs_slot_state;
494 
495 	/* doing get-state above may have caused a freeze operation */
496 	if ((hsp->hs_flags & HSC_SCB_HOTSWAPPED) &&
497 			(rstate == HPC_SLOT_DISCONNECTED)) {
498 		/* freeze puts disconnected boards to connected state */
499 		*hssp = HPC_SLOT_CONNECTED;
500 #if 0
501 		/* in FHS, deassertion of reset may have configured the board */
502 		if (hsp->hs_board_configured == B_TRUE) {
503 			hsp->hs_slot_state = *hssp;
504 		}
505 #endif
506 	}
507 #ifdef	DEBUG
508 	/* a SCB hotswap may have forced a state change on the receptacle */
509 	if (orstate != *hssp) {
510 		cmn_err(CE_NOTE, "hsc_get_state: slot%d state change due"
511 			" to SCB hotswap!", hsp->hs_slot_number);
512 	}
513 #endif
514 	return (HPC_SUCCESS);
515 }
516 
517 
518 static int
519 hsc_set_config_state(hsc_slot_t *hsp, int cmd)
520 {
521 	hsc_state_t	*hsc = hsp->hsc;
522 
523 	DEBUG1("hsc_set_config_state: slot %d", hsp->hs_slot_number);
524 
525 	switch (cmd) {
526 	case HPC_CTRL_DEV_CONFIGURED:
527 		/*
528 		 * Closing of the Ejector switch in configured/busy state can
529 		 * cause duplicate CONFIGURED messages to come down.
530 		 * Make sure our LED states are fine.
531 		 */
532 		if (hsp->hs_board_configured == B_TRUE) {
533 			hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
534 								HPC_LED_ON);
535 			break;
536 		}
537 		hsp->hs_board_configured = B_TRUE;
538 		hsp->hs_board_configuring = B_FALSE;
539 		if ((hsc->state & HSC_ATTACHED) == HSC_ATTACHED &&
540 			hsp->hs_flags & HSC_ALARM_CARD_PRES)
541 			scsb_hsc_ac_op(hsp->hs_hpchandle,
542 				hsp->hs_slot_number, SCSB_HSC_AC_CONFIGURED);
543 		/* LED must be OFF on the occupant. */
544 		(void) hpc_slot_event_notify(hsp->hs_slot_handle,
545 					HPC_EVENT_SLOT_BLUE_LED_OFF, 0);
546 		if (hsp->hs_flags & HSC_AUTOCFG)
547 			(void) hpc_slot_event_notify(hsp->hs_slot_handle,
548 					HPC_EVENT_ENABLE_ENUM, 0);
549 		else
550 			(void) hpc_slot_event_notify(hsp->hs_slot_handle,
551 					HPC_EVENT_DISABLE_ENUM, 0);
552 		hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
553 								HPC_LED_ON);
554 		if (hsc->hsp_last == hsp)
555 			hsc->hsp_last = NULL;
556 		break;
557 	case HPC_CTRL_DEV_UNCONFIGURED:
558 		hsp->hs_board_configured = B_FALSE;
559 		hsp->hs_board_unconfiguring = B_FALSE;
560 		hsp->hs_flags &= ~HSC_SLOT_BAD_STATE;
561 		if (hsp->hs_flags & HSC_ALARM_CARD_PRES)
562 			scsb_hsc_ac_op(hsp->hs_hpchandle,
563 				hsp->hs_slot_number, SCSB_HSC_AC_UNCONFIGURED);
564 		hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
565 							HPC_LED_BLINK);
566 		if (((hsc->state & HSC_ENUM_ENABLED) &&
567 			scsb_hsc_fhs_slot_reset) ||
568 		(((hsc->state & HSC_ENUM_ENABLED) != HSC_ENUM_ENABLED) &&
569 				scsb_hsc_bhs_slot_reset) ||
570 				((hsp->hs_flags & HSC_AUTOCFG) !=
571 					HSC_AUTOCFG)) {
572 			if (scsb_reset_slot(hsp->hs_hpchandle,
573 				hsp->hs_slot_number, SCSB_RESET_SLOT) == 0) {
574 
575 				hsp->hs_slot_state = HPC_SLOT_DISCONNECTED;
576 				hsp->hs_board_healthy = B_FALSE;
577 				hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
578 					HPC_FAULT_LED, HPC_LED_ON);
579 			}
580 		}
581 		break;
582 	case HPC_CTRL_DEV_CONFIG_FAILURE:
583 		hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
584 							HPC_LED_BLINK);
585 		hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
586 				HPC_FAULT_LED, HPC_LED_ON);
587 		break;
588 	case HPC_CTRL_DEV_UNCONFIG_FAILURE:
589 		hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
590 							HPC_LED_ON);
591 		break;
592 	case HPC_CTRL_DEV_CONFIG_START:
593 	case HPC_CTRL_DEV_UNCONFIG_START:
594 			hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED,
595 					HPC_LED_OFF);
596 			hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
597 					HPC_LED_BLINK);
598 		break;
599 	default:
600 		return (HPC_ERR_INVALID);
601 	}
602 
603 	if (cmd != HPC_CTRL_DEV_CONFIG_START &&
604 		cmd != HPC_CTRL_DEV_UNCONFIG_START &&
605 		hsc->regDone == B_FALSE &&
606 			scsb_hsc_numReg < hsc->n_registered_occupants) {
607 		scsb_hsc_numReg++;
608 
609 		/*
610 		 * If the callback is invoked for all registered slots,
611 		 * enable ENUM.
612 		 */
613 		if (((hsc->state & HSC_ATTACHED) == HSC_ATTACHED) &&
614 			(scsb_hsc_numReg == hsc->n_registered_occupants)) {
615 			hsc->regDone = B_TRUE;
616 			if (hsc->hotswap_mode == HSC_HOTSWAP_MODE_FULL) {
617 #ifdef DEBUG
618 				cmn_err(CE_CONT, "%s%d: Enabling full hotswap"
619 					":%d non-empty slots\n",
620 					ddi_driver_name(hsc->dip),
621 					ddi_get_instance(hsc->dip),
622 					hsc->n_registered_occupants);
623 #endif
624 				if (scsb_enable_enum(hsc) != DDI_SUCCESS) {
625 					cmn_err(CE_WARN, "%s#%d: Cannot enable "
626 						"Full Hotswap",
627 						ddi_driver_name(hsc->dip),
628 						ddi_get_instance(hsc->dip));
629 
630 					return (HPC_ERR_FAILED);
631 				}
632 			}
633 		}
634 	}
635 
636 	return (HPC_SUCCESS);
637 }
638 
639 
640 /*ARGSUSED*/
641 static int
642 hsc_get_board_type(hsc_slot_t *hsp, hpc_board_type_t *hbtp)
643 {
644 	*hbtp = hsp->hs_board_type;
645 	return (HPC_SUCCESS);
646 }
647 
648 
649 /* ARGSUSED */
650 static int
651 hsc_autoconfig(hsc_slot_t *hsp, int cmd)
652 {
653 	int res = HPC_SUCCESS, enum_disable = B_TRUE, i;
654 	char slotautocfg_prop[18];
655 	hsc_state_t *hsc;
656 
657 	DEBUG1("hsc_autoconfig: slot %d", hsp->hs_slot_number);
658 	sprintf(slotautocfg_prop, "slot%d-autoconfig", hsp->hs_slot_number);
659 
660 	if (cmd == HPC_CTRL_ENABLE_AUTOCFG) {
661 		hsp->hs_flags |= HSC_AUTOCFG;
662 		ddi_prop_update_string(DDI_DEV_T_NONE, hsp->hsc->dip,
663 				slotautocfg_prop, "enabled");
664 		if ((res = scsb_enable_enum(hsp->hsc)) == DDI_SUCCESS) {
665 			(void) hpc_slot_event_notify(hsp->hs_slot_handle,
666 					HPC_EVENT_ENABLE_ENUM, 0);
667 		}
668 	} else {
669 		ddi_prop_update_string(DDI_DEV_T_NONE, hsp->hsc->dip,
670 				slotautocfg_prop, "disabled");
671 		hsp->hs_flags &= ~HSC_AUTOCFG;
672 		hsc = hsp->hsc;
673 		if (hsc->state & HSC_ATTACHED) {
674 			(void) hpc_slot_event_notify(hsp->hs_slot_handle,
675 						HPC_EVENT_DISABLE_ENUM, 0);
676 			for (i = 0; i < hsc->slot_table_size; i++) {
677 				hsc_slot_t	*thsp;
678 				int slotnum;
679 
680 				slotnum = hsc->slot_table_prop[i].pslotnum;
681 				thsp = hsc_find_slot(slotnum);
682 				if (thsp == NULL) {
683 					cmn_err(CE_WARN, "%s#%d: hsc_autocfg:"
684 						"No Slot Info for slot %d",
685 						ddi_driver_name(hsc->dip),
686 						ddi_get_instance(hsc->dip),
687 						slotnum);
688 					continue;
689 				}
690 				if (thsp->hs_flags & HSC_AUTOCFG) {
691 					enum_disable = B_FALSE;
692 					break;
693 				}
694 			}
695 			if (enum_disable == B_TRUE)
696 				scsb_disable_enum(hsc, SCSB_HSC_FORCE_REMOVE);
697 		}
698 	}
699 	return (res);
700 }
701 
702 
703 /*
704  * This function is invoked to enable/disable a slot
705  */
706 /* ARGSUSED */
707 #ifndef	lint
708 static int
709 hsc_slot_enable(hsc_slot_t *hsp, boolean_t enabled)
710 {
711 	scsb_uinfo_t	sunit;
712 	int		res;
713 
714 	DEBUG1("hsc_slot_enable: slot %d", hsp->hs_slot_number);
715 
716 	sunit.unit_type = SLOT;
717 	sunit.unit_number = hsp->hs_slot_number;
718 	if (enabled)
719 		sunit.unit_state = ON;
720 	else
721 		sunit.unit_state = OFF;
722 
723 	res = scsb_reset_unit(hsp->hs_hpchandle, &sunit);
724 	if (res == 0)
725 		return (HPC_SUCCESS);
726 	else if (res == EINVAL)
727 		return (HPC_ERR_INVALID);
728 	else
729 		return (HPC_ERR_FAILED);
730 }
731 #endif
732 
733 
734 /*ARGSUSED*/
735 static int
736 hsc_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request, caddr_t arg)
737 {
738 	hsc_slot_t *hsp = (hsc_slot_t *)ops_arg;
739 	int rc = HPC_SUCCESS;
740 
741 	DEBUG2("hsc_control: slot %d, op=%x\n", hsp->hs_slot_number, request);
742 
743 	switch (request) {
744 	case HPC_CTRL_GET_LED_STATE:
745 		return (hsc_led_state(hsp,
746 			HPC_CTRL_GET_LED_STATE, (hpc_led_info_t *)arg));
747 
748 	case HPC_CTRL_SET_LED_STATE:
749 		return (hsc_led_state(hsp,
750 			HPC_CTRL_SET_LED_STATE, (hpc_led_info_t *)arg));
751 
752 	case HPC_CTRL_GET_SLOT_STATE:
753 		return (hsc_get_slot_state(hsp, (hpc_slot_state_t *)arg));
754 
755 	case HPC_CTRL_DEV_CONFIGURED:
756 		return (hsc_set_config_state(hsp, HPC_CTRL_DEV_CONFIGURED));
757 
758 	case HPC_CTRL_DEV_UNCONFIGURED:
759 		return (hsc_set_config_state(hsp, HPC_CTRL_DEV_UNCONFIGURED));
760 
761 	case HPC_CTRL_DEV_CONFIG_FAILURE:
762 		return (hsc_set_config_state(hsp, HPC_CTRL_DEV_CONFIG_FAILURE));
763 
764 	case HPC_CTRL_DEV_UNCONFIG_FAILURE:
765 		return (hsc_set_config_state(hsp,
766 				HPC_CTRL_DEV_UNCONFIG_FAILURE));
767 
768 	case HPC_CTRL_DEV_CONFIG_START:
769 	case HPC_CTRL_DEV_UNCONFIG_START:
770 		return (hsc_set_config_state(hsp, request));
771 
772 	case HPC_CTRL_GET_BOARD_TYPE:
773 		return (hsc_get_board_type(hsp, (hpc_board_type_t *)arg));
774 
775 	case HPC_CTRL_DISABLE_AUTOCFG:
776 		return (hsc_autoconfig(hsp, HPC_CTRL_DISABLE_AUTOCFG));
777 
778 	case HPC_CTRL_ENABLE_AUTOCFG:
779 		return (hsc_autoconfig(hsp, HPC_CTRL_ENABLE_AUTOCFG));
780 
781 	case HPC_CTRL_DISABLE_SLOT:
782 		/*
783 		 * No hardware support for disabling the slot.
784 		 * Just imitate a disable_autoconfig operation for now
785 		 */
786 		if (hsp->hs_board_configured == B_TRUE)
787 			return (HPC_ERR_FAILED);
788 		if (scsb_hsc_disable_slot(hsp) != DDI_SUCCESS)
789 			rc = HPC_ERR_FAILED;
790 		return (rc);
791 
792 	case HPC_CTRL_ENABLE_SLOT:
793 		if (scsb_hsc_enable_slot(hsp) != DDI_SUCCESS)
794 			rc = HPC_ERR_FAILED;
795 		return (rc);
796 
797 	case HPC_CTRL_ENABLE_ENUM:
798 		return (scsb_enable_enum(hsp->hsc));
799 
800 	case HPC_CTRL_DISABLE_ENUM:
801 		return (scsb_disable_enum(hsp->hsc, 0));
802 
803 	default:
804 		return (HPC_ERR_INVALID);
805 	}
806 }
807 
808 static int
809 scsb_hsc_disable_slot(hsc_slot_t *hsp)
810 {
811 	int rc;
812 	char slot_disable_prop[18];
813 
814 	DEBUG1("hsc_disable_slot: slot %d", hsp->hs_slot_number);
815 	sprintf(slot_disable_prop, "slot%d-status", hsp->hs_slot_number);
816 
817 	rc = scsb_reset_slot(hsp->hs_hpchandle, hsp->hs_slot_number,
818 					SCSB_RESET_SLOT);
819 	if (rc == DDI_SUCCESS) {
820 		hsc_autoconfig(hsp, HPC_CTRL_DISABLE_AUTOCFG);
821 		hsp->hs_flags &= ~HSC_SLOT_ENABLED;
822 		ddi_prop_update_string(DDI_DEV_T_NONE, hsp->hsc->dip,
823 				slot_disable_prop, "disabled");
824 	} else
825 		rc = DDI_FAILURE;
826 	return (rc);
827 }
828 
829 static int
830 scsb_hsc_enable_slot(hsc_slot_t *hsp)
831 {
832 	int rc;
833 	char slot_disable_prop[18];
834 
835 	DEBUG1("hsc_disable_slot: slot %d", hsp->hs_slot_number);
836 	sprintf(slot_disable_prop, "slot%d-status", hsp->hs_slot_number);
837 
838 	rc = scsb_reset_slot(hsp->hs_hpchandle, hsp->hs_slot_number,
839 					SCSB_UNRESET_SLOT);
840 	if (rc == DDI_SUCCESS) {
841 		hsc_autoconfig(hsp, HPC_CTRL_ENABLE_AUTOCFG);
842 		hsp->hs_flags |= HSC_SLOT_ENABLED;
843 		ddi_prop_remove(DDI_DEV_T_NONE, hsp->hsc->dip,
844 						slot_disable_prop);
845 	} else
846 		rc = HPC_ERR_FAILED;
847 	return (rc);
848 }
849 
850 #define	NEW(type)	(type *) kmem_zalloc(sizeof (type), KM_SLEEP)
851 
852 static hsc_slot_t *
853 hsc_alloc_slot(
854 		uint16_t	device_number,
855 		int		slot_number,
856 		boolean_t	board_in_slot)
857 {
858 	hpc_slot_info_t	*hsip;
859 	hsc_slot_t	*hsp = NEW(hsc_slot_t);
860 
861 	DEBUG2("hsc_alloc_slot: slot %d %s", slot_number,
862 		board_in_slot ? "occupied" : "empty");
863 
864 	if (hsp == NULL) {
865 		cmn_err(CE_NOTE,
866 			"hsc_alloc_slot: allocation failed for slot %d",
867 			slot_number);
868 		return (NULL);
869 	}
870 
871 	hsip = &hsp->hs_info;
872 
873 	hsip->version			= HPC_SLOT_INFO_VERSION;
874 	hsip->slot_type			= HPC_SLOT_TYPE_CPCI;
875 	hsip->pci_dev_num		= device_number;
876 	hsip->pci_slot_capabilities	= 0;
877 	hsip->slot_flags		= HPC_SLOT_CREATE_DEVLINK;
878 	/*
879 	 * Note: the name *must* be 'pci' so that the correct cfgadm plug-in
880 	 *	 library is selected
881 	 */
882 	sprintf(hsip->pci_slot_name, "cpci_slot%d", slot_number);
883 
884 	/*
885 	 * We assume that the following LED settings reflect
886 	 * the hardware state.
887 	 * After we register the slot, we will be invoked by the nexus
888 	 * if the slot is occupied, and we will turn on the LED then.
889 	 */
890 	hsp->hs_active_led_state	= HPC_LED_OFF;
891 	hsp->hs_fault_led_state		= HPC_LED_OFF;
892 
893 	hsp->hs_board_configured	= B_FALSE;
894 	hsp->hs_board_healthy		= B_FALSE;
895 	hsp->hs_board_type		= HPC_BOARD_UNKNOWN;
896 
897 	hsp->hs_flags			= HSC_ENABLED | HSC_SLOT_ENABLED;
898 	hsp->hs_slot_number		= slot_number;
899 
900 	/*
901 	 * we should just set this to connected,
902 	 * as MC slots are always connected.
903 	 */
904 	if (board_in_slot)
905 		hsp->hs_slot_state = HPC_SLOT_CONNECTED;
906 	else
907 		hsp->hs_slot_state = HPC_SLOT_EMPTY;
908 
909 	return (hsp);
910 }
911 
912 
913 static void
914 hsc_free_slot(hsc_slot_t *hsp)
915 {
916 	DEBUG0("hsc_free_slot");
917 
918 	kmem_free(hsp, sizeof (*hsp));
919 }
920 
921 
922 /*
923  * This function is invoked to register a slot
924  */
925 static int
926 hsc_slot_register(
927 	hsc_state_t	*hsc,
928 	char		*bus_path,	/* PCI nexus pathname */
929 	uint16_t	device_number,	/* PCI device number */
930 	uint_t		slot_number,	/* physical slot number */
931 	boolean_t	board_in_slot)	/* receptacle status */
932 {
933 	int		rc = HPC_SUCCESS;
934 	hsc_slot_t	*hsp;
935 
936 	DEBUG2("hsc_slot_register: slot number %d, device number %d",
937 		slot_number, device_number);
938 
939 	hsp = hsc_alloc_slot(device_number, slot_number,
940 			board_in_slot);
941 
942 	if (hsp == NULL) {
943 #ifdef	DEBUG
944 		cmn_err(CE_NOTE, "hsc_slot_register: hsc_alloc_slot failed");
945 #endif
946 		return (HPC_ERR_FAILED);
947 	}
948 
949 	hsp->hs_hpchandle = hsc->scsb_handle; /* handle for call backs */
950 	hsp->hsc = hsc;
951 
952 	rc = scsb_hsc_init_slot_state(hsc, hsp);
953 	if (rc != DDI_SUCCESS)
954 		return (HPC_ERR_FAILED);
955 
956 	/* slot autoconfiguration by default. */
957 	if (hsc->hotswap_mode == HSC_HOTSWAP_MODE_FULL)
958 		(void) hsc_autoconfig(hsp, HPC_CTRL_ENABLE_AUTOCFG);
959 	else
960 		(void) hsc_autoconfig(hsp, HPC_CTRL_DISABLE_AUTOCFG);
961 
962 	/*
963 	 * Append to our list
964 	 */
965 	mutex_enter(&hsc_mutex);
966 	hsp->hs_next = hsc_slot_list;
967 	hsc_slot_list = hsp;
968 	mutex_exit(&hsc_mutex);
969 
970 	rc = hpc_slot_register(hsc->dip,
971 			bus_path,
972 			&hsp->hs_info,
973 			&hsp->hs_slot_handle,	/* return value */
974 			hsc_slotops,
975 			(caddr_t)hsp,
976 			0);
977 
978 	if (rc != HPC_SUCCESS) {
979 		cmn_err(CE_WARN, "%s#%d: failed to register slot %s:%d",
980 			ddi_driver_name(hsc->dip), ddi_get_instance(hsc->dip),
981 			bus_path, device_number);
982 		hsc_free_slot(hsp);
983 		return (rc);
984 	}
985 
986 	DEBUG0("hsc_slot_register: hpc_slot_register successful");
987 
988 	return (rc);
989 }
990 
991 
992 static int
993 hsc_slot_unregister(int slot_number)
994 {
995 	hsc_slot_t	*hsp, *prev;
996 
997 	DEBUG1("hsc_slot_unregister: slot number %d", slot_number);
998 
999 	mutex_enter(&hsc_mutex);
1000 	hsp = prev = NULL;
1001 	for (hsp = hsc_slot_list; hsp != NULL; hsp = hsp->hs_next) {
1002 		if (hsp->hs_slot_number == slot_number) {
1003 			if (prev == NULL) /* first entry */
1004 				hsc_slot_list = hsc_slot_list->hs_next;
1005 			else
1006 				prev->hs_next = hsp->hs_next;
1007 			hsp->hs_next = NULL;
1008 			break;
1009 		}
1010 		prev = hsp;
1011 	}
1012 	mutex_exit(&hsc_mutex);
1013 
1014 	if (hsp != NULL) {
1015 		hpc_slot_unregister(&hsp->hs_slot_handle);
1016 		if ((hsp->hsc->state & HSC_ATTACHED) != HSC_ATTACHED &&
1017 				hsp->hs_slot_state != HPC_SLOT_EMPTY) {
1018 			hsp->hsc->n_registered_occupants--;
1019 		}
1020 		hsc_free_slot(hsp);
1021 		return (0);
1022 	}
1023 	return (1);
1024 }
1025 
1026 static int
1027 scsb_hsc_init_slot_state(hsc_state_t *hsc, hsc_slot_t *hsp)
1028 {
1029 	int rc, rstate;
1030 	int slot_number = hsp->hs_slot_number;
1031 	scsb_state_t	*scsb = (scsb_state_t *)hsc->scsb_handle;
1032 
1033 	rc = scsb_get_slot_state(hsc->scsb_handle, slot_number, &rstate);
1034 	if (rc != DDI_SUCCESS)
1035 		return (DDI_FAILURE);
1036 
1037 	/*
1038 	 * Set the healthy status for this slot
1039 	 */
1040 	hsp->hs_board_healthy = scsb_read_slot_health(scsb, slot_number);
1041 	hsp->hs_slot_state = rstate;
1042 	switch (rstate) {
1043 		case HPC_SLOT_EMPTY:
1044 			/*
1045 			 * this will clear any state differences between
1046 			 * SCB Freeze operations.
1047 			 */
1048 			hsp->hs_slot_state = HPC_SLOT_EMPTY;
1049 			/* slot empty. */
1050 			scsb_reset_slot(hsc->scsb_handle, slot_number,
1051 					SCSB_RESET_SLOT);
1052 			hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
1053 								HPC_LED_OFF);
1054 			hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED,
1055 							HPC_LED_OFF);
1056 			break;
1057 		case HPC_SLOT_DISCONNECTED:
1058 			/*
1059 			 * this will clear any state differences between
1060 			 * SCB Freeze operations.
1061 			 */
1062 			hsp->hs_slot_state = HPC_SLOT_DISCONNECTED;
1063 			/* check recovery from SCB freeze */
1064 			if (hsp->hs_board_configured != B_TRUE) {
1065 				/*
1066 				 * Force a disconnect just in case there are
1067 				 * differences between healthy and reset states.
1068 				 */
1069 				scsb_reset_slot(hsc->scsb_handle, slot_number,
1070 					SCSB_RESET_SLOT);
1071 				/*
1072 				 * Slot in reset. OBP has not probed this
1073 				 * device. Hence it is ok to remove this board.
1074 				 */
1075 				hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
1076 						HPC_ACTIVE_LED, HPC_LED_BLINK);
1077 				hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
1078 						HPC_FAULT_LED, HPC_LED_ON);
1079 				break;
1080 			}
1081 			/*FALLTHROUGH*/
1082 		case HPC_SLOT_CONNECTED:
1083 			/*
1084 			 * this will clear any state differences between
1085 			 * SCB Freeze operations.
1086 			 */
1087 			hsp->hs_slot_state = HPC_SLOT_CONNECTED;
1088 			/*
1089 			 * OBP should have probed this device, unless
1090 			 * it was plugged in during the boot operation
1091 			 * before the driver was loaded. In any case,
1092 			 * no assumption is made and hence we take
1093 			 * the conservative approach by keeping fault
1094 			 * led off so board removal is not allowed.
1095 			 */
1096 			if (hsp->hs_board_configured == B_TRUE)
1097 				hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
1098 					HPC_ACTIVE_LED, HPC_LED_ON);
1099 			else
1100 				hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
1101 					HPC_ACTIVE_LED, HPC_LED_BLINK);
1102 			hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED,
1103 							HPC_LED_OFF);
1104 			/*
1105 			 * Netra ct alarm card hotswap support
1106 			 */
1107 			if (slot_number == scsb->ac_slotnum &&
1108 				scsb->scsb_hsc_state & SCSB_ALARM_CARD_PRES) {
1109 				hsp->hs_flags |= HSC_ALARM_CARD_PRES;
1110 				DEBUG0("Xscsb_hsc_init_slot_state: "
1111 						"set HSC_ALARM_CARD_PRES");
1112 			}
1113 			break;
1114 		default:
1115 			break;
1116 	}
1117 	return (rc);
1118 }
1119 
1120 static hsc_slot_t *
1121 hsc_get_slot_info(hsc_state_t *hsc, int pci_devno)
1122 {
1123 	int i;
1124 
1125 	for (i = 0; i < hsc->slot_table_size; i++) {
1126 
1127 		if (hsc->slot_table_prop[i].pci_devno == pci_devno)
1128 			return ((hsc_slot_t *)hsc_find_slot(
1129 				hsc->slot_table_prop[i].pslotnum));
1130 	}
1131 	return (NULL);
1132 }
1133 
1134 static hsc_slot_t *
1135 hsc_find_slot(int slot_number)
1136 {
1137 	hsc_slot_t	*hsp;
1138 
1139 	mutex_enter(&hsc_mutex);
1140 	for (hsp = hsc_slot_list; hsp != NULL; hsp = hsp->hs_next) {
1141 		if (hsp->hs_slot_number == slot_number)
1142 			break;
1143 	}
1144 	mutex_exit(&hsc_mutex);
1145 	return (hsp);
1146 }
1147 
1148 
1149 /*
1150  * This function is invoked by the SCSB when an interrupt
1151  * happens to indicate that a board has been inserted-in/removed-from
1152  * the specified slot.
1153  */
1154 int
1155 hsc_slot_occupancy(int slot_number, boolean_t occupied, int flags, int healthy)
1156 {
1157 	static const char	func[]	= "hsc_slot_occupancy";
1158 	hsc_slot_t		*hsp;
1159 	int			rc = DDI_SUCCESS;
1160 
1161 	DEBUG4("hsc_slot_occupancy: slot %d %s, ac=%d, healthy=%d",
1162 			slot_number, occupied ? "occupied" : "not occupied",
1163 			(flags == ALARM_CARD_ON_SLOT) ? 1:0, healthy);
1164 
1165 	hsp = hsc_find_slot(slot_number);
1166 
1167 	if (hsp == NULL) {
1168 		cmn_err(CE_NOTE,
1169 			"%s: cannot map slot number %d to a hsc_slot_t",
1170 			func, slot_number);
1171 		return (DDI_FAILURE);
1172 	}
1173 
1174 	hsp->hs_board_healthy = healthy;
1175 	if (occupied) {
1176 		/*
1177 		 * A board was just inserted. We are disconnected at this point.
1178 		 */
1179 		if (hsp->hs_slot_state == HPC_SLOT_EMPTY)
1180 			hsp->hs_board_type = HPC_BOARD_CPCI_HS;
1181 		hsp->hs_slot_state = HPC_SLOT_DISCONNECTED;
1182 		if (flags == ALARM_CARD_ON_SLOT) {
1183 			hsp->hs_flags |= HSC_ALARM_CARD_PRES;
1184 			DEBUG0("Xhsc_slot_occupancy: set HSC_ALARM_CARD_PRES");
1185 		}
1186 		hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED,
1187 						HPC_LED_ON);
1188 		/*
1189 		 * if previous occupant stayed configured, do not allow another
1190 		 * occupant to be connected.
1191 		 * So as soon as the board is plugged in, we turn both LEDs On.
1192 		 * This behaviour is an indication that the slot state
1193 		 * is not clean.
1194 		 */
1195 		if (hsp->hs_flags & HSC_SLOT_BAD_STATE) {
1196 			hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
1197 								HPC_LED_ON);
1198 			return (DDI_SUCCESS);
1199 		}
1200 
1201 		/* Do not allow connect if slot is disabled */
1202 		if ((hsp->hs_flags & HSC_SLOT_ENABLED) != HSC_SLOT_ENABLED)
1203 			return (DDI_SUCCESS);
1204 		/* if no healthy, we stay disconnected. */
1205 		if (healthy == B_FALSE) {
1206 			return (DDI_SUCCESS);
1207 		}
1208 		rc = hsc_slot_autoconnect(hsp);
1209 		hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
1210 								HPC_LED_BLINK);
1211 	} else {
1212 		/*
1213 		 * A board was just removed
1214 		 */
1215 		hsp->hs_slot_state = HPC_SLOT_EMPTY;
1216 		hsp->hs_board_type = HPC_BOARD_UNKNOWN;
1217 		hsp->hs_flags &= ~HSC_ENUM_FAILED;
1218 		if (hsp->hs_flags & HSC_ALARM_CARD_PRES) {
1219 			hsp->hs_flags &= ~HSC_ALARM_CARD_PRES;
1220 			DEBUG0("Xhsc_slot_occupancy:clear HSC_ALARM_CARD_PRES");
1221 		}
1222 		if (hsp->hs_board_configured == B_TRUE) {
1223 			(void) hpc_slot_event_notify(hsp->hs_slot_handle,
1224 					HPC_EVENT_SLOT_NOT_HEALTHY, 0);
1225 			cmn_err(CE_WARN, "%s#%d: ALERT! Surprise Removal "
1226 				" on Slot %d, Occupant Online!!",
1227 					ddi_driver_name(hsp->hsc->dip),
1228 					ddi_get_instance(hsp->hsc->dip),
1229 					slot_number);
1230 			cmn_err(CE_WARN, "%s#%d: ALERT! System now in "
1231 				" Inconsistent State! Slot disabled. Halt!",
1232 					ddi_driver_name(hsp->hsc->dip),
1233 					ddi_get_instance(hsp->hsc->dip));
1234 			/* Slot in reset and disabled */
1235 			scsb_hsc_disable_slot(hsp);
1236 			hsp->hs_flags |= HSC_SLOT_BAD_STATE;
1237 			/* the following works for P1.0 only. */
1238 			hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED,
1239 						HPC_LED_ON);
1240 			hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
1241 								HPC_LED_ON);
1242 		} else {
1243 			hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED,
1244 						HPC_LED_OFF);
1245 			hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
1246 								HPC_LED_OFF);
1247 		}
1248 	}
1249 	return (rc);
1250 }
1251 
1252 
1253 /*
1254  * This function is invoked by the SCSB when the health status of
1255  * a board changes.
1256  */
1257 /*ARGSUSED*/
1258 int
1259 scsb_hsc_board_healthy(int slot_number, boolean_t healthy)
1260 {
1261 	hsc_slot_t		*hsp;
1262 	hsc_state_t		*hsc;
1263 
1264 	DEBUG2("hsc_board_healthy: slot %d = %d\n", slot_number, healthy);
1265 
1266 	hsp = hsc_find_slot(slot_number);
1267 	if (hsp == NULL) {
1268 		cmn_err(CE_NOTE, "hsc_board_healthy: No Slot Info.");
1269 		return (DDI_FAILURE);
1270 	}
1271 
1272 	hsc = hsp->hsc;
1273 	if (hsp->hs_slot_state == HPC_SLOT_EMPTY) {
1274 #ifdef	DEBUG
1275 		cmn_err(CE_NOTE, "%s#%d: Healthy# %s on "
1276 			"empty slot %d", ddi_driver_name(hsc->dip),
1277 			ddi_get_instance(hsc->dip),
1278 			healthy == B_TRUE ? "On" : "Off", slot_number);
1279 #endif
1280 		return (DDI_FAILURE);
1281 	}
1282 	if (hsp->hs_slot_state == HPC_SLOT_DISCONNECTED) {
1283 		DEBUG2("healthy %s on disconnected slot %d\n",
1284 			healthy == B_TRUE ? "On":"Off", slot_number);
1285 		/*
1286 		 * Connect the slot if board healthy and in autoconfig mode.
1287 		 */
1288 		hsp->hs_board_healthy = healthy;
1289 		if (healthy == B_TRUE)
1290 			return (hsc_slot_autoconnect(hsp));
1291 	}
1292 
1293 	/*
1294 	 * the board is connected. The result could be seviour depending
1295 	 * on the occupant state.
1296 	 */
1297 	if (healthy == B_TRUE) {
1298 		if (hsp->hs_board_healthy != B_TRUE) {
1299 			hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED,
1300 					HPC_LED_OFF);
1301 			/* Regained HEALTHY# at Run Time...!!! */
1302 			cmn_err(CE_NOTE, "%s#%d: slot %d Occupant "
1303 				"%s, Regained HEALTHY#!",
1304 				ddi_driver_name(hsc->dip),
1305 				ddi_get_instance(hsc->dip), slot_number,
1306 				hsp->hs_board_configured == B_TRUE ?
1307 						"configured" : "Unconfigured");
1308 			(void) hpc_slot_event_notify(hsp->hs_slot_handle,
1309 				HPC_EVENT_SLOT_HEALTHY_OK, 0);
1310 		}
1311 	} else {
1312 		if (hsp->hs_board_configured == B_TRUE) {
1313 			/* Lost HEALTHY# at Run Time...Serious Condition. */
1314 			cmn_err(CE_WARN, "%s#%d: ALERT! Lost HEALTHY#"
1315 				" on Slot %d, Occupant %s",
1316 				ddi_driver_name(hsc->dip),
1317 				ddi_get_instance(hsc->dip), slot_number,
1318 					hsp->hs_board_configured == B_TRUE ?
1319 						"Online!!!" : "Offline");
1320 			(void) hpc_slot_event_notify(hsp->hs_slot_handle,
1321 					HPC_EVENT_SLOT_NOT_HEALTHY, 0);
1322 		}
1323 		if ((hsp->hs_board_configured != B_TRUE) ||
1324 						scsb_hsc_healthy_reset) {
1325 			if (scsb_reset_slot(hsp->hs_hpchandle,
1326 					slot_number, SCSB_RESET_SLOT) == 0) {
1327 				/* signal Ok to remove board. */
1328 				hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
1329 					HPC_FAULT_LED, HPC_LED_ON);
1330 				cmn_err(CE_WARN, "%s#%d: Slot %d "
1331 					"successfully taken offline",
1332 					ddi_driver_name(hsc->dip),
1333 					ddi_get_instance(hsc->dip),
1334 					slot_number);
1335 			}
1336 		}
1337 	}
1338 	hsp->hs_board_healthy = healthy;
1339 	return (DDI_SUCCESS);
1340 }
1341 
1342 static int
1343 hsc_slot_autoconnect(hsc_slot_t *hsp)
1344 {
1345 	hsc_state_t *hsc = hsp->hsc;
1346 	int rc = DDI_SUCCESS;
1347 	/*
1348 	 * Keep slot in reset unless autoconfiguration is enabled
1349 	 * Ie. for Basic Hotswap mode, we stay disconnected at
1350 	 * insertion. For full hotswap mode, we automatically
1351 	 * go into connected state at insertion, so that occupant
1352 	 * autoconfiguration is possible.
1353 	 */
1354 	if (((hsc->state & HSC_ENUM_ENABLED) == HSC_ENUM_ENABLED) &&
1355 			(hsp->hs_flags & HSC_AUTOCFG)) {
1356 		/* this statement must be here before unreset. */
1357 		hsc->hsp_last = hsp;
1358 		if ((rc = scsb_reset_slot(hsp->hs_hpchandle,
1359 			hsp->hs_slot_number, SCSB_UNRESET_SLOT)) == 0) {
1360 
1361 			hsp->hs_slot_state = HPC_SLOT_CONNECTED;
1362 			hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
1363 					HPC_FAULT_LED, HPC_LED_OFF);
1364 		} else {
1365 			hsc->hsp_last = NULL;
1366 			rc = DDI_FAILURE;
1367 		}
1368 	}
1369 	return (rc);
1370 }
1371 
1372 /*
1373  * The SCSB code should invoke this function from its _init() function.
1374  */
1375 int
1376 hsc_init()
1377 {
1378 	int rc;
1379 
1380 	rc = ddi_soft_state_init(&hsc_state, sizeof (hsc_state_t), 1);
1381 	if (rc != 0)
1382 		return (rc);
1383 
1384 	hsc_slotops = hpc_alloc_slot_ops(KM_SLEEP);
1385 
1386 	hsc_slotops->hpc_version	= HPC_SLOT_OPS_VERSION;
1387 	hsc_slotops->hpc_op_connect	= hsc_connect;
1388 	hsc_slotops->hpc_op_disconnect	= hsc_disconnect;
1389 	hsc_slotops->hpc_op_insert	= hsc_insert;
1390 	hsc_slotops->hpc_op_remove	= hsc_remove;
1391 	hsc_slotops->hpc_op_control	= hsc_control;
1392 
1393 	return (DDI_SUCCESS);
1394 }
1395 
1396 
1397 /*
1398  * The SCSB code should invoke this function from its _fini() function.
1399  */
1400 int
1401 hsc_fini()
1402 {
1403 	if (hsc_slotops != NULL) {
1404 		hpc_free_slot_ops(hsc_slotops);
1405 		hsc_slotops = NULL;
1406 	}
1407 	ddi_soft_state_fini(&hsc_state);
1408 	return (DDI_SUCCESS);
1409 }
1410 
1411 static int
1412 scsb_enable_enum(hsc_state_t *hsc)
1413 {
1414 	DEBUG0("hsc: Enable ENUM#\n");
1415 
1416 	if ((hsc->state & HSC_ENUM_ENABLED) == HSC_ENUM_ENABLED)
1417 		return (DDI_SUCCESS);
1418 	if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED)
1419 		return (DDI_FAILURE);
1420 
1421 	if (ddi_add_intr(hsc->dip, 1, NULL, NULL,
1422 			hsc_enum_intr, (caddr_t)hsc) != DDI_SUCCESS) {
1423 		cmn_err(CE_WARN, "%s#%d: failed ENUM# interrupt registration",
1424 			ddi_driver_name(hsc->dip), ddi_get_instance(hsc->dip));
1425 		return (DDI_FAILURE);
1426 	}
1427 	cmn_err(CE_CONT, "?%s%d: Successfully Upgraded to "
1428 			"Full Hotswap Mode\n", ddi_driver_name(hsc->dip),
1429 			ddi_get_instance(hsc->dip));
1430 	hsc->state |= HSC_ENUM_ENABLED;
1431 	ddi_prop_update_string(DDI_DEV_T_NONE, hsc->dip, HOTSWAP_MODE_PROP,
1432 					"full");
1433 	return (DDI_SUCCESS);
1434 
1435 }
1436 
1437 /*ARGSUSED*/
1438 static int
1439 scsb_disable_enum(hsc_state_t *hsc, int op)
1440 {
1441 
1442 	DEBUG0("hsc: Disable ENUM#\n");
1443 	if (op == SCSB_HSC_FORCE_REMOVE) {
1444 		/*
1445 		 * Clear all pending interrupts before unregistering
1446 		 * the interrupt. Otherwise the system will hang.
1447 		 *
1448 		 * Due to the hang problem, we'll not turn off or disable
1449 		 * interrupts because if there's a non-friendly full hotswap
1450 		 * device out there, the ENUM# will be kept asserted and
1451 		 * hence hsc_clear_all_enum() can never deassert ENUM#.
1452 		 * So the system will hang.
1453 		 */
1454 		if ((hsc->state & HSC_ENUM_ENABLED) == HSC_ENUM_ENABLED) {
1455 			/* hsc_clear_all_enum(hsc); */
1456 			ddi_remove_intr(hsc->dip, 1, NULL);
1457 			hsc->state &= ~HSC_ENUM_ENABLED;
1458 			cmn_err(CE_CONT, "?%s%d: Successfully Downgraded to "
1459 				"Basic Hotswap Mode\n",
1460 				ddi_driver_name(hsc->dip),
1461 				ddi_get_instance(hsc->dip));
1462 		}
1463 		ddi_prop_update_string(DDI_DEV_T_NONE, hsc->dip,
1464 				HOTSWAP_MODE_PROP, "basic");
1465 		return (DDI_SUCCESS);
1466 	} else
1467 		/* No programming interface for disabling ENUM# on MC/Tonga */
1468 		return (HPC_ERR_NOTSUPPORTED);
1469 }
1470 
1471 #ifndef	lint
1472 static int
1473 hsc_clear_all_enum(hsc_state_t *hsc)
1474 {
1475 	int i, rc;
1476 	hsc_slot_t *hsp;
1477 
1478 	for (i = 0; i < hsc->slot_table_size; i++) {
1479 
1480 		hsp = hsc_find_slot(hsc->slot_table_prop[i].pslotnum);
1481 		if (hsp == NULL)
1482 			continue;
1483 		rc = hpc_slot_event_notify(hsp->hs_slot_handle,
1484 					HPC_EVENT_CLEAR_ENUM,
1485 						HPC_EVENT_SYNCHRONOUS);
1486 		if (rc == HPC_EVENT_UNCLAIMED)
1487 			break;	/* no pending interrupts across the bus */
1488 		DEBUG1("Pending Intr on slot %d\n",
1489 			hsc->slot_table_prop[i].pslotnum);
1490 	}
1491 	return (0);
1492 }
1493 #endif
1494 
1495 int
1496 scsb_hsc_attach(dev_info_t *dip, void *scsb_handle, int instance)
1497 {
1498 	int i, n, prop_len;
1499 	int prom_prop = 0;	/* default: OS property gives slot-table */
1500 	int rc;
1501 	char *hotswap_model;
1502 	hsc_state_t	*hsc;
1503 	scsb_state_t	*scsb = (scsb_state_t *)scsb_handle;
1504 	caddr_t hpc_slot_table_data, s;
1505 	int hpc_slot_table_size;
1506 	hsc_prom_slot_table_t	*hpstp;
1507 	int rstate;
1508 
1509 	DEBUG0("hsc_attach: enter\n");
1510 	/*
1511 	 * To get the slot information,
1512 	 * The OBP defines the 'slot-table' property. But the OS
1513 	 * can override it with 'hsc-slot-map' property
1514 	 * through the .conf file.
1515 	 * Since the formats are different, 2 different property names
1516 	 * are chosen.
1517 	 * The OBP property format is
1518 	 * <phandle>,<pci-devno>,<phys-slotno>,<ga-bits>
1519 	 * The OS property format is (ga-bits is not used however)
1520 	 * <busnexus-path>,<pci-devno>,<phys-slotno>,<ga-bits>
1521 	 */
1522 	rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1523 		"hsc-slot-map", (caddr_t)&hpc_slot_table_data,
1524 		&hpc_slot_table_size);
1525 	if (rc != DDI_PROP_SUCCESS)  {
1526 		prom_prop = 1;
1527 		rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1528 			"slot-table", (caddr_t)&hpc_slot_table_data,
1529 			&hpc_slot_table_size);
1530 		if (rc != DDI_PROP_SUCCESS) {
1531 			cmn_err(CE_WARN, "%s#%d: 'slot-table' property "
1532 				"missing!", ddi_driver_name(dip),
1533 						ddi_get_instance(dip));
1534 			return (DDI_FAILURE);
1535 		}
1536 	}
1537 	rc = ddi_soft_state_zalloc(hsc_state, instance);
1538 	if (rc != DDI_SUCCESS)
1539 		return (DDI_FAILURE);
1540 
1541 	hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance);
1542 	hsc->scsb_handle = scsb_handle;
1543 	hsc->dip = dip;
1544 	hsc->instance = instance;
1545 	hsc->n_registered_occupants = 0;
1546 	hsc->regDone = B_FALSE;
1547 	/* hsc->slot_info = hsc_slot_list; */
1548 
1549 	/*
1550 	 * Check whether the system should be in basic or full
1551 	 * hotswap mode. The PROM property always says full, so
1552 	 * look at the .conf file property whether this is "full"
1553 	 */
1554 	if (scsb_hsc_enable_fhs) {
1555 		hsc->hotswap_mode = HSC_HOTSWAP_MODE_FULL;
1556 	} else {
1557 		hsc->hotswap_mode = HSC_HOTSWAP_MODE_BASIC;
1558 	}
1559 
1560 	rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1561 		"default-hotswap-mode", (caddr_t)&hotswap_model, &prop_len);
1562 
1563 	if (rc == DDI_PROP_SUCCESS) {
1564 		if (strcmp(hotswap_model, "full") == 0) {
1565 			hsc->hotswap_mode = HSC_HOTSWAP_MODE_FULL;
1566 		} else if (strcmp(hotswap_model, "basic") == 0) {
1567 			hsc->hotswap_mode = HSC_HOTSWAP_MODE_BASIC;
1568 		}
1569 
1570 		kmem_free(hotswap_model, prop_len);
1571 	}
1572 
1573 	/*
1574 	 * Determine the size of the slot table from the property and
1575 	 * allocate the slot table arrary..Decoding is different for
1576 	 * OS and PROM property.
1577 	 */
1578 	if (!prom_prop) {	/* OS .conf property */
1579 		for (i = 0, n = 0; i < hpc_slot_table_size; i++) {
1580 			if (hpc_slot_table_data[i] == 0) {
1581 				n++;
1582 			}
1583 		}
1584 
1585 		/* There should be four elements per entry */
1586 		if (n % 4) {
1587 			cmn_err(CE_WARN, "%s#%d: bad format for "
1588 				"slot-table(%d)", ddi_driver_name(dip),
1589 						ddi_get_instance(dip), n);
1590 			kmem_free(hpc_slot_table_data, hpc_slot_table_size);
1591 			ddi_soft_state_free(hsc_state, instance);
1592 			return (DDI_FAILURE);
1593 		}
1594 
1595 		hsc->slot_table_size = n / 4;
1596 	} else {
1597 		hsc->slot_table_size = hpc_slot_table_size /
1598 						sizeof (hsc_prom_slot_table_t);
1599 		n = hpc_slot_table_size % sizeof (hsc_prom_slot_table_t);
1600 		if (n) {
1601 			cmn_err(CE_WARN, "%s#%d: bad format for "
1602 				"slot-table(%d)", ddi_driver_name(dip),
1603 				ddi_get_instance(dip), hpc_slot_table_size);
1604 			kmem_free(hpc_slot_table_data, hpc_slot_table_size);
1605 			ddi_soft_state_free(hsc_state, instance);
1606 			return (DDI_FAILURE);
1607 		}
1608 	}
1609 
1610 	/*
1611 	 * Netract800 FTC (formerly known as CFTM) workaround.
1612 	 * Leave Slot 2 out of the HS table if FTC is present in Slot 2
1613 	 */
1614 	if (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES) {
1615 		hsc->slot_table_size -= 1;
1616 	}
1617 	DEBUG1("hsc_attach: %d hotplug slots on bus\n", hsc->slot_table_size);
1618 	/*
1619 	 * Create enough space for each slot table entry
1620 	 * based on how many entries in the property
1621 	 */
1622 	hsc->slot_table_prop = (hsc_slot_table_t *)
1623 		kmem_zalloc(hsc->slot_table_size *
1624 			sizeof (hsc_slot_table_t), KM_SLEEP);
1625 
1626 	if (!prom_prop) {
1627 		s = hpc_slot_table_data;
1628 		for (i = 0; i < hsc->slot_table_size; i++) {
1629 
1630 			char *nexus, *pcidev, *phys_slotname, *ga;
1631 
1632 			/* Pick off pointer to nexus path or PROM handle */
1633 			nexus = s;
1634 			while (*s != NULL)
1635 				s++;
1636 			s++;
1637 
1638 			/* Pick off pointer to the pci device number */
1639 			pcidev = s;
1640 			while (*s != NULL)
1641 				s++;
1642 			s++;
1643 
1644 			/* Pick off physical slot no */
1645 			phys_slotname = s;
1646 			while (*s != NULL)
1647 				s++;
1648 			s++;
1649 
1650 			/* Pick off GA bits which we dont use for now. */
1651 			ga = s;
1652 			while (*s != NULL)
1653 				s++;
1654 			s++;
1655 
1656 			if (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES &&
1657 					atoi(phys_slotname) == SC_MC_CTC_SLOT) {
1658 				--i;
1659 				continue;
1660 			}
1661 			hsc->slot_table_prop[i].pslotnum = atoi(phys_slotname);
1662 			hsc->slot_table_prop[i].ga = atoi(ga);
1663 			hsc->slot_table_prop[i].pci_devno = atoi(pcidev);
1664 			strcpy(hsc->slot_table_prop[i].nexus, nexus);
1665 		}
1666 	} else {
1667 		hpstp = (hsc_prom_slot_table_t *)hpc_slot_table_data;
1668 		for (i = 0; i < hsc->slot_table_size; i++, hpstp++) {
1669 			if (scsb->scsb_hsc_state & SCSB_HSC_CTC_PRES &&
1670 					hpstp->pslotnum == SC_MC_CTC_SLOT) {
1671 				--i;
1672 				continue;
1673 			}
1674 			hsc->slot_table_prop[i].pslotnum = hpstp->pslotnum;
1675 			hsc->slot_table_prop[i].ga = hpstp->ga;
1676 			hsc->slot_table_prop[i].pci_devno = hpstp->pci_devno;
1677 
1678 			if (prom_phandle_to_path((uint_t)hpstp->phandle,
1679 				hsc->slot_table_prop[i].nexus,
1680 				sizeof (hsc->slot_table_prop[i].nexus))
1681 						== -1) {
1682 				cmn_err(CE_WARN, "%s#%d: Cannot get phandle "
1683 					"to nexus path", ddi_driver_name(dip),
1684 					ddi_get_instance(dip));
1685 				kmem_free(hsc->slot_table_prop,
1686 					(hsc->slot_table_size *
1687 						sizeof (hsc_slot_table_t)));
1688 				kmem_free(hpc_slot_table_data,
1689 						hpc_slot_table_size);
1690 				ddi_soft_state_free(hsc_state, instance);
1691 				return (DDI_FAILURE);
1692 			}
1693 		}
1694 	}
1695 
1696 	/* keep healthy register cache uptodate before reading slot state */
1697 	if (scsb_read_bhealthy(scsb_handle) != 0) {
1698 		cmn_err(CE_WARN, "%s#%d: hsc_attach: Cannot read "
1699 			"Healthy Registers", ddi_driver_name(dip),
1700 				ddi_get_instance(dip));
1701 		kmem_free(hsc->slot_table_prop,
1702 			(hsc->slot_table_size *
1703 				sizeof (hsc_slot_table_t)));
1704 		kmem_free(hpc_slot_table_data,
1705 				hpc_slot_table_size);
1706 		ddi_soft_state_free(hsc_state, instance);
1707 		return (DDI_FAILURE);
1708 	}
1709 
1710 	/*
1711 	 * Before we start registering the slots, calculate how many
1712 	 * slots are occupied.
1713 	 */
1714 
1715 	for (i = 0; i < hsc->slot_table_size; i++) {
1716 		if (scsb_get_slot_state(scsb_handle,
1717 				hsc->slot_table_prop[i].pslotnum, &rstate) !=
1718 				DDI_SUCCESS)
1719 				return (rc);
1720 		if (rstate != HPC_SLOT_EMPTY)
1721 			hsc->n_registered_occupants++;
1722 	}
1723 
1724 	mutex_init(&hsc->hsc_mutex, NULL, MUTEX_DRIVER, NULL);
1725 	for (i = 0; i < hsc->slot_table_size; i++) {
1726 
1727 		DEBUG2("Registering on nexus [%s] cPCI device [%d]\n",
1728 			hsc->slot_table_prop[i].nexus,
1729 			hsc->slot_table_prop[i].pci_devno);
1730 
1731 		if (hsc_slot_register(hsc, hsc->slot_table_prop[i].nexus,
1732 			hsc->slot_table_prop[i].pci_devno,
1733 			hsc->slot_table_prop[i].pslotnum, B_FALSE) !=
1734 								HPC_SUCCESS) {
1735 
1736 			cmn_err(CE_WARN, "%s#%d: Slot Registration Failure",
1737 				ddi_driver_name(dip), ddi_get_instance(dip));
1738 			while (i) {
1739 				i--;
1740 				n = hsc->slot_table_prop[i].pslotnum;
1741 				if (hsc_slot_unregister(n) != 0) {
1742 					cmn_err(CE_WARN,
1743 						"%s#%d: failed to unregister"
1744 						" slot %d",
1745 						ddi_driver_name(dip),
1746 						ddi_get_instance(dip), n);
1747 
1748 				}
1749 			}
1750 			mutex_destroy(&hsc->hsc_mutex);
1751 			kmem_free(hsc->slot_table_prop, (hsc->slot_table_size *
1752 					sizeof (hsc_slot_table_t)));
1753 			kmem_free(hpc_slot_table_data, hpc_slot_table_size);
1754 			ddi_soft_state_free(hsc_state, instance);
1755 			return (DDI_FAILURE);
1756 		}
1757 	}
1758 
1759 	hsc->hsp_last = NULL;
1760 	hsc->hsc_intr_counter = 0;
1761 	kmem_free(hpc_slot_table_data, hpc_slot_table_size);
1762 	ddi_prop_update_string(DDI_DEV_T_NONE, hsc->dip, HOTSWAP_MODE_PROP,
1763 								"basic");
1764 	hsc->state |= (HSC_ATTACHED|HSC_SCB_CONNECTED);
1765 
1766 	/*
1767 	 * We enable full hotswap right here if all the slots are empty.
1768 	 */
1769 	if ((hsc->regDone == B_FALSE && hsc->n_registered_occupants == 0) ||
1770 			scsb_hsc_numReg == hsc->n_registered_occupants) {
1771 		hsc->regDone = B_TRUE;
1772 		if (hsc->hotswap_mode == HSC_HOTSWAP_MODE_FULL) {
1773 			if (scsb_enable_enum(hsc) != DDI_SUCCESS) {
1774 				cmn_err(CE_WARN, "%s#%d: Cannot enable "
1775 					"Full Hotswap", ddi_driver_name(dip),
1776 					ddi_get_instance(dip));
1777 			}
1778 		}
1779 	}
1780 	return (DDI_SUCCESS);
1781 }
1782 
1783 /*ARGSUSED*/
1784 int
1785 scsb_hsc_detach(dev_info_t *dip, void *scsb_handle, int instance)
1786 {
1787 	int i = 0;
1788 	hsc_state_t	*hsc;
1789 	char slotautocfg_prop[18];
1790 
1791 	DEBUG0("hsc_detach: enter\n");
1792 	hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance);
1793 	if (hsc == NULL) {
1794 		DEBUG2("%s#%d: hsc_detach: Soft state NULL",
1795 				ddi_driver_name(dip), ddi_get_instance(dip));
1796 		return (DDI_FAILURE);
1797 	}
1798 
1799 	if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED)
1800 		return (DDI_FAILURE);
1801 	/*
1802 	 * let's unregister the hotpluggable slots with hotplug service.
1803 	 */
1804 	for (i = 0; i < hsc->slot_table_size; i++) {
1805 
1806 		hsc_slot_t	*hsp;
1807 
1808 		hsp = hsc_find_slot(hsc->slot_table_prop[i].pslotnum);
1809 		if (hsp == NULL) {
1810 			cmn_err(CE_WARN, "%s#%d: hsc_detach: No Slot Info",
1811 				ddi_driver_name(dip), ddi_get_instance(dip));
1812 		} else {
1813 			hpc_led_info_t	aledinfo;	/* active led info. */
1814 			hpc_led_info_t	fledinfo;	/* fault led info. */
1815 
1816 			aledinfo.led = HPC_ACTIVE_LED;
1817 			aledinfo.state = HPC_LED_BLINK;
1818 			fledinfo.led = HPC_FAULT_LED;
1819 			fledinfo.state = HPC_LED_OFF;
1820 			(void) hsc_led_state(hsp, HPC_CTRL_SET_LED_STATE,
1821 							&aledinfo);
1822 			(void) hsc_led_state(hsp, HPC_CTRL_SET_LED_STATE,
1823 							&fledinfo);
1824 		}
1825 		sprintf(slotautocfg_prop, "slot%d-autoconfig",
1826 						hsp->hs_slot_number);
1827 		ddi_prop_remove(DDI_DEV_T_NONE, hsc->dip, slotautocfg_prop);
1828 		if (hsc_slot_unregister(hsc->slot_table_prop[i].pslotnum)
1829 						!= 0) {
1830 			cmn_err(CE_NOTE, "%s#%d: failed to unregister"
1831 				" slot %d\n", ddi_driver_name(dip),
1832 				ddi_get_instance(dip),
1833 				hsc->slot_table_prop[i].pslotnum);
1834 			return (DDI_FAILURE);
1835 		}
1836 	}
1837 	kmem_free(hsc->slot_table_prop, (hsc->slot_table_size *
1838 					sizeof (hsc_slot_table_t)));
1839 	if ((hsc->state & HSC_ENUM_ENABLED) == HSC_ENUM_ENABLED) {
1840 		ddi_remove_intr(hsc->dip, 1, hsc->enum_iblock);
1841 		hsc->state &= ~HSC_ENUM_ENABLED;
1842 	}
1843 	mutex_destroy(&hsc->hsc_mutex);
1844 	ddi_prop_remove(DDI_DEV_T_NONE, hsc->dip, HOTSWAP_MODE_PROP);
1845 	hsc->state &= ~(HSC_ATTACHED|HSC_SCB_CONNECTED);
1846 	ddi_soft_state_free(hsc_state, instance);
1847 	return (DDI_SUCCESS);
1848 }
1849 
1850 /*
1851  * The following function is called when the SCSB is hot extracted from
1852  * the system.
1853  */
1854 int
1855 scsb_hsc_freeze(dev_info_t *dip)
1856 {
1857 	hsc_state_t	*hsc;
1858 	int instance = ddi_get_instance(dip);
1859 	int i;
1860 	hsc_slot_t	*hsp;
1861 
1862 	hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance);
1863 	if (hsc == NULL) {
1864 		DEBUG2("%s#%d: Soft state NULL",
1865 				ddi_driver_name(dip), ddi_get_instance(dip));
1866 		return (DDI_SUCCESS);
1867 	}
1868 	if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED)
1869 		return (DDI_SUCCESS);
1870 	hsc->state &= ~HSC_SCB_CONNECTED;
1871 
1872 	for (i = 0; i < hsc->slot_table_size; i++) {
1873 		hsp = hsc_find_slot(hsc->slot_table_prop[i].pslotnum);
1874 
1875 		if (hsp == NULL) {
1876 			cmn_err(CE_NOTE, "hsc_freeze: "
1877 				" Cannot map slot number %d to a hsc_slot_t",
1878 					hsc->slot_table_prop[i].pslotnum);
1879 			continue;
1880 		}
1881 		/*
1882 		 * Since reset lines are pulled low, lets mark these
1883 		 * slots and not allow a connect operation.
1884 		 * Note that we still keep the slot as slot disconnected,
1885 		 * although it is connected from the hardware standpoint.
1886 		 * As soon as the SCB is plugged back in, we check these
1887 		 * states and put the hardware state back to its original
1888 		 * state.
1889 		 */
1890 		if (hsp->hs_slot_state == HPC_SLOT_DISCONNECTED) {
1891 			cmn_err(CE_WARN, "%s#%d: Slot %d Now out of Reset!",
1892 				ddi_driver_name(hsc->dip),
1893 				ddi_get_instance(hsc->dip),
1894 				hsp->hs_slot_number);
1895 		}
1896 		hsp->hs_flags |= HSC_SCB_HOTSWAPPED;
1897 	}
1898 
1899 	return (DDI_SUCCESS);
1900 }
1901 
1902 /*
1903  * The following function is called when the SCSB is hot inserted from
1904  * the system. We must update the LED status and set the RST# registers
1905  * again.
1906  */
1907 int
1908 scsb_hsc_restore(dev_info_t *dip)
1909 {
1910 	int i;
1911 	hsc_state_t	*hsc;
1912 	hsc_slot_t	*hsp;
1913 	int instance = ddi_get_instance(dip);
1914 
1915 	hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance);
1916 	if (hsc == NULL) {
1917 		DEBUG2("%s#%d: Soft state NULL",
1918 				ddi_driver_name(dip), ddi_get_instance(dip));
1919 		return (DDI_SUCCESS);
1920 	}
1921 
1922 	if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED)
1923 		return (DDI_SUCCESS);
1924 	hsc->state |= HSC_SCB_CONNECTED;
1925 	for (i = 0; i < hsc->slot_table_size; i++) {
1926 		hsp = hsc_find_slot(hsc->slot_table_prop[i].pslotnum);
1927 
1928 		if (hsp == NULL) {
1929 			cmn_err(CE_NOTE, "%s#%d: hsc_restore: "
1930 				" Cannot map slot number %d to a hsc_slot_t",
1931 					ddi_driver_name(hsc->dip),
1932 					ddi_get_instance(hsc->dip),
1933 					hsc->slot_table_prop[i].pslotnum);
1934 			continue;
1935 		}
1936 		if ((hsp->hs_slot_state == HPC_SLOT_DISCONNECTED) &&
1937 				(hsp->hs_board_configured == B_FALSE)) {
1938 			if (scsb_reset_slot(hsp->hs_hpchandle,
1939 					hsp->hs_slot_number,
1940 					SCSB_RESET_SLOT) != 0) {
1941 				cmn_err(CE_WARN, "%s#%d: hsc_restore: "
1942 					" Cannot reset disconnected slot %d",
1943 						ddi_driver_name(hsc->dip),
1944 						ddi_get_instance(hsc->dip),
1945 						hsp->hs_slot_number);
1946 			}
1947 		}
1948 
1949 		if (scsb_hsc_init_slot_state(hsc, hsp) != DDI_SUCCESS) {
1950 
1951 			cmn_err(CE_WARN, "%s#%d: hsc_freeze: Cannot init"
1952 				" slot%d state",
1953 				ddi_driver_name(hsc->dip),
1954 				ddi_get_instance(hsc->dip),
1955 				hsp->hs_slot_number);
1956 		}
1957 		hsp->hs_flags &= ~HSC_SCB_HOTSWAPPED;
1958 	}
1959 	return (DDI_SUCCESS);
1960 }
1961 
1962 #ifndef	lint
1963 int
1964 scsb_hsc_freeze_check(dev_info_t *dip)
1965 {
1966 	hsc_state_t	*hsc;
1967 	int instance = ddi_get_instance(dip);
1968 
1969 	hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance);
1970 	if (hsc == NULL) {
1971 		DEBUG2("%s#%d: Soft state NULL",
1972 				ddi_driver_name(dip), ddi_get_instance(dip));
1973 		return (DDI_SUCCESS);
1974 	}
1975 	if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED)
1976 		return (DDI_SUCCESS);
1977 	return (DDI_SUCCESS);
1978 }
1979 #endif
1980 
1981 /*
1982  * update info about Alarm Card insert/remove mechanism.
1983  */
1984 void
1985 hsc_ac_op(int instance, int pslotnum, int op, void *arg)
1986 {
1987 	hsc_slot_t *hsp;
1988 	hsc_state_t	*hsc;
1989 
1990 	hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance);
1991 	if (hsc == NULL) {
1992 		cmn_err(CE_WARN, "%s#%d: hsc_ac_op: No Soft State Info",
1993 			ddi_driver_name(hsc->dip), ddi_get_instance(hsc->dip));
1994 		return;
1995 	}
1996 
1997 	hsp = hsc_find_slot(pslotnum);
1998 	if (hsp == NULL) {
1999 		cmn_err(CE_WARN, "%s#%d: hsc_ac_op: No Slot Info",
2000 			ddi_driver_name(hsc->dip), ddi_get_instance(hsc->dip));
2001 		return;
2002 	}
2003 
2004 	switch (op) {
2005 		case SCSB_HSC_AC_UNCONFIGURE :
2006 			/*
2007 			 * If ENUM# is enabled, then action is pending on
2008 			 * this slot, just send a event.
2009 			 */
2010 			if (hsc->state & HSC_ENUM_ENABLED)
2011 				hpc_slot_event_notify(hsp->hs_slot_handle,
2012 					HPC_EVENT_PROCESS_ENUM, 0);
2013 			break;
2014 		case SCSB_HSC_AC_GET_SLOT_INFO :
2015 			*(hsc_slot_t **)arg = hsp;
2016 			break;
2017 		default :
2018 			break;
2019 	}
2020 }
2021 
2022 static uint_t
2023 hsc_enum_intr(caddr_t iarg)
2024 {
2025 	int rc;
2026 	hsc_state_t *hsc = (hsc_state_t *)iarg;
2027 	hsc_slot_t *hsp;
2028 
2029 	DEBUG0("!E!");
2030 	if ((hsc->state & HSC_ATTACHED) == 0)
2031 		return (DDI_INTR_UNCLAIMED);
2032 
2033 	hsp = hsc_find_slot(hsc->slot_table_prop[0].pslotnum);
2034 	if (hsp == NULL)	/* No slots registered */
2035 		return (DDI_INTR_UNCLAIMED);
2036 
2037 	/*
2038 	 * The following must be done to clear interrupt (synchronous event).
2039 	 * To process the interrupt, we send an asynchronous event.
2040 	 */
2041 	rc = hpc_slot_event_notify(hsp->hs_slot_handle,
2042 					HPC_EVENT_CLEAR_ENUM,
2043 						HPC_EVENT_SYNCHRONOUS);
2044 	if (rc == HPC_EVENT_UNCLAIMED) {
2045 		/*
2046 		 * possible support for handling insertion of non friendly
2047 		 * full hotswap boards, otherwise the system hangs due
2048 		 * to uncleared interrupt bursts.
2049 		 */
2050 		DEBUG2("!E>counter %d, last op@slot %lx\n",
2051 				hsc->hsc_intr_counter, hsc->hsp_last);
2052 		hsc->hsc_intr_counter ++;
2053 		if (hsc->hsc_intr_counter == scsb_hsc_max_intr_count) {
2054 			if (!hsc->hsp_last) {
2055 				cmn_err(CE_WARN, "%s#%d: hsc_enum_intr: "
2056 					" No Last Board Insertion Info.",
2057 					ddi_driver_name(hsc->dip),
2058 					ddi_get_instance(hsc->dip));
2059 				hsc->hsc_intr_counter = 0;
2060 				return (DDI_INTR_UNCLAIMED);
2061 			}
2062 			hsp = hsc->hsp_last;
2063 			cmn_err(CE_WARN, "%s#%d: Bad (non friendly ?) Board "
2064 				"in Slot %d ? Taking it Offline.",
2065 				ddi_driver_name(hsc->dip),
2066 				ddi_get_instance(hsc->dip),
2067 				hsp->hs_slot_number);
2068 			/*
2069 			 * this should put just inserted board back in
2070 			 * reset, thus deasserting the ENUM# and the
2071 			 * system hang.
2072 			 */
2073 			if (scsb_reset_slot(hsp->hs_hpchandle,
2074 					hsp->hs_slot_number,
2075 					SCSB_RESET_SLOT) == 0) {
2076 				/* Enumeration failed on this board */
2077 				hsp->hs_flags |= HSC_ENUM_FAILED;
2078 				if (hsp->hs_board_configured == B_TRUE)
2079 					cmn_err(CE_WARN, "%s#%d: ALERT! System"
2080 						" now in Inconsistent State."
2081 						" Halt!",
2082 					    ddi_driver_name(hsc->dip),
2083 					    ddi_get_instance(hsc->dip));
2084 				hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
2085 						HPC_FAULT_LED, HPC_LED_ON);
2086 			}
2087 			hsc->hsc_intr_counter = 0;
2088 		}
2089 		return (DDI_INTR_UNCLAIMED);
2090 	}
2091 	hsc->hsc_intr_counter = 0;
2092 	/*
2093 	 * if interrupt success, rc denotes the PCI device number which
2094 	 * generated the ENUM# interrupt.
2095 	 */
2096 	hsp = hsc_get_slot_info(hsc, rc);
2097 	if (hsp == NULL) {
2098 		cmn_err(CE_WARN, "%s#%d: hsc_enum_intr: no slot info for "
2099 			"dev %x", ddi_driver_name(hsc->dip),
2100 			ddi_get_instance(hsc->dip), rc);
2101 		return (DDI_INTR_CLAIMED);	/* interrupt already cleared */
2102 	}
2103 	/* if this is Alarm Card and if it is busy, dont process event */
2104 	if (hsp->hs_flags & HSC_ALARM_CARD_PRES) {
2105 		if (scsb_hsc_ac_op(hsp->hs_hpchandle, hsp->hs_slot_number,
2106 						SCSB_HSC_AC_BUSY) == B_TRUE) {
2107 			/*
2108 			 * Busy means we need to inform (envmond)alarmcard.so
2109 			 * that it should save the AC configuration, stop the
2110 			 * heartbeat, and shutdown the RSC link.
2111 			 */
2112 			(void) scsb_hsc_ac_op(hsp->hs_hpchandle,
2113 					hsp->hs_slot_number,
2114 					SCSB_HSC_AC_REMOVAL_ALERT);
2115 			return (DDI_INTR_CLAIMED);
2116 		}
2117 	}
2118 	/*
2119 	 * If SCB was swapped out, dont process ENUM#. We put this slot
2120 	 * back in reset after SCB is inserted.
2121 	 */
2122 	if ((hsp->hs_flags & HSC_SCB_HOTSWAPPED) &&
2123 			(hsp->hs_slot_state == HPC_SLOT_DISCONNECTED))
2124 		return (DDI_INTR_CLAIMED);
2125 
2126 	hpc_slot_event_notify(hsp->hs_slot_handle, HPC_EVENT_PROCESS_ENUM, 0);
2127 	return (DDI_INTR_CLAIMED);
2128 }
2129 /*
2130  * A routine to convert a number (represented as a string) to
2131  * the integer value it represents.
2132  */
2133 
2134 static int
2135 isdigit(int ch)
2136 {
2137 	return (ch >= '0' && ch <= '9');
2138 }
2139 
2140 #define	isspace(c)	((c) == ' ' || (c) == '\t' || (c) == '\n')
2141 #define	bad(val)	(val == NULL || !isdigit(*val))
2142 
2143 static int
2144 atoi(const char *p)
2145 {
2146 	int n;
2147 	int c, neg = 0;
2148 
2149 	if (!isdigit(c = *p)) {
2150 		while (isspace(c))
2151 			c = *++p;
2152 		switch (c) {
2153 			case '-':
2154 				neg++;
2155 				/* FALLTHROUGH */
2156 			case '+':
2157 			c = *++p;
2158 		}
2159 		if (!isdigit(c))
2160 			return (0);
2161 	}
2162 	for (n = '0' - c; isdigit(c = *++p); ) {
2163 		n *= 10; /* two steps to avoid unnecessary overflow */
2164 		n += '0' - c; /* accum neg to avoid surprises at MAX */
2165 	}
2166 	return (neg ? n : -n);
2167 }
2168