xref: /titanic_44/usr/src/uts/sun4u/montecarlo/io/hsc.c (revision 726fad2a65f16c200a03969c29cb5c86c2d427db)
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 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * MonteCarlo HotSwap Controller functionality
29  */
30 
31 #include	<sys/types.h>
32 #include	<sys/stropts.h>
33 #include	<sys/stream.h>
34 #include	<sys/strsun.h>
35 #include	<sys/kmem.h>
36 #include	<sys/cmn_err.h>
37 #include	<sys/errno.h>
38 #include	<sys/cpuvar.h>
39 #include	<sys/open.h>
40 #include	<sys/stat.h>
41 #include	<sys/conf.h>
42 #include	<sys/ddi.h>
43 #include	<sys/sunddi.h>
44 #include	<sys/modctl.h>
45 #include	<sys/promif.h>
46 #include	<sys/hotplug/hpcsvc.h>
47 
48 #include	<sys/hscimpl.h>
49 #include	<sys/hsc.h>
50 
51 #include	<sys/mct_topology.h>
52 #include	<sys/scsbioctl.h>
53 #include	<sys/scsb.h>
54 
55 #define	HOTSWAP_MODE_PROP	"hotswap-mode"
56 #define	ALARM_CARD_ON_SLOT	1
57 #define	SCSB_HSC_FORCE_REMOVE	1	/* force remove enum intr handler */
58 
59 /* TUNABLE PARAMETERS. Some are Debug Only. Please take care when using. */
60 
61 /*
62  * Set this flag to 1, to enable full hotswap mode at boot time.
63  * Since HPS is threaded, it is not recommended that we set this flag
64  * to 1 because enabling full hotswap interrupt can invoke the ENUM
65  * event handler accessing the slot data structure which may have not
66  * been initialized in the hotplug framework since the HPS may not yet
67  * have called the slot registration function with the bus nexus.
68  */
69 static int	scsb_hsc_enable_fhs = 0;
70 
71 /*
72  * Every time  a slot is registered with the hotswap framework, the
73  * framework calls back. This variable keeps a count on how many
74  * callbacks are done.
75  */
76 static int scsb_hsc_numReg = 0;
77 /*
78  * When this flag is set, the board is taken offline (put in reset) after
79  * a unconfigure operation, in Basic Hotswap mode.
80  */
81 static int	scsb_hsc_bhs_slot_reset = 1;
82 /*
83  * When this flag is set, we take the board to reset after unconfigure
84  * operation when operating in full hotswap mode.
85  */
86 static int	scsb_hsc_fhs_slot_reset = 1;
87 /*
88  * Implementation of this counter will work only on Montecarlo since
89  * the ENUM# Interrupt line is not shared with other interrupts.
90  * When the hardware routing changes, then there may be need to remove
91  * or change this functionality.
92  * This functionality is provided so that a bad or non friendly full hotswap
93  * board does not hang the system in full hotswap mode. Atleast the
94  * intent is that! Eventually Solaris kernel will provide similar support
95  * for recovering from a stuck interrupt line. Till then, lets do this.
96  */
97 static int	scsb_hsc_max_intr_count = 8;
98 /*
99  * Since the hardware does not support enabling/disabling ENUM#, the
100  * following flag can be used for imitating that behaviour.
101  * Currently we can set this flag and use the remove op to remove the
102  * interrupt handler from the system. Care must be taken when using this
103  * function since trying to remove the interrupt handler when the interrupts
104  * are pending may hang the system permanently.
105  * Since the hardware does not support this functionality, we adopt this
106  * approach for debugs.
107  */
108 static int	scsb_hsc_enum_switch = 0;
109 
110 /*
111  * When the board loses Healthy# at runtime (with the board being configured),
112  * cPCI specs states that a Reset has to be asserted immediately.
113  * We dont do this currently, until satellite processor support is given
114  * and the implications of such a act is fully understood.
115  * To adopt the cPCI specs recommendation, set this flag to 1.
116  */
117 static	int	scsb_hsc_healthy_reset = 0;
118 
119 /*
120  * According to PCI 2.2 specification, once a board comes out of PCI_RST#,
121  * it may take upto 2^25 clock cycles to respond to config cycles. For
122  * montecarlo using a 33MHz cPCI bus, it's around 1.024 s. The variable
123  * will specify the time in ms to wait before attempting config access.
124  */
125 static	int scsb_connect_delay = 1025;
126 
127 /*
128  * slot map property for MC should be
129  *
130  *	hsc-slot-map="/pci@1f,0/pci@1/pci@1","15","2",
131  *               "/pci@1f,0/pci@1/pci@1","14","3",
132  *               "/pci@1f,0/pci@1/pci@1","13","4",
133  *               "/pci@1f,0/pci@1/pci@1","12","5"
134  *               "/pci@1f,0/pci@1/pci@1","11","6"
135  *               "/pci@1f,0/pci@1/pci@1","10","7"
136  *               "/pci@1f,0/pci@1/pci@1","8","8";
137  *
138  * slot map property for Tonga should be
139  *	hsc-slot-map="/pci@1f,0/pci@1/pci@1","8","1"
140  *		"/pci@1f,0/pci@1/pci@1", "15", "2"
141  *		"/pci@1f,0/pci@1/pci@1", "14", "4"
142  *		"/pci@1f,0/pci@1/pci@1", "13", "5"
143  *
144  * Please note that the CPU slot number is 3 for Tonga.
145  */
146 
147 /*
148  * Services we require from the SCSB
149  */
150 extern int	scsb_get_slot_state(void *, int, int *);
151 extern int	scsb_read_bhealthy(scsb_state_t *scsb);
152 extern int	scsb_read_slot_health(scsb_state_t *scsb, int pslotnum);
153 extern int	scsb_connect_slot(void *, int, int);
154 extern int	scsb_disconnect_slot(void *, int, int);
155 
156 static void	*hsc_state;
157 
158 static uint_t	hsc_enum_intr(char *);
159 static hsc_slot_t *hsc_get_slot_info(hsc_state_t *, int);
160 static int	scsb_enable_enum(hsc_state_t *);
161 static int	scsb_disable_enum(hsc_state_t *, int);
162 static int	atoi(const char *);
163 static int	isdigit(int);
164 static hsc_slot_t *hsc_find_slot(int);
165 static void	hsc_led_op(hsc_slot_t *, int, hpc_led_t, hpc_led_state_t);
166 static int	hsc_led_state(hsc_slot_t *, int, hpc_led_info_t *);
167 static int	scsb_hsc_disable_slot(hsc_slot_t *);
168 static int	scsb_hsc_enable_slot(hsc_slot_t *);
169 #ifndef	lint
170 static int hsc_clear_all_enum(hsc_state_t *);
171 #endif
172 static int	hsc_slot_register(hsc_state_t *, char *, uint16_t, uint_t,
173 					boolean_t);
174 static int	hsc_slot_unregister(int);
175 static int	scsb_hsc_init_slot_state(hsc_state_t *, hsc_slot_t *);
176 static int	hsc_slot_autoconnect(hsc_slot_t *);
177 
178 static hpc_slot_ops_t	*hsc_slotops;
179 static hsc_slot_t	*hsc_slot_list;		/* linked list of slots */
180 
181 /*
182  * This mutex protects the following variables:
183  *	hsc_slot_list
184  */
185 static kmutex_t		hsc_mutex;
186 
187 
188 /* ARGSUSED */
189 static int
190 hsc_connect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags)
191 {
192 	hsc_slot_t *hsp = (hsc_slot_t *)ops_arg;
193 	int rc, rstate;
194 	hsc_state_t	*hsc;
195 
196 	DEBUG2("hsc_connect: slot %d, healthy %d", hsp->hs_slot_number,
197 						hsp->hs_board_healthy);
198 
199 	if (!(hsp->hs_flags & (HSC_ENABLED|HSC_SLOT_ENABLED)))
200 		return (HPC_ERR_FAILED);
201 	/* if SCB hotswapped, do not allow connect operations */
202 	if (hsp->hs_flags & HSC_SCB_HOTSWAPPED)
203 		return (HPC_ERR_FAILED);
204 	/*
205 	 * if previous occupant stayed configured, do not allow another
206 	 * occupant to be connected.
207 	 * This behaviour is an indication that the slot state
208 	 * is not clean.
209 	 */
210 	if (hsp->hs_flags & HSC_SLOT_BAD_STATE) {
211 		/*
212 		 * In the current implementation, we turn both fault
213 		 * and active LEDs to ON state in this situation.
214 		 */
215 		hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
216 							HPC_LED_ON);
217 		return (HPC_ERR_FAILED);
218 	}
219 	/*
220 	 * Get the actual status from the i2c bus
221 	 */
222 	rc = scsb_get_slot_state(hsp->hs_hpchandle, hsp->hs_slot_number,
223 								&rstate);
224 	if (rc != DDI_SUCCESS)
225 		return (HPC_ERR_FAILED);
226 
227 	hsp->hs_slot_state = rstate;
228 	if (hsp->hs_slot_state == HPC_SLOT_EMPTY) {
229 #ifdef DEBUG
230 		cmn_err(CE_CONT,
231 			"?hsc_connect: slot %d is empty\n",
232 			hsp->hs_slot_number);
233 #endif
234 		return (HPC_ERR_FAILED);
235 	}
236 
237 	if (hsp->hs_slot_state == HPC_SLOT_CONNECTED)
238 		return (HPC_SUCCESS);
239 
240 	rc = HPC_SUCCESS;
241 	/*
242 	 * call scsb to connect the slot. This also makes sure board is healthy
243 	 */
244 	if (scsb_connect_slot(hsp->hs_hpchandle, hsp->hs_slot_number,
245 				hsp->hs_board_healthy) != DDI_SUCCESS) {
246 		DEBUG1("hsc_connect: slot %d connection failed",
247 				hsp->hs_slot_number);
248 		rc = HPC_ERR_FAILED;
249 	} else {
250 		if (hsp->hs_slot_state != HPC_SLOT_CONNECTED) {
251 			if (hsp->hs_board_healthy == B_FALSE) {
252 				cmn_err(CE_NOTE, "HEALTHY# not asserted on "
253 					" slot %d", hsp->hs_slot_number);
254 				return (HPC_ERR_FAILED);
255 			}
256 			hsc = hsp->hsc;
257 			hsc->hsp_last = hsp;
258 			if (scsb_reset_slot(hsp->hs_hpchandle,
259 				hsp->hs_slot_number, SCSB_UNRESET_SLOT) != 0) {
260 
261 				return (HPC_ERR_FAILED);
262 			}
263 			/*
264 			 * Unresetting a board may have caused an interrupt
265 			 * burst in case of non friendly boards. So it is
266 			 * important to make sure that the ISR has not
267 			 * put this board back to disconnect state.
268 			 */
269 			delay(1);
270 			if (hsp->hs_flags & HSC_ENUM_FAILED) {
271 				hsp->hs_flags &= ~HSC_ENUM_FAILED;
272 				return (HPC_ERR_FAILED);
273 			}
274 			DEBUG1("hsc_connect: slot %d connected",
275 						hsp->hs_slot_number);
276 			rc = HPC_SUCCESS;
277 			hsp->hs_slot_state = HPC_SLOT_CONNECTED;
278 			(void) hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
279 				HPC_FAULT_LED, HPC_LED_OFF);
280 		}
281 	}
282 
283 	/*
284 	 * PCI 2.2 specs recommend that the probe software wait
285 	 * for upto 2^25 PCI clock cycles after deassertion of
286 	 * PCI_RST# before the board is able to respond to config
287 	 * cycles. So, before we return, we wait for ~1 sec.
288 	 */
289 	delay(drv_usectohz(scsb_connect_delay * 1000));
290 	return (rc);
291 }
292 
293 
294 /* ARGSUSED */
295 static int
296 hsc_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags)
297 {
298 	hsc_slot_t		*hsp = (hsc_slot_t *)ops_arg;
299 	hsc_state_t		*hsc;
300 #ifdef	DEBUG
301 	static const char	func[] = "hsc_disconnect";
302 #endif
303 
304 	DEBUG1("hsc_disconnect: slot %d", hsp->hs_slot_number);
305 
306 	if (hsp->hs_board_configured) {
307 #ifdef	DEBUG
308 		cmn_err(CE_NOTE,
309 			"%s: cannot disconnect configured board in slot %d",
310 			func, hsp->hs_slot_number);
311 #endif
312 		return (HPC_ERR_FAILED);
313 	}
314 
315 	if (hsp->hs_slot_state == HPC_SLOT_EMPTY) {
316 #ifdef	DEBUG
317 		cmn_err(CE_NOTE, "%s: slot %d is empty",
318 			func, hsp->hs_slot_number);
319 #endif
320 		return (HPC_SUCCESS);
321 	}
322 
323 	if (hsp->hs_slot_state == HPC_SLOT_DISCONNECTED) {
324 		/*
325 		 * if already disconnected, just return success
326 		 * Duplicate disconnect messages should not be failed!
327 		 */
328 		return (HPC_SUCCESS);
329 	}
330 	/* if SCB hotswapped, do not allow disconnect operations */
331 	if (hsp->hs_flags & HSC_SCB_HOTSWAPPED)
332 		return (HPC_ERR_FAILED);
333 
334 	/* call scsb to disconnect the slot */
335 	if (scsb_disconnect_slot(hsp->hs_hpchandle, B_TRUE, hsp->hs_slot_number)
336 			!= DDI_SUCCESS)
337 		return (HPC_ERR_FAILED);
338 	hsc = hsp->hsc;
339 	if (hsc->hsp_last == hsp)
340 		hsc->hsp_last = NULL;
341 
342 	return (HPC_SUCCESS);
343 }
344 
345 
346 /*
347  * In the cPCI world, this operation is not applicable.
348  * However, we use this function to enable full hotswap mode in debug mode.
349  */
350 /* ARGSUSED */
351 static int
352 hsc_insert(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags)
353 {
354 	hsc_slot_t		*hsp = (hsc_slot_t *)ops_arg;
355 
356 	if (scsb_hsc_enum_switch &&
357 			(scsb_enable_enum(hsp->hsc) == DDI_SUCCESS)) {
358 		return (HPC_SUCCESS);
359 	}
360 	return (HPC_ERR_NOTSUPPORTED);
361 }
362 
363 
364 /*
365  * In the cPCI world, this operation is not applicable.
366  * However, we use this function to disable full hotswap mode in debug mode.
367  */
368 /* ARGSUSED */
369 static int
370 hsc_remove(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags)
371 {
372 	hsc_slot_t		*hsp = (hsc_slot_t *)ops_arg;
373 
374 	if (scsb_hsc_enum_switch &&
375 			(scsb_disable_enum(hsp->hsc, SCSB_HSC_FORCE_REMOVE)
376 					== DDI_SUCCESS)) {
377 		hsp->hs_flags &= ~HSC_ENUM_FAILED;
378 		return (HPC_SUCCESS);
379 	}
380 	return (HPC_ERR_NOTSUPPORTED);
381 }
382 
383 static void
384 hsc_led_op(hsc_slot_t *hsp, int cmd, hpc_led_t led, hpc_led_state_t led_state)
385 {
386 	hpc_led_info_t	ledinfo;
387 
388 	ledinfo.led = led;
389 	ledinfo.state = led_state;
390 	(void) hsc_led_state(hsp, cmd, &ledinfo);
391 }
392 
393 static int
394 hsc_led_state(hsc_slot_t *hsp, int cmd, hpc_led_info_t *hlip)
395 {
396 	hpc_led_state_t	*hlsp;
397 	scsb_uinfo_t	sunit;
398 	int		res;
399 
400 	DEBUG3("hsc_led_state: slot %d, led %x, state %x",
401 		hsp->hs_slot_number, hlip->led, hlip->state);
402 
403 	sunit.unit_type = SLOT;
404 	sunit.unit_number = hsp->hs_slot_number;
405 	/*
406 	 * We ignore operations on LEDs that we don't support
407 	 */
408 	switch (hlip->led) {
409 		case HPC_FAULT_LED:
410 			sunit.led_type = NOK;
411 			hlsp = &hsp->hs_fault_led_state;
412 			break;
413 		case HPC_ACTIVE_LED:
414 			sunit.led_type = OK;
415 			hlsp = &hsp->hs_active_led_state;
416 			break;
417 		default:
418 			return (HPC_ERR_NOTSUPPORTED);
419 	}
420 
421 	switch (hlip->state) {
422 		case HPC_LED_BLINK:
423 			sunit.unit_state = BLINK;
424 			if (hlip->led != HPC_ACTIVE_LED)
425 				return (HPC_ERR_NOTSUPPORTED);
426 			break;
427 		case HPC_LED_ON:
428 			sunit.unit_state = ON;
429 			break;
430 		case HPC_LED_OFF:
431 			sunit.unit_state = OFF;
432 			break;
433 		default:
434 			break;
435 	}
436 
437 	switch (cmd) {
438 	case HPC_CTRL_SET_LED_STATE:
439 		res = scsb_led_set(hsp->hs_hpchandle, &sunit, sunit.led_type);
440 		if (res != 0)
441 			return (HPC_ERR_FAILED);
442 		*hlsp = (hpc_led_state_t)sunit.unit_state;
443 		break;
444 
445 	case HPC_CTRL_GET_LED_STATE:
446 		res = scsb_led_get(hsp->hs_hpchandle, &sunit, sunit.led_type);
447 		if (res)
448 			return (HPC_ERR_FAILED);
449 		/* hlip->state = sunit.unit_state; */
450 		break;
451 
452 	default:
453 		return (HPC_ERR_INVALID);
454 	}
455 
456 	return (HPC_SUCCESS);
457 
458 }
459 
460 
461 static int
462 hsc_get_slot_state(hsc_slot_t *hsp, hpc_slot_state_t *hssp)
463 {
464 	int rstate = 0;
465 	int rc;
466 #ifdef	DEBUG
467 	int orstate;	/* original rstate */
468 #endif
469 
470 	DEBUG1("hsc_get_slot_state: slot %d", hsp->hs_slot_number);
471 	rc = scsb_get_slot_state(hsp->hs_hpchandle, hsp->hs_slot_number,
472 								&rstate);
473 	if (rc != DDI_SUCCESS)
474 		return (HPC_ERR_FAILED);
475 #ifdef	DEBUG
476 	orstate = hsp->hs_slot_state;
477 #endif
478 	hsp->hs_slot_state = rstate;
479 	switch (hsp->hs_slot_state) {
480 	case HPC_SLOT_EMPTY:
481 		DEBUG0("empty");
482 		break;
483 	case HPC_SLOT_CONNECTED:
484 		DEBUG0("connected");
485 		break;
486 	case HPC_SLOT_DISCONNECTED:
487 		DEBUG0("disconnected");
488 		break;
489 	}
490 
491 	*hssp = hsp->hs_slot_state;
492 
493 	/* doing get-state above may have caused a freeze operation */
494 	if ((hsp->hs_flags & HSC_SCB_HOTSWAPPED) &&
495 			(rstate == HPC_SLOT_DISCONNECTED)) {
496 		/* freeze puts disconnected boards to connected state */
497 		*hssp = HPC_SLOT_CONNECTED;
498 #if 0
499 		/* in FHS, deassertion of reset may have configured the board */
500 		if (hsp->hs_board_configured == B_TRUE) {
501 			hsp->hs_slot_state = *hssp;
502 		}
503 #endif
504 	}
505 #ifdef	DEBUG
506 	/* a SCB hotswap may have forced a state change on the receptacle */
507 	if (orstate != *hssp) {
508 		cmn_err(CE_NOTE, "hsc_get_state: slot%d state change due"
509 			" to SCB hotswap!", hsp->hs_slot_number);
510 	}
511 #endif
512 	return (HPC_SUCCESS);
513 }
514 
515 
516 static int
517 hsc_set_config_state(hsc_slot_t *hsp, int cmd)
518 {
519 	hsc_state_t	*hsc = hsp->hsc;
520 
521 	DEBUG1("hsc_set_config_state: slot %d", hsp->hs_slot_number);
522 
523 	switch (cmd) {
524 	case HPC_CTRL_DEV_CONFIGURED:
525 		/*
526 		 * Closing of the Ejector switch in configured/busy state can
527 		 * cause duplicate CONFIGURED messages to come down.
528 		 * Make sure our LED states are fine.
529 		 */
530 		if (hsp->hs_board_configured == B_TRUE) {
531 			hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
532 								HPC_LED_ON);
533 			break;
534 		}
535 		hsp->hs_board_configured = B_TRUE;
536 		hsp->hs_board_configuring = B_FALSE;
537 		if ((hsc->state & HSC_ATTACHED) == HSC_ATTACHED &&
538 			hsp->hs_flags & HSC_ALARM_CARD_PRES)
539 			(void) scsb_hsc_ac_op(hsp->hs_hpchandle,
540 				hsp->hs_slot_number, SCSB_HSC_AC_CONFIGURED);
541 		/* LED must be OFF on the occupant. */
542 		(void) hpc_slot_event_notify(hsp->hs_slot_handle,
543 					HPC_EVENT_SLOT_BLUE_LED_OFF, 0);
544 		if (hsp->hs_flags & HSC_AUTOCFG)
545 			(void) hpc_slot_event_notify(hsp->hs_slot_handle,
546 					HPC_EVENT_ENABLE_ENUM, 0);
547 		else
548 			(void) hpc_slot_event_notify(hsp->hs_slot_handle,
549 					HPC_EVENT_DISABLE_ENUM, 0);
550 		hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
551 								HPC_LED_ON);
552 		if (hsc->hsp_last == hsp)
553 			hsc->hsp_last = NULL;
554 		break;
555 	case HPC_CTRL_DEV_UNCONFIGURED:
556 		hsp->hs_board_configured = B_FALSE;
557 		hsp->hs_board_unconfiguring = B_FALSE;
558 		hsp->hs_flags &= ~HSC_SLOT_BAD_STATE;
559 		if (hsp->hs_flags & HSC_ALARM_CARD_PRES)
560 			(void) scsb_hsc_ac_op(hsp->hs_hpchandle,
561 				hsp->hs_slot_number, SCSB_HSC_AC_UNCONFIGURED);
562 		hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
563 							HPC_LED_BLINK);
564 		if (((hsc->state & HSC_ENUM_ENABLED) &&
565 			scsb_hsc_fhs_slot_reset) ||
566 		(((hsc->state & HSC_ENUM_ENABLED) != HSC_ENUM_ENABLED) &&
567 				scsb_hsc_bhs_slot_reset) ||
568 				((hsp->hs_flags & HSC_AUTOCFG) !=
569 					HSC_AUTOCFG)) {
570 			if (scsb_reset_slot(hsp->hs_hpchandle,
571 				hsp->hs_slot_number, SCSB_RESET_SLOT) == 0) {
572 
573 				hsp->hs_slot_state = HPC_SLOT_DISCONNECTED;
574 				hsp->hs_board_healthy = B_FALSE;
575 				hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
576 					HPC_FAULT_LED, HPC_LED_ON);
577 			}
578 		}
579 		break;
580 	case HPC_CTRL_DEV_CONFIG_FAILURE:
581 		hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
582 							HPC_LED_BLINK);
583 		hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
584 				HPC_FAULT_LED, HPC_LED_ON);
585 		break;
586 	case HPC_CTRL_DEV_UNCONFIG_FAILURE:
587 		hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
588 							HPC_LED_ON);
589 		break;
590 	case HPC_CTRL_DEV_CONFIG_START:
591 	case HPC_CTRL_DEV_UNCONFIG_START:
592 			hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_FAULT_LED,
593 					HPC_LED_OFF);
594 			hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE, HPC_ACTIVE_LED,
595 					HPC_LED_BLINK);
596 		break;
597 	default:
598 		return (HPC_ERR_INVALID);
599 	}
600 
601 	if (cmd != HPC_CTRL_DEV_CONFIG_START &&
602 		cmd != HPC_CTRL_DEV_UNCONFIG_START &&
603 		hsc->regDone == B_FALSE &&
604 			scsb_hsc_numReg < hsc->n_registered_occupants) {
605 		scsb_hsc_numReg++;
606 
607 		/*
608 		 * If the callback is invoked for all registered slots,
609 		 * enable ENUM.
610 		 */
611 		if (((hsc->state & HSC_ATTACHED) == HSC_ATTACHED) &&
612 			(scsb_hsc_numReg == hsc->n_registered_occupants)) {
613 			hsc->regDone = B_TRUE;
614 			if (hsc->hotswap_mode == HSC_HOTSWAP_MODE_FULL) {
615 #ifdef DEBUG
616 				cmn_err(CE_CONT, "%s%d: Enabling full hotswap"
617 					":%d non-empty slots\n",
618 					ddi_driver_name(hsc->dip),
619 					ddi_get_instance(hsc->dip),
620 					hsc->n_registered_occupants);
621 #endif
622 				if (scsb_enable_enum(hsc) != DDI_SUCCESS) {
623 					cmn_err(CE_WARN, "%s#%d: Cannot enable "
624 						"Full Hotswap",
625 						ddi_driver_name(hsc->dip),
626 						ddi_get_instance(hsc->dip));
627 
628 					return (HPC_ERR_FAILED);
629 				}
630 			}
631 		}
632 	}
633 
634 	return (HPC_SUCCESS);
635 }
636 
637 
638 /*ARGSUSED*/
639 static int
640 hsc_get_board_type(hsc_slot_t *hsp, hpc_board_type_t *hbtp)
641 {
642 	*hbtp = hsp->hs_board_type;
643 	return (HPC_SUCCESS);
644 }
645 
646 
647 /* ARGSUSED */
648 static int
649 hsc_autoconfig(hsc_slot_t *hsp, int cmd)
650 {
651 	int res = HPC_SUCCESS, enum_disable = B_TRUE, i;
652 	char slotautocfg_prop[18];
653 	hsc_state_t *hsc;
654 
655 	DEBUG1("hsc_autoconfig: slot %d", hsp->hs_slot_number);
656 	(void) sprintf(slotautocfg_prop, "slot%d-autoconfig",
657 	    hsp->hs_slot_number);
658 
659 	if (cmd == HPC_CTRL_ENABLE_AUTOCFG) {
660 		hsp->hs_flags |= HSC_AUTOCFG;
661 		(void) ddi_prop_update_string(DDI_DEV_T_NONE, hsp->hsc->dip,
662 				slotautocfg_prop, "enabled");
663 		if ((res = scsb_enable_enum(hsp->hsc)) == DDI_SUCCESS) {
664 			(void) hpc_slot_event_notify(hsp->hs_slot_handle,
665 					HPC_EVENT_ENABLE_ENUM, 0);
666 		}
667 	} else {
668 		(void) ddi_prop_update_string(DDI_DEV_T_NONE, hsp->hsc->dip,
669 		    slotautocfg_prop, "disabled");
670 		hsp->hs_flags &= ~HSC_AUTOCFG;
671 		hsc = hsp->hsc;
672 		if (hsc->state & HSC_ATTACHED) {
673 			(void) hpc_slot_event_notify(hsp->hs_slot_handle,
674 						HPC_EVENT_DISABLE_ENUM, 0);
675 			for (i = 0; i < hsc->slot_table_size; i++) {
676 				hsc_slot_t	*thsp;
677 				int slotnum;
678 
679 				slotnum = hsc->slot_table_prop[i].pslotnum;
680 				thsp = hsc_find_slot(slotnum);
681 				if (thsp == NULL) {
682 					cmn_err(CE_WARN, "%s#%d: hsc_autocfg:"
683 						"No Slot Info for slot %d",
684 						ddi_driver_name(hsc->dip),
685 						ddi_get_instance(hsc->dip),
686 						slotnum);
687 					continue;
688 				}
689 				if (thsp->hs_flags & HSC_AUTOCFG) {
690 					enum_disable = B_FALSE;
691 					break;
692 				}
693 			}
694 			if (enum_disable == B_TRUE)
695 				(void) scsb_disable_enum(hsc,
696 				    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 	(void) 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 		(void) hsc_autoconfig(hsp, HPC_CTRL_DISABLE_AUTOCFG);
821 		hsp->hs_flags &= ~HSC_SLOT_ENABLED;
822 		(void) 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 	(void) 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 		(void) hsc_autoconfig(hsp, HPC_CTRL_ENABLE_AUTOCFG);
842 		hsp->hs_flags |= HSC_SLOT_ENABLED;
843 		(void) 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 	(void) 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 		(void) 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 			(void) 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 				(void) scsb_reset_slot(hsc->scsb_handle,
1070 				    slot_number, 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 			(void) 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 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, hsc->dip,
1432 	    HOTSWAP_MODE_PROP, "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 		(void) 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 			(void) 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 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, hsc->dip,
1763 	    HOTSWAP_MODE_PROP, "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 		(void) sprintf(slotautocfg_prop, "slot%d-autoconfig",
1826 		    hsp->hs_slot_number);
1827 		(void) ddi_prop_remove(DDI_DEV_T_NONE, hsc->dip,
1828 		    slotautocfg_prop);
1829 		if (hsc_slot_unregister(hsc->slot_table_prop[i].pslotnum)
1830 						!= 0) {
1831 			cmn_err(CE_NOTE, "%s#%d: failed to unregister"
1832 				" slot %d\n", ddi_driver_name(dip),
1833 				ddi_get_instance(dip),
1834 				hsc->slot_table_prop[i].pslotnum);
1835 			return (DDI_FAILURE);
1836 		}
1837 	}
1838 	kmem_free(hsc->slot_table_prop, (hsc->slot_table_size *
1839 					sizeof (hsc_slot_table_t)));
1840 	if ((hsc->state & HSC_ENUM_ENABLED) == HSC_ENUM_ENABLED) {
1841 		ddi_remove_intr(hsc->dip, 1, hsc->enum_iblock);
1842 		hsc->state &= ~HSC_ENUM_ENABLED;
1843 	}
1844 	mutex_destroy(&hsc->hsc_mutex);
1845 	(void) ddi_prop_remove(DDI_DEV_T_NONE, hsc->dip, HOTSWAP_MODE_PROP);
1846 	hsc->state &= ~(HSC_ATTACHED|HSC_SCB_CONNECTED);
1847 	ddi_soft_state_free(hsc_state, instance);
1848 	return (DDI_SUCCESS);
1849 }
1850 
1851 /*
1852  * The following function is called when the SCSB is hot extracted from
1853  * the system.
1854  */
1855 int
1856 scsb_hsc_freeze(dev_info_t *dip)
1857 {
1858 	hsc_state_t	*hsc;
1859 	int instance = ddi_get_instance(dip);
1860 	int i;
1861 	hsc_slot_t	*hsp;
1862 
1863 	hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance);
1864 	if (hsc == NULL) {
1865 		DEBUG2("%s#%d: Soft state NULL",
1866 				ddi_driver_name(dip), ddi_get_instance(dip));
1867 		return (DDI_SUCCESS);
1868 	}
1869 	if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED)
1870 		return (DDI_SUCCESS);
1871 	hsc->state &= ~HSC_SCB_CONNECTED;
1872 
1873 	for (i = 0; i < hsc->slot_table_size; i++) {
1874 		hsp = hsc_find_slot(hsc->slot_table_prop[i].pslotnum);
1875 
1876 		if (hsp == NULL) {
1877 			cmn_err(CE_NOTE, "hsc_freeze: "
1878 				" Cannot map slot number %d to a hsc_slot_t",
1879 					hsc->slot_table_prop[i].pslotnum);
1880 			continue;
1881 		}
1882 		/*
1883 		 * Since reset lines are pulled low, lets mark these
1884 		 * slots and not allow a connect operation.
1885 		 * Note that we still keep the slot as slot disconnected,
1886 		 * although it is connected from the hardware standpoint.
1887 		 * As soon as the SCB is plugged back in, we check these
1888 		 * states and put the hardware state back to its original
1889 		 * state.
1890 		 */
1891 		if (hsp->hs_slot_state == HPC_SLOT_DISCONNECTED) {
1892 			cmn_err(CE_WARN, "%s#%d: Slot %d Now out of Reset!",
1893 				ddi_driver_name(hsc->dip),
1894 				ddi_get_instance(hsc->dip),
1895 				hsp->hs_slot_number);
1896 		}
1897 		hsp->hs_flags |= HSC_SCB_HOTSWAPPED;
1898 	}
1899 
1900 	return (DDI_SUCCESS);
1901 }
1902 
1903 /*
1904  * The following function is called when the SCSB is hot inserted from
1905  * the system. We must update the LED status and set the RST# registers
1906  * again.
1907  */
1908 int
1909 scsb_hsc_restore(dev_info_t *dip)
1910 {
1911 	int i;
1912 	hsc_state_t	*hsc;
1913 	hsc_slot_t	*hsp;
1914 	int instance = ddi_get_instance(dip);
1915 
1916 	hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance);
1917 	if (hsc == NULL) {
1918 		DEBUG2("%s#%d: Soft state NULL",
1919 				ddi_driver_name(dip), ddi_get_instance(dip));
1920 		return (DDI_SUCCESS);
1921 	}
1922 
1923 	if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED)
1924 		return (DDI_SUCCESS);
1925 	hsc->state |= HSC_SCB_CONNECTED;
1926 	for (i = 0; i < hsc->slot_table_size; i++) {
1927 		hsp = hsc_find_slot(hsc->slot_table_prop[i].pslotnum);
1928 
1929 		if (hsp == NULL) {
1930 			cmn_err(CE_NOTE, "%s#%d: hsc_restore: "
1931 				" Cannot map slot number %d to a hsc_slot_t",
1932 					ddi_driver_name(hsc->dip),
1933 					ddi_get_instance(hsc->dip),
1934 					hsc->slot_table_prop[i].pslotnum);
1935 			continue;
1936 		}
1937 		if ((hsp->hs_slot_state == HPC_SLOT_DISCONNECTED) &&
1938 				(hsp->hs_board_configured == B_FALSE)) {
1939 			if (scsb_reset_slot(hsp->hs_hpchandle,
1940 					hsp->hs_slot_number,
1941 					SCSB_RESET_SLOT) != 0) {
1942 				cmn_err(CE_WARN, "%s#%d: hsc_restore: "
1943 					" Cannot reset disconnected slot %d",
1944 						ddi_driver_name(hsc->dip),
1945 						ddi_get_instance(hsc->dip),
1946 						hsp->hs_slot_number);
1947 			}
1948 		}
1949 
1950 		if (scsb_hsc_init_slot_state(hsc, hsp) != DDI_SUCCESS) {
1951 
1952 			cmn_err(CE_WARN, "%s#%d: hsc_freeze: Cannot init"
1953 				" slot%d state",
1954 				ddi_driver_name(hsc->dip),
1955 				ddi_get_instance(hsc->dip),
1956 				hsp->hs_slot_number);
1957 		}
1958 		hsp->hs_flags &= ~HSC_SCB_HOTSWAPPED;
1959 	}
1960 	return (DDI_SUCCESS);
1961 }
1962 
1963 #ifndef	lint
1964 int
1965 scsb_hsc_freeze_check(dev_info_t *dip)
1966 {
1967 	hsc_state_t	*hsc;
1968 	int instance = ddi_get_instance(dip);
1969 
1970 	hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance);
1971 	if (hsc == NULL) {
1972 		DEBUG2("%s#%d: Soft state NULL",
1973 				ddi_driver_name(dip), ddi_get_instance(dip));
1974 		return (DDI_SUCCESS);
1975 	}
1976 	if ((hsc->state & HSC_ATTACHED) != HSC_ATTACHED)
1977 		return (DDI_SUCCESS);
1978 	return (DDI_SUCCESS);
1979 }
1980 #endif
1981 
1982 /*
1983  * update info about Alarm Card insert/remove mechanism.
1984  */
1985 void
1986 hsc_ac_op(int instance, int pslotnum, int op, void *arg)
1987 {
1988 	hsc_slot_t *hsp;
1989 	hsc_state_t	*hsc;
1990 
1991 	hsc = (hsc_state_t *)ddi_get_soft_state(hsc_state, instance);
1992 	if (hsc == NULL) {
1993 		cmn_err(CE_WARN, "%s#%d: hsc_ac_op: No Soft State Info",
1994 			ddi_driver_name(hsc->dip), ddi_get_instance(hsc->dip));
1995 		return;
1996 	}
1997 
1998 	hsp = hsc_find_slot(pslotnum);
1999 	if (hsp == NULL) {
2000 		cmn_err(CE_WARN, "%s#%d: hsc_ac_op: No Slot Info",
2001 			ddi_driver_name(hsc->dip), ddi_get_instance(hsc->dip));
2002 		return;
2003 	}
2004 
2005 	switch (op) {
2006 		case SCSB_HSC_AC_UNCONFIGURE :
2007 			/*
2008 			 * If ENUM# is enabled, then action is pending on
2009 			 * this slot, just send a event.
2010 			 */
2011 			if (hsc->state & HSC_ENUM_ENABLED)
2012 				(void) hpc_slot_event_notify(
2013 				    hsp->hs_slot_handle,
2014 				    HPC_EVENT_PROCESS_ENUM, 0);
2015 			break;
2016 		case SCSB_HSC_AC_GET_SLOT_INFO :
2017 			*(hsc_slot_t **)arg = hsp;
2018 			break;
2019 		default :
2020 			break;
2021 	}
2022 }
2023 
2024 static uint_t
2025 hsc_enum_intr(caddr_t iarg)
2026 {
2027 	int rc;
2028 	hsc_state_t *hsc = (hsc_state_t *)iarg;
2029 	hsc_slot_t *hsp;
2030 
2031 	DEBUG0("!E!");
2032 	if ((hsc->state & HSC_ATTACHED) == 0)
2033 		return (DDI_INTR_UNCLAIMED);
2034 
2035 	hsp = hsc_find_slot(hsc->slot_table_prop[0].pslotnum);
2036 	if (hsp == NULL)	/* No slots registered */
2037 		return (DDI_INTR_UNCLAIMED);
2038 
2039 	/*
2040 	 * The following must be done to clear interrupt (synchronous event).
2041 	 * To process the interrupt, we send an asynchronous event.
2042 	 */
2043 	rc = hpc_slot_event_notify(hsp->hs_slot_handle,
2044 					HPC_EVENT_CLEAR_ENUM,
2045 						HPC_EVENT_SYNCHRONOUS);
2046 	if (rc == HPC_EVENT_UNCLAIMED) {
2047 		/*
2048 		 * possible support for handling insertion of non friendly
2049 		 * full hotswap boards, otherwise the system hangs due
2050 		 * to uncleared interrupt bursts.
2051 		 */
2052 		DEBUG2("!E>counter %d, last op@slot %lx\n",
2053 				hsc->hsc_intr_counter, hsc->hsp_last);
2054 		hsc->hsc_intr_counter ++;
2055 		if (hsc->hsc_intr_counter == scsb_hsc_max_intr_count) {
2056 			if (!hsc->hsp_last) {
2057 				cmn_err(CE_WARN, "%s#%d: hsc_enum_intr: "
2058 					" No Last Board Insertion Info.",
2059 					ddi_driver_name(hsc->dip),
2060 					ddi_get_instance(hsc->dip));
2061 				hsc->hsc_intr_counter = 0;
2062 				return (DDI_INTR_UNCLAIMED);
2063 			}
2064 			hsp = hsc->hsp_last;
2065 			cmn_err(CE_WARN, "%s#%d: Bad (non friendly ?) Board "
2066 				"in Slot %d ? Taking it Offline.",
2067 				ddi_driver_name(hsc->dip),
2068 				ddi_get_instance(hsc->dip),
2069 				hsp->hs_slot_number);
2070 			/*
2071 			 * this should put just inserted board back in
2072 			 * reset, thus deasserting the ENUM# and the
2073 			 * system hang.
2074 			 */
2075 			if (scsb_reset_slot(hsp->hs_hpchandle,
2076 					hsp->hs_slot_number,
2077 					SCSB_RESET_SLOT) == 0) {
2078 				/* Enumeration failed on this board */
2079 				hsp->hs_flags |= HSC_ENUM_FAILED;
2080 				if (hsp->hs_board_configured == B_TRUE)
2081 					cmn_err(CE_WARN, "%s#%d: ALERT! System"
2082 						" now in Inconsistent State."
2083 						" Halt!",
2084 					    ddi_driver_name(hsc->dip),
2085 					    ddi_get_instance(hsc->dip));
2086 				hsc_led_op(hsp, HPC_CTRL_SET_LED_STATE,
2087 						HPC_FAULT_LED, HPC_LED_ON);
2088 			}
2089 			hsc->hsc_intr_counter = 0;
2090 		}
2091 		return (DDI_INTR_UNCLAIMED);
2092 	}
2093 	hsc->hsc_intr_counter = 0;
2094 	/*
2095 	 * if interrupt success, rc denotes the PCI device number which
2096 	 * generated the ENUM# interrupt.
2097 	 */
2098 	hsp = hsc_get_slot_info(hsc, rc);
2099 	if (hsp == NULL) {
2100 		cmn_err(CE_WARN, "%s#%d: hsc_enum_intr: no slot info for "
2101 			"dev %x", ddi_driver_name(hsc->dip),
2102 			ddi_get_instance(hsc->dip), rc);
2103 		return (DDI_INTR_CLAIMED);	/* interrupt already cleared */
2104 	}
2105 	/* if this is Alarm Card and if it is busy, dont process event */
2106 	if (hsp->hs_flags & HSC_ALARM_CARD_PRES) {
2107 		if (scsb_hsc_ac_op(hsp->hs_hpchandle, hsp->hs_slot_number,
2108 						SCSB_HSC_AC_BUSY) == B_TRUE) {
2109 			/*
2110 			 * Busy means we need to inform (envmond)alarmcard.so
2111 			 * that it should save the AC configuration, stop the
2112 			 * heartbeat, and shutdown the RSC link.
2113 			 */
2114 			(void) scsb_hsc_ac_op(hsp->hs_hpchandle,
2115 					hsp->hs_slot_number,
2116 					SCSB_HSC_AC_REMOVAL_ALERT);
2117 			return (DDI_INTR_CLAIMED);
2118 		}
2119 	}
2120 	/*
2121 	 * If SCB was swapped out, dont process ENUM#. We put this slot
2122 	 * back in reset after SCB is inserted.
2123 	 */
2124 	if ((hsp->hs_flags & HSC_SCB_HOTSWAPPED) &&
2125 			(hsp->hs_slot_state == HPC_SLOT_DISCONNECTED))
2126 		return (DDI_INTR_CLAIMED);
2127 
2128 	(void) hpc_slot_event_notify(hsp->hs_slot_handle,
2129 	    HPC_EVENT_PROCESS_ENUM, 0);
2130 	return (DDI_INTR_CLAIMED);
2131 }
2132 /*
2133  * A routine to convert a number (represented as a string) to
2134  * the integer value it represents.
2135  */
2136 
2137 static int
2138 isdigit(int ch)
2139 {
2140 	return (ch >= '0' && ch <= '9');
2141 }
2142 
2143 #define	isspace(c)	((c) == ' ' || (c) == '\t' || (c) == '\n')
2144 #define	bad(val)	(val == NULL || !isdigit(*val))
2145 
2146 static int
2147 atoi(const char *p)
2148 {
2149 	int n;
2150 	int c, neg = 0;
2151 
2152 	if (!isdigit(c = *p)) {
2153 		while (isspace(c))
2154 			c = *++p;
2155 		switch (c) {
2156 			case '-':
2157 				neg++;
2158 				/* FALLTHROUGH */
2159 			case '+':
2160 			c = *++p;
2161 		}
2162 		if (!isdigit(c))
2163 			return (0);
2164 	}
2165 	for (n = '0' - c; isdigit(c = *++p); ) {
2166 		n *= 10; /* two steps to avoid unnecessary overflow */
2167 		n += '0' - c; /* accum neg to avoid surprises at MAX */
2168 	}
2169 	return (neg ? n : -n);
2170 }
2171