Print this page
5083 avoid undefined order of operations in assignments
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/sun4u/serengeti/io/sghsc.c
+++ new/usr/src/uts/sun4u/serengeti/io/sghsc.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27
28 28 /*
29 29 *
30 30 * Serengeti CompactPCI Hot Swap Controller Driver.
31 31 *
32 32 */
33 33
34 34 #include <sys/types.h>
35 35 #include <sys/cmn_err.h>
36 36 #include <sys/kmem.h>
37 37 #include <sys/errno.h>
38 38 #include <sys/cpuvar.h>
39 39 #include <sys/open.h>
40 40 #include <sys/stat.h>
41 41 #include <sys/conf.h>
42 42 #include <sys/ddi.h>
43 43 #include <sys/sunddi.h>
44 44 #include <sys/modctl.h>
45 45 #include <sys/ksynch.h>
46 46 #include <sys/pci.h>
47 47 #include <sys/serengeti.h>
48 48 #include <sys/sghsc.h>
49 49 #include <sys/promif.h>
50 50
51 51 /*
52 52 * Debug flags
53 53 */
54 54
55 55 int sghsc_configure_ack = 0;
56 56 int cpci_enable = 1;
57 57 #ifdef DEBUG
58 58 #define SGHSC_DEBUG
59 59 #endif
60 60
61 61 #ifdef SGHSC_DEBUG
62 62 int sghsc_debug = 0;
63 63 #define DEBUGF(level, args) \
64 64 { if (sghsc_debug >= (level)) cmn_err args; }
65 65 #define DEBUGON sghsc_debug = 3
66 66 #define DEBUGOFF sghsc_debug = 0
67 67 #else
68 68 #define DEBUGF(level, args) /* nothing */
69 69 #define DEBUGON
70 70 #define DEBUGOFF
71 71 #endif
72 72
73 73 /*
74 74 * Global data
75 75 */
76 76 static void *sghsc_state; /* soft state */
77 77 static sghsc_rb_head_t sghsc_rb_header; /* ring buffer header */
78 78
79 79 /*
80 80 * Definitions for events thread (outside interrupt context), mutex and
81 81 * condition variable.
82 82 */
83 83 static kthread_t *sghsc_event_thread;
84 84 static kmutex_t sghsc_event_thread_mutex;
85 85 static kcondvar_t sghsc_event_thread_cv;
86 86 static boolean_t sghsc_event_thread_exit = B_FALSE;
87 87
88 88 static struct cb_ops sghsc_cb_ops = {
89 89 nodev, /* open */
90 90 nodev, /* close */
91 91 nodev, /* strategy */
92 92 nodev, /* print */
93 93 nodev, /* dump */
94 94 nodev, /* read */
95 95 nodev, /* write */
96 96 nodev, /* ioctl */
97 97 nodev, /* devmap */
98 98 nodev, /* mmap */
99 99 nodev, /* segmap */
100 100 nochpoll, /* poll */
101 101 ddi_prop_op, /* prop_op */
102 102 0, /* streamtab */
103 103 D_NEW | D_MP, /* Driver compatibility flag */
104 104 CB_REV, /* rev */
105 105 nodev, /* int (*cb_aread)() */
106 106 nodev /* int (*cb_awrite)() */
107 107 };
108 108
109 109 /*
110 110 * Function prototype for dev_ops
111 111 */
112 112
113 113 static int sghsc_attach(dev_info_t *, ddi_attach_cmd_t);
114 114 static int sghsc_detach(dev_info_t *, ddi_detach_cmd_t);
115 115
116 116 static struct dev_ops sghsc_dev_ops = {
117 117 DEVO_REV, /* devo_rev, */
118 118 0, /* refcnt */
119 119 nulldev, /* get_dev_info */
120 120 nulldev, /* identify */
121 121 nulldev, /* probe */
122 122 sghsc_attach, /* attach */
123 123 sghsc_detach, /* detach */
124 124 nodev, /* reset */
125 125 &sghsc_cb_ops, /* driver operations */
126 126 (struct bus_ops *)0, /* no bus operations */
127 127 NULL, /* power */
128 128 ddi_quiesce_not_needed, /* quiesce */
129 129 };
130 130
131 131 static struct modldrv modldrv = {
132 132 &mod_driverops,
133 133 "Serengeti CompactPCI HSC",
134 134 &sghsc_dev_ops,
135 135 };
136 136
137 137 static struct modlinkage modlinkage = {
138 138 MODREV_1,
139 139 &modldrv,
140 140 NULL
141 141 };
142 142
143 143 /*
144 144 * Function prototype for HP support
145 145 */
146 146 static int sghsc_connect(caddr_t, hpc_slot_t slot, void *, uint_t);
147 147 static int sghsc_disconnect(caddr_t, hpc_slot_t, void *, uint_t);
148 148 static int sghsc_control(caddr_t, hpc_slot_t, int, caddr_t);
149 149
150 150 /*
151 151 * Function prototypes for internal functions
152 152 */
153 153 static int sghsc_register_slots(sghsc_t *, int);
154 154 static int sghsc_get_slotnum(sghsc_t *, hpc_slot_t);
155 155 static int sghsc_scctl(int, int, int, int, int *);
156 156 static void sghsc_freemem(sghsc_t *);
157 157 static hpc_slot_t sghsc_find_sloth(int, int, int);
158 158 static sghsc_t *sghsc_find_softstate(int, int, int);
159 159 static int sghsc_led_state(sghsc_t *, hpc_slot_t, int, hpc_led_info_t *);
160 160 static void sghsc_rb_setup(sghsc_rb_head_t *);
161 161 static void sghsc_rb_teardown(sghsc_rb_head_t *);
162 162 static int sghsc_rb_get(sghsc_rb_head_t *, sghsc_event_t *);
163 163 static int sghsc_rb_put(sghsc_rb_head_t *, sghsc_event_t *);
164 164
165 165 /*
166 166 * Patchable timeout value
167 167 */
168 168 int sghsc_mbx_timeout = SGHSC_MBX_TIMEOUT;
169 169
170 170 /*
171 171 * Data for self-identification. This will help enumerate all soft states.
172 172 */
173 173 static int sghsc_maxinst;
174 174
175 175 /*
176 176 * Six slot boat and four slot boats are different in topology (slot to
177 177 * bus assignment) and here we should have 2 separate maps (the first 3
178 178 * slots have the same topology). The map is in the "delta" form. Logical
179 179 * slots correspond to indexes in the map.
180 180 */
181 181 static sdesc_t four_slot_wib_bd[] = {
182 182 0, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 0 - Schizo0/A */
183 183 1, 0, 2, 0, /* logical/physical slot 1 - paroli2 */
184 184 1, 0, 0, 0, /* logical/physical slot 2 - paroli0 */
185 185 0, 7, 1, HPC_SLOT_TYPE_CPCI /* logical/physical slot 3 - Schizo0/B */
186 186 };
187 187 static sdesc_t four_slot_bd[] = {
188 188 0, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 0 - Schizo0/A */
189 189 1, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 1 - Schizo1/A */
190 190 0, 7, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 2 - Schizo0/B */
191 191 1, 7, 1, HPC_SLOT_TYPE_CPCI /* logical/physical slot 3 - Schizo1/B */
192 192 };
193 193 static sdesc_t six_slot_wib_bd[] = {
194 194 0, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 0 - Schizo0/A */
195 195 1, 0, 2, 0, /* logical/physical slot 1 - paroli2 */
196 196 1, 0, 0, 0, /* logical/physical slot 2 - paroli0 */
197 197 0, 7, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 3 - Schizo0/B */
198 198 0, 7, 2, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 4 - Schizo0/B */
199 199 0, 7, 3, HPC_SLOT_TYPE_CPCI /* logical/physical slot 5 - Schizo0/B */
200 200 };
201 201 static sdesc_t six_slot_bd[] = {
202 202 0, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 0 - Schizo0/A */
203 203 1, 6, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 1 - Schizo1/A */
204 204 0, 7, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 2 - Schizo0/B */
205 205 0, 7, 2, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 3 - Schizo0/B */
206 206 1, 7, 1, HPC_SLOT_TYPE_CPCI, /* logical/physical slot 4 - Schizo1/B */
207 207 1, 7, 2, HPC_SLOT_TYPE_CPCI /* logical/physical slot 5 - Schizo1/B */
208 208 };
209 209
210 210 /*
211 211 * DR event handlers
212 212 * We want to register the event handlers once for all instances. In the
213 213 * other hand we have register them after the sghsc has been attached.
214 214 * event_initialize gives us the logic of only registering the events only
215 215 * once. The event thread will do all the work when called from interrupts.
216 216 */
217 217 int sghsc_event_init = 0;
218 218 static uint_t sghsc_event_handler(char *);
219 219 static void sghsc_event_thread_code(void);
220 220
221 221 /*
222 222 * DR event msg and payload
223 223 */
224 224 static sbbc_msg_t event_msg;
225 225 static sghsc_event_t payload;
226 226
227 227 /*
228 228 * Event lock and state
229 229 */
230 230 static kmutex_t sghsc_event_lock;
231 231 int sghsc_event_state;
232 232
233 233 int
234 234 _init(void)
235 235 {
236 236 int error;
237 237
238 238 sghsc_maxinst = 0;
239 239
240 240 if ((error = ddi_soft_state_init(&sghsc_state,
241 241 sizeof (sghsc_t), 1)) != 0)
242 242 return (error);
243 243
244 244 if ((error = mod_install(&modlinkage)) != 0) {
245 245 ddi_soft_state_fini(&sghsc_state);
246 246 return (error);
247 247 }
248 248
249 249 sghsc_rb_header.buf = NULL;
250 250
251 251 mutex_init(&sghsc_event_thread_mutex, NULL, MUTEX_DRIVER, NULL);
252 252 cv_init(&sghsc_event_thread_cv, NULL, CV_DRIVER, NULL);
253 253
254 254 return (error);
255 255 }
256 256
257 257 int
258 258 _fini(void)
259 259 {
260 260 int error;
261 261
262 262 if ((error = mod_remove(&modlinkage)) != 0)
263 263 return (error);
264 264 /*
265 265 * Unregister the event handler
266 266 */
267 267 (void) sbbc_mbox_unreg_intr(MBOX_EVENT_CPCI_ENUM, sghsc_event_handler);
268 268 mutex_destroy(&sghsc_event_lock);
269 269
270 270 /*
271 271 * Kill the event thread if it is running.
272 272 */
273 273 if (sghsc_event_thread != NULL) {
274 274 mutex_enter(&sghsc_event_thread_mutex);
275 275 sghsc_event_thread_exit = B_TRUE;
276 276 /*
277 277 * Goes to the thread at once.
278 278 */
279 279 cv_signal(&sghsc_event_thread_cv);
280 280 /*
281 281 * Waiting for the response from the thread.
282 282 */
283 283 cv_wait(&sghsc_event_thread_cv, &sghsc_event_thread_mutex);
284 284 mutex_exit(&sghsc_event_thread_mutex);
285 285 sghsc_event_thread = NULL;
286 286 }
287 287 mutex_destroy(&sghsc_event_thread_mutex);
288 288 cv_destroy(&sghsc_event_thread_cv);
289 289
290 290 /*
291 291 * tear down shared, global ring buffer now that it is safe to
292 292 * do so because sghsc_event_handler has been unregistered and
293 293 * sghsc_event_thread_code has exited
294 294 */
295 295 sghsc_rb_teardown(&sghsc_rb_header);
296 296
297 297 sghsc_maxinst = 0;
298 298 ddi_soft_state_fini(&sghsc_state);
299 299
300 300 return (0);
301 301 }
302 302
303 303 int
304 304 _info(struct modinfo *modinfop)
305 305 {
306 306 return (mod_info(&modlinkage, modinfop));
307 307 }
308 308
309 309 /*
310 310 * sghsc_attach()
311 311 */
312 312 /* ARGSUSED */
313 313 static int
314 314 sghsc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
315 315 {
316 316 sghsc_t *sghsc;
317 317 uint_t instance;
318 318 uint_t portid;
319 319 int rc;
320 320 int board_type = 0;
321 321
322 322 instance = ddi_get_instance(dip);
323 323
324 324 switch (cmd) {
325 325 case DDI_RESUME:
326 326 return (DDI_SUCCESS);
327 327
328 328 case DDI_ATTACH:
329 329 break;
330 330 default:
331 331 cmn_err(CE_WARN, "sghsc%d: unsupported cmd %d",
332 332 instance, cmd);
333 333 return (DDI_FAILURE);
334 334 }
335 335
336 336 DEBUGF(1, (CE_NOTE, "attach sghsc driver. "));
337 337
338 338 /* Fetch Safari Extended Agent ID of this device. */
339 339 portid = (uint_t)ddi_getprop(DDI_DEV_T_ANY, dip,
340 340 DDI_PROP_DONTPASS, "portid", -1);
341 341
342 342 if (!SG_PORTID_IS_IO_TYPE(portid)) {
343 343 cmn_err(CE_WARN, "sghsc%d: property %s out of bounds %d\n",
344 344 instance, "portid", portid);
345 345 return (DDI_FAILURE);
346 346 }
347 347
348 348 if (ddi_soft_state_zalloc(sghsc_state, instance) != DDI_SUCCESS)
349 349 return (DDI_FAILURE);
350 350
351 351 sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance);
352 352
353 353 sghsc->sghsc_dip = dip;
354 354 sghsc->sghsc_instance = instance;
355 355 sghsc->sghsc_board = SG_PORTID_TO_BOARD_NUM(portid);
356 356 sghsc->sghsc_node_id = SG_PORTID_TO_NODEID(portid);
357 357 sghsc->sghsc_portid = portid;
358 358
359 359 ddi_set_driver_private(dip, sghsc);
360 360
361 361 mutex_init(SGHSC_MUTEX(sghsc), NULL, MUTEX_DRIVER, NULL);
362 362
363 363 rc = sghsc_scctl(SGHSC_GET_NUM_SLOTS, sghsc->sghsc_node_id,
364 364 sghsc->sghsc_board, 0, (int *)&sghsc->sghsc_num_slots);
365 365
366 366 if (rc) {
367 367 cmn_err(CE_WARN, "sghsc%d: unable to size node %d / board %d",
368 368 instance, sghsc->sghsc_node_id, sghsc->sghsc_board);
369 369 goto cleanup_stage2;
370 370 }
371 371
372 372 DEBUGF(1, (CE_NOTE, "sghsc%d: node %d / board %d has %d slots",
373 373 instance, sghsc->sghsc_node_id, sghsc->sghsc_board,
374 374 sghsc->sghsc_num_slots));
375 375
376 376 switch (sghsc->sghsc_num_slots) {
377 377 case 4:
378 378 case 6:
379 379 rc = 0;
380 380 break;
381 381 default:
382 382 rc = -1;
383 383 break;
384 384 }
385 385
386 386 if (rc) {
387 387 cmn_err(CE_WARN, "sghsc%d: wrong num of slots %d for node %d"
388 388 " / board %d", instance, sghsc->sghsc_num_slots,
389 389 sghsc->sghsc_node_id, sghsc->sghsc_board);
390 390 goto cleanup_stage2;
391 391 }
392 392
393 393 rc = sghsc_scctl(SGHSC_GET_CPCI_BOARD_TYPE, sghsc->sghsc_node_id,
394 394 sghsc->sghsc_board, 0, &board_type);
395 395
396 396 DEBUGF(1, (CE_NOTE, "sghsc%d: node %d / board %d is type %d",
397 397 instance, sghsc->sghsc_node_id, sghsc->sghsc_board, board_type));
398 398
399 399 sghsc->sghsc_slot_table = (sghsc_slot_t *)kmem_zalloc((size_t)
400 400 (sghsc->sghsc_num_slots * sizeof (sghsc_slot_t)), KM_SLEEP);
401 401
402 402
403 403 if (sghsc_register_slots(sghsc, board_type) != DDI_SUCCESS) {
404 404 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_register_slots"
405 405 " failed for node %d / board %d",
406 406 instance, sghsc->sghsc_node_id, sghsc->sghsc_board));
407 407 goto cleanup;
408 408 }
409 409
410 410 if (sghsc_connect((caddr_t)sghsc, 0, 0, SGHSC_ALL_SLOTS_ENABLE)
411 411 != HPC_SUCCESS) {
412 412 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_connect failed for"
413 413 " node %d / board %d", instance, sghsc->sghsc_node_id,
414 414 sghsc->sghsc_board));
415 415 goto cleanup;
416 416 }
417 417
418 418
419 419 if (sghsc_event_init == 0) {
420 420
421 421 /*
422 422 * allocate shared, global ring buffer before registering
423 423 * sghsc_event_handler and before starting
424 424 * sghsc_event_thread_code
425 425 */
426 426 sghsc_rb_setup(&sghsc_rb_header);
427 427
428 428 /*
429 429 * Regiter cpci DR event handler
430 430 *
431 431 */
432 432 mutex_init(&sghsc_event_lock, NULL, MUTEX_DRIVER, NULL);
433 433 event_msg.msg_buf = (caddr_t)&payload;
434 434 event_msg.msg_len = sizeof (payload);
435 435 rc = sbbc_mbox_reg_intr(MBOX_EVENT_CPCI_ENUM,
436 436 sghsc_event_handler, &event_msg,
437 437 (uint_t *)&sghsc_event_state, &sghsc_event_lock);
438 438
439 439 if (rc != 0)
440 440 cmn_err(CE_WARN, "sghsc%d: failed to register events"
441 441 " for node %d", instance, sghsc->sghsc_node_id);
442 442
443 443 sghsc_event_init = 1;
444 444
445 445 /*
446 446 * Create the event thread if it is not already created.
447 447 */
448 448 if (sghsc_event_thread == NULL) {
449 449 DEBUGF(1, (CE_NOTE, "sghsc: creating event thread"
450 450 "for node %d", sghsc->sghsc_node_id));
451 451 sghsc_event_thread = thread_create(NULL, 0,
452 452 sghsc_event_thread_code, NULL, 0, &p0,
453 453 TS_RUN, minclsyspri);
454 454 }
455 455 }
456 456
457 457 ddi_report_dev(dip);
458 458
459 459 /*
460 460 * Grossly bump up the instance counter. We may have holes inside.
461 461 */
462 462 sghsc_maxinst++;
463 463 sghsc->sghsc_valid = 1;
464 464
465 465 return (DDI_SUCCESS);
466 466
467 467 cleanup:
468 468 /*
469 469 * Free up allocated resources and return error
470 470 * sghsc_register_slots => unregister all slots
471 471 */
472 472 sghsc_freemem(sghsc);
473 473
474 474 cleanup_stage2:
475 475 DEBUGF(1, (CE_NOTE, "sghsc%d: attach failed for node %d",
476 476 instance, sghsc->sghsc_node_id));
477 477 mutex_destroy(SGHSC_MUTEX(sghsc));
478 478 ddi_set_driver_private(dip, NULL);
479 479 ddi_soft_state_free(sghsc_state, instance);
480 480 return (DDI_FAILURE);
481 481 }
482 482
483 483 /*
484 484 * detach(9E)
485 485 */
486 486 /* ARGSUSED */
487 487 static int
488 488 sghsc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
489 489 {
490 490 sghsc_t *sghsc;
491 491 int instance;
492 492 int i;
493 493
494 494 instance = ddi_get_instance(dip);
495 495 sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance);
496 496
497 497 if (sghsc == NULL)
498 498 return (DDI_FAILURE);
499 499
500 500 switch (cmd) {
501 501 case DDI_DETACH:
502 502 /*
503 503 * We don't allow to detach in case the pci nexus
504 504 * didn't run pcihp_uninit(). The buses should be
505 505 * unregistered by now, otherwise slot info will be
506 506 * corrupted on the next 'cfgadm'.
507 507 */
508 508 for (i = 0; i < sghsc->sghsc_num_slots; i++) {
509 509 if (sghsc->sghsc_slot_table[i].handle &&
510 510 hpc_bus_registered(
511 511 sghsc->sghsc_slot_table[i].handle)) {
512 512 cmn_err(CE_WARN,
513 513 "sghsc: must detach buses first");
514 514 return (DDI_FAILURE);
515 515 }
516 516 }
517 517
518 518 if (mutex_tryenter(&sghsc_event_thread_mutex) == 0)
519 519 return (EBUSY);
520 520
521 521 sghsc->sghsc_valid = 0;
522 522 sghsc_freemem(sghsc);
523 523 mutex_destroy(SGHSC_MUTEX(sghsc));
524 524 ddi_set_driver_private(dip, NULL);
525 525 ddi_soft_state_free(sghsc_state, instance);
526 526
527 527 /*
528 528 * Grossly decrement the counter. We may have holes inside.
529 529 */
530 530 if (instance == (sghsc_maxinst - 1))
531 531 sghsc_maxinst--;
532 532 mutex_exit(&sghsc_event_thread_mutex);
533 533 return (DDI_SUCCESS);
534 534
535 535 case DDI_SUSPEND:
536 536 return (DDI_SUCCESS);
537 537
538 538 default:
539 539 return (DDI_FAILURE);
540 540 }
541 541 }
542 542
543 543
544 544 /*
545 545 * Set up and register slot 0 to num_slots with hotplug
546 546 * framework
547 547 * Assume SGHSC_MUTEX is held
548 548 *
549 549 * Return val: DDI_SUCCESS
550 550 * DDI_FAILURE
551 551 */
552 552 static int
553 553 sghsc_register_slots(sghsc_t *sghsc, int board_type)
554 554 {
555 555 int i;
556 556 dev_info_t *dip = sghsc->sghsc_dip;
557 557 hpc_slot_ops_t *slot_ops = NULL;
558 558 sdesc_t *slot2bus;
559 559
560 560
561 561 DEBUGF(1, (CE_NOTE, "sghsc%d: slot table has %d entries for "
562 562 "node %d / board %d", sghsc->sghsc_instance, sghsc->sghsc_num_slots,
563 563 sghsc->sghsc_node_id, sghsc->sghsc_board));
564 564
565 565 if ((cpci_enable == 0) || (sg_prom_cpci_dr_check() != 0))
566 566 return (DDI_SUCCESS);
567 567
568 568 if (sghsc->sghsc_slot_table == NULL)
569 569 return (DDI_FAILURE);
570 570
571 571 switch (board_type) {
572 572 /*
573 573 * If the GET_CPCI_BOARD_TYPE request failed, board type
574 574 * will be NO_BOARD_TYPE. In that case, assume it is an
575 575 * io boat and make board type determination based on the
576 576 * number of slots.
577 577 */
578 578 case NO_BOARD_TYPE:
579 579 case CPCI_BOARD:
580 580 case SP_CPCI_BOARD:
581 581 switch (sghsc->sghsc_num_slots) {
582 582 case 4:
583 583 slot2bus = four_slot_bd;
584 584 break;
585 585 case 6:
586 586 slot2bus = six_slot_bd;
587 587 break;
588 588 default:
589 589 cmn_err(CE_WARN, "sghsc%d: unknown size %d for"
590 590 " node %d / board %d",
591 591 sghsc->sghsc_instance,
592 592 sghsc->sghsc_num_slots,
593 593 sghsc->sghsc_node_id, sghsc->sghsc_board);
594 594 break;
595 595 }
596 596 break;
597 597 case WCI_CPCI_BOARD:
598 598 slot2bus = four_slot_wib_bd;
599 599 break;
600 600 case WCI_SP_CPCI_BOARD:
601 601 slot2bus = six_slot_wib_bd;
602 602 break;
603 603 default:
604 604 cmn_err(CE_WARN, "sghsc%d: unknown type %d for"
605 605 " node %d / board %d", sghsc->sghsc_instance,
606 606 board_type, sghsc->sghsc_node_id,
607 607 sghsc->sghsc_board);
608 608 return (DDI_FAILURE);
609 609 }
610 610
611 611 /*
612 612 * constructing the slot table array and register the
613 613 * slot with the HPS
614 614 * we don't depend on the .conf file
615 615 */
616 616 for (i = 0; i < sghsc->sghsc_num_slots; i++) {
617 617 char *nexuspath;
618 618 hpc_slot_info_t *slot_info;
619 619 uint32_t base_id;
620 620
621 621 /*
622 622 * Some kind of black list may be needed
623 623 */
624 624
625 625 /*
626 626 * Need to talk to SC and get slot info and set slot state:
627 627 * 1. slot status
628 628 * 2. slot capabilities
629 629 * 3. LED status
630 630 * 4. get bus num
631 631 */
632 632
633 633 /*
634 634 * fill up nexuspath, extended id is used instead of the
635 635 * local one, the node id is encoded in the path twice.
636 636 */
637 637 base_id = sghsc->sghsc_portid & SGHSC_SAFARI_ID_EVEN;
638 638 nexuspath = sghsc->sghsc_slot_table[i].nexus_path;
639 639
640 640 (void) sprintf(nexuspath, SGHSC_PATH, sghsc->sghsc_node_id,
641 641 (base_id + slot2bus[i].agent_delta), slot2bus[i].off);
642 642 sghsc->sghsc_slot_table[i].pci_device_num =
643 643 slot2bus[i].pcidev;
644 644
645 645 /*
646 646 * fill up slot_info
647 647 */
648 648 slot_info = &sghsc->sghsc_slot_table[i].slot_info;
649 649
650 650 slot_info->version = HPC_SLOT_INFO_VERSION;
651 651 slot_info->slot_type = slot2bus[i].slot_type;
652 652 /* capabilities need to be discovered via SC */
653 653 slot_info->pci_slot_capabilities = HPC_SLOT_64BITS;
654 654 slot_info->pci_dev_num = slot2bus[i].pcidev;
655 655
656 656 (void) sprintf(slot_info->pci_slot_name,
657 657 "sg%dslot%d", sghsc->sghsc_board, i);
658 658 DEBUGF(1, (CE_NOTE, "pci_slot_name is %s at pci_dev_num %d"
659 659 " on node %d / board %d", slot_info->pci_slot_name,
660 660 slot_info->pci_dev_num, sghsc->sghsc_node_id,
661 661 sghsc->sghsc_board));
662 662
663 663 /*
664 664 * allocate and fill up slot_ops
665 665 */
666 666 slot_ops = hpc_alloc_slot_ops(KM_SLEEP);
667 667 sghsc->sghsc_slot_table[i].slot_ops = slot_ops;
668 668
669 669 /* assign slot ops for HPS */
670 670 slot_ops->hpc_version = HPC_SLOT_OPS_VERSION;
671 671 slot_ops->hpc_op_connect = sghsc_connect;
672 672 slot_ops->hpc_op_disconnect = sghsc_disconnect;
673 673 slot_ops->hpc_op_insert = nodev;
674 674 slot_ops->hpc_op_remove = nodev;
675 675 slot_ops->hpc_op_control = sghsc_control;
676 676
677 677 /*
678 678 * HA (Full Hot Swap) is the default mode of operation
679 679 * but the type of the board is set conservstively as
680 680 * sghsc has no way of knowing it. The HP Framwork will
681 681 * overwrite the value set at boot time.
682 682 */
683 683 sghsc->sghsc_slot_table[i].flags = SGHSC_SLOT_AUTO_CFG_EN;
684 684 sghsc->sghsc_slot_table[i].board_type = HPC_BOARD_UNKNOWN;
685 685
686 686 /* Only register CPCI slots */
687 687 if (slot_info->slot_type != HPC_SLOT_TYPE_CPCI) {
688 688 DEBUGF(1, (CE_NOTE, "sghsc_register_slots: "
689 689 "slot %d is non-cpci", i));
690 690 continue;
691 691 }
692 692
693 693 /*
694 694 * register slots
695 695 */
696 696 if ((hpc_slot_register(dip, nexuspath, slot_info,
697 697 &sghsc->sghsc_slot_table[i].handle,
698 698 slot_ops, (caddr_t)sghsc, 0)) != 0) {
699 699
700 700 /*
701 701 * return failure and let attach()
702 702 * do the cleanup
703 703 */
704 704 cmn_err(CE_WARN, "sghsc%d: Slot <%s> failed during HPS"
705 705 " registration process for node %d / board %d",
706 706 sghsc->sghsc_instance, slot_info->pci_slot_name,
707 707 sghsc->sghsc_node_id, sghsc->sghsc_board);
708 708 return (DDI_FAILURE);
709 709 }
710 710
711 711 }
712 712 DEBUGF(1, (CE_NOTE, "sghsc registered successfully for"
713 713 " node %d / board %d", sghsc->sghsc_node_id, sghsc->sghsc_board));
714 714 return (DDI_SUCCESS);
715 715 }
716 716
717 717 /*
718 718 * Connecting a slot or all slots
719 719 * State Diagram:
720 720 * states
721 721 * hw bits EMPTY DISCONNECT CONNECT
722 722 * slot_enable NO NO YES
723 723 * card_present NO YES YES
724 724 * slot_switch N/A NO/YES YES
725 725 *
726 726 * Return val: HPC_SUCCESS if the slot(s) are enabled
727 727 * HPC_ERR_FAILED if the slot can't be enabled
728 728 */
729 729 /* ARGSUSED */
730 730 static int
731 731 sghsc_connect(caddr_t op_arg, hpc_slot_t sloth, void *data,
732 732 uint_t flag)
733 733 {
734 734 int i = 0;
735 735 sghsc_t *sghsc = (sghsc_t *)op_arg;
736 736 int rc;
737 737 int result;
738 738 int slot_num = sghsc_get_slotnum(sghsc, sloth);
739 739
740 740 switch (flag) {
741 741
742 742 case SGHSC_ALL_SLOTS_ENABLE:
743 743 for (i = 0; i < sghsc->sghsc_num_slots; i++) {
744 744 /*
745 745 * All slots will be marked 'empty' as HP Framework
746 746 * will try to connect those which have no kernel node.
747 747 */
748 748 sghsc->sghsc_slot_table[i].slot_status =
749 749 HPC_SLOT_EMPTY;
750 750 }
751 751
752 752 return (HPC_SUCCESS);
753 753 }
754 754
755 755 if (slot_num == -1)
756 756 return (HPC_ERR_INVALID);
757 757
758 758 SGHSC_MUTEX_ENTER(sghsc);
759 759
760 760 DEBUGF(1, (CE_NOTE, "sghsc%d: connecting logical slot%d for"
761 761 " node %d / board %d", sghsc->sghsc_instance, slot_num,
762 762 sghsc->sghsc_node_id, sghsc->sghsc_board));
763 763
764 764 /*
765 765 * Powering an empty slot is highly illegal so far
766 766 * (before SC implemented a constant poll). Otherwise
767 767 * it breaks ddi framework and HP. The workaround
768 768 * is to check for a card first.
769 769 */
770 770 rc = sghsc_scctl(SGHSC_GET_SLOT_STATUS, sghsc->sghsc_node_id,
771 771 sghsc->sghsc_board, slot_num, &result);
772 772
773 773 if (rc == ETIMEDOUT) {
774 774 SGHSC_MUTEX_EXIT(sghsc);
775 775 return (HPC_ERR_FAILED);
776 776 }
777 777
778 778 if (rc) {
779 779 cmn_err(CE_NOTE, "sghsc%d: unable to stat slot %d for"
780 780 " node %d / board %d", sghsc->sghsc_instance, slot_num,
781 781 sghsc->sghsc_node_id, sghsc->sghsc_board);
782 782 sghsc->sghsc_slot_table[i].slot_status = HPC_SLOT_UNKNOWN;
783 783 SGHSC_MUTEX_EXIT(sghsc);
784 784 return (HPC_ERR_FAILED);
785 785 }
786 786
787 787
788 788 if ((result >> CPCI_STAT_SLOT_EMPTY_SHIFT) & ONE_BIT) {
789 789 sghsc->sghsc_slot_table[i].slot_status = HPC_SLOT_EMPTY;
790 790 SGHSC_MUTEX_EXIT(sghsc);
791 791 return (HPC_ERR_FAILED);
792 792 }
793 793
794 794 rc = sghsc_scctl(SGHSC_SET_SLOT_POWER_ON, sghsc->sghsc_node_id,
795 795 sghsc->sghsc_board, slot_num, &result);
796 796 if (rc) {
797 797 cmn_err(CE_WARN, "sghsc%d: unable to poweron slot %d for"
798 798 " node %d / board %d", sghsc->sghsc_instance,
799 799 slot_num, sghsc->sghsc_node_id, sghsc->sghsc_board);
800 800 SGHSC_MUTEX_EXIT(sghsc);
801 801 return (HPC_ERR_FAILED);
802 802 } else {
803 803 sghsc->sghsc_slot_table[slot_num].slot_status =
804 804 HPC_SLOT_CONNECTED;
805 805 }
806 806
807 807 SGHSC_MUTEX_EXIT(sghsc);
808 808
809 809 return (HPC_SUCCESS);
810 810 }
811 811
812 812
813 813 /*
814 814 * Disconnecting a slot or slots
815 815 *
816 816 * return: HPC_SUCCESS if slot(s) are successfully disconnected
817 817 * HPC_ERR_FAILED if slot(s) can't be disconnected
818 818 *
819 819 */
820 820 /* ARGSUSED */
821 821 static int
822 822 sghsc_disconnect(caddr_t op_arg, hpc_slot_t sloth, void *data,
823 823 uint_t flag)
824 824 {
825 825 sghsc_t *sghsc = (sghsc_t *)op_arg;
826 826 int rc;
827 827 int result;
828 828 int slot_num = sghsc_get_slotnum(sghsc, sloth);
829 829
830 830 switch (flag) {
831 831 case SGHSC_ALL_SLOTS_DISABLE:
832 832 return (HPC_SUCCESS);
833 833
834 834 }
835 835
836 836 if (slot_num == -1)
837 837 return (HPC_ERR_INVALID);
838 838
839 839 SGHSC_MUTEX_ENTER(sghsc);
840 840
841 841 /*
842 842 * Disconnecting an empty or disconnected slot
843 843 * does't make sense.
844 844 */
845 845 if (sghsc->sghsc_slot_table[slot_num].slot_status !=
846 846 HPC_SLOT_CONNECTED) {
847 847 SGHSC_MUTEX_EXIT(sghsc);
848 848 return (HPC_SUCCESS);
849 849 }
850 850
851 851 rc = sghsc_scctl(SGHSC_SET_SLOT_POWER_OFF, sghsc->sghsc_node_id,
852 852 sghsc->sghsc_board, slot_num, &result);
853 853 if (rc) {
854 854 cmn_err(CE_WARN, "sghsc%d: unable to poweroff slot %d for"
855 855 " node %d / board %d", sghsc->sghsc_instance,
856 856 slot_num, sghsc->sghsc_node_id, sghsc->sghsc_board);
857 857 SGHSC_MUTEX_EXIT(sghsc);
858 858 return (HPC_ERR_FAILED);
859 859 } else {
860 860 sghsc->sghsc_slot_table[slot_num].slot_status =
861 861 HPC_SLOT_DISCONNECTED;
862 862 }
863 863
864 864 SGHSC_MUTEX_EXIT(sghsc);
865 865
866 866 return (HPC_SUCCESS);
867 867 }
868 868
869 869 /*
870 870 * Entry point from the hotplug framework to do
871 871 * the main hotplug operations
872 872 * Return val: HPC_SUCCESS success on ops
873 873 * HPC_NOT_SUPPORTED not supported feature
874 874 * HPC_ERR_FAILED ops failed
875 875 */
876 876 /*ARGSUSED*/
877 877 static int
878 878 sghsc_control(caddr_t op_arg, hpc_slot_t sloth, int request,
879 879 caddr_t arg)
880 880 {
881 881 sghsc_t *sghsc = (sghsc_t *)op_arg;
882 882 int slot = sghsc_get_slotnum(sghsc, sloth);
883 883 int error = HPC_SUCCESS;
884 884 int rc;
885 885 int result;
886 886
887 887 if ((sghsc == NULL) || (slot < 0) ||
888 888 (slot >= sghsc->sghsc_num_slots)) {
889 889 cmn_err(CE_WARN, "sghsc%d: sghsc_control fails with slot = %d"
890 890 " max = %d, sloth = 0x%p for node %d / board %d",
891 891 sghsc->sghsc_instance, slot, sghsc->sghsc_num_slots,
892 892 sloth, sghsc->sghsc_node_id, sghsc->sghsc_board);
893 893 return (HPC_ERR_INVALID);
894 894 }
895 895
896 896 SGHSC_MUTEX_ENTER(sghsc);
897 897
898 898 switch (request) {
899 899 case HPC_CTRL_GET_LED_STATE: {
900 900 /* arg == hpc_led_info_t */
901 901
902 902 hpc_led_info_t *ledinfo;
903 903
904 904 ledinfo = (hpc_led_info_t *)arg;
905 905
906 906 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
907 907 " HPC_CTRL_GET_LED_STATE for node %d / board %d slot %d",
908 908 sghsc->sghsc_instance, sghsc->sghsc_node_id,
909 909 sghsc->sghsc_board, slot));
910 910
911 911 switch (ledinfo->led) {
912 912 case HPC_POWER_LED:
913 913 case HPC_ATTN_LED:
914 914 case HPC_FAULT_LED:
915 915 case HPC_ACTIVE_LED:
916 916 error = sghsc_led_state(sghsc, sloth,
917 917 HPC_CTRL_GET_LED_STATE, ledinfo);
918 918 break;
919 919 default:
920 920 cmn_err(CE_WARN, "sghsc%d: sghsc_control"
921 921 " HPC_CTRL_GET_LED_STATE "
922 922 " unknown led state %d for node %d / board %d"
923 923 " slot handle 0x%p", sghsc->sghsc_instance,
924 924 ledinfo->led, sghsc->sghsc_node_id,
925 925 sghsc->sghsc_board, sloth);
926 926 error = HPC_ERR_NOTSUPPORTED;
927 927 break;
928 928 }
929 929
930 930 break;
931 931 }
932 932
933 933 case HPC_CTRL_SET_LED_STATE: {
934 934 /* arg == hpc_led_info_t */
935 935 hpc_led_info_t *ledinfo;
936 936
937 937 ledinfo = (hpc_led_info_t *)arg;
938 938
939 939 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
940 940 " HPC_CTRL_SET_LED_STATE for node %d / board %d slot %d",
941 941 sghsc->sghsc_instance, sghsc->sghsc_node_id,
942 942 sghsc->sghsc_board, slot));
943 943
944 944 switch (ledinfo->led) {
945 945 case HPC_POWER_LED:
946 946 case HPC_ATTN_LED:
947 947 case HPC_FAULT_LED:
948 948 case HPC_ACTIVE_LED:
949 949 DEBUGF(1, (CE_NOTE, "sghsc:"
950 950 " LED writing not supported "));
951 951 break;
952 952
953 953 default:
954 954 DEBUGF(1, (CE_NOTE, "sghsc:"
955 955 " LED not supported "));
956 956 error = HPC_ERR_NOTSUPPORTED;
957 957 }
958 958 break;
959 959 }
960 960
961 961 case HPC_CTRL_GET_SLOT_STATE: {
962 962 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
963 963 " HPC_CTRL_GET_SLOT_STATE for node %d / board %d slot %d",
964 964 sghsc->sghsc_instance, sghsc->sghsc_node_id,
965 965 sghsc->sghsc_board, slot));
966 966
967 967 /*
968 968 * Send mailbox cmd to SC to query the latest state
969 969 */
970 970 rc = sghsc_scctl(SGHSC_GET_SLOT_STATUS, sghsc->sghsc_node_id,
971 971 sghsc->sghsc_board, slot, &result);
972 972
973 973 if (rc == ETIMEDOUT) {
974 974 error = HPC_ERR_FAILED;
975 975 break;
976 976 }
977 977
978 978 if (rc) {
979 979 cmn_err(CE_NOTE, "sghsc%d: unable to stat slot %d for "
980 980 "node %d / board %d", sghsc->sghsc_instance, slot,
981 981 sghsc->sghsc_node_id, sghsc->sghsc_board);
982 982 sghsc->sghsc_slot_table[slot].slot_status =
983 983 HPC_SLOT_UNKNOWN;
984 984 *(hpc_slot_state_t *)arg = HPC_SLOT_UNKNOWN;
985 985 break;
986 986 }
987 987
988 988 /*
989 989 * Update the cached state if needed. Initally all
990 990 * slots are marked as empty for the Hot Plug Framwork.
991 991 */
992 992 if ((result >> CPCI_STAT_SLOT_EMPTY_SHIFT) & ONE_BIT) {
993 993 sghsc->sghsc_slot_table[slot].slot_status =
994 994 HPC_SLOT_EMPTY;
995 995 } else if ((result >> CPCI_STAT_POWER_ON_SHIFT) & ONE_BIT) {
996 996 sghsc->sghsc_slot_table[slot].slot_status =
997 997 HPC_SLOT_CONNECTED;
998 998 } else if (sghsc->sghsc_slot_table[slot].slot_status ==
999 999 HPC_SLOT_EMPTY ||
1000 1000 sghsc->sghsc_slot_table[slot].slot_status ==
1001 1001 HPC_SLOT_UNKNOWN) {
1002 1002 sghsc->sghsc_slot_table[slot].slot_status =
1003 1003 HPC_SLOT_DISCONNECTED;
1004 1004 }
1005 1005 /*
1006 1006 * No change
1007 1007 */
1008 1008 *(hpc_slot_state_t *)arg =
1009 1009 sghsc->sghsc_slot_table[slot].slot_status;
1010 1010
1011 1011 break;
1012 1012 }
1013 1013
1014 1014 case HPC_CTRL_DEV_CONFIGURED:
1015 1015 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
1016 1016 " HPC_CTRL_DEV_CONFIGURED for node %d / board %d slot %d",
1017 1017 sghsc->sghsc_instance, sghsc->sghsc_node_id,
1018 1018 sghsc->sghsc_board, slot));
1019 1019
1020 1020 if (sghsc_configure_ack)
1021 1021 cmn_err(CE_NOTE, "sghsc%d:"
1022 1022 " node %d / board %d slot %d configured",
1023 1023 sghsc->sghsc_instance, sghsc->sghsc_node_id,
1024 1024 sghsc->sghsc_board, slot);
1025 1025 /*
1026 1026 * This is important to tell SC:
1027 1027 * "start looking for ENUMs"
1028 1028 */
1029 1029 if (sghsc->sghsc_slot_table[slot].flags &
1030 1030 SGHSC_SLOT_AUTO_CFG_EN)
1031 1031 (void) sghsc_scctl(SGHSC_SET_ENUM_CLEARED,
1032 1032 sghsc->sghsc_node_id, sghsc->sghsc_board,
1033 1033 slot, &result);
1034 1034
1035 1035 break;
1036 1036
1037 1037 case HPC_CTRL_DEV_UNCONFIGURED:
1038 1038 /*
1039 1039 * due to unclean drivers, unconfigure may leave
1040 1040 * some state on card, configure may actually
1041 1041 * use these invalid values. therefore, may force
1042 1042 * disconnect.
1043 1043 */
1044 1044
1045 1045 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control "
1046 1046 "HPC_CTRL_DEV_UNCONFIGURED for node %d / board %d slot %d",
1047 1047 sghsc->sghsc_instance, sghsc->sghsc_node_id,
1048 1048 sghsc->sghsc_board, slot));
1049 1049
1050 1050 SGHSC_MUTEX_EXIT(sghsc);
1051 1051 if (sghsc_disconnect(op_arg, sloth, 0,
1052 1052 0) != HPC_SUCCESS) {
1053 1053 DEBUGF(1, (CE_NOTE, "sghsc_control: "
1054 1054 "disconnect failed"));
1055 1055 error = HPC_ERR_FAILED;
1056 1056 }
1057 1057
1058 1058 cmn_err(CE_NOTE, "sghsc%d: node %d / board %d "
1059 1059 "slot %d unconfigured", sghsc->sghsc_instance,
1060 1060 sghsc->sghsc_node_id, sghsc->sghsc_board, slot);
1061 1061 return (error);
1062 1062
1063 1063
1064 1064 case HPC_CTRL_GET_BOARD_TYPE: {
1065 1065 /* arg = hpc_board_type_t */
1066 1066
1067 1067 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
1068 1068 " HPC_CTRL_GET_BOARD_TYPE for node %d / board %d slot %d",
1069 1069 sghsc->sghsc_instance, sghsc->sghsc_node_id,
1070 1070 sghsc->sghsc_board, slot));
1071 1071
1072 1072 *(hpc_board_type_t *)arg =
1073 1073 sghsc->sghsc_slot_table[slot].board_type;
1074 1074
1075 1075 break;
1076 1076 }
1077 1077
1078 1078 case HPC_CTRL_ENABLE_AUTOCFG:
1079 1079 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
1080 1080 " HPC_CTRL_ENABLE_AUTOCFG for node %d / board %d slot %d",
1081 1081 sghsc->sghsc_instance, sghsc->sghsc_node_id,
1082 1082 sghsc->sghsc_board, slot));
1083 1083
1084 1084 sghsc->sghsc_slot_table[slot].flags |= SGHSC_SLOT_AUTO_CFG_EN;
1085 1085 (void) hpc_slot_event_notify(sloth, HPC_EVENT_ENABLE_ENUM,
1086 1086 HPC_EVENT_NORMAL);
1087 1087
1088 1088 /*
1089 1089 * Tell SC to start looking for ENUMs on this slot.
1090 1090 */
1091 1091 rc = sghsc_scctl(SGHSC_SET_ENUM_CLEARED, sghsc->sghsc_node_id,
1092 1092 sghsc->sghsc_board, slot, &result);
1093 1093
1094 1094 if (rc)
1095 1095 cmn_err(CE_WARN, "sghsc%d: unable to arm ENUM for"
1096 1096 " node %d / board %d, slot %d",
1097 1097 sghsc->sghsc_instance, sghsc->sghsc_node_id,
1098 1098 sghsc->sghsc_board, slot);
1099 1099 break;
1100 1100
1101 1101 case HPC_CTRL_DISABLE_AUTOCFG:
1102 1102 DEBUGF(1, (CE_NOTE, "sghsc%d: sghsc_control"
1103 1103 " HPC_CTRL_DISABLE_AUTOCFG for node %d / board %d slot %d",
1104 1104 sghsc->sghsc_instance, sghsc->sghsc_node_id,
1105 1105 sghsc->sghsc_board, slot));
1106 1106
1107 1107 sghsc->sghsc_slot_table[slot].flags &= ~SGHSC_SLOT_AUTO_CFG_EN;
1108 1108 (void) hpc_slot_event_notify(sloth, HPC_EVENT_DISABLE_ENUM,
1109 1109 HPC_EVENT_NORMAL);
1110 1110 break;
1111 1111
1112 1112 case HPC_CTRL_DISABLE_SLOT:
1113 1113 case HPC_CTRL_ENABLE_SLOT:
1114 1114 break;
1115 1115
1116 1116 /* need to add support for enable/disable_ENUM */
1117 1117 case HPC_CTRL_DISABLE_ENUM:
1118 1118 case HPC_CTRL_ENABLE_ENUM:
1119 1119 default:
1120 1120 DEBUGF(1, (CE_CONT, "sghsc%d: sghsc_control "
1121 1121 "request (0x%x) not supported", sghsc->sghsc_instance,
1122 1122 request));
1123 1123
1124 1124 /* invalid request */
1125 1125 error = HPC_ERR_NOTSUPPORTED;
1126 1126 }
1127 1127
1128 1128 SGHSC_MUTEX_EXIT(sghsc);
1129 1129
1130 1130 return (error);
1131 1131 }
1132 1132
1133 1133 /*
1134 1134 * Read/write slot's led
1135 1135 * Assume MUTEX_HELD
1136 1136 *
1137 1137 * return: HPC_SUCCESS if the led's status is avaiable,
1138 1138 * SC return status otherwise.
1139 1139 */
1140 1140 static int
1141 1141 sghsc_led_state(sghsc_t *sghsc, hpc_slot_t sloth, int op,
1142 1142 hpc_led_info_t *ledinfo)
1143 1143 {
1144 1144 int rval;
1145 1145 int slot_num;
1146 1146 int result;
1147 1147
1148 1148 slot_num = sghsc_get_slotnum(sghsc, sloth);
1149 1149 rval = sghsc_scctl(SGHSC_GET_SLOT_STATUS, sghsc->sghsc_node_id,
1150 1150 sghsc->sghsc_board, slot_num, &result);
1151 1151 if (rval != HPC_SUCCESS)
1152 1152 return (rval);
1153 1153
1154 1154 switch (op) {
1155 1155 case HPC_CTRL_GET_LED_STATE:
1156 1156 switch (ledinfo->led) {
1157 1157 case HPC_POWER_LED:
1158 1158 if ((result >> CPCI_STAT_LED_POWER_SHIFT) & ONE_BIT)
1159 1159 ledinfo->state = HPC_LED_ON;
1160 1160 else
1161 1161 ledinfo->state = HPC_LED_OFF;
1162 1162 break;
1163 1163
1164 1164 case HPC_ATTN_LED:
1165 1165 case HPC_FAULT_LED:
1166 1166 if ((result >> CPCI_STAT_LED_FAULT_SHIFT) & ONE_BIT)
1167 1167 ledinfo->state = HPC_LED_ON;
1168 1168 else
1169 1169 ledinfo->state = HPC_LED_OFF;
1170 1170 break;
1171 1171
1172 1172 case HPC_ACTIVE_LED:
1173 1173 if ((result >> CPCI_STAT_LED_HP_SHIFT) & ONE_BIT)
1174 1174 ledinfo->state = HPC_LED_ON;
1175 1175 else
1176 1176 ledinfo->state = HPC_LED_OFF;
1177 1177 break;
1178 1178 }
1179 1179
1180 1180 break;
1181 1181
1182 1182 case HPC_CTRL_SET_LED_STATE:
1183 1183 return (HPC_ERR_NOTSUPPORTED);
1184 1184 }
1185 1185
1186 1186 return (HPC_SUCCESS);
1187 1187 }
1188 1188
1189 1189 /*
1190 1190 * sghsc_get_slotnum()
1191 1191 * get slot number from the slot handle
1192 1192 * returns non-negative value to indicate slot number
1193 1193 * -1 for failure
1194 1194 */
1195 1195 static int
1196 1196 sghsc_get_slotnum(sghsc_t *sghsc, hpc_slot_t sloth)
1197 1197 {
1198 1198 int i;
1199 1199
1200 1200 if (sloth == NULL || sghsc == NULL)
1201 1201 return (-1);
1202 1202
1203 1203 for (i = 0; i < sghsc->sghsc_num_slots; i++) {
1204 1204
1205 1205 if (sghsc->sghsc_slot_table[i].handle == sloth)
1206 1206 return (i);
1207 1207 }
1208 1208
1209 1209 return (-1);
1210 1210
1211 1211 }
1212 1212
1213 1213 /*
1214 1214 * sghsc_scctl()
1215 1215 * mailbox interface
1216 1216 *
1217 1217 * return result code from mailbox operation
1218 1218 */
1219 1219 static int
1220 1220 sghsc_scctl(int cmd, int node_id, int board, int slot, int *resultp)
1221 1221 {
1222 1222 int ret = 0xbee;
1223 1223 bitcmd_info_t cmd_info, *cmd_infop = &cmd_info;
1224 1224 bitcmd_resp_t cmd_info_r, *cmd_info_r_p = &cmd_info_r;
1225 1225 sbbc_msg_t request, *reqp = &request;
1226 1226 sbbc_msg_t response, *resp = &response;
1227 1227
1228 1228 cmd_infop->cmd_id = 0x01234567;
1229 1229 cmd_infop->node_id = node_id;
1230 1230 cmd_infop->board = board;
1231 1231 cmd_infop->slot = slot;
1232 1232
1233 1233 reqp->msg_type.type = CPCI_MBOX;
1234 1234 reqp->msg_status = 0xeeeeffff;
1235 1235 reqp->msg_len = sizeof (cmd_info);
1236 1236 reqp->msg_bytes = 8;
1237 1237 reqp->msg_buf = (caddr_t)cmd_infop;
1238 1238 reqp->msg_data[0] = 0;
1239 1239 reqp->msg_data[1] = 0;
1240 1240
1241 1241 bzero(resp, sizeof (*resp));
1242 1242 bzero(cmd_info_r_p, sizeof (*cmd_info_r_p));
1243 1243
1244 1244 resp->msg_buf = (caddr_t)cmd_info_r_p;
1245 1245 resp->msg_len = sizeof (cmd_info_r);
1246 1246
1247 1247 resp->msg_type.type = CPCI_MBOX;
1248 1248 resp->msg_bytes = 8;
1249 1249 resp->msg_status = 0xddddffff;
1250 1250
1251 1251 switch (cmd) {
1252 1252 case SGHSC_GET_SLOT_STATUS:
1253 1253 reqp->msg_type.sub_type = CPCI_GET_SLOT_STATUS;
1254 1254 resp->msg_type.sub_type = CPCI_GET_SLOT_STATUS;
1255 1255 reqp->msg_len -= 4;
1256 1256 break;
1257 1257 case SGHSC_GET_NUM_SLOTS:
1258 1258 reqp->msg_type.sub_type = CPCI_GET_NUM_SLOTS;
1259 1259 resp->msg_type.sub_type = CPCI_GET_NUM_SLOTS;
1260 1260 reqp->msg_len -= 8;
1261 1261 break;
1262 1262 case SGHSC_SET_SLOT_STATUS_RESET:
1263 1263 reqp->msg_type.sub_type = CPCI_SET_SLOT_STATUS;
1264 1264 resp->msg_type.sub_type = CPCI_SET_SLOT_STATUS;
1265 1265 cmd_infop->info = CPCI_SET_STATUS_SLOT_RESET;
1266 1266 break;
1267 1267 case SGHSC_SET_SLOT_STATUS_READY:
1268 1268 reqp->msg_type.sub_type = CPCI_SET_SLOT_STATUS;
1269 1269 resp->msg_type.sub_type = CPCI_SET_SLOT_STATUS;
1270 1270 cmd_infop->info = CPCI_SET_STATUS_SLOT_READY;
1271 1271 break;
1272 1272 case SGHSC_SET_SLOT_FAULT_LED_ON:
1273 1273 reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
1274 1274 resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
1275 1275 cmd_infop->info = CPCI_SET_FAULT_LED_ON;
1276 1276 break;
1277 1277 case SGHSC_SET_SLOT_FAULT_LED_OFF:
1278 1278 reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
1279 1279 resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
1280 1280 cmd_infop->info = CPCI_SET_FAULT_LED_OFF;
1281 1281 break;
1282 1282 case SGHSC_SET_SLOT_FAULT_LED_KEEP:
1283 1283 reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
1284 1284 resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
1285 1285 cmd_infop->info = CPCI_SET_FAULT_LED_KEEP;
1286 1286 break;
1287 1287 case SGHSC_SET_SLOT_FAULT_LED_TOGGLE:
1288 1288 reqp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
1289 1289 resp->msg_type.sub_type = CPCI_SET_SLOT_FAULT_LED;
1290 1290 cmd_infop->info = CPCI_SET_FAULT_LED_TOGGLE;
1291 1291 break;
1292 1292 case SGHSC_SET_SLOT_POWER_OFF:
1293 1293 reqp->msg_type.sub_type = CPCI_SET_SLOT_POWER;
1294 1294 resp->msg_type.sub_type = CPCI_SET_SLOT_POWER;
1295 1295 cmd_infop->info = CPCI_POWER_OFF;
1296 1296 break;
1297 1297 case SGHSC_SET_SLOT_POWER_ON:
1298 1298 reqp->msg_type.sub_type = CPCI_SET_SLOT_POWER;
1299 1299 resp->msg_type.sub_type = CPCI_SET_SLOT_POWER;
1300 1300 cmd_infop->info = CPCI_POWER_ON;
1301 1301 break;
1302 1302 case SGHSC_GET_CPCI_BOARD_TYPE:
1303 1303 reqp->msg_type.sub_type = CPCI_BOARD_TYPE;
1304 1304 resp->msg_type.sub_type = CPCI_BOARD_TYPE;
1305 1305 reqp->msg_len -= 8;
1306 1306 break;
1307 1307 case SGHSC_SET_ENUM_CLEARED:
1308 1308 reqp->msg_type.sub_type = CPCI_SET_ENUM_CLEARED;
1309 1309 resp->msg_type.sub_type = CPCI_SET_ENUM_CLEARED;
1310 1310 break;
1311 1311 default:
1312 1312 cmn_err(CE_WARN, "sghsc: unrecognized action code 0x%x\n",
1313 1313 cmd);
1314 1314 }
1315 1315
1316 1316 DEBUGF(1, (CE_NOTE,
1317 1317 "sghsc: sending mbox command type=%d subtype=0x%x size=%d buf=%p",
1318 1318 reqp->msg_type.type, reqp->msg_type.sub_type,
1319 1319 reqp->msg_len, (void *)reqp->msg_buf));
1320 1320
1321 1321 DEBUGF(1, (CE_NOTE,
1322 1322 "sghsc: sending buf cmd_id=0x%x node_id=0x%x board=0x%x "
1323 1323 "slot=0x%x info=0x%x", cmd_infop->cmd_id, cmd_infop->node_id,
1324 1324 cmd_infop->board, cmd_infop->slot, cmd_infop->info));
1325 1325
1326 1326
1327 1327 ret = sbbc_mbox_request_response(reqp, resp, sghsc_mbx_timeout);
1328 1328
1329 1329 /*
1330 1330 * The resp->msg_status field may contain an SC error or a common
1331 1331 * error such as ETIMEDOUT.
1332 1332 */
1333 1333 if ((ret != 0) || (resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
1334 1334 DEBUGF(1, (CE_NOTE, "sghsc: mailbox command error = 0x%x, "
1335 1335 "status = 0x%x", ret, resp->msg_status));
1336 1336 return (-1);
1337 1337 }
1338 1338
1339 1339 DEBUGF(1, (CE_NOTE, "sghsc: reply request status=0x%x",
1340 1340 reqp->msg_status));
1341 1341 DEBUGF(1, (CE_NOTE, "sghsc: reply resp status=0x%x",
1342 1342 resp->msg_status));
1343 1343 DEBUGF(1, (CE_NOTE, "sghsc: reply buf cmd_id=0x%x result=0x%x\n",
1344 1344 cmd_info_r_p->cmd_id, cmd_info_r_p->result));
1345 1345
1346 1346 #ifdef DEBUG_EXTENDED
1347 1347 if (cmd == SGHSC_GET_NUM_SLOTS) {
1348 1348 DEBUGF(1, (CE_NOTE, "sghsc: node %d / board %d has %d slots",
1349 1349 cmd_infop->node_id, cmd_infop->board,
1350 1350 cmd_info_r_p->result));
1351 1351 *resultp = cmd_info_r_p->result;
1352 1352 return (0);
1353 1353 }
1354 1354
1355 1355 if ((cmd_info_r_p->result >> CPCI_STAT_POWER_ON_SHIFT) & ONE_BIT)
1356 1356 DEBUGF(1, (CE_NOTE, "sghsc: cpower on"));
1357 1357
1358 1358 if ((cmd_info_r_p->result >> CPCI_STAT_LED_POWER_SHIFT) & ONE_BIT)
1359 1359 DEBUGF(1, (CE_NOTE, "sghsc: power led on"));
1360 1360
1361 1361 if ((cmd_info_r_p->result >> CPCI_STAT_LED_FAULT_SHIFT) & ONE_BIT)
1362 1362 DEBUGF(1, (CE_NOTE, "sghsc: fault led on"));
1363 1363
1364 1364 if ((cmd_info_r_p->result >> CPCI_STAT_LED_HP_SHIFT) & ONE_BIT)
1365 1365 DEBUGF(1, (CE_NOTE, "sghsc: remove(hp) led on"));
1366 1366
1367 1367 if ((cmd_info_r_p->result >> CPCI_STAT_SLOT_EMPTY_SHIFT) & ONE_BIT)
1368 1368 DEBUGF(1, (CE_NOTE, "sghsc: slot empty"));
1369 1369
1370 1370 tmp = ((cmd_info_r_p->result >> CPCI_STAT_HOT_SWAP_STATUS_SHIFT) &
1371 1371 THREE_BITS);
1372 1372 if (tmp)
1373 1373 DEBUGF(1, (CE_NOTE,
1374 1374 "sghsc: slot condition(hot swap status) is 0x%x", tmp));
1375 1375
1376 1376 if (cmd_info_r_p->result & CPCI_GET_STAT_SLOT_HZ_CAP)
1377 1377 DEBUGF(1, (CE_NOTE,
1378 1378 "sghsc: freq cap %x", cmd_info_r_p->result &
1379 1379 CPCI_GET_STAT_SLOT_HZ_CAP));
1380 1380
1381 1381 if (cmd_info_r_p->result & CPCI_GET_STAT_SLOT_HZ_SET)
1382 1382 DEBUGF(1, (CE_NOTE,
1383 1383 "sghsc: freq setting %x", cmd_info_r_p->result &
1384 1384 CPCI_GET_STAT_SLOT_HZ_SET));
1385 1385
1386 1386
1387 1387 if ((cmd_info_r_p->result >> CPCI_STAT_HEALTHY_SHIFT) & ONE_BIT)
1388 1388 DEBUGF(1, (CE_NOTE, "sghsc: healthy"));
1389 1389
1390 1390 if ((cmd_info_r_p->result >> CPCI_STAT_RESET_SHIFT) & ONE_BIT)
1391 1391 DEBUGF(1, (CE_NOTE, "sghsc: in reset"));
1392 1392
1393 1393 if (cmd_info_r_p->result & CPCI_GET_STAT_POWER_GOOD)
1394 1394 DEBUGF(1, (CE_NOTE, "sghsc: power good"));
1395 1395
1396 1396 if (cmd_info_r_p->result & CPCI_GET_STAT_POWER_FAULT)
1397 1397 DEBUGF(1, (CE_NOTE, "sghsc: power fault"));
1398 1398
1399 1399 if (cmd_info_r_p->result & CPCI_GET_STAT_PCI_PRESENT)
1400 1400 DEBUGF(1, (CE_NOTE, "sghsc: pci present"));
1401 1401 #endif
1402 1402
1403 1403 *resultp = cmd_info_r_p->result;
1404 1404 return (0);
1405 1405 }
1406 1406
1407 1407
1408 1408 /*
1409 1409 * sghsc_freemem()
1410 1410 * deallocates memory resources
1411 1411 *
1412 1412 */
1413 1413 static void
1414 1414 sghsc_freemem(sghsc_t *sghsc)
1415 1415 {
1416 1416 int i;
1417 1417
1418 1418 /*
1419 1419 * Free up allocated resources
1420 1420 * sghsc_register_slots => unregister all slots
1421 1421 */
1422 1422 for (i = 0; i < sghsc->sghsc_num_slots; i++) {
1423 1423 if (sghsc->sghsc_slot_table[i].slot_ops)
1424 1424 hpc_free_slot_ops(sghsc->sghsc_slot_table[i].slot_ops);
1425 1425 if (sghsc->sghsc_slot_table[i].handle)
1426 1426 (void) hpc_slot_unregister(
1427 1427 &sghsc->sghsc_slot_table[i].handle);
1428 1428 }
1429 1429
1430 1430 /* finally free up slot_table */
1431 1431 kmem_free(sghsc->sghsc_slot_table,
1432 1432 (size_t)(sghsc->sghsc_num_slots * sizeof (sghsc_slot_t)));
1433 1433
1434 1434 }
1435 1435
1436 1436 /*
1437 1437 * sghsc_find_sloth()
1438 1438 * Find slot handle by node id, board number and slot numbert
1439 1439 * Returns slot handle or 0 if slot not found.
1440 1440 */
1441 1441 static hpc_slot_t
1442 1442 sghsc_find_sloth(int node_id, int board, int slot)
1443 1443 {
1444 1444 int instance;
1445 1445 sghsc_t *sghsc;
1446 1446
1447 1447 for (instance = 0; instance < sghsc_maxinst; instance++) {
1448 1448 sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance);
1449 1449
1450 1450 if (sghsc == NULL || sghsc->sghsc_node_id != node_id ||
1451 1451 sghsc->sghsc_board != board)
1452 1452 continue;
1453 1453
1454 1454 DEBUGF(1, (CE_NOTE, "sghsc_find_sloth on board %d at node %d"
1455 1455 " slot %d", board, node_id, slot))
1456 1456
1457 1457 if (sghsc->sghsc_num_slots < (slot + 1)) {
1458 1458 cmn_err(CE_WARN, "sghsc%d: slot data corruption at"
1459 1459 "node %d / board %d", instance, node_id, board);
1460 1460 return (NULL);
1461 1461 }
1462 1462
1463 1463 if (sghsc->sghsc_valid == 0)
1464 1464 return (NULL);
1465 1465
1466 1466 /*
1467 1467 * Found matching slot, return handle.
1468 1468 */
1469 1469 return (sghsc->sghsc_slot_table[slot].handle);
1470 1470 }
1471 1471
1472 1472 DEBUGF(1, (CE_WARN, "sghsc_find_sloth: slot %d not found for node %d"
1473 1473 " / board %d", slot, node_id, board));
1474 1474 return (NULL);
1475 1475 }
1476 1476
1477 1477 /*
1478 1478 * sghsc_event_handler()
1479 1479 * Event Handler. This is what for other platforms was an interrupt
1480 1480 * Handler servicing events. It accepts an event and signals it to
1481 1481 * non-interrupt thread.
1482 1482 */
1483 1483 uint_t
1484 1484 sghsc_event_handler(char *arg)
1485 1485 {
1486 1486 sghsc_event_t *rsp_data;
1487 1487 hpc_slot_t sloth;
1488 1488 sghsc_t *enum_state;
1489 1489
1490 1490 DEBUGF(1, (CE_NOTE, "sghsc: sghsc_event_handler called"))
1491 1491
1492 1492 rsp_data = (sghsc_event_t *)(((sbbc_msg_t *)arg)->msg_buf);
1493 1493
1494 1494 if (rsp_data == NULL) {
1495 1495 cmn_err(CE_WARN,
1496 1496 ("sghsc: sghsc_event_handler argument is null\n"));
1497 1497 return (DDI_INTR_CLAIMED);
1498 1498 }
1499 1499
1500 1500 sloth = sghsc_find_sloth(rsp_data->node_id, rsp_data->board,
1501 1501 rsp_data->slot);
1502 1502 /*
1503 1503 * On a board disconnect sghsc soft state may not exist
1504 1504 * when the interrupt occurs. We should treat these
1505 1505 * interrupts as noise and but them.
1506 1506 */
1507 1507 if (sloth == NULL) {
1508 1508 DEBUGF(1, (CE_WARN, "sghsc: slot info not available for"
1509 1509 " node %d / board %d slot %d. CPCI event rejected",
1510 1510 rsp_data->node_id, rsp_data->board, rsp_data->slot));
1511 1511 return (DDI_INTR_CLAIMED);
1512 1512 }
1513 1513
1514 1514 enum_state = sghsc_find_softstate(rsp_data->node_id, rsp_data->board,
1515 1515 rsp_data->slot);
1516 1516 if (enum_state == NULL) {
1517 1517 cmn_err(CE_WARN, "sghsc: soft state not available for"
1518 1518 " node %d / board %d slot %d", rsp_data->node_id,
1519 1519 rsp_data->board, rsp_data->slot);
1520 1520 return (DDI_INTR_UNCLAIMED);
1521 1521 }
1522 1522
1523 1523 DEBUGF(1, (CE_NOTE, "sghsc: node %d", rsp_data->node_id));
1524 1524 DEBUGF(1, (CE_NOTE, "sghsc: board %d", rsp_data->board));
1525 1525 DEBUGF(1, (CE_NOTE, "sghsc: slot %d", rsp_data->slot));
1526 1526 DEBUGF(1, (CE_NOTE, "sghsc: event info %d", rsp_data->info));
1527 1527
1528 1528 switch (rsp_data->info) {
1529 1529 case SGHSC_EVENT_CARD_INSERT:
1530 1530 DEBUGF(1, (CE_NOTE, "sghsc: card inserted node %d / board %d"
1531 1531 " slot %d", rsp_data->node_id, rsp_data->board,
1532 1532 rsp_data->slot));
1533 1533 enum_state->sghsc_slot_table[rsp_data->slot].board_type =
1534 1534 HPC_BOARD_CPCI_HS;
1535 1535 enum_state->sghsc_slot_table[rsp_data->slot].slot_status =
1536 1536 HPC_SLOT_DISCONNECTED;
1537 1537 break;
1538 1538 case SGHSC_EVENT_CARD_REMOVE:
1539 1539 DEBUGF(1, (CE_NOTE, "sghsc: card removed node %d / board %d"
1540 1540 " slot %d", rsp_data->node_id, rsp_data->board,
1541 1541 rsp_data->slot));
1542 1542 enum_state->sghsc_slot_table[rsp_data->slot].board_type =
1543 1543 HPC_BOARD_UNKNOWN;
1544 1544 enum_state->sghsc_slot_table[rsp_data->slot].slot_status =
1545 1545 HPC_SLOT_EMPTY;
1546 1546 return (DDI_INTR_CLAIMED);
1547 1547 case SGHSC_EVENT_POWER_ON:
1548 1548 DEBUGF(1, (CE_NOTE, "sghsc: power on node %d / board %d"
1549 1549 " slot %d", rsp_data->node_id, rsp_data->board,
1550 1550 rsp_data->slot));
1551 1551 return (DDI_INTR_CLAIMED);
1552 1552 case SGHSC_EVENT_POWER_OFF:
1553 1553 DEBUGF(1, (CE_NOTE, "sghsc: power off node %d / board %d"
1554 1554 " slot %d", rsp_data->node_id, rsp_data->board,
1555 1555 rsp_data->slot));
1556 1556 return (DDI_INTR_CLAIMED);
1557 1557 case SGHSC_EVENT_HEALTHY_LOST:
1558 1558 DEBUGF(1, (CE_NOTE, "sghsc: healthy lost node %d / board %d"
1559 1559 " slot %d", rsp_data->node_id, rsp_data->board,
1560 1560 rsp_data->slot));
1561 1561 return (DDI_INTR_CLAIMED);
1562 1562 case SGHSC_EVENT_LEVER_ACTION:
1563 1563 DEBUGF(1, (CE_NOTE, "sghsc: ENUM generated for node %d /"
1564 1564 "board %d slot %d", rsp_data->node_id, rsp_data->board,
1565 1565 rsp_data->slot));
1566 1566 break;
1567 1567 default:
1568 1568 DEBUGF(1, (CE_NOTE, "sghsc: unrecognized event info for"
1569 1569 " node %d / board %d slot %d", rsp_data->node_id,
1570 1570 rsp_data->board, rsp_data->slot));
1571 1571 return (DDI_INTR_CLAIMED);
1572 1572 }
1573 1573
1574 1574 /*
1575 1575 * Signal the ENUM event to the non-interrupt thread as the Hot
1576 1576 * Plug Framework will eventually call sghsc_control() but all
1577 1577 * the mailbox messages are not allowed from interrupt context.
1578 1578 */
1579 1579
1580 1580 if (sghsc_rb_put(&sghsc_rb_header, rsp_data) != DDI_SUCCESS) {
1581 1581 cmn_err(CE_WARN, "sghsc: no space to store #ENUM info");
1582 1582 return (DDI_INTR_UNCLAIMED);
1583 1583 }
1584 1584
1585 1585 cv_signal(&sghsc_event_thread_cv);
1586 1586
1587 1587 return (DDI_INTR_CLAIMED);
1588 1588 }
1589 1589
1590 1590 /*
1591 1591 * sghsc_event_thread_code()
1592 1592 * Event Thread. This is non-interrupt thread servicing #ENUM, Insert,
1593 1593 * Remove, Power on/off, Healthy lost events.
1594 1594 */
1595 1595 static void
1596 1596 sghsc_event_thread_code(void)
1597 1597 {
1598 1598 int rc;
1599 1599 int result;
1600 1600 hpc_slot_t sloth;
1601 1601 sghsc_t *sghsc;
1602 1602 sghsc_event_t rsp_data;
1603 1603
1604 1604 mutex_enter(&sghsc_event_thread_mutex);
1605 1605
1606 1606 for (;;) {
1607 1607 /*
1608 1608 * Wait for Event handler to signal event or self destruction.
1609 1609 * Assuming the mutex will be automatically reaccuired.
1610 1610 */
1611 1611 cv_wait(&sghsc_event_thread_cv, &sghsc_event_thread_mutex);
1612 1612
1613 1613 if (sghsc_event_thread_exit)
1614 1614 break;
1615 1615
1616 1616 /*
1617 1617 * Pick up all the relevant events from the ring buffer.
1618 1618 */
1619 1619 while (sghsc_rb_get(&sghsc_rb_header, &rsp_data) ==
1620 1620 DDI_SUCCESS) {
1621 1621
1622 1622 sghsc = sghsc_find_softstate(rsp_data.node_id,
1623 1623 rsp_data.board, rsp_data.slot);
1624 1624 if (sghsc == NULL)
1625 1625 continue;
1626 1626 sloth = sghsc_find_sloth(rsp_data.node_id,
1627 1627 rsp_data.board, rsp_data.slot);
1628 1628 if (sloth == NULL)
1629 1629 continue;
1630 1630
1631 1631 if (!(sghsc->sghsc_slot_table[rsp_data.slot].flags &
1632 1632 SGHSC_SLOT_AUTO_CFG_EN))
1633 1633 continue;
1634 1634 /*
1635 1635 * Insert event leads only to the electrical
1636 1636 * connection.
1637 1637 */
1638 1638 if (rsp_data.info == SGHSC_EVENT_CARD_INSERT) {
1639 1639 rc = sghsc_connect((caddr_t)sghsc, sloth,
1640 1640 NULL, 0);
1641 1641 if (rc != HPC_SUCCESS)
1642 1642 cmn_err(CE_WARN, "sghsc:"
1643 1643 " could not connect inserted card,"
1644 1644 " node %d / board %d slot %d",
1645 1645 rsp_data.node_id, rsp_data.board,
1646 1646 rsp_data.slot);
1647 1647 continue;
1648 1648 }
1649 1649
1650 1650 /*
1651 1651 * ENUM event received.
1652 1652 * Reset ENUM and notify SC to poll for the next one.
1653 1653 */
1654 1654 rc = hpc_slot_event_notify(sloth, HPC_EVENT_CLEAR_ENUM,
1655 1655 HPC_EVENT_SYNCHRONOUS);
1656 1656
1657 1657 if (rc == HPC_EVENT_UNCLAIMED) {
1658 1658 DEBUGF(1, (CE_WARN,
1659 1659 "sghsc: unable to clear ENUM"));
1660 1660 continue;
1661 1661 }
1662 1662
1663 1663 rc = sghsc_scctl(SGHSC_SET_ENUM_CLEARED,
1664 1664 rsp_data.node_id, rsp_data.board,
1665 1665 rsp_data.slot, &result);
1666 1666 if (rc) {
1667 1667 DEBUGF(1, (CE_WARN,
1668 1668 "sghsc: unable to ACK cleared ENUM"));
1669 1669 continue;
1670 1670 }
1671 1671
1672 1672 /*
1673 1673 * process the ENUM.
1674 1674 */
1675 1675 rc = hpc_slot_event_notify(sloth,
1676 1676 HPC_EVENT_PROCESS_ENUM, HPC_EVENT_SYNCHRONOUS);
1677 1677
1678 1678 if (rc == HPC_EVENT_UNCLAIMED) {
1679 1679 DEBUGF(1, (CE_WARN,
1680 1680 "sghsc: could not process ENUM"));
1681 1681 }
1682 1682 }
1683 1683 }
1684 1684
1685 1685 DEBUGF(1, (CE_NOTE, "sghsc: thread_exit"));
1686 1686 cv_signal(&sghsc_event_thread_cv);
1687 1687 mutex_exit(&sghsc_event_thread_mutex);
1688 1688 thread_exit();
1689 1689 }
1690 1690
1691 1691 /*
1692 1692 * sghsc_find_softstate()
1693 1693 * Find softstate by node id and board number. Slot number is used for
1694 1694 * verification.
1695 1695 * Returns board's softstate or 0 if not found.
1696 1696 */
1697 1697 static sghsc_t *
1698 1698 sghsc_find_softstate(int node_id, int board, int slot)
1699 1699 {
1700 1700 int instance;
1701 1701 sghsc_t *sghsc;
1702 1702
1703 1703 for (instance = 0; instance < sghsc_maxinst; instance++) {
1704 1704 sghsc = (sghsc_t *)ddi_get_soft_state(sghsc_state, instance);
1705 1705
1706 1706 if (sghsc == NULL || sghsc->sghsc_node_id != node_id ||
1707 1707 sghsc->sghsc_board != board)
1708 1708 continue;
1709 1709
1710 1710 if (sghsc->sghsc_num_slots < (slot + 1)) {
1711 1711 cmn_err(CE_WARN, "sghsc%d: "
1712 1712 "slot data corruption", instance);
1713 1713 return (NULL);
1714 1714 }
1715 1715
1716 1716 if (sghsc->sghsc_valid == 0)
1717 1717 return (NULL);
1718 1718
1719 1719 /*
1720 1720 * Found matching data, return soft state.
1721 1721 */
1722 1722 return (sghsc);
1723 1723 }
1724 1724
1725 1725 cmn_err(CE_WARN, "sghsc: soft state not found");
1726 1726 return (NULL);
1727 1727 }
1728 1728
1729 1729 /*
1730 1730 * sghsc_rb_setup()
1731 1731 * Initialize the event ring buffer with a fixed size. It may require
1732 1732 * a more elaborate scheme with buffer extension
1733 1733 */
1734 1734 static void
1735 1735 sghsc_rb_setup(sghsc_rb_head_t *rb_head)
1736 1736 {
1737 1737 if (rb_head->buf == NULL) {
1738 1738 rb_head->put_idx = 0;
1739 1739 rb_head->get_idx = 0;
1740 1740 rb_head->size = SGHSC_RING_BUFFER_SZ;
1741 1741 rb_head->state = SGHSC_RB_EMPTY;
1742 1742
1743 1743 /*
1744 1744 * Allocate space for event ring buffer
1745 1745 */
1746 1746 rb_head->buf = (sghsc_event_t *)kmem_zalloc(
1747 1747 sizeof (sghsc_event_t) * rb_head->size, KM_SLEEP);
1748 1748 }
1749 1749 }
1750 1750
1751 1751 /*
1752 1752 * sghsc_rb_teardown()
1753 1753 * Free event ring buffer resources.
1754 1754 */
1755 1755 static void
1756 1756 sghsc_rb_teardown(sghsc_rb_head_t *rb_head)
1757 1757 {
1758 1758 if (rb_head->buf != NULL) {
1759 1759 /*
1760 1760 * Deallocate space for event ring buffer
1761 1761 */
1762 1762 kmem_free(rb_head->buf,
1763 1763 (size_t)(sizeof (sghsc_event_t) * rb_head->size));
1764 1764
1765 1765 rb_head->buf = NULL;
1766 1766 rb_head->put_idx = 0;
1767 1767 rb_head->get_idx = 0;
1768 1768 rb_head->size = 0;
1769 1769 rb_head->state = SGHSC_RB_EMPTY;
1770 1770 }
1771 1771 }
1772 1772
1773 1773 /*
1774 1774 * sghsc_rb_put()
1775 1775 * Insert an event info into the event ring buffer.
↓ open down ↓ |
1775 lines elided |
↑ open up ↑ |
1776 1776 * Returns DDI_FAILURE if the buffer is full, DDI_SUCCESS otherwise
1777 1777 */
1778 1778 static int
1779 1779 sghsc_rb_put(sghsc_rb_head_t *rb_head, sghsc_event_t *event)
1780 1780 {
1781 1781 if (rb_head->state == SGHSC_RB_FULL)
1782 1782 return (DDI_FAILURE);
1783 1783
1784 1784 rb_head->buf[rb_head->put_idx] = *event;
1785 1785
1786 - rb_head->put_idx = ++rb_head->put_idx & (rb_head->size - 1);
1786 + rb_head->put_idx = (rb_head->put_idx + 1) & (rb_head->size - 1);
1787 1787
1788 1788 if (rb_head->put_idx == rb_head->get_idx)
1789 1789 rb_head->state = SGHSC_RB_FULL;
1790 1790 else
1791 1791 rb_head->state = SGHSC_RB_FLOAT;
1792 1792
1793 1793 return (DDI_SUCCESS);
1794 1794 }
1795 1795 /*
1796 1796 * sghsc_rb_get()
1797 1797 * Remove an event info from the event ring buffer.
1798 1798 * Returns DDI_FAILURE if the buffer is empty, DDI_SUCCESS otherwise.
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
1799 1799 */
1800 1800 static int
1801 1801 sghsc_rb_get(sghsc_rb_head_t *rb_head, sghsc_event_t *event)
1802 1802 {
1803 1803
1804 1804 if (rb_head->state == SGHSC_RB_EMPTY)
1805 1805 return (DDI_FAILURE);
1806 1806
1807 1807 *event = rb_head->buf[rb_head->get_idx];
1808 1808
1809 - rb_head->get_idx = ++rb_head->get_idx & (rb_head->size - 1);
1809 + rb_head->get_idx = (rb_head->get_idx + 1) & (rb_head->size - 1);
1810 1810
1811 1811 if (rb_head->get_idx == rb_head->put_idx)
1812 1812 rb_head->state = SGHSC_RB_EMPTY;
1813 1813 else
1814 1814 rb_head->state = SGHSC_RB_FLOAT;
1815 1815
1816 1816 return (DDI_SUCCESS);
1817 1817 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX