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
hsc_connect(caddr_t ops_arg,hpc_slot_t slot_hdl,void * data,uint_t flags)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
hsc_disconnect(caddr_t ops_arg,hpc_slot_t slot_hdl,void * data,uint_t flags)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
hsc_insert(caddr_t ops_arg,hpc_slot_t slot_hdl,void * data,uint_t flags)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
hsc_remove(caddr_t ops_arg,hpc_slot_t slot_hdl,void * data,uint_t flags)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
hsc_led_op(hsc_slot_t * hsp,int cmd,hpc_led_t led,hpc_led_state_t led_state)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
hsc_led_state(hsc_slot_t * hsp,int cmd,hpc_led_info_t * hlip)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
hsc_get_slot_state(hsc_slot_t * hsp,hpc_slot_state_t * hssp)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
hsc_set_config_state(hsc_slot_t * hsp,int cmd)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
hsc_get_board_type(hsc_slot_t * hsp,hpc_board_type_t * hbtp)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
hsc_autoconfig(hsc_slot_t * hsp,int cmd)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
hsc_slot_enable(hsc_slot_t * hsp,boolean_t enabled)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
hsc_control(caddr_t ops_arg,hpc_slot_t slot_hdl,int request,caddr_t arg)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
scsb_hsc_disable_slot(hsc_slot_t * hsp)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
scsb_hsc_enable_slot(hsc_slot_t * hsp)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 *
hsc_alloc_slot(uint16_t device_number,int slot_number,boolean_t board_in_slot)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
hsc_free_slot(hsc_slot_t * hsp)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
hsc_slot_register(hsc_state_t * hsc,char * bus_path,uint16_t device_number,uint_t slot_number,boolean_t board_in_slot)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
hsc_slot_unregister(int slot_number)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
scsb_hsc_init_slot_state(hsc_state_t * hsc,hsc_slot_t * hsp)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 *
hsc_get_slot_info(hsc_state_t * hsc,int pci_devno)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 *
hsc_find_slot(int slot_number)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
hsc_slot_occupancy(int slot_number,boolean_t occupied,int flags,int healthy)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
scsb_hsc_board_healthy(int slot_number,boolean_t healthy)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
hsc_slot_autoconnect(hsc_slot_t * hsp)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
hsc_init()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
hsc_fini()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
scsb_enable_enum(hsc_state_t * hsc)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
scsb_disable_enum(hsc_state_t * hsc,int op)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
hsc_clear_all_enum(hsc_state_t * hsc)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
scsb_hsc_attach(dev_info_t * dip,void * scsb_handle,int instance)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
scsb_hsc_detach(dev_info_t * dip,void * scsb_handle,int instance)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
scsb_hsc_freeze(dev_info_t * dip)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
scsb_hsc_restore(dev_info_t * dip)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
scsb_hsc_freeze_check(dev_info_t * dip)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
hsc_ac_op(int instance,int pslotnum,int op,void * arg)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
hsc_enum_intr(caddr_t iarg)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
isdigit(int ch)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
atoi(const char * p)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