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 /*
29 * Starcat IOSRAM/Tunnel PCI Hot Plug Controller Driver
30 */
31
32 #define CPCI_ENUM
33
34 #include <sys/note.h>
35 #include <sys/types.h>
36 #include <sys/cmn_err.h>
37 #include <sys/kmem.h>
38 #include <sys/errno.h>
39 #include <sys/open.h>
40 #include <sys/stat.h>
41 #include <sys/conf.h>
42 #include <sys/ddi.h>
43 #include <sys/cmn_err.h>
44 #include <sys/sunddi.h>
45 #include <sys/sunndi.h>
46 #include <sys/ddi_impldefs.h>
47 #include <sys/ndi_impldefs.h>
48 #include <sys/modctl.h>
49 #include <sys/disp.h>
50 #include <sys/async.h>
51 #include <sys/hotplug/hpcsvc.h>
52 #include <sys/mboxsc.h>
53 #include <sys/schpc_msg.h>
54 #include <sys/schpc.h>
55 #include <post/scat_dcd.h>
56 #include <sys/taskq.h>
57
58 #ifdef DEBUG
59 int schpc_dump_save_regs = 0;
60 static uint_t schpc_debug_flags = 0;
61 #define SCHPC_DEBUG0(f, s) if ((f)& schpc_debug_flags) \
62 cmn_err(CE_CONT, "schpc: " s "\n")
63 #define SCHPC_DEBUG1(f, s, a) if ((f)& schpc_debug_flags) \
64 cmn_err(CE_CONT, "schpc: " s "\n", a)
65 #define SCHPC_DEBUG2(f, s, a, b) if ((f)& schpc_debug_flags) \
66 cmn_err(CE_CONT, "schpc: " s "\n", a, b)
67 #define SCHPC_DEBUG3(f, s, a, b, c) if ((f)& schpc_debug_flags) \
68 cmn_err(CE_CONT, "schpc: " s "\n", a, b, c)
69 #define SCHPC_DEBUG4(f, s, a, b, c, d) if ((f)& schpc_debug_flags) \
70 cmn_err(CE_CONT, "schpc: " s "\n", a, b, c, d)
71 #define SCHPC_DEBUG5(f, s, a, b, c, d, e) if ((f)& schpc_debug_flags) \
72 cmn_err(CE_CONT, "schpc: " s "\n", a, b, c, d, e)
73 #define SCHPC_DEBUG6(f, s, a, b, c, d, e, ff) if ((f)& schpc_debug_flags) \
74 cmn_err(CE_CONT, "schpc: " s "\n", a, b, c, d, e, ff)
75 #else
76
77 #define SCHPC_DEBUG0(f, s)
78 #define SCHPC_DEBUG1(f, s, a)
79 #define SCHPC_DEBUG2(f, s, a, b)
80 #define SCHPC_DEBUG3(f, s, a, b, c)
81 #define SCHPC_DEBUG4(f, s, a, b, c, d)
82 #define SCHPC_DEBUG5(f, s, a, b, c, d, e)
83 #define SCHPC_DEBUG6(f, s, a, b, c, d, e, ff)
84
85 #endif
86
87 #define D_IDENTIFY 0x00000001
88 #define D_ATTACH 0x00000002
89 #define D_DETACH 0x00000004
90 #define D_OPEN 0x00000008
91 #define D_GETSLOTSTATUS 0x00000010
92 #define D_SETSLOTSTATUS 0x00000020
93 #define D_IOCTL 0x00010000
94 #define D_IOC_CONNECT 0x00020000
95 #define D_IOC_CONTROL 0x00040000
96 #define D_IOC_CONFIG 0x00080000
97 #define D_IOC_STATUS 0x00100000
98 #define D_IOC_MSG 0x00200000
99 #define D_IOC_TEST 0x00400000
100 #define D_IOC_LED 0x00800000
101 #define D_EVENT 0x01000000
102 #define D_THREAD 0x02000000
103 #define D_TRANSID 0x04000000
104 #define D_SLOTTABLE 0x08000000
105 #define D_FREQCHG 0x10000000
106 #define D_APID 0x20000000
107
108 /*
109 * driver global data:
110 */
111 static void *per_schpc_state; /* soft state head */
112 dev_info_t *schpc_devi;
113 static schpc_t *schpc_p;
114
115 clock_t schpc_timeout_putmsg = 60 * 1000; /* 60 seconds */
116 clock_t schpc_timeout_getmsg = 60 * 1000; /* 60 seconds */
117 clock_t schpc_timeout_event = 60 * 5 * 1000; /* 5 minutes */
118
119 int schpc_use_legacy_apid = 0;
120
121 static mboxsc_timeout_range_t schpc_putmsg_timeout_range;
122 static mboxsc_timeout_range_t schpc_getmsg_timeout_range;
123
124 static taskq_t *schpc_event_taskq = NULL;
125
126 /*
127 * replies to mboxsc_getmsg() are handled asynchronously by the
128 * schpc_msg_thread using a linked list of schpc_replylist_t
129 * elements
130 */
131 typedef struct schpc_replylist {
132 struct schpc_replylist *prev; /* link to previous entry */
133 struct schpc_replylist *next; /* link to next entry */
134 kcondvar_t reply_cv; /* condvar for getting reply */
135 kmutex_t reply_lock; /* mutex for getting reply */
136 uint32_t type; /* mboxsc_xxxmsg() msg type */
137 uint32_t cmd; /* mboxsc_xxxmsg() cmd */
138 uint64_t transid; /* mboxsc_xxxmsg() trans id */
139 uint32_t length; /* mboxsc_xxxmsg() length */
140 pcimsg_t reply; /* mboxsc_xxxmsg() reply msg */
141 boolean_t reply_recvd; /* msg reply received */
142 boolean_t reply_cexit; /* client early exit */
143 } schpc_replylist_t;
144
145 static kmutex_t schpc_replylist_mutex; /* replylist mutex */
146 static uint32_t schpc_replylist_count; /* replylist size */
147 static schpc_replylist_t *schpc_replylist_first; /* replylist 1st elem */
148 static schpc_replylist_t *schpc_replylist_last; /* replylist last elem */
149 static boolean_t slots_registered = B_FALSE; /* slots registered? */
150
151 typedef struct {
152 char *cname;
153 char *caddr;
154 char schizo;
155 char leaf;
156 dev_info_t *dip;
157 } find_dev_t;
158
159 /*
160 * Function prototypes for local functions
161 */
162 static int schpc_getexpander(dev_info_t *);
163 static int schpc_getboard(dev_info_t *);
164 static void schpc_event_handler(void *);
165 static void schpc_event_filter(pcimsg_t *msg);
166 static void schpc_reply_handler(pcimsg_t *pmsg, uint32_t type, uint32_t cmd,
167 uint64_t transid, uint32_t length);
168 static uint64_t schpc_gettransid(schpc_t *, int);
169 static int schpc_slot_get_index(schpc_t *, hpc_slot_t);
170 static void schpc_register_all_slots(schpc_t *);
171 static void schpc_setslotled(int, int, int, uint32_t);
172 static void schpc_init_setslot_message(pci_setslot_t *);
173 static void schpc_test(caddr_t, int, void *, uint_t);
174 static int schpc_getslotstatus(uint32_t, uint32_t, uint32_t, pci_getslot_t *);
175 static int schpc_setslotstatus(uint32_t, uint32_t, uint32_t, pci_setslot_t *);
176 static int schpc_match_dip(dev_info_t *, void *);
177 static void schpc_buildapid(dev_info_t *, int, char *);
178 static int schpc_get_slot_status(uint_t, uint_t, uint_t);
179 static void schpc_replylist_unlink(schpc_replylist_t *entry);
180 static schpc_replylist_t *schpc_replylist_link(uint32_t cmd, uint64_t transid,
181 uint32_t length);
182 static void schpc_msg_thread(void);
183 static int schpc_putrequest(uint32_t key, uint32_t type, uint32_t cmd,
184 uint64_t *transidp, uint32_t length,
185 void *datap, clock_t timeout,
186 schpc_replylist_t **entryp);
187 static int schpc_getreply(uint32_t key, uint32_t *typep, uint32_t *cmdp,
188 uint64_t *transidp, uint32_t *lengthp, void *datap,
189 clock_t timeout, schpc_replylist_t *listp);
190
191 static int schpc_slot_freq(pci_getslot_t *);
192 static int schpc_find_dip(dev_info_t *, void *);
193
194 static int schpc_save_leaf(int slot);
195 static void schpc_restore_leaf(int slot);
196 static int schpc_is_leaf_reset_required(int slot);
197 static int schpc_is_freq_switchable(int slot);
198 static void schpc_save_entry(int slot, int list_entry, int save_entry);
199 static void schpc_restore_entry(int slot, int list_entry, int save_entry);
200
201 /*
202 * Function prototype for Hot Plug Services
203 */
204 static int schpc_connect(caddr_t, hpc_slot_t, void *, uint_t);
205 static int schpc_disconnect(caddr_t, hpc_slot_t, void *, uint_t);
206 static int schpc_cpci_control(caddr_t, hpc_slot_t, int, caddr_t);
207 static int schpc_pci_control(caddr_t, hpc_slot_t, int, caddr_t);
208
209 extern int iosram_rd(uint32_t, uint32_t, uint32_t, caddr_t);
210
211 /*
212 * cb_ops and dev_ops:
213 */
214 static struct cb_ops schpc_cb_ops = {
215 nodev, /* open */
216 nodev, /* close */
217 nodev, /* strategy */
218 nodev, /* print */
219 nodev, /* dump */
220 nodev, /* read */
221 nodev, /* write */
222 nodev, /* ioctl */
223 nodev, /* devmap */
224 nodev, /* mmap */
225 nodev, /* segmap */
226 nochpoll, /* poll */
227 ddi_prop_op, /* prop_op */
228 0, /* streamtab */
229 D_NEW | D_MP | D_HOTPLUG /* Driver compatibility flag */
230 };
231
232 /*
233 * Function prototype for dev_ops
234 */
235 static int schpc_attach(dev_info_t *, ddi_attach_cmd_t);
236 static int schpc_detach(dev_info_t *, ddi_detach_cmd_t);
237 static int schpc_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
238
239 static struct dev_ops schpc_dev_ops = {
240 DEVO_REV, /* devo_rev, */
241 0, /* refcnt */
242 schpc_info, /* get_dev_info */
243 nulldev, /* identify */
244 nulldev, /* probe */
245 schpc_attach, /* attach */
246 schpc_detach, /* detach */
247 nodev, /* reset */
248 &schpc_cb_ops, /* driver operations */
249 (struct bus_ops *)0, /* no bus operations */
250 NULL, /* power */
251 ddi_quiesce_not_supported, /* devo_quiesce */
252 };
253
254 /*
255 * loadable module declarations:
256 */
257 static struct modldrv modldrv = {
258 &mod_driverops,
259 "PCI Hot Plug Controller Driver (schpc)",
260 &schpc_dev_ops,
261 };
262
263 static struct modlinkage modlinkage = {
264 MODREV_1,
265 (void *)&modldrv,
266 NULL
267 };
268
269 int
_init(void)270 _init(void)
271 {
272 int ret;
273 int rv;
274
275 SCHPC_DEBUG0(D_ATTACH, "_init() installing module");
276
277 ret = ddi_soft_state_init(&per_schpc_state, sizeof (schpc_t), 1);
278 if (ret != 0) {
279 return (ret);
280 }
281
282 /*
283 * Initialize Outgoing Mailbox.
284 */
285 ret = mboxsc_init(KEY_PCSC, MBOXSC_MBOX_OUT, NULL);
286
287 if (ret != 0) {
288 ddi_soft_state_fini(&per_schpc_state);
289 return (ret);
290 }
291
292 ret = mboxsc_ctrl(KEY_PCSC, MBOXSC_CMD_PUTMSG_TIMEOUT_RANGE,
293 (void *) &schpc_putmsg_timeout_range);
294
295 if (ret != 0) {
296 ddi_soft_state_fini(&per_schpc_state);
297 return (ret);
298 }
299
300 if (schpc_timeout_putmsg < schpc_putmsg_timeout_range.min_timeout) {
301 schpc_timeout_putmsg = schpc_putmsg_timeout_range.min_timeout;
302 cmn_err(CE_WARN, " schpc: resetting putmsg timeout to %ld\n",
303 schpc_timeout_putmsg);
304 }
305
306 if (schpc_timeout_putmsg > schpc_putmsg_timeout_range.max_timeout) {
307 schpc_timeout_putmsg = schpc_putmsg_timeout_range.max_timeout;
308 cmn_err(CE_WARN, " schpc: resetting putmsg timeout to %ld\n",
309 schpc_timeout_putmsg);
310 }
311
312 /*
313 * Create the schpc_event_taskq for MBOXSC_MSG_EVENT processing.
314 */
315 schpc_event_taskq = taskq_create("schpc_event_taskq", 2,
316 minclsyspri, 4, 4, TASKQ_PREPOPULATE);
317
318 /*
319 * Initialize Incoming Mailbox.
320 * NOTE: the callback is null because the schpc_msg_thread will
321 * handle all incoming MBOXSC_MSG_EVENT and MBOXSC_MSG_REPLY
322 * messages.
323 */
324 ret = mboxsc_init(KEY_SCPC, MBOXSC_MBOX_IN, NULL);
325
326 if (ret != 0) {
327 cmn_err(CE_WARN, "schpc: can not initialize KEY_SCPC as "
328 "MBOXSC_MBOX_IN");
329 ddi_soft_state_fini(&per_schpc_state);
330 return (ret);
331 }
332
333 ret = mboxsc_ctrl(KEY_SCPC, MBOXSC_CMD_GETMSG_TIMEOUT_RANGE,
334 (void *) &schpc_getmsg_timeout_range);
335
336 if (ret != 0) {
337 ddi_soft_state_fini(&per_schpc_state);
338 return (ret);
339 }
340
341 if (schpc_timeout_getmsg < schpc_getmsg_timeout_range.min_timeout) {
342 schpc_timeout_getmsg = schpc_getmsg_timeout_range.min_timeout;
343 cmn_err(CE_WARN, " schpc: resetting getmsg timeout to %ld\n",
344 schpc_timeout_getmsg);
345 }
346
347 if (schpc_timeout_getmsg > schpc_getmsg_timeout_range.max_timeout) {
348 schpc_timeout_getmsg = schpc_getmsg_timeout_range.max_timeout;
349 cmn_err(CE_WARN, " schpc: resetting putmsg timeout to %ld\n",
350 schpc_timeout_putmsg);
351 }
352
353 if (schpc_timeout_event < schpc_getmsg_timeout_range.min_timeout) {
354 schpc_timeout_event = schpc_getmsg_timeout_range.min_timeout;
355 cmn_err(CE_WARN, " schpc: resetting event timeout to %ld\n",
356 schpc_timeout_event);
357 }
358
359 if (schpc_timeout_event > schpc_getmsg_timeout_range.max_timeout) {
360 schpc_timeout_event = schpc_getmsg_timeout_range.max_timeout;
361 cmn_err(CE_WARN, " schpc: resetting event timeout to %ld\n",
362 schpc_timeout_event);
363 }
364
365 ret = mod_install(&modlinkage);
366 if (ret != 0) {
367 if ((rv = mboxsc_fini(KEY_PCSC)) != 0) {
368 cmn_err(CE_WARN, "schpc: _init() - "
369 "mboxsc_fini(KEY_PCSC) failed: 0x%x", rv);
370 }
371 if ((rv = mboxsc_fini(KEY_SCPC)) != 0) {
372 cmn_err(CE_WARN, "schpc: _init() - "
373 "mboxsc_fini(KEY_SCPC) failed: 0x%x", rv);
374 }
375 taskq_destroy(schpc_event_taskq);
376 ddi_soft_state_fini(&per_schpc_state);
377 return (ret);
378 }
379
380 SCHPC_DEBUG0(D_ATTACH, "_init() module installed");
381
382 /*
383 * Start the schpc_msg_thread to continuously monitor the
384 * MBOXSC_MBOX_IN mailbox for incoming MBOXSC_MSG_EVENTs and
385 * MBOXSC_MSG_REPLYs.
386 */
387 mutex_init(&schpc_replylist_mutex, NULL, MUTEX_DRIVER, NULL);
388 (void) thread_create(NULL, 0, schpc_msg_thread,
389 NULL, 0, &p0, TS_RUN, minclsyspri);
390
391 SCHPC_DEBUG0(D_ATTACH, "_init() started schpc_msg_thread");
392
393 return (ret);
394 }
395
396 int
_fini(void)397 _fini(void)
398 {
399 SCHPC_DEBUG0(D_ATTACH, "_fini()");
400
401 return (DDI_FAILURE);
402 }
403
404 int
_info(struct modinfo * modinfop)405 _info(struct modinfo *modinfop)
406 {
407 SCHPC_DEBUG0(D_ATTACH, "_info() called.");
408
409 return (mod_info(&modlinkage, modinfop));
410 }
411
412 static int
schpc_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)413 schpc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
414 {
415 int instance = ddi_get_instance(devi);
416 int rval;
417
418 SCHPC_DEBUG1(D_ATTACH, "attach(%x) ATTACH", instance);
419
420 switch (cmd) {
421 case DDI_ATTACH:
422
423 /*
424 * Allocate the soft state structure for this instance.
425 */
426 rval = ddi_soft_state_zalloc(per_schpc_state, instance);
427
428 if (rval != DDI_SUCCESS) {
429 SCHPC_DEBUG1(D_ATTACH,
430 "schpc_attach(%x) Can not allocate "
431 "soft state structure", instance);
432 return (DDI_FAILURE);
433 }
434
435 schpc_p = (schpc_t *)ddi_get_soft_state(per_schpc_state,
436 instance);
437
438 if (schpc_p == NULL) {
439 return (DDI_FAILURE);
440 }
441
442 mutex_init(&schpc_p->schpc_mutex, NULL, MUTEX_DRIVER, NULL);
443 cv_init(&schpc_p->schpc_cv, NULL, CV_DRIVER, NULL);
444
445 /*
446 * Put schpc structure on global linked list.
447 */
448
449 /*
450 * Initialize starting transaction ID.
451 */
452 schpc_p->schpc_transid = 0;
453
454 schpc_p->schpc_number_of_slots = STARCAT_MAX_SLOTS;
455
456 SCHPC_DEBUG2(D_ATTACH, "schpc_attach(%x) slot-table property "
457 "describes %d slots", instance,
458 schpc_p->schpc_number_of_slots);
459
460 schpc_p->schpc_hotplugmodel = ddi_getprop(DDI_DEV_T_ANY,
461 devi, 0, "hot-plug-model", SCHPC_HOTPLUGTYPE_CPCIHOTPLUG);
462
463 SCHPC_DEBUG2(D_ATTACH, "attach(%x) ATTACH - Hot Plug Model=%x",
464 instance, schpc_p->schpc_hotplugmodel);
465
466 /*
467 * What type of hot plug do these slots support? The only
468 * types of slots we support is the cPCI Hot Plug Model
469 * and Not Hot Pluggable.
470 */
471 if (schpc_p->schpc_hotplugmodel !=
472 SCHPC_HOTPLUGTYPE_CPCIHOTPLUG) {
473 schpc_p->schpc_hotplugmodel =
474 SCHPC_HOTPLUGTYPE_NOTHOTPLUGGABLE;
475 }
476
477 schpc_p->schpc_slot = (schpc_slot_t *)kmem_zalloc((size_t)
478 (schpc_p->schpc_number_of_slots * sizeof (schpc_slot_t)),
479 KM_SLEEP);
480
481 schpc_p->schpc_devi = devi;
482 schpc_p->schpc_instance = instance;
483
484 /*
485 * Start thread to search the device tree and register
486 * all found pci slots.
487 */
488 (void) thread_create(NULL, 0, schpc_register_all_slots,
489 (void *)schpc_p, 0, &p0, TS_RUN, minclsyspri);
490
491 break;
492
493 case DDI_PM_RESUME:
494 case DDI_RESUME:
495 return (DDI_SUCCESS);
496 default:
497 cmn_err(CE_WARN, "schpc%d: Cmd != DDI_ATTACH/DDI_RESUME",
498 instance);
499
500 return (DDI_FAILURE);
501 }
502
503 SCHPC_DEBUG1(D_ATTACH,
504 "schpc_attach(%x) Attach - DDI_SUCCESS", instance);
505
506 return (DDI_SUCCESS);
507 }
508
509 /*ARGSUSED*/
510 static int
schpc_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)511 schpc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
512 {
513 int instance = ddi_get_instance(devi);
514
515 SCHPC_DEBUG1(D_DETACH, "detach(%x) DETACH", instance);
516
517 return (DDI_FAILURE);
518 }
519
520 /*ARGSUSED*/
521 static int
schpc_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)522 schpc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
523 void **result)
524 {
525 int error;
526
527 switch (infocmd) {
528 case DDI_INFO_DEVT2DEVINFO:
529 *result = (void *)schpc_devi;
530 error = DDI_SUCCESS;
531 break;
532 case DDI_INFO_DEVT2INSTANCE:
533 *result = (void *)0;
534 error = DDI_SUCCESS;
535 break;
536 default:
537 error = DDI_FAILURE;
538 }
539 return (error);
540 }
541
542 /*
543 * schpc_connect()
544 *
545 * Called by Hot Plug Services to connect a slot to the bus.
546 */
547
548 /*ARGSUSED*/
549 static int
schpc_connect(caddr_t ops_arg,hpc_slot_t slot_hdl,void * data,uint_t flags)550 schpc_connect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags)
551 {
552 int rval;
553 int expander, board;
554 pci_setslot_t setslot;
555 pci_getslot_t getslot;
556 int slot;
557
558 SCHPC_DEBUG2(D_IOC_CONNECT, "schpc_connect( ops_arg=%p slot_hdl=%p)",
559 (void *)ops_arg, (void *)slot_hdl);
560
561 mutex_enter(&schpc_p->schpc_mutex);
562
563 slot = schpc_slot_get_index(schpc_p, slot_hdl);
564
565 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
566 SCHPC_DEBUG0(D_IOC_CONNECT, "schpc_connect - HPC Not Inited");
567 mutex_exit(&schpc_p->schpc_mutex);
568 return (HPC_ERR_FAILED);
569 }
570
571 /*
572 * Check to see if the slot is already connected.
573 */
574 if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_CONNECTED) {
575 mutex_exit(&schpc_p->schpc_mutex);
576 return (0);
577 }
578
579 /*
580 * Block if another thread is executing a HPC command.
581 */
582 while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
583 cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
584 }
585
586 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
587
588 mutex_exit(&schpc_p->schpc_mutex);
589
590 expander = schpc_p->schpc_slot[slot].expander; /* get expander */
591 board = schpc_p->schpc_slot[slot].board; /* get board */
592
593 SCHPC_DEBUG3(D_IOC_CONNECT,
594 "schpc_connect Expander=%x Board=%x Slot=%x",
595 expander, board, SCHPC_SLOT_NUM(slot));
596
597
598 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_OCC_GOOD)) {
599 cmn_err(CE_WARN, "schpc: Hot Plug - Unable to complete "
600 "connection on Expander %d Board %d Slot %d - "
601 "Ap_Id=%s : Occupant is in failed state",
602 expander, board, SCHPC_SLOT_NUM(slot),
603 schpc_p->schpc_slot[slot].ap_id);
604
605 /* Fault LED should already be illuminated */
606
607 goto failed;
608 }
609
610 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_REC_GOOD)) {
611 cmn_err(CE_WARN, "schpc: Hot Plug - Unable to complete "
612 "connection on Expander %d Board %d Slot %d - "
613 "Ap_Id=%s : Receptacle is in failed state",
614 expander, board, SCHPC_SLOT_NUM(slot),
615 schpc_p->schpc_slot[slot].ap_id);
616
617 /* Fault LED should already be illuminated */
618
619 goto failed;
620 }
621
622 rval = schpc_getslotstatus(expander, board, slot, &getslot);
623
624 if (rval) {
625 /*
626 * System Controller/Mailbox failure.
627 */
628 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on "
629 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
630 "Communicate with System Controller", expander, board,
631 SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
632
633 schpc_setslotled(expander, board, slot, FAULT_LED_ON);
634
635 goto failed;
636 }
637
638 if (getslot.slot_replystatus != PCIMSG_REPLY_GOOD) {
639
640 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on "
641 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
642 "Read Slot Status", expander, board,
643 SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
644
645 schpc_setslotled(expander, board, slot, FAULT_LED_ON);
646
647 goto failed;
648 }
649
650 if (getslot.slot_empty) {
651 /*
652 * If the slot is empty - fail the connection request.
653 */
654 goto failed;
655 }
656
657 SCHPC_DEBUG3(D_FREQCHG, "Slot %d - slot_freq_setting %d "
658 "slot_freq_cap %d", slot, getslot.slot_freq_setting,
659 getslot.slot_freq_cap);
660
661 if (!schpc_is_freq_switchable(slot) &&
662 (getslot.slot_freq_setting > getslot.slot_freq_cap)) {
663
664 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
665 "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
666 "Bus Speed Mismatch", expander,
667 board, SCHPC_SLOT_NUM(slot),
668 schpc_p->schpc_slot[slot].ap_id);
669
670 schpc_setslotled(expander, board, slot, FAULT_LED_ON);
671
672 goto failed;
673 }
674
675 if (schpc_is_leaf_reset_required(slot) &&
676 (schpc_p->schpc_slot[slot].saved_regs == NULL)) {
677
678 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Save Regs before connect",
679 slot);
680
681 /*
682 * A prior disconnect had not saved off the leaf so lets
683 * save it now. This is probably due to the domain being
684 * booted with a slot with no cassette.
685 */
686 if (schpc_save_leaf(slot) != 0) {
687 cmn_err(CE_WARN, "schpc - Unable to save leaf regs on "
688
689 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : ",
690 expander, board, slot & 3,
691 schpc_p->schpc_slot[slot].ap_id);
692
693 schpc_setslotled(expander, board, slot, FAULT_LED_ON);
694
695 goto failed;
696 }
697 }
698
699 /*
700 * Initialize Set Slot Command.
701 */
702 schpc_init_setslot_message(&setslot);
703
704 setslot.slot_power_on = PCIMSG_ON; /* Turn slot power on */
705
706 setslot.slot_led_fault = PCIMSG_LED_FLASH; /* Flash Fault LED */
707
708 rval = schpc_setslotstatus(expander, board, slot, &setslot);
709
710 if (rval != 0) {
711 /*
712 * System Controller/Mailbox failure.
713 */
714 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on "
715 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
716 "Communicate with System Controller", expander, board,
717 SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
718
719 schpc_setslotled(expander, board, slot, FAULT_LED_ON);
720
721 goto failed;
722 }
723
724 if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) {
725
726 /*
727 * The Request was successfully completed.
728 */
729
730 SCHPC_DEBUG0(D_IOC_CONNECT, "schpc_connect() - setslotstatus "
731 "succeeded");
732
733 /*
734 * Need to check HEALTHY# signal.
735 */
736 rval = schpc_getslotstatus(expander, board, slot, &getslot);
737
738 if (rval) {
739 /*
740 * System Controller/Mailbox failure.
741 */
742 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
743 "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
744 "Unable to Communicate with System Controller",
745 expander, board, SCHPC_SLOT_NUM(slot),
746 schpc_p->schpc_slot[slot].ap_id);
747
748 schpc_setslotled(expander, board, slot, FAULT_LED_ON);
749
750 goto failed;
751 }
752
753 if (getslot.slot_replystatus != PCIMSG_REPLY_GOOD) {
754
755 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
756 "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
757 "Unable to Read Slot Status", expander, board,
758 SCHPC_SLOT_NUM(slot),
759 schpc_p->schpc_slot[slot].ap_id);
760
761 schpc_setslotled(expander, board, slot, FAULT_LED_ON);
762
763 goto failed;
764 }
765
766 if ((getslot.slot_powergood != PCIMSG_ON) ||
767 (getslot.slot_powerfault == PCIMSG_ON)) {
768 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
769 "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
770 "Power failure detected", expander, board,
771 SCHPC_SLOT_NUM(slot),
772 schpc_p->schpc_slot[slot].ap_id);
773
774 /*
775 * Initialize Set Slot Command.
776 */
777 schpc_init_setslot_message(&setslot);
778
779 /*
780 * Turn slot power off.
781 */
782 setslot.slot_power_off = PCIMSG_ON;
783
784 (void) schpc_setslotstatus(expander, board,
785 slot, &setslot);
786
787 schpc_setslotled(expander, board, slot,
788 (SERVICE_LED_ON | FAULT_LED_ON));
789
790 goto failed;
791 }
792
793 if (!getslot.slot_HEALTHY) {
794 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
795 "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
796 "Adapter did not assert HEALTHY#", expander, board,
797 SCHPC_SLOT_NUM(slot),
798 schpc_p->schpc_slot[slot].ap_id);
799
800 /*
801 * Initialize Set Slot Command.
802 */
803 schpc_init_setslot_message(&setslot);
804
805 /*
806 * Turn slot power off.
807 */
808 setslot.slot_power_off = PCIMSG_ON;
809
810 (void) schpc_setslotstatus(expander, board, slot,
811 &setslot);
812
813 schpc_setslotled(expander, board, slot,
814 (SERVICE_LED_ON | FAULT_LED_ON));
815
816 goto failed;
817 }
818
819 /*
820 * Initialize Set Slot Command.
821 */
822 schpc_init_setslot_message(&setslot);
823
824 /*
825 * Start monitoring ENUM# and HEALTHY#
826 */
827 setslot.slot_enable_HEALTHY = PCIMSG_ON;
828 setslot.slot_enable_ENUM = PCIMSG_ON;
829
830 rval = schpc_setslotstatus(expander, board, slot, &setslot);
831
832 if (rval != 0) {
833 /*
834 * System Controller/Mailbox failure.
835 */
836 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
837 "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
838 "Unable to Communicate with System Controller",
839 expander, board, SCHPC_SLOT_NUM(slot),
840 schpc_p->schpc_slot[slot].ap_id);
841
842 schpc_setslotled(expander, board, slot, FAULT_LED_ON);
843
844 goto failed;
845 }
846 if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) {
847
848 int freq;
849 find_dev_t find_dev;
850
851 /*
852 * The Request was successfully completed.
853 */
854
855 SCHPC_DEBUG0(D_IOC_CONNECT,
856 "schpc_connect() - setslotstatus succeeded");
857
858 schpc_p->schpc_slot[slot].state |=
859 SCHPC_SLOTSTATE_CONNECTED;
860
861 schpc_setslotled(expander, board, slot,
862 (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_OFF));
863
864 find_dev.cname = schpc_p->schpc_slot[slot].nexus_path;
865 find_dev.caddr = (char *)kmem_alloc(MAXPATHLEN,
866 KM_SLEEP);
867 find_dev.dip = NULL;
868
869 /* root node doesn't have to be held */
870 ddi_walk_devs(ddi_root_node(), schpc_find_dip,
871 &find_dev);
872 if (find_dev.dip != NULL) {
873 /*
874 * Update the clock-frequency property to
875 * reflect the new slot-frequency.
876 */
877 freq = schpc_slot_freq(&getslot);
878 SCHPC_DEBUG2(D_FREQCHG,
879 "schpc_connect: updating dip=%p freq=%dHZ",
880 (void *)find_dev.dip, freq);
881 if (ndi_prop_update_int(DDI_DEV_T_NONE,
882 find_dev.dip, "clock-frequency", freq)
883 != DDI_SUCCESS) {
884 cmn_err(CE_WARN,
885 "schpc: - failed to update "
886 "clock-frequency property for %s",
887 find_dev.cname);
888 }
889 ndi_rele_devi(find_dev.dip);
890 } else {
891 cmn_err(CE_WARN,
892 "schpc: couldn't find dip for %s ",
893 find_dev.cname);
894 }
895 kmem_free(find_dev.caddr, MAXPATHLEN);
896
897 mutex_enter(&schpc_p->schpc_mutex);
898 schpc_p->schpc_slot[slot].state &=
899 ~SCHPC_SLOTSTATE_EXECUTING;
900
901 /*
902 * If leaf registers were saved off, then they
903 * need to be restored.
904 */
905 schpc_restore_leaf(slot);
906
907 /*
908 * Since the device saw a PCI Reset, we need to
909 * wait 2^25 clock cycles before the first
910 * Configuration access. The worst case is 33MHz,
911 * which is a 1 second wait.
912 */
913 drv_usecwait(1000000);
914
915 cv_signal(&schpc_p->schpc_cv);
916 mutex_exit(&schpc_p->schpc_mutex);
917
918 return (0);
919 } else {
920 /*
921 * The System Controller Rejected the
922 * connection request.
923 */
924 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
925 "on Expander %d Board %d PCI Slot %d - Ap_Id=%s :"
926 "System Controller failed connection request",
927 expander, board, SCHPC_SLOT_NUM(slot),
928 schpc_p->schpc_slot[slot].ap_id);
929
930 schpc_setslotled(expander, board, slot, FAULT_LED_ON);
931
932 goto failed;
933 }
934 }
935
936 /*
937 * The System Controller Rejected the connection request.
938 */
939 cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on "
940 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : System Controller "
941 "failed connection request", expander, board, SCHPC_SLOT_NUM(slot),
942 schpc_p->schpc_slot[slot].ap_id);
943
944 schpc_setslotled(expander, board, slot, FAULT_LED_ON);
945
946 failed:
947 mutex_enter(&schpc_p->schpc_mutex);
948 schpc_p->schpc_slot[slot].state &=
949 ~SCHPC_SLOTSTATE_EXECUTING;
950 cv_signal(&schpc_p->schpc_cv);
951 mutex_exit(&schpc_p->schpc_mutex);
952
953 return (HPC_ERR_FAILED);
954 }
955
956 /*
957 * schpc_disconnect()
958 *
959 * Called by Hot Plug Services to disconnect a slot to the bus.
960 */
961
962 /*ARGSUSED*/
963 static int
schpc_disconnect(caddr_t ops_arg,hpc_slot_t slot_hdl,void * data,uint_t flags)964 schpc_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data,
965 uint_t flags)
966 {
967 int rval;
968 int expander, board, slot;
969 pci_setslot_t setslot;
970
971 SCHPC_DEBUG2(D_IOC_CONNECT,
972 "schpc_disconnect( ops_arg=%p slot_hdl=%p)", (void *)ops_arg,
973 slot_hdl);
974
975 mutex_enter(&schpc_p->schpc_mutex);
976
977 slot = schpc_slot_get_index(schpc_p, slot_hdl);
978
979 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
980 SCHPC_DEBUG0(D_IOC_CONNECT,
981 "schpc_disconnect - HPC Not Inited");
982 mutex_exit(&schpc_p->schpc_mutex);
983 return (HPC_ERR_FAILED);
984 }
985
986 /*
987 * Check to see if we are already disconnected.
988 */
989 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_CONNECTED)) {
990 mutex_exit(&schpc_p->schpc_mutex);
991 return (0);
992 }
993
994 /*
995 * Block if another thread is executing a HPC command.
996 */
997 while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
998 cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
999 }
1000
1001 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
1002
1003 mutex_exit(&schpc_p->schpc_mutex);
1004
1005 expander = schpc_p->schpc_slot[slot].expander; /* get expander */
1006 board = schpc_p->schpc_slot[slot].board; /* get board */
1007
1008 /*
1009 * If a leaf reset is going to be asserted due to a mode/freq.
1010 * change, then the leaf registers of the XMITS bridge will need
1011 * to be saved off prior to the connect.
1012 */
1013 if (schpc_is_leaf_reset_required(slot)) {
1014 if (schpc_save_leaf(slot) != 0) {
1015
1016 cmn_err(CE_WARN, "schpc - Unable to save leaf regs on "
1017 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : ",
1018 expander, board, slot & 3,
1019 schpc_p->schpc_slot[slot].ap_id);
1020
1021 schpc_setslotled(expander, board, slot, FAULT_LED_ON);
1022
1023 goto failed;
1024 }
1025 }
1026
1027 /*
1028 * Initialize Set Slot Command.
1029 */
1030 schpc_init_setslot_message(&setslot);
1031
1032 setslot.slot_power_off = PCIMSG_ON; /* Turn Power Off */
1033
1034 setslot.slot_led_fault = PCIMSG_LED_FLASH; /* Flash the Fault LED */
1035
1036 setslot.slot_disable_ENUM = PCIMSG_ON; /* Mask the ENUM# signal */
1037 setslot.slot_disable_HEALTHY = PCIMSG_ON; /* Mask the HEALTHY# sig */
1038
1039 rval = schpc_setslotstatus(expander, board, slot, &setslot);
1040
1041 SCHPC_DEBUG1(D_IOC_CONNECT, "schpc_disconnect() - "
1042 "setslotstatus returned 0x%x", rval);
1043
1044 if (rval != 0) {
1045 /*
1046 * System Controller/Mailbox failure.
1047 */
1048 cmn_err(CE_WARN, "schpc - Hot Plug Disconnection Failed on "
1049 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
1050 "Communicate with System Controller", expander, board,
1051 SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
1052
1053 schpc_setslotled(expander, board, slot, FAULT_LED_ON);
1054
1055 goto failed;
1056 }
1057
1058 SCHPC_DEBUG1(D_IOC_CONNECT, "schpc_disconnect() - "
1059 "slot_replystatus returned 0x%x", setslot.slot_replystatus);
1060
1061 if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) {
1062
1063 /*
1064 * The Request was successfully completed.
1065 */
1066 schpc_p->schpc_slot[slot].state &=
1067 ~SCHPC_SLOTSTATE_CONNECTED;
1068
1069 schpc_setslotled(expander, board, slot,
1070 (POWER_LED_OFF | SERVICE_LED_ON | FAULT_LED_OFF));
1071
1072 SCHPC_DEBUG0(D_IOC_CONNECT,
1073 "schpc_disconnect() - setslotstatus succeeded");
1074
1075 mutex_enter(&schpc_p->schpc_mutex);
1076 schpc_p->schpc_slot[slot].state &=
1077 ~SCHPC_SLOTSTATE_EXECUTING;
1078 cv_signal(&schpc_p->schpc_cv);
1079 mutex_exit(&schpc_p->schpc_mutex);
1080
1081 return (0);
1082 }
1083 /*
1084 * System Controller/Mailbox failure.
1085 */
1086 cmn_err(CE_WARN, "schpc - Hot Plug Disconnection Failed on "
1087 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : System Controller "
1088 "failed disconnection request", expander, board,
1089 SCHPC_SLOT_NUM(slot),
1090 schpc_p->schpc_slot[slot].ap_id);
1091
1092 schpc_setslotled(expander, board, slot, FAULT_LED_ON);
1093
1094 failed:
1095 schpc_restore_leaf(slot);
1096 mutex_enter(&schpc_p->schpc_mutex);
1097 schpc_p->schpc_slot[slot].state &=
1098 ~SCHPC_SLOTSTATE_EXECUTING;
1099 cv_signal(&schpc_p->schpc_cv);
1100 mutex_exit(&schpc_p->schpc_mutex);
1101
1102 return (HPC_ERR_FAILED);
1103 }
1104
1105 /*
1106 * schpc_cpci_control
1107 *
1108 * Called by Hot Plug Services to perform a attachment point specific
1109 * on a Hot Pluggable Compact PCI Slot.
1110 */
1111 /*ARGSUSED*/
1112 static int
schpc_cpci_control(caddr_t ops_arg,hpc_slot_t slot_hdl,int request,caddr_t arg)1113 schpc_cpci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request,
1114 caddr_t arg)
1115 {
1116 int rval;
1117 int expander, board, slot;
1118 pci_setslot_t setslot;
1119 pci_getslot_t slotstatus;
1120 hpc_led_info_t *hpc_led_info;
1121
1122 SCHPC_DEBUG3(D_IOC_CONTROL,
1123 "schpc_cpci_control(op_args=%p slot_hdl=%p request=%x)",
1124 (void *)ops_arg, (void *)slot_hdl, request);
1125
1126 mutex_enter(&schpc_p->schpc_mutex);
1127
1128 slot = schpc_slot_get_index(schpc_p, slot_hdl);
1129
1130 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
1131 SCHPC_DEBUG0(D_IOC_CONNECT,
1132 "schpc_disconnect - HPC Not Inited");
1133 mutex_exit(&schpc_p->schpc_mutex);
1134 return (HPC_ERR_FAILED);
1135 }
1136
1137 /*
1138 * Block if another thread is executing a HPC command.
1139 */
1140 while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
1141 cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
1142 }
1143
1144 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
1145
1146 mutex_exit(&schpc_p->schpc_mutex);
1147
1148 expander = schpc_p->schpc_slot[slot].expander; /* get expander */
1149 board = schpc_p->schpc_slot[slot].board; /* get board */
1150
1151 /*
1152 * Initialize Set Slot Command.
1153 */
1154 schpc_init_setslot_message(&setslot);
1155
1156 /*
1157 * Initialize LED to last know state.
1158 */
1159 switch (schpc_p->schpc_slot[slot].led.led_power) {
1160 case LED_ON:
1161 setslot.slot_led_power = PCIMSG_LED_ON;
1162 break;
1163 case LED_OFF:
1164 setslot.slot_led_power = PCIMSG_LED_OFF;
1165 break;
1166 case LED_FLASH:
1167 setslot.slot_led_power = PCIMSG_LED_FLASH;
1168 break;
1169 }
1170
1171 switch (schpc_p->schpc_slot[slot].led.led_service) {
1172 case LED_ON:
1173 setslot.slot_led_service = PCIMSG_LED_ON;
1174 break;
1175 case LED_OFF:
1176 setslot.slot_led_service = PCIMSG_LED_OFF;
1177 break;
1178 case LED_FLASH:
1179 setslot.slot_led_service = PCIMSG_LED_FLASH;
1180 break;
1181 }
1182
1183 switch (schpc_p->schpc_slot[slot].led.led_fault) {
1184 case LED_ON:
1185 setslot.slot_led_fault = PCIMSG_LED_ON;
1186 break;
1187 case LED_OFF:
1188 setslot.slot_led_fault = PCIMSG_LED_OFF;
1189 break;
1190 case LED_FLASH:
1191 setslot.slot_led_fault = PCIMSG_LED_FLASH;
1192 break;
1193 }
1194
1195 switch (request) {
1196
1197 case HPC_CTRL_GET_LED_STATE:
1198 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1199 "HPC_CTRL_GET_LED_STATE");
1200 hpc_led_info = (hpc_led_info_t *)arg;
1201
1202 switch (hpc_led_info->led) {
1203 case HPC_FAULT_LED:
1204 switch (schpc_p->schpc_slot[slot].led.led_fault) {
1205 case LED_OFF:
1206 hpc_led_info->state = HPC_LED_OFF;
1207 break;
1208 case LED_ON:
1209 hpc_led_info->state = HPC_LED_ON;
1210 break;
1211 case LED_FLASH:
1212 hpc_led_info->state = HPC_LED_BLINK;
1213 break;
1214 }
1215 break;
1216
1217 case HPC_POWER_LED:
1218 switch (schpc_p->schpc_slot[slot].led.led_power) {
1219 case LED_OFF:
1220 hpc_led_info->state = HPC_LED_OFF;
1221 break;
1222 case LED_ON:
1223 hpc_led_info->state = HPC_LED_ON;
1224 break;
1225 case LED_FLASH:
1226 hpc_led_info->state = HPC_LED_BLINK;
1227 break;
1228 }
1229 break;
1230 case HPC_ATTN_LED:
1231 switch (schpc_p->schpc_slot[slot].led.led_fault) {
1232 case LED_OFF:
1233 hpc_led_info->state = HPC_LED_OFF;
1234 break;
1235 case LED_ON:
1236 hpc_led_info->state = HPC_LED_OFF;
1237 break;
1238 case LED_FLASH:
1239 hpc_led_info->state = HPC_LED_ON;
1240 break;
1241 }
1242 break;
1243 case HPC_ACTIVE_LED:
1244 switch (schpc_p->schpc_slot[slot].led.led_service) {
1245 case LED_OFF:
1246 hpc_led_info->state = HPC_LED_OFF;
1247 break;
1248 case LED_ON:
1249 hpc_led_info->state = HPC_LED_ON;
1250 break;
1251 case LED_FLASH:
1252 hpc_led_info->state = HPC_LED_BLINK;
1253 break;
1254 }
1255 break;
1256 default:
1257 SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - "
1258 "Invalid LED %x", hpc_led_info->led);
1259
1260 mutex_enter(&schpc_p->schpc_mutex);
1261 schpc_p->schpc_slot[slot].state &=
1262 ~SCHPC_SLOTSTATE_EXECUTING;
1263 cv_signal(&schpc_p->schpc_cv);
1264 mutex_exit(&schpc_p->schpc_mutex);
1265
1266 return (HPC_ERR_FAILED);
1267 }
1268
1269 mutex_enter(&schpc_p->schpc_mutex);
1270 schpc_p->schpc_slot[slot].state &=
1271 ~SCHPC_SLOTSTATE_EXECUTING;
1272 cv_signal(&schpc_p->schpc_cv);
1273 mutex_exit(&schpc_p->schpc_mutex);
1274
1275 return (0);
1276
1277 case HPC_CTRL_SET_LED_STATE:
1278 hpc_led_info = (hpc_led_info_t *)arg;
1279
1280 SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - "
1281 "HPC_CTRL_SET_LED_STATE hpc_led_info=%p",
1282 (void *)hpc_led_info);
1283
1284 switch (hpc_led_info->led) {
1285 case HPC_FAULT_LED:
1286 switch (hpc_led_info->state) {
1287 case HPC_LED_OFF:
1288 schpc_p->schpc_slot[slot].led.led_fault =
1289 LED_OFF;
1290 setslot.slot_led_fault = PCIMSG_LED_OFF;
1291 break;
1292 case HPC_LED_ON:
1293 schpc_p->schpc_slot[slot].led.led_fault =
1294 LED_ON;
1295 setslot.slot_led_fault = PCIMSG_LED_ON;
1296 break;
1297 case HPC_LED_BLINK:
1298 schpc_p->schpc_slot[slot].led.led_fault =
1299 LED_FLASH;
1300 setslot.slot_led_fault = PCIMSG_LED_FLASH;
1301 break;
1302 }
1303 break;
1304 case HPC_POWER_LED:
1305 switch (hpc_led_info->state) {
1306 case HPC_LED_OFF:
1307 schpc_p->schpc_slot[slot].led.led_power =
1308 LED_OFF;
1309 setslot.slot_led_power = PCIMSG_LED_OFF;
1310 break;
1311 case HPC_LED_ON:
1312 schpc_p->schpc_slot[slot].led.led_power =
1313 LED_ON;
1314 setslot.slot_led_power = PCIMSG_LED_ON;
1315 break;
1316 case HPC_LED_BLINK:
1317 schpc_p->schpc_slot[slot].led.led_power =
1318 LED_FLASH;
1319 setslot.slot_led_power = PCIMSG_LED_FLASH;
1320 break;
1321 }
1322 break;
1323 case HPC_ATTN_LED:
1324 switch (hpc_led_info->state) {
1325 case HPC_LED_OFF:
1326 schpc_p->schpc_slot[slot].led.led_fault =
1327 LED_OFF;
1328 setslot.slot_led_fault = PCIMSG_LED_OFF;
1329 break;
1330 case HPC_LED_ON:
1331 schpc_p->schpc_slot[slot].led.led_fault =
1332 LED_FLASH;
1333 setslot.slot_led_fault = PCIMSG_LED_FLASH;
1334 break;
1335 case HPC_LED_BLINK:
1336 schpc_p->schpc_slot[slot].led.led_fault =
1337 LED_FLASH;
1338 setslot.slot_led_fault = PCIMSG_LED_FLASH;
1339 break;
1340 }
1341 break;
1342 case HPC_ACTIVE_LED:
1343 switch (hpc_led_info->state) {
1344 case HPC_LED_OFF:
1345 schpc_p->schpc_slot[slot].led.led_service =
1346 LED_OFF;
1347 setslot.slot_led_service = PCIMSG_LED_OFF;
1348 break;
1349 case HPC_LED_ON:
1350 schpc_p->schpc_slot[slot].led.led_service =
1351 LED_ON;
1352 setslot.slot_led_service = PCIMSG_LED_ON;
1353 break;
1354 case HPC_LED_BLINK:
1355 schpc_p->schpc_slot[slot].led.led_service =
1356 LED_FLASH;
1357 setslot.slot_led_service = PCIMSG_LED_FLASH;
1358 break;
1359 }
1360 break;
1361 default:
1362 mutex_enter(&schpc_p->schpc_mutex);
1363 schpc_p->schpc_slot[slot].state &=
1364 ~SCHPC_SLOTSTATE_EXECUTING;
1365 cv_signal(&schpc_p->schpc_cv);
1366 mutex_exit(&schpc_p->schpc_mutex);
1367
1368 return (0);
1369 }
1370
1371 (void) schpc_setslotstatus(expander, board, slot, &setslot);
1372
1373 mutex_enter(&schpc_p->schpc_mutex);
1374 schpc_p->schpc_slot[slot].state &=
1375 ~SCHPC_SLOTSTATE_EXECUTING;
1376 cv_signal(&schpc_p->schpc_cv);
1377 mutex_exit(&schpc_p->schpc_mutex);
1378
1379 return (0);
1380
1381 case HPC_CTRL_GET_SLOT_STATE: {
1382 hpc_slot_state_t *hpc_slot_state;
1383
1384 hpc_slot_state = (hpc_slot_state_t *)arg;
1385
1386 SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - "
1387 "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=%p",
1388 (void *)hpc_slot_state);
1389
1390 rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
1391
1392 if (!rval) {
1393
1394 if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
1395 return (HPC_ERR_FAILED);
1396 }
1397
1398 if (slotstatus.slot_empty == PCIMSG_ON) {
1399 *hpc_slot_state = HPC_SLOT_EMPTY;
1400 SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Empty");
1401 } else if (slotstatus.slot_power_on == PCIMSG_ON) {
1402 *hpc_slot_state = HPC_SLOT_CONNECTED;
1403 SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Connected");
1404 schpc_p->schpc_slot[slot].state |=
1405 SCHPC_SLOTSTATE_CONNECTED;
1406 } else {
1407 *hpc_slot_state = HPC_SLOT_DISCONNECTED;
1408 SCHPC_DEBUG0(D_IOC_CONTROL,
1409 "Slot Disconnected");
1410 schpc_p->schpc_slot[slot].state &=
1411 ~SCHPC_SLOTSTATE_CONNECTED;
1412 }
1413 } else {
1414 SCHPC_DEBUG0(D_IOC_CONTROL, "Mailbox Command failed");
1415
1416 mutex_enter(&schpc_p->schpc_mutex);
1417 schpc_p->schpc_slot[slot].state &=
1418 ~SCHPC_SLOTSTATE_EXECUTING;
1419 cv_signal(&schpc_p->schpc_cv);
1420 mutex_exit(&schpc_p->schpc_mutex);
1421
1422 return (HPC_ERR_FAILED);
1423 }
1424
1425 mutex_enter(&schpc_p->schpc_mutex);
1426 schpc_p->schpc_slot[slot].state &=
1427 ~SCHPC_SLOTSTATE_EXECUTING;
1428 cv_signal(&schpc_p->schpc_cv);
1429 mutex_exit(&schpc_p->schpc_mutex);
1430
1431 return (0);
1432 }
1433 case HPC_CTRL_GET_BOARD_TYPE: {
1434 hpc_board_type_t *hpc_board_type;
1435
1436 hpc_board_type = (hpc_board_type_t *)arg;
1437
1438 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1439 "HPC_CTRL_GET_BOARD_TYPE");
1440
1441 /*
1442 * The HPC driver does not know what board type
1443 * is plugged in.
1444 */
1445 *hpc_board_type = HPC_BOARD_CPCI_HS;
1446
1447 mutex_enter(&schpc_p->schpc_mutex);
1448 schpc_p->schpc_slot[slot].state &=
1449 ~SCHPC_SLOTSTATE_EXECUTING;
1450 cv_signal(&schpc_p->schpc_cv);
1451 mutex_exit(&schpc_p->schpc_mutex);
1452
1453 return (0);
1454
1455 }
1456 case HPC_CTRL_DEV_CONFIGURED:
1457 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1458 "HPC_CTRL_DEV_CONFIGURED");
1459
1460 mutex_enter(&schpc_p->schpc_mutex);
1461 schpc_p->schpc_slot[slot].state &=
1462 ~SCHPC_SLOTSTATE_EXECUTING;
1463 cv_signal(&schpc_p->schpc_cv);
1464 mutex_exit(&schpc_p->schpc_mutex);
1465
1466 return (0);
1467
1468 case HPC_CTRL_DEV_UNCONFIGURED:
1469 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1470 "HPC_CTRL_DEV_UNCONFIGURED");
1471
1472 if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_ENUM) {
1473 /*
1474 * When the occupant is unconfigured, power
1475 * down the slot.
1476 */
1477 rval = schpc_disconnect((caddr_t)schpc_p,
1478 schpc_p->schpc_slot[slot].slot_handle,
1479 0, 0);
1480
1481 schpc_p->schpc_slot[slot].state &=
1482 ~SCHPC_SLOTSTATE_ENUM;
1483 }
1484
1485 mutex_enter(&schpc_p->schpc_mutex);
1486 schpc_p->schpc_slot[slot].state &=
1487 ~SCHPC_SLOTSTATE_EXECUTING;
1488 cv_signal(&schpc_p->schpc_cv);
1489 mutex_exit(&schpc_p->schpc_mutex);
1490
1491 return (0);
1492
1493 case HPC_CTRL_ENABLE_AUTOCFG:
1494 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1495 "HPC_CTRL_ENABLE_AUTOCFG");
1496
1497 schpc_p->schpc_slot[slot].state |=
1498 SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
1499
1500 mutex_enter(&schpc_p->schpc_mutex);
1501 schpc_p->schpc_slot[slot].state &=
1502 ~SCHPC_SLOTSTATE_EXECUTING;
1503 cv_signal(&schpc_p->schpc_cv);
1504 mutex_exit(&schpc_p->schpc_mutex);
1505
1506 return (0);
1507
1508 case HPC_CTRL_DISABLE_AUTOCFG:
1509 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1510 "HPC_CTRL_DISABLE_AUTOCFG");
1511 schpc_p->schpc_slot[slot].state &=
1512 ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
1513
1514 mutex_enter(&schpc_p->schpc_mutex);
1515 schpc_p->schpc_slot[slot].state &=
1516 ~SCHPC_SLOTSTATE_EXECUTING;
1517 cv_signal(&schpc_p->schpc_cv);
1518 mutex_exit(&schpc_p->schpc_mutex);
1519
1520 return (0);
1521
1522 case HPC_CTRL_DISABLE_ENUM:
1523 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1524 "HPC_CTRL_DISABLE_ENUM");
1525
1526 setslot.slot_disable_ENUM = PCIMSG_ON;
1527
1528 rval = schpc_setslotstatus(expander, board, slot, &setslot);
1529
1530 if (rval)
1531 rval = HPC_ERR_FAILED;
1532
1533 mutex_enter(&schpc_p->schpc_mutex);
1534 schpc_p->schpc_slot[slot].state &=
1535 ~SCHPC_SLOTSTATE_EXECUTING;
1536 cv_signal(&schpc_p->schpc_cv);
1537 mutex_exit(&schpc_p->schpc_mutex);
1538
1539 return (rval);
1540
1541 case HPC_CTRL_ENABLE_ENUM:
1542 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1543 "HPC_CTRL_ENABLE_ENUM");
1544
1545 setslot.slot_enable_ENUM = PCIMSG_ON;
1546
1547 rval = schpc_setslotstatus(expander, board, slot, &setslot);
1548
1549 if (rval)
1550 rval = HPC_ERR_FAILED;
1551
1552 mutex_enter(&schpc_p->schpc_mutex);
1553 schpc_p->schpc_slot[slot].state &=
1554 ~SCHPC_SLOTSTATE_EXECUTING;
1555 cv_signal(&schpc_p->schpc_cv);
1556 mutex_exit(&schpc_p->schpc_mutex);
1557
1558 return (rval);
1559
1560 default:
1561 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
1562 "****NOT SUPPORTED CONTROL CMD");
1563
1564 mutex_enter(&schpc_p->schpc_mutex);
1565 schpc_p->schpc_slot[slot].state &=
1566 ~SCHPC_SLOTSTATE_EXECUTING;
1567 cv_signal(&schpc_p->schpc_cv);
1568 mutex_exit(&schpc_p->schpc_mutex);
1569
1570 return (HPC_ERR_NOTSUPPORTED);
1571 }
1572 }
1573
1574 /*
1575 * schpc_pci_control
1576 *
1577 * Called by Hot Plug Services to perform a attachment point specific
1578 * on a Hot Pluggable Standard PCI Slot.
1579 */
1580 /*ARGSUSED*/
1581 static int
schpc_pci_control(caddr_t ops_arg,hpc_slot_t slot_hdl,int request,caddr_t arg)1582 schpc_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request,
1583 caddr_t arg)
1584 {
1585 int rval;
1586 int expander, board, slot;
1587 pci_setslot_t setslot;
1588 pci_getslot_t slotstatus;
1589 hpc_led_info_t *hpc_led_info;
1590
1591 SCHPC_DEBUG3(D_IOC_CONTROL,
1592 "schpc_pci_control(op_args=%p slot_hdl=%p request=%x)",
1593 (void *)ops_arg, (void *)slot_hdl, request);
1594
1595 mutex_enter(&schpc_p->schpc_mutex);
1596
1597 slot = schpc_slot_get_index(schpc_p, slot_hdl);
1598
1599 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
1600 SCHPC_DEBUG0(D_IOC_CONNECT,
1601 "schpc_disconnect - HPC Not Inited");
1602 mutex_exit(&schpc_p->schpc_mutex);
1603 return (HPC_ERR_FAILED);
1604 }
1605
1606 /*
1607 * Block if another thread is executing a HPC command.
1608 */
1609 while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
1610 cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
1611 }
1612
1613 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
1614
1615 mutex_exit(&schpc_p->schpc_mutex);
1616
1617 expander = schpc_p->schpc_slot[slot].expander; /* get expander */
1618 board = schpc_p->schpc_slot[slot].board; /* get board */
1619
1620 /*
1621 * Initialize Set Slot Command.
1622 */
1623 schpc_init_setslot_message(&setslot);
1624
1625 /*
1626 * Initialize LED to last know state.
1627 */
1628 switch (schpc_p->schpc_slot[slot].led.led_power) {
1629 case LED_ON:
1630 setslot.slot_led_power = PCIMSG_LED_ON;
1631 break;
1632 case LED_OFF:
1633 setslot.slot_led_power = PCIMSG_LED_OFF;
1634 break;
1635 case LED_FLASH:
1636 setslot.slot_led_power = PCIMSG_LED_FLASH;
1637 break;
1638 }
1639
1640 switch (schpc_p->schpc_slot[slot].led.led_service) {
1641 case LED_ON:
1642 setslot.slot_led_service = PCIMSG_LED_ON;
1643 break;
1644 case LED_OFF:
1645 setslot.slot_led_service = PCIMSG_LED_OFF;
1646 break;
1647 case LED_FLASH:
1648 setslot.slot_led_service = PCIMSG_LED_FLASH;
1649 break;
1650 }
1651
1652 switch (schpc_p->schpc_slot[slot].led.led_fault) {
1653 case LED_ON:
1654 setslot.slot_led_fault = PCIMSG_LED_ON;
1655 break;
1656 case LED_OFF:
1657 setslot.slot_led_fault = PCIMSG_LED_OFF;
1658 break;
1659 case LED_FLASH:
1660 setslot.slot_led_fault = PCIMSG_LED_FLASH;
1661 break;
1662 }
1663
1664 switch (request) {
1665
1666
1667 case HPC_CTRL_GET_SLOT_STATE: {
1668 hpc_slot_state_t *hpc_slot_state;
1669
1670 hpc_slot_state = (hpc_slot_state_t *)arg;
1671
1672 SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - "
1673 "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=%p",
1674 (void *)hpc_slot_state);
1675
1676 rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
1677
1678 if (!rval) {
1679
1680 if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
1681
1682 mutex_enter(&schpc_p->schpc_mutex);
1683 schpc_p->schpc_slot[slot].state &=
1684 ~SCHPC_SLOTSTATE_EXECUTING;
1685 cv_signal(&schpc_p->schpc_cv);
1686 mutex_exit(&schpc_p->schpc_mutex);
1687
1688 return (HPC_ERR_FAILED);
1689 }
1690
1691 if (slotstatus.slot_empty == PCIMSG_ON) {
1692 *hpc_slot_state = HPC_SLOT_EMPTY;
1693 SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Empty");
1694 } else if (slotstatus.slot_power_on == PCIMSG_ON) {
1695 *hpc_slot_state = HPC_SLOT_CONNECTED;
1696 SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Connected");
1697 schpc_p->schpc_slot[slot].state |=
1698 SCHPC_SLOTSTATE_CONNECTED;
1699 } else {
1700 *hpc_slot_state = HPC_SLOT_DISCONNECTED;
1701 SCHPC_DEBUG0(D_IOC_CONTROL,
1702 "Slot Disconnected");
1703 schpc_p->schpc_slot[slot].state &=
1704 ~SCHPC_SLOTSTATE_CONNECTED;
1705 }
1706 } else {
1707 SCHPC_DEBUG0(D_IOC_CONTROL, "Mailbox Command failed");
1708
1709 mutex_enter(&schpc_p->schpc_mutex);
1710 schpc_p->schpc_slot[slot].state &=
1711 ~SCHPC_SLOTSTATE_EXECUTING;
1712 cv_signal(&schpc_p->schpc_cv);
1713 mutex_exit(&schpc_p->schpc_mutex);
1714
1715 return (HPC_ERR_FAILED);
1716 }
1717
1718 mutex_enter(&schpc_p->schpc_mutex);
1719 schpc_p->schpc_slot[slot].state &=
1720 ~SCHPC_SLOTSTATE_EXECUTING;
1721 cv_signal(&schpc_p->schpc_cv);
1722 mutex_exit(&schpc_p->schpc_mutex);
1723
1724 return (0);
1725 }
1726 case HPC_CTRL_GET_BOARD_TYPE: {
1727 hpc_board_type_t *hpc_board_type;
1728
1729 hpc_board_type = (hpc_board_type_t *)arg;
1730
1731 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
1732 "HPC_CTRL_GET_BOARD_TYPE");
1733
1734
1735 /*
1736 * The HPC driver does not know what board type
1737 * is plugged in.
1738 */
1739 *hpc_board_type = HPC_BOARD_PCI_HOTPLUG;
1740
1741 mutex_enter(&schpc_p->schpc_mutex);
1742 schpc_p->schpc_slot[slot].state &=
1743 ~SCHPC_SLOTSTATE_EXECUTING;
1744 cv_signal(&schpc_p->schpc_cv);
1745 mutex_exit(&schpc_p->schpc_mutex);
1746
1747 return (0);
1748
1749 }
1750 case HPC_CTRL_DEV_UNCONFIG_START:
1751 case HPC_CTRL_DEV_CONFIG_START:
1752 case HPC_CTRL_DEV_CONFIGURED:
1753 case HPC_CTRL_DEV_UNCONFIGURED:
1754 mutex_enter(&schpc_p->schpc_mutex);
1755 schpc_p->schpc_slot[slot].state &=
1756 ~SCHPC_SLOTSTATE_EXECUTING;
1757 cv_signal(&schpc_p->schpc_cv);
1758 mutex_exit(&schpc_p->schpc_mutex);
1759
1760 return (0);
1761
1762 case HPC_CTRL_GET_LED_STATE:
1763 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
1764 "HPC_CTRL_GET_LED_STATE");
1765 hpc_led_info = (hpc_led_info_t *)arg;
1766
1767 switch (hpc_led_info->led) {
1768 case HPC_FAULT_LED:
1769 switch (schpc_p->schpc_slot[slot].led.led_fault) {
1770 case LED_OFF:
1771 hpc_led_info->state = HPC_LED_OFF;
1772 break;
1773 case LED_ON:
1774 hpc_led_info->state = HPC_LED_ON;
1775 break;
1776 case LED_FLASH:
1777 hpc_led_info->state = HPC_LED_BLINK;
1778 break;
1779 }
1780 break;
1781
1782 case HPC_POWER_LED:
1783 switch (schpc_p->schpc_slot[slot].led.led_power) {
1784 case LED_OFF:
1785 hpc_led_info->state = HPC_LED_OFF;
1786 break;
1787 case LED_ON:
1788 hpc_led_info->state = HPC_LED_ON;
1789 break;
1790 case LED_FLASH:
1791 hpc_led_info->state = HPC_LED_BLINK;
1792 break;
1793 }
1794 break;
1795 case HPC_ATTN_LED:
1796 switch (schpc_p->schpc_slot[slot].led.led_fault) {
1797 case LED_OFF:
1798 hpc_led_info->state = HPC_LED_OFF;
1799 break;
1800 case LED_ON:
1801 hpc_led_info->state = HPC_LED_OFF;
1802 break;
1803 case LED_FLASH:
1804 hpc_led_info->state = HPC_LED_ON;
1805 break;
1806 }
1807 break;
1808 case HPC_ACTIVE_LED:
1809 switch (schpc_p->schpc_slot[slot].led.led_service) {
1810 case LED_OFF:
1811 hpc_led_info->state = HPC_LED_OFF;
1812 break;
1813 case LED_ON:
1814 hpc_led_info->state = HPC_LED_ON;
1815 break;
1816 case LED_FLASH:
1817 hpc_led_info->state = HPC_LED_BLINK;
1818 break;
1819 }
1820 break;
1821 default:
1822 SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - "
1823 "Invalid LED %x", hpc_led_info->led);
1824
1825 mutex_enter(&schpc_p->schpc_mutex);
1826 schpc_p->schpc_slot[slot].state &=
1827 ~SCHPC_SLOTSTATE_EXECUTING;
1828 cv_signal(&schpc_p->schpc_cv);
1829 mutex_exit(&schpc_p->schpc_mutex);
1830
1831 return (HPC_ERR_FAILED);
1832 }
1833
1834 mutex_enter(&schpc_p->schpc_mutex);
1835 schpc_p->schpc_slot[slot].state &=
1836 ~SCHPC_SLOTSTATE_EXECUTING;
1837 cv_signal(&schpc_p->schpc_cv);
1838 mutex_exit(&schpc_p->schpc_mutex);
1839
1840 return (0);
1841
1842 case HPC_CTRL_SET_LED_STATE:
1843 hpc_led_info = (hpc_led_info_t *)arg;
1844
1845 SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - "
1846 "HPC_CTRL_SET_LED_STATE hpc_led_info=%p",
1847 (void *)hpc_led_info);
1848
1849 switch (hpc_led_info->led) {
1850 case HPC_FAULT_LED:
1851 switch (hpc_led_info->state) {
1852 case HPC_LED_OFF:
1853 schpc_p->schpc_slot[slot].led.led_fault =
1854 LED_OFF;
1855 setslot.slot_led_fault = PCIMSG_LED_OFF;
1856 break;
1857 case HPC_LED_ON:
1858 schpc_p->schpc_slot[slot].led.led_fault =
1859 LED_ON;
1860 setslot.slot_led_fault = PCIMSG_LED_ON;
1861 break;
1862 case HPC_LED_BLINK:
1863 schpc_p->schpc_slot[slot].led.led_fault =
1864 LED_FLASH;
1865 setslot.slot_led_fault = PCIMSG_LED_FLASH;
1866 break;
1867 }
1868 break;
1869 case HPC_POWER_LED:
1870 switch (hpc_led_info->state) {
1871 case HPC_LED_OFF:
1872 schpc_p->schpc_slot[slot].led.led_power =
1873 LED_OFF;
1874 setslot.slot_led_power = PCIMSG_LED_OFF;
1875 break;
1876 case HPC_LED_ON:
1877 schpc_p->schpc_slot[slot].led.led_power =
1878 LED_ON;
1879 setslot.slot_led_power = PCIMSG_LED_ON;
1880 break;
1881 case HPC_LED_BLINK:
1882 schpc_p->schpc_slot[slot].led.led_power =
1883 LED_FLASH;
1884 setslot.slot_led_power = PCIMSG_LED_FLASH;
1885 break;
1886 }
1887 break;
1888 case HPC_ATTN_LED:
1889 switch (hpc_led_info->state) {
1890 case HPC_LED_OFF:
1891 schpc_p->schpc_slot[slot].led.led_fault =
1892 LED_OFF;
1893 setslot.slot_led_fault = PCIMSG_LED_OFF;
1894 break;
1895 case HPC_LED_ON:
1896 schpc_p->schpc_slot[slot].led.led_fault =
1897 LED_FLASH;
1898 setslot.slot_led_fault = PCIMSG_LED_FLASH;
1899 break;
1900 case HPC_LED_BLINK:
1901 schpc_p->schpc_slot[slot].led.led_fault =
1902 LED_FLASH;
1903 setslot.slot_led_fault = PCIMSG_LED_FLASH;
1904 break;
1905 }
1906 break;
1907 case HPC_ACTIVE_LED:
1908 switch (hpc_led_info->state) {
1909 case HPC_LED_OFF:
1910 schpc_p->schpc_slot[slot].led.led_service =
1911 LED_OFF;
1912 setslot.slot_led_service = PCIMSG_LED_OFF;
1913 break;
1914 case HPC_LED_ON:
1915 schpc_p->schpc_slot[slot].led.led_service =
1916 LED_ON;
1917 setslot.slot_led_service = PCIMSG_LED_ON;
1918 break;
1919 case HPC_LED_BLINK:
1920 schpc_p->schpc_slot[slot].led.led_service =
1921 LED_FLASH;
1922 setslot.slot_led_service = PCIMSG_LED_FLASH;
1923 break;
1924 }
1925 break;
1926 default:
1927 mutex_enter(&schpc_p->schpc_mutex);
1928 schpc_p->schpc_slot[slot].state &=
1929 ~SCHPC_SLOTSTATE_EXECUTING;
1930 cv_signal(&schpc_p->schpc_cv);
1931 mutex_exit(&schpc_p->schpc_mutex);
1932
1933 return (0);
1934 }
1935
1936 (void) schpc_setslotstatus(expander, board, slot, &setslot);
1937
1938 mutex_enter(&schpc_p->schpc_mutex);
1939 schpc_p->schpc_slot[slot].state &=
1940 ~SCHPC_SLOTSTATE_EXECUTING;
1941 cv_signal(&schpc_p->schpc_cv);
1942 mutex_exit(&schpc_p->schpc_mutex);
1943
1944 return (0);
1945
1946 case HPC_CTRL_ENABLE_AUTOCFG:
1947 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
1948 "HPC_CTRL_ENABLE_AUTOCFG");
1949
1950 schpc_p->schpc_slot[slot].state |=
1951 SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
1952
1953 mutex_enter(&schpc_p->schpc_mutex);
1954 schpc_p->schpc_slot[slot].state &=
1955 ~SCHPC_SLOTSTATE_EXECUTING;
1956 cv_signal(&schpc_p->schpc_cv);
1957 mutex_exit(&schpc_p->schpc_mutex);
1958
1959 return (0);
1960
1961 case HPC_CTRL_DISABLE_AUTOCFG:
1962 SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
1963 "HPC_CTRL_DISABLE_AUTOCFG");
1964 schpc_p->schpc_slot[slot].state &=
1965 ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
1966
1967 mutex_enter(&schpc_p->schpc_mutex);
1968 schpc_p->schpc_slot[slot].state &=
1969 ~SCHPC_SLOTSTATE_EXECUTING;
1970 cv_signal(&schpc_p->schpc_cv);
1971 mutex_exit(&schpc_p->schpc_mutex);
1972
1973 return (0);
1974
1975 case HPC_CTRL_DISABLE_ENUM:
1976 case HPC_CTRL_ENABLE_ENUM:
1977 default:
1978 mutex_enter(&schpc_p->schpc_mutex);
1979 schpc_p->schpc_slot[slot].state &=
1980 ~SCHPC_SLOTSTATE_EXECUTING;
1981 cv_signal(&schpc_p->schpc_cv);
1982 mutex_exit(&schpc_p->schpc_mutex);
1983
1984 return (HPC_ERR_NOTSUPPORTED);
1985 }
1986 }
1987
1988 /*
1989 * schpc_test
1990 *
1991 * Tests the slot.
1992 */
1993 /*ARGSUSED*/
1994 static void
schpc_test(caddr_t ops_arg,int slot,void * data,uint_t flags)1995 schpc_test(caddr_t ops_arg, int slot, void *data, uint_t flags)
1996 {
1997 pci_getslot_t slotstatus;
1998 pci_setslot_t setslot;
1999 int expander, board;
2000 int rval;
2001 int retry = 1;
2002
2003 SCHPC_DEBUG2(D_IOC_TEST, "schpc_test(op_args=%p slot=%x)",
2004 (void *)ops_arg, SCHPC_SLOT_NUM(slot));
2005
2006 SCHPC_DEBUG3(D_IOC_TEST,
2007 " schpc_test() Expander=%d Board=%d Slot=%d",
2008 schpc_p->schpc_slot[slot].expander,
2009 schpc_p->schpc_slot[slot].board, SCHPC_SLOT_NUM(slot));
2010
2011 expander = schpc_p->schpc_slot[slot].expander;
2012 board = schpc_p->schpc_slot[slot].board;
2013
2014 restart_test:
2015 /*
2016 * Initial the slot with its occupant and receptacle in good condition.
2017 */
2018 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_REC_GOOD;
2019 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_OCC_GOOD;
2020
2021
2022 rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
2023
2024 if (rval) {
2025 /*
2026 * System Controller/Mailbox failure.
2027 */
2028 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2029 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
2030 "Communicate with System Controller", expander, board,
2031 SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
2032
2033 schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD;
2034 return;
2035 }
2036
2037 if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
2038
2039 cmn_err(CE_WARN, "schpc - Expander %d Board %d PCI Slot %d "
2040 "is not hot pluggable\n", expander, board,
2041 SCHPC_SLOT_NUM(slot));
2042
2043 schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD;
2044 return;
2045 }
2046
2047 switch (slotstatus.slot_condition) {
2048 case PCIMSG_SLOTCOND_OCC_FAIL:
2049 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2050 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
2051 "System Controller/Occupant Failed",
2052 expander, board, SCHPC_SLOT_NUM(slot),
2053 schpc_p->schpc_slot[slot].ap_id);
2054
2055 schpc_setslotled(expander, board, slot,
2056 (POWER_LED_OFF | SERVICE_LED_ON | FAULT_LED_ON));
2057
2058 schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_OCC_GOOD;
2059 return;
2060 case PCIMSG_SLOTCOND_REC_FAIL:
2061 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2062 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
2063 "System Controller/Receptacle Failed",
2064 expander, board, SCHPC_SLOT_NUM(slot),
2065 schpc_p->schpc_slot[slot].ap_id);
2066
2067 schpc_setslotled(expander, board, slot,
2068 (POWER_LED_OFF | SERVICE_LED_OFF | FAULT_LED_ON));
2069
2070 schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD;
2071 return;
2072 case PCIMSG_SLOTCOND_NOHOTPLUG:
2073 cmn_err(CE_WARN, "schpc - Expander %d Board %d PCI Slot %d "
2074 "is not hot pluggable\n", expander, board,
2075 SCHPC_SLOT_NUM(slot));
2076
2077 schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD;
2078 return;
2079 }
2080
2081 if (slotstatus.slot_power_on) {
2082 schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON;
2083
2084 if (!slotstatus.slot_HEALTHY) {
2085 /*
2086 * cPCI Adapter is not asserting HEALTHY#.
2087 */
2088 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2089 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
2090 "PCI adapter not HEALTHY", expander, board,
2091 SCHPC_SLOT_NUM(slot),
2092 schpc_p->schpc_slot[slot].ap_id);
2093
2094 schpc_setslotled(expander, board, slot,
2095 (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
2096
2097 schpc_p->schpc_slot[slot].state &=
2098 ~SCHPC_SLOTSTATE_OCC_GOOD;
2099
2100 return;
2101 }
2102
2103 if (!slotstatus.slot_powergood) {
2104 /*
2105 * PCI Power Input is not good.
2106 */
2107 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2108 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
2109 "System Controller PCI Power Input Not Good",
2110 expander, board, SCHPC_SLOT_NUM(slot),
2111 schpc_p->schpc_slot[slot].ap_id);
2112
2113 schpc_setslotled(expander, board, slot,
2114 (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
2115
2116 schpc_p->schpc_slot[slot].state &=
2117 ~SCHPC_SLOTSTATE_OCC_GOOD;
2118
2119 return;
2120 }
2121
2122 if (slotstatus.slot_powerfault) {
2123 /*
2124 * PCI Power Fault.
2125 */
2126 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2127 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
2128 "System Controller PCI Power Fault",
2129 expander, board, SCHPC_SLOT_NUM(slot),
2130 schpc_p->schpc_slot[slot].ap_id);
2131
2132 schpc_setslotled(expander, board, slot,
2133 (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
2134
2135 schpc_p->schpc_slot[slot].state &=
2136 ~SCHPC_SLOTSTATE_OCC_GOOD;
2137
2138 return;
2139 }
2140 }
2141
2142 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Test Successful - ret 0");
2143
2144 /*
2145 * Is the slot empty?
2146 */
2147 if (slotstatus.slot_empty) {
2148 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Empty");
2149
2150 schpc_p->schpc_slot[slot].state &=
2151 ~SCHPC_SLOTSTATE_PRESENT;
2152
2153 if (slotstatus.slot_power_on) {
2154
2155 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Empty Slot "
2156 "is powered ON");
2157
2158 /*
2159 * Tests will be retried once after powering off
2160 * an empty slot.
2161 */
2162 if (retry) {
2163
2164 /*
2165 * Turn off the slot and restart test.
2166 */
2167 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() "
2168 "Turning Empty Slot OFF");
2169
2170 schpc_init_setslot_message(&setslot);
2171 setslot.slot_power_off = PCIMSG_ON;
2172 (void) schpc_setslotstatus(
2173 expander, board, slot, &setslot);
2174
2175 retry = 0;
2176
2177 goto restart_test;
2178 }
2179 }
2180 } else {
2181 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Adapter Present");
2182
2183 if (!slotstatus.slot_power_on) {
2184 if (retry) {
2185 /*
2186 * If there is a cassette present and the
2187 * power is off, try turning the power on and
2188 * restart the test. This allows access to
2189 * the FRUID when an empty cassette is
2190 * installed.
2191 */
2192 SCHPC_DEBUG0(D_IOC_TEST,
2193 "schpc_test() Power On Adapter");
2194 schpc_init_setslot_message(&setslot);
2195 setslot.slot_power_on = PCIMSG_ON;
2196 (void) schpc_setslotstatus(
2197 expander, board, slot, &setslot);
2198 retry = 0;
2199 goto restart_test;
2200 }
2201 }
2202
2203 schpc_p->schpc_slot[slot].state |=
2204 SCHPC_SLOTSTATE_PRESENT;
2205 }
2206
2207 /*
2208 * Is the slot powered up?
2209 */
2210 schpc_init_setslot_message(&setslot);
2211
2212 if (slotstatus.slot_power_on) {
2213 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power On");
2214
2215 schpc_p->schpc_slot[slot].state |=
2216 SCHPC_SLOTSTATE_CONNECTED;
2217
2218 setslot.slot_led_power = PCIMSG_LED_ON;
2219 setslot.slot_led_service = PCIMSG_LED_OFF;
2220 setslot.slot_enable_ENUM = PCIMSG_ON;
2221 setslot.slot_enable_HEALTHY = PCIMSG_ON;
2222 } else {
2223 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power Off");
2224
2225 schpc_p->schpc_slot[slot].state &=
2226 ~SCHPC_SLOTSTATE_CONNECTED;
2227
2228 setslot.slot_led_power = PCIMSG_LED_OFF;
2229 setslot.slot_led_service = PCIMSG_LED_ON;
2230 setslot.slot_disable_ENUM = PCIMSG_ON;
2231 setslot.slot_disable_HEALTHY = PCIMSG_ON;
2232 }
2233
2234 setslot.slot_led_fault = PCIMSG_LED_OFF;
2235
2236 (void) schpc_setslotstatus(expander, board, slot, &setslot);
2237
2238 /*
2239 * Save LED State.
2240 */
2241 switch (setslot.slot_led_power) {
2242 case PCIMSG_LED_ON:
2243 schpc_p->schpc_slot[slot].led.led_power = LED_ON;
2244 break;
2245 case PCIMSG_LED_OFF:
2246 schpc_p->schpc_slot[slot].led.led_power = LED_OFF;
2247 break;
2248 case PCIMSG_LED_FLASH:
2249 schpc_p->schpc_slot[slot].led.led_power = LED_FLASH;
2250 break;
2251 }
2252 switch (setslot.slot_led_service) {
2253 case PCIMSG_LED_ON:
2254 schpc_p->schpc_slot[slot].led.led_service = LED_ON;
2255 break;
2256 case PCIMSG_LED_OFF:
2257 schpc_p->schpc_slot[slot].led.led_service = LED_OFF;
2258 break;
2259 case PCIMSG_LED_FLASH:
2260 schpc_p->schpc_slot[slot].led.led_service = LED_FLASH;
2261 break;
2262 }
2263 switch (setslot.slot_led_fault) {
2264 case PCIMSG_LED_ON:
2265 schpc_p->schpc_slot[slot].led.led_fault = LED_ON;
2266 break;
2267 case PCIMSG_LED_OFF:
2268 schpc_p->schpc_slot[slot].led.led_fault = LED_OFF;
2269 break;
2270 case PCIMSG_LED_FLASH:
2271 schpc_p->schpc_slot[slot].led.led_fault = LED_FLASH;
2272 break;
2273 }
2274 }
2275
2276
2277 /*
2278 * schpc_event_handler
2279 *
2280 * Placed on the schpc_event_taskq by schpc_event_filter when an
2281 * unsolicited MBOXSC_MSG_EVENT is received from the SC. It handles
2282 * things like power insertion/removal, ENUM#, etc.
2283 */
2284 static void
schpc_event_handler(void * arg)2285 schpc_event_handler(void *arg)
2286 {
2287 pci_getslot_t slotstatus;
2288 uint8_t expander, board, slot;
2289 int rval;
2290 pcimsg_t *event = (pcimsg_t *)arg;
2291
2292 /*
2293 * OK, we got an event message. Since the event message only tells
2294 * us something has changed and not changed to what, we need to get
2295 * the current slot status to find how WHAT was change to WHAT.
2296 */
2297
2298 slot = event->pcimsg_slot;
2299 expander = event->pcimsg_node; /* get expander */
2300 board = event->pcimsg_board; /* get board */
2301
2302 SCHPC_DEBUG3(D_EVENT,
2303 "schpc_event_handler() - exp=%d board=%d slot=%d",
2304 expander, board, slot);
2305
2306 /* create a slot table index */
2307 slot = SCHPC_MAKE_SLOT_INDEX2(expander, slot);
2308
2309 SCHPC_DEBUG1(D_EVENT,
2310 "schpc_event_handler() - expanded slot %d", slot);
2311
2312 if (schpc_p == NULL) {
2313 cmn_err(CE_WARN, "schpc/Event Handler - Can not find schpc");
2314 kmem_free(event, sizeof (pcimsg_t));
2315 return;
2316 }
2317
2318 mutex_enter(&schpc_p->schpc_mutex);
2319
2320 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
2321 SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - HPC Not Inited");
2322 mutex_exit(&schpc_p->schpc_mutex);
2323 kmem_free(event, sizeof (pcimsg_t));
2324 return;
2325 }
2326 /*
2327 * Block if another thread is executing a HPC command.
2328 */
2329 while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
2330 SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - Slot is busy");
2331 cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
2332 }
2333
2334 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
2335
2336 mutex_exit(&schpc_p->schpc_mutex);
2337
2338 rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
2339
2340 if (rval) {
2341 cmn_err(CE_WARN, "schpc/Event Handler - Can not get status "
2342 "for expander=%d board=%d slot=%d\n",
2343 expander, board, SCHPC_SLOT_NUM(slot));
2344
2345 mutex_enter(&schpc_p->schpc_mutex);
2346 schpc_p->schpc_slot[slot].state &=
2347 ~SCHPC_SLOTSTATE_EXECUTING;
2348 cv_signal(&schpc_p->schpc_cv);
2349 mutex_exit(&schpc_p->schpc_mutex);
2350 kmem_free(event, sizeof (pcimsg_t));
2351 return;
2352 }
2353
2354 if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
2355 cmn_err(CE_WARN, "schpc/Event Handler - Can not get good "
2356 "status for expander=%d board=%d slot=%d\n",
2357 expander, board, SCHPC_SLOT_NUM(slot));
2358
2359 mutex_enter(&schpc_p->schpc_mutex);
2360 schpc_p->schpc_slot[slot].state &=
2361 ~SCHPC_SLOTSTATE_EXECUTING;
2362 cv_signal(&schpc_p->schpc_cv);
2363 mutex_exit(&schpc_p->schpc_mutex);
2364
2365 kmem_free(event, sizeof (pcimsg_t));
2366 return;
2367 }
2368
2369 SCHPC_DEBUG3(D_EVENT, "Event Received - Expander %d Board %d Slot %d",
2370 expander, board, SCHPC_SLOT_NUM(slot));
2371
2372 if (schpc_p->schpc_slot[slot].slot_ops == NULL) {
2373 SCHPC_DEBUG3(D_EVENT, "schpc/Event Handler - Received event "
2374 "for unregistered slot for expander=%d board=%d slot=%d",
2375 expander, board, SCHPC_SLOT_NUM(slot));
2376
2377 mutex_enter(&schpc_p->schpc_mutex);
2378 schpc_p->schpc_slot[slot].state &=
2379 ~SCHPC_SLOTSTATE_EXECUTING;
2380 cv_signal(&schpc_p->schpc_cv);
2381 mutex_exit(&schpc_p->schpc_mutex);
2382
2383 kmem_free(event, sizeof (pcimsg_t));
2384 return;
2385 }
2386
2387 /* Slot Power Event */
2388
2389 if (event->pcimsg_type.pcimsg_slotevent.slot_power) {
2390 SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Event");
2391 /*
2392 * The SC may have changed to slot power status.
2393 */
2394 if (slotstatus.slot_power_on) {
2395 schpc_p->schpc_slot[slot].state |=
2396 SCHPC_SLOTSTATE_CONNECTED;
2397
2398 (void) hpc_slot_event_notify(
2399 schpc_p->schpc_slot[slot].slot_handle,
2400 HPC_EVENT_SLOT_POWER_ON, 0);
2401 } else {
2402 schpc_p->schpc_slot[slot].state &=
2403 ~SCHPC_SLOTSTATE_CONNECTED;
2404
2405 (void) hpc_slot_event_notify(
2406 schpc_p->schpc_slot[slot].slot_handle,
2407 HPC_EVENT_SLOT_POWER_OFF, 0);
2408 }
2409 }
2410
2411 /* Adapter Insertion/Removal Event */
2412
2413 if (event->pcimsg_type.pcimsg_slotevent.slot_presence) {
2414 if (slotstatus.slot_empty == PCIMSG_ON) {
2415
2416 /* Adapter Removed */
2417
2418 SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Removed");
2419
2420 if (schpc_p->schpc_slot[slot].state &
2421 SCHPC_SLOTSTATE_CONNECTED) {
2422 /*
2423 * If the adapter has been removed while
2424 * there the slot is connected, it could be
2425 * due to a ENUM handling.
2426 */
2427 cmn_err(CE_WARN, "Card removed from "
2428 "powered on slot at "
2429 "expander=%d board=%d slot=%d\n",
2430 expander, board, SCHPC_SLOT_NUM(slot));
2431
2432 schpc_p->schpc_slot[slot].state &=
2433 ~SCHPC_SLOTSTATE_EXECUTING;
2434 rval = schpc_disconnect((caddr_t)schpc_p,
2435 schpc_p->schpc_slot[slot].slot_handle,
2436 0, 0);
2437 mutex_enter(&schpc_p->schpc_mutex);
2438 while (schpc_p->schpc_slot[slot].state &
2439 SCHPC_SLOTSTATE_EXECUTING) {
2440 SCHPC_DEBUG0(D_EVENT,
2441 "schpc_event_handler - "
2442 "Slot is busy");
2443 cv_wait(&schpc_p->schpc_cv,
2444 &schpc_p->schpc_mutex);
2445 }
2446
2447 schpc_p->schpc_slot[slot].state |=
2448 SCHPC_SLOTSTATE_EXECUTING;
2449
2450 mutex_exit(&schpc_p->schpc_mutex);
2451 }
2452 schpc_p->schpc_slot[slot].state |=
2453 SCHPC_SLOTSTATE_OCC_GOOD;
2454
2455 schpc_p->schpc_slot[slot].state &=
2456 ~SCHPC_SLOTSTATE_PRESENT;
2457
2458 (void) hpc_slot_event_notify(
2459 schpc_p->schpc_slot[slot].slot_handle,
2460 HPC_EVENT_SLOT_REMOVAL, 0);
2461 } else {
2462
2463 /* Adapter Inserted */
2464
2465 SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Inserted");
2466
2467 if (schpc_p->schpc_slot[slot].state &
2468 SCHPC_SLOTSTATE_PRESENT) {
2469 /*
2470 * If the adapter is already present
2471 * throw the this event away.
2472 */
2473
2474 SCHPC_DEBUG0(D_EVENT,
2475 "Adapter is already present");
2476
2477 mutex_enter(&schpc_p->schpc_mutex);
2478 schpc_p->schpc_slot[slot].state &=
2479 ~SCHPC_SLOTSTATE_EXECUTING;
2480 cv_signal(&schpc_p->schpc_cv);
2481 mutex_exit(&schpc_p->schpc_mutex);
2482
2483 kmem_free(event, sizeof (pcimsg_t));
2484 return;
2485 }
2486
2487 schpc_p->schpc_slot[slot].state |=
2488 SCHPC_SLOTSTATE_PRESENT;
2489
2490 schpc_p->schpc_slot[slot].state &=
2491 ~SCHPC_SLOTSTATE_CONNECTED;
2492
2493 (void) hpc_slot_event_notify(
2494 schpc_p->schpc_slot[slot].slot_handle,
2495 HPC_EVENT_SLOT_INSERTION, 0);
2496
2497 if (schpc_p->schpc_slot[slot].state &
2498 SCHPC_SLOTSTATE_AUTOCFG_ENABLE) {
2499 SCHPC_DEBUG0(D_EVENT, "Auto Configuration "
2500 "(Connect/Configure) Started");
2501
2502 schpc_p->schpc_slot[slot].state &=
2503 ~SCHPC_SLOTSTATE_EXECUTING;
2504
2505 rval = schpc_connect((caddr_t)schpc_p,
2506 schpc_p->schpc_slot[slot].slot_handle,
2507 0, 0);
2508
2509 if (rval) {
2510 cmn_err(CE_WARN, "schpc/Event Handler -"
2511 " Can not connect");
2512
2513 mutex_enter(&schpc_p->schpc_mutex);
2514 schpc_p->schpc_slot[slot].state &=
2515 ~SCHPC_SLOTSTATE_EXECUTING;
2516 cv_signal(&schpc_p->schpc_cv);
2517 mutex_exit(&schpc_p->schpc_mutex);
2518
2519 kmem_free(event, sizeof (pcimsg_t));
2520 return;
2521 }
2522 mutex_enter(&schpc_p->schpc_mutex);
2523 while (schpc_p->schpc_slot[slot].state &
2524 SCHPC_SLOTSTATE_EXECUTING) {
2525 SCHPC_DEBUG0(D_EVENT,
2526 "schpc_event_handler - "
2527 "Slot is busy");
2528 cv_wait(&schpc_p->schpc_cv,
2529 &schpc_p->schpc_mutex);
2530 }
2531
2532 schpc_p->schpc_slot[slot].state |=
2533 SCHPC_SLOTSTATE_EXECUTING;
2534
2535 mutex_exit(&schpc_p->schpc_mutex);
2536
2537 (void) hpc_slot_event_notify(
2538 schpc_p->schpc_slot[slot].slot_handle,
2539 HPC_EVENT_SLOT_CONFIGURE, 0);
2540 } else {
2541 schpc_setslotled(expander, board, slot,
2542 SERVICE_LED_ON);
2543 }
2544 }
2545 }
2546
2547 /* ENUM# signal change event */
2548
2549 if (event->pcimsg_type.pcimsg_slotevent.slot_ENUM) {
2550 /*
2551 * ENUM should only be received to the adapter remove
2552 * procedure.
2553 */
2554
2555 SCHPC_DEBUG0(D_EVENT, "Event Type: ENUM Asserted");
2556
2557 schpc_setslotled(expander, board, slot, FAULT_LED_FLASH);
2558
2559 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_ENUM;
2560
2561 (void) hpc_slot_event_notify(
2562 schpc_p->schpc_slot[slot].slot_handle,
2563 HPC_EVENT_SLOT_ENUM, 0);
2564 }
2565
2566 /* HEALTHY# signal change event */
2567
2568 if (event->pcimsg_type.pcimsg_slotevent.slot_HEALTHY) {
2569
2570 if (!slotstatus.slot_HEALTHY) {
2571
2572 SCHPC_DEBUG0(D_EVENT, "Event Type: !HEALTHY ASSERTED");
2573
2574 schpc_p->schpc_slot[slot].state &=
2575 ~SCHPC_SLOTSTATE_OCC_GOOD;
2576
2577 (void) hpc_slot_event_notify(
2578 schpc_p->schpc_slot[slot].slot_handle,
2579 HPC_EVENT_SLOT_NOT_HEALTHY, 0);
2580
2581 schpc_setslotled(expander, board, slot, FAULT_LED_ON);
2582 } else {
2583 SCHPC_DEBUG0(D_EVENT, "Event Type: HEALTHY OK");
2584
2585 schpc_p->schpc_slot[slot].state |=
2586 SCHPC_SLOTSTATE_OCC_GOOD;
2587
2588 (void) hpc_slot_event_notify(
2589 schpc_p->schpc_slot[slot].slot_handle,
2590 HPC_EVENT_SLOT_HEALTHY_OK, 0);
2591
2592 schpc_setslotled(expander, board, slot,
2593 FAULT_LED_OFF);
2594 }
2595 }
2596
2597 /* Good Power change event */
2598
2599 if (event->pcimsg_type.pcimsg_slotevent.slot_powergood) {
2600 if (slotstatus.slot_powergood == PCIMSG_ON) {
2601
2602 SCHPC_DEBUG0(D_EVENT,
2603 "Event Type: Slot Power Good Detected");
2604
2605 schpc_p->schpc_slot[slot].state |=
2606 SCHPC_SLOTSTATE_OCC_GOOD;
2607
2608 (void) hpc_slot_event_notify(
2609 schpc_p->schpc_slot[slot].slot_handle,
2610 HPC_EVENT_SLOT_HEALTHY_OK, 0);
2611
2612 schpc_setslotled(expander, board, slot,
2613 FAULT_LED_OFF);
2614 } else {
2615 SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Not Good "
2616 "Detected");
2617
2618 if (schpc_p->schpc_slot[slot].state &
2619 SCHPC_SLOTSTATE_CONNECTED) {
2620
2621 SCHPC_DEBUG0(D_EVENT, "Slot Power Not Good: "
2622 "power failed");
2623
2624 schpc_p->schpc_slot[slot].state &=
2625 ~SCHPC_SLOTSTATE_OCC_GOOD;
2626
2627 (void) hpc_slot_event_notify(
2628 schpc_p->schpc_slot[slot].slot_handle,
2629 HPC_EVENT_SLOT_NOT_HEALTHY, 0);
2630
2631 schpc_setslotled(expander, board, slot,
2632 FAULT_LED_ON);
2633 }
2634 }
2635 }
2636
2637 /* Power Fault change event */
2638
2639 if (event->pcimsg_type.pcimsg_slotevent.slot_powerfault) {
2640 if (slotstatus.slot_powerfault == PCIMSG_ON) {
2641
2642 SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault "
2643 "Detected");
2644
2645 schpc_p->schpc_slot[slot].state &=
2646 ~SCHPC_SLOTSTATE_OCC_GOOD;
2647
2648 (void) hpc_slot_event_notify(
2649 schpc_p->schpc_slot[slot].slot_handle,
2650 HPC_EVENT_SLOT_NOT_HEALTHY, 0);
2651
2652 schpc_setslotled(expander, board, slot, FAULT_LED_ON);
2653 } else {
2654 SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault "
2655 "Cleared");
2656
2657 schpc_p->schpc_slot[slot].state |=
2658 SCHPC_SLOTSTATE_OCC_GOOD;
2659
2660 (void) hpc_slot_event_notify(
2661 schpc_p->schpc_slot[slot].slot_handle,
2662 HPC_EVENT_SLOT_HEALTHY_OK, 0);
2663
2664 schpc_setslotled(expander, board, slot,
2665 FAULT_LED_OFF);
2666 }
2667 }
2668 mutex_enter(&schpc_p->schpc_mutex);
2669 schpc_p->schpc_slot[slot].state &=
2670 ~SCHPC_SLOTSTATE_EXECUTING;
2671 cv_signal(&schpc_p->schpc_cv);
2672 mutex_exit(&schpc_p->schpc_mutex);
2673
2674 kmem_free(event, sizeof (pcimsg_t));
2675 }
2676
2677
2678 /*
2679 * schpc_event_filter
2680 *
2681 * The schpc_event_filter enqueues MBOXSC_MSG_EVENTs into the
2682 * schpc_event_taskq for processing by the schpc_event_handler _if_
2683 * hotpluggable pci slots have been registered; otherwise, the
2684 * MBOXSC_MSG_EVENTs are discarded in order to keep the incoming mailbox
2685 * open for future messages.
2686 */
2687 static void
schpc_event_filter(pcimsg_t * pmsg)2688 schpc_event_filter(pcimsg_t *pmsg)
2689 {
2690 if (slots_registered == B_TRUE) {
2691
2692 pcimsg_t *pevent;
2693
2694 /*
2695 * If hotpluggable pci slots have been registered then enqueue
2696 * the event onto the schpc_event_taskq for processing.
2697 */
2698
2699 SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
2700 "slots_registered = B_TRUE");
2701
2702 pevent = (pcimsg_t *)kmem_zalloc(sizeof (pcimsg_t), KM_SLEEP);
2703 bcopy(pmsg, pevent, sizeof (pcimsg_t));
2704
2705 SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
2706 "event alloc'd");
2707
2708 if (taskq_dispatch(schpc_event_taskq, schpc_event_handler,
2709 (void *)pevent, TQ_SLEEP) == NULL) {
2710 cmn_err(CE_WARN, "schpc: schpc_event_filter - "
2711 "taskq_dispatch failed to enqueue event");
2712 kmem_free(pevent, sizeof (pcimsg_t));
2713 return;
2714 }
2715
2716 SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
2717 "event was taskq_dispatch'ed to schpc_event_handler");
2718 } else {
2719 /*
2720 * Oops, schpc received an event _before_ the slots have been
2721 * registered. In that case there is no choice but to toss
2722 * the event.
2723 */
2724 cmn_err(CE_WARN, "schpc: schpc_event_filter - discarding "
2725 "premature event");
2726 }
2727 }
2728
2729
2730 /*
2731 * schpc_msg_thread
2732 * A stand-alone thread that monitors the incoming mailbox for
2733 * MBOXSC_MSG_REPLYs and MBOXSC_MSG_EVENTs, and removes them from
2734 * the mailbox for processing.
2735 *
2736 * MBOXSC_MSG_REPLYs are matched against outstanding REPLYs in the
2737 * schpc_replylist, and the waiting thread is notified that its REPLY
2738 * message has arrived; otherwise, if no REPLY match is found, then it is
2739 * discarded.
2740 *
2741 * MBOXSC_MSG_EVENTs are enqueued into the schpc_event_taskq and processed
2742 * by the schpc_event_handler.
2743 *
2744 * The schpc_msg_thread is started in _init().
2745 */
2746 void
schpc_msg_thread(void)2747 schpc_msg_thread(void)
2748 {
2749 int err;
2750 uint32_t type;
2751 uint32_t cmd;
2752 uint64_t transid;
2753 uint32_t length;
2754 pcimsg_t msg;
2755
2756 SCHPC_DEBUG0(D_THREAD, "schpc_msg_thread() running");
2757
2758 /* CONSTCOND */
2759 while (1) {
2760
2761 /* setup wildcard arguments */
2762 type = 0;
2763 cmd = 0;
2764 transid = 0;
2765 length = sizeof (pcimsg_t);
2766 bzero(&msg, sizeof (pcimsg_t));
2767
2768 err = mboxsc_getmsg(KEY_SCPC, &type, &cmd,
2769 &transid, &length, (void *)&msg,
2770 schpc_timeout_getmsg);
2771
2772 if (err) {
2773 switch (err) {
2774
2775 /*FALLTHROUGH*/
2776 case ETIMEDOUT:
2777 case EAGAIN:
2778 continue;
2779
2780 default:
2781 /*
2782 * unfortunately, we can't do very much here
2783 * because we're wildcarding mboxsc_getmsg
2784 * so if it encounters an error, we can't
2785 * identify which transid it belongs to.
2786 */
2787 cmn_err(CE_WARN,
2788 "schpc - mboxsc_getmsg failed, err=0x%x", err);
2789 delay(drv_usectohz(100000));
2790 continue;
2791 }
2792 }
2793
2794 if (msg.pcimsg_revision != PCIMSG_REVISION) {
2795 /*
2796 * This version of the schpc driver only understands
2797 * version 1.0 of the PCI Hot Plug Message format.
2798 */
2799 cmn_err(CE_WARN, " schpc: schpc_msg_thread - "
2800 "discarding event w/ unknown message version %x",
2801 msg.pcimsg_revision);
2802 continue;
2803 }
2804
2805 switch (type) {
2806
2807 case MBOXSC_MSG_EVENT:
2808 schpc_event_filter(&msg);
2809 break;
2810
2811 case MBOXSC_MSG_REPLY:
2812 schpc_reply_handler(&msg, type, cmd, transid, length);
2813 break;
2814
2815 default:
2816 cmn_err(CE_WARN,
2817 "schpc - mboxsc_getmsg unknown msg"
2818 " type=0x%x", type);
2819 break;
2820 }
2821 }
2822 /* this thread never exits */
2823 }
2824
2825
2826 void
schpc_reply_handler(pcimsg_t * pmsg,uint32_t type,uint32_t cmd,uint64_t transid,uint32_t length)2827 schpc_reply_handler(pcimsg_t *pmsg, uint32_t type, uint32_t cmd,
2828 uint64_t transid, uint32_t length)
2829 {
2830 schpc_replylist_t *entry;
2831
2832 mutex_enter(&schpc_replylist_mutex);
2833 entry = schpc_replylist_first;
2834 while (entry != NULL) {
2835 if (entry->transid == transid) {
2836 break;
2837 } else
2838 entry = entry->next;
2839 }
2840 if (entry) {
2841 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2842 "schpc_reply_handler() - 0x%lx transid reply "
2843 "received", transid);
2844
2845 mutex_enter(&entry->reply_lock);
2846 if (entry->reply_cexit == B_FALSE) {
2847 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2848 "schpc_reply_handler() - 0x%lx transid"
2849 " cv_signal waiting thread", transid);
2850
2851 /*
2852 * emulate mboxsc_getmsg by copying the reply
2853 */
2854 entry->type = type;
2855 entry->cmd = cmd;
2856 entry->transid = transid;
2857 entry->length = length;
2858 bcopy((caddr_t)pmsg, &entry->reply, length);
2859
2860 /* reply was received */
2861 entry->reply_recvd = B_TRUE;
2862
2863 /*
2864 * wake up thread waiting for reply with transid
2865 */
2866 cv_signal(&entry->reply_cv);
2867 }
2868 mutex_exit(&entry->reply_lock);
2869 } else {
2870 cmn_err(CE_WARN, "schpc - no match for transid 0x%lx",
2871 transid);
2872 }
2873 mutex_exit(&schpc_replylist_mutex);
2874 }
2875
2876
2877 /*
2878 * schpc_putrequest
2879 *
2880 * A wrapper around the synchronous call mboxsc_putmsg().
2881 */
2882 int
schpc_putrequest(uint32_t key,uint32_t type,uint32_t cmd,uint64_t * transidp,uint32_t length,void * datap,clock_t timeout,schpc_replylist_t ** entryp)2883 schpc_putrequest(uint32_t key, uint32_t type, uint32_t cmd, uint64_t *transidp,
2884 uint32_t length, void *datap, clock_t timeout,
2885 schpc_replylist_t **entryp)
2886 {
2887 int rval;
2888
2889 /* add the request to replylist to keep track of outstanding requests */
2890 *entryp = schpc_replylist_link(cmd, *transidp, length);
2891
2892 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - "
2893 "0x%lx transid mboxsc_putmsg called", *transidp);
2894
2895 /* wait synchronously for request to be sent */
2896 rval = mboxsc_putmsg(key, type, cmd, transidp, length,
2897 (void *)datap, timeout);
2898
2899 SCHPC_DEBUG2(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - "
2900 "0x%lx transid mboxsc_putmsg returned 0x%x", *transidp, rval);
2901
2902 /* if problem is encountered then remove the request from replylist */
2903 if (rval)
2904 schpc_replylist_unlink(*entryp);
2905
2906 return (rval);
2907 }
2908
2909
2910 /*
2911 * schpc_getreply
2912 *
2913 * Wait for the schpc_msg_thread to respond that a matching reply has
2914 * arrived; otherwise, timeout and remove the entry from the schpc_replylist.
2915 */
2916 /*ARGSUSED*/
2917 int
schpc_getreply(uint32_t key,uint32_t * typep,uint32_t * cmdp,uint64_t * transidp,uint32_t * lengthp,void * datap,clock_t timeout,schpc_replylist_t * listp)2918 schpc_getreply(uint32_t key, uint32_t *typep, uint32_t *cmdp,
2919 uint64_t *transidp, uint32_t *lengthp, void *datap,
2920 clock_t timeout, schpc_replylist_t *listp)
2921 {
2922 int rc = 0;
2923
2924 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2925 "schpc_getreply() - 0x%lx transid waiting for reply",
2926 *transidp);
2927
2928 /*
2929 * wait here until schpc_msg_thread because it's always
2930 * looking for reply messages
2931 */
2932 mutex_enter(&listp->reply_lock);
2933
2934 while (listp->reply_recvd == B_FALSE) {
2935 /*
2936 * wait for reply or timeout
2937 */
2938 rc = cv_timedwait(&listp->reply_cv, &listp->reply_lock,
2939 ddi_get_lbolt() + drv_usectohz(timeout * 1000));
2940 switch (rc) {
2941 case -1: /* most likely a timeout, but check anyway */
2942
2943 /* message was received after all */
2944 if (listp->reply_recvd == B_TRUE)
2945 break;
2946
2947 /* no, it's really a timeout */
2948 listp->reply_cexit = B_TRUE;
2949 mutex_exit(&listp->reply_lock);
2950 cmn_err(CE_WARN,
2951 "schpc - 0x%lx transid reply timed out", *transidp);
2952 schpc_replylist_unlink(listp);
2953 return (ETIMEDOUT);
2954
2955 default:
2956 break;
2957 }
2958 }
2959
2960 *typep = listp->type;
2961 *cmdp = listp->cmd;
2962 *transidp = listp->transid;
2963 *lengthp = listp->length;
2964 bcopy((caddr_t)&listp->reply, datap, *lengthp);
2965 mutex_exit(&listp->reply_lock);
2966 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2967 "schpc_getreply() - 0x%lx transid received", *transidp);
2968 schpc_replylist_unlink(listp);
2969 return (0);
2970 }
2971
2972
2973 /*
2974 * schpc_replylist_unlink
2975 *
2976 * Deallocate a schpc_replylist_t element.
2977 */
2978 void
schpc_replylist_unlink(schpc_replylist_t * entry)2979 schpc_replylist_unlink(schpc_replylist_t *entry)
2980 {
2981 #if DEBUG
2982 schpc_replylist_t *dbg_entry;
2983 #endif /* DEBUG */
2984
2985 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2986 "schpc_replylist_unlink() - 0x%lx transid deleted from replylist",
2987 entry->transid);
2988
2989 mutex_enter(&schpc_replylist_mutex);
2990 if (entry->prev) {
2991 entry->prev->next = entry->next;
2992 if (entry->next)
2993 entry->next->prev = entry->prev;
2994 } else {
2995 schpc_replylist_first = entry->next;
2996 if (entry->next)
2997 entry->next->prev = NULL;
2998 }
2999 if (entry == schpc_replylist_last) {
3000 schpc_replylist_last = entry->prev;
3001 }
3002 kmem_free(entry, sizeof (schpc_replylist_t));
3003 schpc_replylist_count--;
3004
3005 #if DEBUG
3006 if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) {
3007 dbg_entry = schpc_replylist_first;
3008 cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - replylist "
3009 "count = %d\n", schpc_replylist_count);
3010 while (dbg_entry != NULL) {
3011 cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - "
3012 "0x%lx transid\n", dbg_entry->transid);
3013 dbg_entry = dbg_entry->next;
3014 }
3015 }
3016 #endif /* DEBUG */
3017
3018 mutex_exit(&schpc_replylist_mutex);
3019 }
3020
3021
3022 /*
3023 * schpc_replylist_link
3024 *
3025 * Allocate and initialize a schpc_replylist_t element.
3026 */
3027 schpc_replylist_t *
schpc_replylist_link(uint32_t cmd,uint64_t transid,uint32_t length)3028 schpc_replylist_link(uint32_t cmd, uint64_t transid, uint32_t length)
3029 {
3030 schpc_replylist_t *entry;
3031 #if DEBUG
3032 schpc_replylist_t *dbg_entry;
3033 #endif /* DEBUG */
3034
3035 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
3036 "schpc_replylist_link() - 0x%lx transid inserting into replylist",
3037 transid);
3038
3039 entry = kmem_zalloc(sizeof (schpc_replylist_t), KM_SLEEP);
3040 mutex_init(&entry->reply_lock, NULL, MUTEX_DRIVER, NULL);
3041 cv_init(&entry->reply_cv, NULL, CV_DRIVER, NULL);
3042 entry->type = MBOXSC_MSG_REPLY;
3043 entry->cmd = cmd;
3044 entry->transid = transid;
3045 entry->length = length;
3046 entry->reply_recvd = B_FALSE;
3047 entry->reply_cexit = B_FALSE;
3048
3049 mutex_enter(&schpc_replylist_mutex);
3050 if (schpc_replylist_last) {
3051 entry->prev = schpc_replylist_last;
3052 schpc_replylist_last->next = entry;
3053 schpc_replylist_last = entry;
3054 } else {
3055 schpc_replylist_last = schpc_replylist_first = entry;
3056 }
3057
3058 schpc_replylist_count++;
3059
3060 #if DEBUG
3061 if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) {
3062 dbg_entry = schpc_replylist_first;
3063 cmn_err(CE_CONT, "schpc: schpc_replylist_link() - replylist "
3064 "count = %d\n", schpc_replylist_count);
3065 while (dbg_entry != NULL) {
3066 cmn_err(CE_CONT, "schpc: schpc_replylist_link() - "
3067 "0x%lx transid\n", dbg_entry->transid);
3068 dbg_entry = dbg_entry->next;
3069 }
3070 }
3071 #endif /* DEBUG */
3072
3073 mutex_exit(&schpc_replylist_mutex);
3074
3075 return (entry);
3076 }
3077
3078
3079 /*
3080 * schpc_getslotstatus
3081 *
3082 * Issues a Get Slot Status command to the System Controller
3083 * for a specific slot.
3084 */
3085 static int
schpc_getslotstatus(uint32_t expander,uint32_t board,uint32_t slot,pci_getslot_t * slotstatus)3086 schpc_getslotstatus(uint32_t expander, uint32_t board, uint32_t slot,
3087 pci_getslot_t *slotstatus)
3088 {
3089 pcimsg_t request;
3090 pcimsg_t reply;
3091 int rval;
3092 uint32_t type, cmd, length;
3093 uint64_t transid;
3094 schpc_replylist_t *entry;
3095
3096 SCHPC_DEBUG4(D_GETSLOTSTATUS,
3097 "schpc_getslotstatus(expander=%d board=%d "
3098 "slot=%d slotstatus=0x%p", expander, board,
3099 SCHPC_SLOT_NUM(slot), (void *)slotstatus);
3100
3101 if (schpc_p == NULL) {
3102 return (1);
3103 }
3104
3105 bzero(&request, sizeof (pcimsg_t));
3106
3107 request.pcimsg_node = expander;
3108 request.pcimsg_board = board;
3109 request.pcimsg_slot = SCHPC_SLOT_NUM(slot);
3110 request.pcimsg_revision = PCIMSG_REVISION;
3111 request.pcimsg_command = PCIMSG_GETSLOTSTATUS;
3112
3113 type = MBOXSC_MSG_REQUEST;
3114 cmd = PCIMSG_GETSLOTSTATUS;
3115 transid = schpc_gettransid(schpc_p, slot);
3116 length = sizeof (pcimsg_t);
3117
3118 SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
3119 "0x%lx transid schpc_putrequest called", transid);
3120
3121 rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length,
3122 (void *)&request, schpc_timeout_putmsg, &entry);
3123
3124 SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
3125 "0x%lx transid schpc_putrequest returned 0x%x", transid, rval);
3126
3127 if (rval) {
3128 return (rval);
3129 }
3130
3131 bzero(&reply, sizeof (pcimsg_t));
3132 type = MBOXSC_MSG_REPLY;
3133
3134 SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
3135 "0x%lx transid schpc_getreply called", transid);
3136
3137 rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length,
3138 (void *)&reply, schpc_timeout_getmsg, entry);
3139
3140 SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
3141 "0x%lx transid schpc_getreply returned 0x%x", transid, rval);
3142
3143 if (rval == 0) {
3144 *slotstatus = reply.pcimsg_type.pcimsg_getslot;
3145
3146 SCHPC_DEBUG0(D_GETSLOTSTATUS, "schpc_getslotstatus()");
3147 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_power_on %x",
3148 reply.pcimsg_type.pcimsg_getslot.slot_power_on);
3149 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_powergood %x",
3150 reply.pcimsg_type.pcimsg_getslot.slot_powergood);
3151 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_powerfault %x",
3152 reply.pcimsg_type.pcimsg_getslot.slot_powerfault);
3153 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_empty %x",
3154 reply.pcimsg_type.pcimsg_getslot.slot_empty);
3155 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_freq_cap %x",
3156 reply.pcimsg_type.pcimsg_getslot.slot_freq_cap);
3157 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_freq_setting %x",
3158 reply.pcimsg_type.pcimsg_getslot.slot_freq_setting);
3159 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_condition %x",
3160 reply.pcimsg_type.pcimsg_getslot.slot_condition);
3161 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_HEALTHY %x",
3162 reply.pcimsg_type.pcimsg_getslot.slot_HEALTHY);
3163 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_ENUM %x",
3164 reply.pcimsg_type.pcimsg_getslot.slot_ENUM);
3165 }
3166
3167 return (rval);
3168 }
3169
3170
3171 /*
3172 * schpc_setslotstatus
3173 *
3174 * Issues a Set Slot Status command to the System Controller
3175 * for a specific slot.
3176 */
3177 static int
schpc_setslotstatus(uint32_t expander,uint32_t board,uint32_t slot,pci_setslot_t * slotstatus)3178 schpc_setslotstatus(uint32_t expander, uint32_t board, uint32_t slot,
3179 pci_setslot_t *slotstatus)
3180 {
3181 pcimsg_t request;
3182 pcimsg_t reply;
3183 int rval;
3184 uint32_t type, cmd, length;
3185 uint64_t transid;
3186 schpc_replylist_t *entry;
3187
3188 SCHPC_DEBUG4(D_SETSLOTSTATUS,
3189 "schpc_setslotstatus(expander=%d board=%d "
3190 "slot=%d slotstatus=0x%p", expander, board,
3191 SCHPC_SLOT_NUM(slot), (void *)slotstatus);
3192
3193 bzero(&request, sizeof (pcimsg_t));
3194
3195 if (schpc_p == NULL) {
3196 return (1);
3197 }
3198
3199 request.pcimsg_node = expander;
3200 request.pcimsg_board = board;
3201 request.pcimsg_slot = SCHPC_SLOT_NUM(slot);
3202 request.pcimsg_revision = PCIMSG_REVISION;
3203 request.pcimsg_command = PCIMSG_SETSLOTSTATUS;
3204
3205 request.pcimsg_type.pcimsg_setslot = *slotstatus;
3206
3207 SCHPC_DEBUG0(D_IOC_LED, "schpc_setslotstatus() - LED state change");
3208 SCHPC_DEBUG3(D_IOC_LED, "LED Power %d Service %d Fault %d",
3209 slotstatus->slot_led_power,
3210 slotstatus->slot_led_service,
3211 slotstatus->slot_led_fault);
3212
3213 type = MBOXSC_MSG_REQUEST;
3214 cmd = PCIMSG_SETSLOTSTATUS;
3215 transid = schpc_gettransid(schpc_p, slot);
3216 length = sizeof (pcimsg_t);
3217
3218 SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
3219 "0x%lx transid schpc_putrequest called", transid);
3220
3221 rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length,
3222 (void *)&request, schpc_timeout_putmsg, &entry);
3223
3224 SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
3225 "0x%lx transid schpc_putrequest returned 0x%x", transid, rval);
3226
3227 if (rval) {
3228 return (rval);
3229 }
3230
3231 bzero(&reply, sizeof (pcimsg_t));
3232 type = MBOXSC_MSG_REPLY;
3233
3234 SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
3235 "0x%lx transid schpc_getreply called", transid);
3236
3237 rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length,
3238 (void *)&reply, schpc_timeout_getmsg, entry);
3239
3240 SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
3241 "0x%lx transid schpc_getreply returned 0x%x", transid, rval);
3242
3243 if (rval == 0) {
3244 slotstatus->slot_replystatus =
3245 reply.pcimsg_type.pcimsg_setslot.slot_replystatus;
3246 }
3247
3248 return (rval);
3249 }
3250
3251 /*
3252 * schpc_setslotled
3253 *
3254 * Changes the attention indicators for a given slot.
3255 */
3256 static void
schpc_setslotled(int expander,int board,int slot,uint32_t led_state)3257 schpc_setslotled(int expander, int board, int slot, uint32_t led_state)
3258 {
3259
3260 pci_setslot_t setslot;
3261
3262 if (schpc_p == NULL) {
3263 return;
3264 }
3265
3266 schpc_init_setslot_message(&setslot);
3267
3268 if (led_state & POWER_LED_ON) {
3269 schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON;
3270 }
3271 if (led_state & POWER_LED_OFF) {
3272 schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_OFF;
3273 }
3274 if (led_state & POWER_LED_FLASH) {
3275 schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_FLASH;
3276 }
3277 if (led_state & SERVICE_LED_ON) {
3278 schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_ON;
3279 }
3280 if (led_state & SERVICE_LED_OFF) {
3281 schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_OFF;
3282 }
3283 if (led_state & SERVICE_LED_FLASH) {
3284 schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_FLASH;
3285 }
3286 if (led_state & FAULT_LED_ON) {
3287 schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_ON;
3288 }
3289 if (led_state & FAULT_LED_OFF) {
3290 schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_OFF;
3291 }
3292 if (led_state & FAULT_LED_FLASH) {
3293 schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_FLASH;
3294 }
3295
3296 switch (schpc_p->schpc_slot[slot].led.led_power) {
3297 case PCIMSG_LED_ON:
3298 setslot.slot_led_power = PCIMSG_LED_ON;
3299 break;
3300 case PCIMSG_LED_OFF:
3301 setslot.slot_led_power = PCIMSG_LED_OFF;
3302 break;
3303 case PCIMSG_LED_FLASH:
3304 setslot.slot_led_power = PCIMSG_LED_FLASH;
3305 break;
3306 }
3307 switch (schpc_p->schpc_slot[slot].led.led_service) {
3308 case PCIMSG_LED_ON:
3309 setslot.slot_led_service = PCIMSG_LED_ON;
3310 break;
3311 case PCIMSG_LED_OFF:
3312 setslot.slot_led_service = PCIMSG_LED_OFF;
3313 break;
3314 case PCIMSG_LED_FLASH:
3315 setslot.slot_led_service = PCIMSG_LED_FLASH;
3316 break;
3317 }
3318 switch (schpc_p->schpc_slot[slot].led.led_fault) {
3319 case PCIMSG_LED_ON:
3320 setslot.slot_led_fault = PCIMSG_LED_ON;
3321 break;
3322 case PCIMSG_LED_OFF:
3323 setslot.slot_led_fault = PCIMSG_LED_OFF;
3324 break;
3325 case PCIMSG_LED_FLASH:
3326 setslot.slot_led_fault = PCIMSG_LED_FLASH;
3327 break;
3328 }
3329
3330 (void) schpc_setslotstatus(expander, board, slot, &setslot);
3331 }
3332
3333 /*
3334 * schpc_init_setslot_message
3335 *
3336 * Initialize Set Slot Message before using it.
3337 */
3338 static void
schpc_init_setslot_message(pci_setslot_t * setslot)3339 schpc_init_setslot_message(pci_setslot_t *setslot)
3340 {
3341 /*
3342 * Initialize Set Slot Command.
3343 */
3344 setslot->slot_power_on = PCIMSG_OFF;
3345 setslot->slot_power_off = PCIMSG_OFF;
3346 setslot->slot_led_power = PCIMSG_LED_OFF;
3347 setslot->slot_led_service = PCIMSG_LED_OFF;
3348 setslot->slot_led_fault = PCIMSG_LED_OFF;
3349 setslot->slot_disable_ENUM = PCIMSG_OFF;
3350 setslot->slot_enable_ENUM = PCIMSG_OFF;
3351 setslot->slot_disable_HEALTHY = PCIMSG_OFF;
3352 setslot->slot_enable_HEALTHY = PCIMSG_OFF;
3353 }
3354
3355 /*
3356 * schpc_gettransid
3357 *
3358 * Builds a unique transaction ID.
3359 */
3360 static uint64_t
schpc_gettransid(schpc_t * schpc_p,int slot)3361 schpc_gettransid(schpc_t *schpc_p, int slot)
3362 {
3363 uint64_t trans_id;
3364
3365 mutex_enter(&schpc_p->schpc_mutex);
3366
3367 if (++schpc_p->schpc_transid == 0)
3368 schpc_p->schpc_transid = 1;
3369
3370 trans_id = (schpc_p->schpc_slot[slot].expander<<24) |
3371 (schpc_p->schpc_slot[slot].board << 16) | schpc_p->schpc_transid;
3372
3373 mutex_exit(&schpc_p->schpc_mutex);
3374
3375 SCHPC_DEBUG1(D_TRANSID, "schpc_gettransid() - 0x%lx transid returning",
3376 trans_id);
3377
3378 return (trans_id);
3379 }
3380
3381 /*
3382 * schpc_slot_get_index
3383 *
3384 * get slot table index from the slot handle
3385 */
3386 static int
schpc_slot_get_index(schpc_t * schpc_p,hpc_slot_t slot)3387 schpc_slot_get_index(schpc_t *schpc_p, hpc_slot_t slot)
3388 {
3389 int i;
3390 int rval = -1;
3391
3392 ASSERT(MUTEX_HELD(&schpc_p->schpc_mutex));
3393
3394 for (i = 0; i < schpc_p->schpc_number_of_slots; i++) {
3395 if (schpc_p->schpc_slot[i].slot_handle == slot)
3396 return (i);
3397 }
3398
3399 return (rval);
3400 }
3401
3402 /*
3403 * schpc_register_all_slots
3404 *
3405 * Search device tree for pci nodes and register attachment points
3406 * for all hot pluggable slots.
3407 */
3408 /*ARGSUSED*/
3409 static void
schpc_register_all_slots(schpc_t * schpc_p)3410 schpc_register_all_slots(schpc_t *schpc_p)
3411 {
3412 int slot = 0;
3413 char caddr[64];
3414 dev_info_t *pci_dip = NULL;
3415 find_dev_t find_dev;
3416 int leaf, schizo, expander, portid, offset;
3417
3418 SCHPC_DEBUG1(D_ATTACH,
3419 "schpc_register_all_slots(schpc_p=%p)", (void *)schpc_p);
3420
3421 /*
3422 * Allow the event_handler to start processing unsolicited
3423 * events now that slots are about to be registered.
3424 */
3425 slots_registered = B_TRUE;
3426
3427 for (slot = 0; slot < STARCAT_MAX_SLOTS; slot++) {
3428
3429 leaf = SCHPC_SLOT_LEAF(slot);
3430 schizo = SCHPC_SLOT_SCHIZO(slot);
3431 expander = SCHPC_SLOT_EXPANDER(slot);
3432
3433 if (schizo == 0)
3434 portid = 0x1c;
3435 else
3436 portid = 0x1d;
3437
3438 if (leaf == 0)
3439 offset = 0x600000;
3440 else
3441 offset = 0x700000;
3442
3443 portid = (expander << 5) | portid;
3444
3445 (void) sprintf(caddr, "%x,%x", portid, offset);
3446
3447 SCHPC_DEBUG3(D_ATTACH,
3448 "schpc_register_all_slots: searching for pci@%s"
3449 " schizo=%d, leaf=%d", caddr, schizo, leaf);
3450
3451 find_dev.cname = "pci";
3452 find_dev.caddr = caddr;
3453 find_dev.schizo = schizo;
3454 find_dev.leaf = leaf;
3455 find_dev.dip = NULL;
3456
3457 /* root node doesn't have to be held */
3458 ddi_walk_devs(ddi_root_node(), schpc_match_dip,
3459 &find_dev);
3460
3461 pci_dip = find_dev.dip;
3462
3463 if (pci_dip == NULL) {
3464
3465 SCHPC_DEBUG1(D_ATTACH,
3466 "schpc_register_all_slots: pci@%s NOT FOUND",
3467 caddr);
3468
3469 continue;
3470 }
3471
3472 SCHPC_DEBUG2(D_ATTACH,
3473 "schpc_register_all_slots: pci@%s FOUND dip=0x%p",
3474 caddr, (void *)pci_dip);
3475
3476 (void) schpc_add_pci(pci_dip);
3477
3478 /*
3479 * Release hold acquired in schpc_match_dip()
3480 */
3481 ndi_rele_devi(pci_dip);
3482 }
3483
3484 SCHPC_DEBUG0(D_ATTACH, "schpc_register_all_slots: Thread Exit");
3485
3486 thread_exit();
3487 }
3488
3489 /*
3490 * schpc_add_pci
3491 *
3492 * Routine to add attachments points associated with a pci node.
3493 * Can be call externally by DR when configuring a PCI I/O Board.
3494 */
3495 int
schpc_add_pci(dev_info_t * bdip)3496 schpc_add_pci(dev_info_t *bdip)
3497 {
3498 int portid;
3499 int expander, board, schizo, leaf, slot, status;
3500 char ap_id[MAXNAMELEN];
3501 char caddr[64];
3502 char *naddr;
3503 hpc_slot_info_t slot_info;
3504 hpc_slot_ops_t *slot_ops;
3505 dev_info_t *sdip = bdip;
3506
3507 SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci(dip=0x%p)", (void *)sdip);
3508
3509 if (schpc_p == NULL) {
3510 /*
3511 * The schpc driver has not been attached yet.
3512 */
3513 return (DDI_SUCCESS);
3514 }
3515
3516 if ((portid = ddi_getprop(DDI_DEV_T_ANY, sdip, 0, "portid", -1)) < 0) {
3517 cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - no portid\n",
3518 (void *)sdip);
3519 return (DDI_FAILURE);
3520 }
3521
3522 expander = schpc_getexpander(sdip);
3523 board = schpc_getboard(sdip);
3524
3525 switch (portid & 0x1f) {
3526
3527 case 0x1c:
3528 schizo = 0;
3529 break;
3530 case 0x1d:
3531 schizo = 1;
3532 break;
3533 default:
3534 cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3535 "Invalid pci portid 0x%x\n", (void *)sdip, portid);
3536 return (DDI_FAILURE);
3537 }
3538
3539 naddr = ddi_get_name_addr(sdip);
3540 if (naddr == NULL) {
3541 SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci: ddi_get_name_addr"
3542 "(0x%p) returns null", (void *)sdip);
3543 return (DDI_FAILURE);
3544 }
3545
3546 (void) sprintf(caddr, "%x,600000", portid);
3547
3548 if (strcmp(caddr, naddr) == 0) {
3549 leaf = 0;
3550 } else {
3551 (void) sprintf(caddr, "%x,700000", portid);
3552 if (strcmp(caddr, naddr) == 0) {
3553 char *name;
3554
3555 leaf = 1;
3556 name = ddi_binding_name(sdip);
3557 if ((strcmp(name, "pci108e,8002") == 0) &&
3558 (schizo == 0)) {
3559 int circ;
3560 dev_info_t *cdip;
3561 /*
3562 * XMITS 0 Leaf B will have its hot
3563 * pluggable slot off a PCI-PCI bridge,
3564 * which is the only child.
3565 */
3566 ndi_devi_enter(sdip, &circ);
3567 cdip = ddi_get_child(sdip);
3568 if (cdip == NULL) {
3569 cmn_err(CE_WARN,
3570 "schpc_add_pci(dip=0x%p) - "
3571 "Invalid pci name addr %s\n",
3572 (void *)sdip, naddr);
3573 ndi_devi_exit(sdip, circ);
3574 return (DDI_FAILURE);
3575 }
3576 ndi_devi_exit(sdip, circ);
3577 sdip = cdip;
3578 }
3579 } else {
3580 cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3581 "Invalid pci name addr %s\n", (void *)sdip, naddr);
3582 return (DDI_FAILURE);
3583 }
3584 }
3585
3586 /* create a slot table index */
3587 slot = SCHPC_MAKE_SLOT_INDEX3(expander, schizo, leaf);
3588
3589 if (schpc_p->schpc_slot[slot].devi) {
3590 cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3591 "pci node already registered\n", (void *)sdip);
3592 return (DDI_FAILURE);
3593 }
3594
3595 /*
3596 * There is no need to hold the dip while saving it in
3597 * the devi field below. The dip is never dereferenced.
3598 * (If that changes, this code should be modified).
3599 * We want to avoid holding the dip here because it
3600 * prevents DR.
3601 *
3602 * NOTE: Even though the slot on XMITS0 Leaf-B
3603 * is connected to a pci_pci bridge, we will be saving
3604 * the busdip in this datastructure. This will make
3605 * it easier to identify the dip being removed in
3606 * schpc_remove_pci().
3607 */
3608 schpc_p->schpc_slot[slot].devi = bdip;
3609
3610 schpc_p->schpc_slot[slot].expander = expander;
3611 schpc_p->schpc_slot[slot].board = board;
3612 schpc_p->schpc_slot[slot].schizo = schizo;
3613 schpc_p->schpc_slot[slot].leaf = leaf;
3614
3615 /*
3616 * Starcat PCI slots are always PCI device 1.
3617 */
3618 schpc_p->schpc_slot[slot].pci_id = 1;
3619
3620 schpc_buildapid(sdip, slot, (char *)&ap_id);
3621
3622 (void) strcpy(schpc_p->schpc_slot[slot].ap_id, (char *)&ap_id);
3623
3624 /* safe to call ddi_pathname(): bdip is held */
3625 (void) ddi_pathname(sdip, schpc_p->schpc_slot[slot].nexus_path);
3626
3627 status = schpc_get_slot_status(expander, board, SCHPC_SLOT_NUM(slot));
3628 switch (status) {
3629 case RSV_UNKNOWN:
3630 case RSV_PRESENT:
3631 case RSV_MISS:
3632 case RSV_PASS:
3633 case RSV_EMPTY_CASSETTE:
3634
3635 /*
3636 * Test the condition of the slot.
3637 */
3638 schpc_test((caddr_t)schpc_p, slot, 0, 0);
3639 break;
3640 case RSV_BLACK:
3641 schpc_p->schpc_slot[slot].state = 0;
3642 cmn_err(CE_WARN, "schpc: PCI card blacklisted: "
3643 "expander=%d board=%d slot=%d\n", expander,
3644 board, SCHPC_SLOT_NUM(slot));
3645 break;
3646 default:
3647 schpc_p->schpc_slot[slot].state = 0;
3648 cmn_err(CE_WARN, "schpc: PCI card failed by POST: "
3649 "expander=%d board=%d slot=%d failure=0x%x\n",
3650 expander, board, SCHPC_SLOT_NUM(slot), status);
3651 break;
3652 }
3653
3654 if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_REC_GOOD) {
3655
3656 /* allocate slot ops */
3657
3658 slot_ops = hpc_alloc_slot_ops(KM_SLEEP);
3659 schpc_p->schpc_slot[slot].slot_ops = slot_ops;
3660
3661 /*
3662 * Default to Autoconfiguration disabled.
3663 */
3664 schpc_p->schpc_slot[slot].state &=
3665 ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
3666
3667 /*
3668 * Fill in the slot information structure that
3669 * describes the slot.
3670 */
3671 slot_info.version = HPC_SLOT_OPS_VERSION;
3672
3673 if (schpc_p->schpc_hotplugmodel ==
3674 SCHPC_HOTPLUGTYPE_CPCIHOTPLUG)
3675 slot_info.slot_type = HPC_SLOT_TYPE_PCI;
3676 else
3677 slot_info.slot_type = HPC_SLOT_TYPE_CPCI;
3678
3679 slot_info.slot.pci.device_number =
3680 schpc_p->schpc_slot[slot].pci_id;
3681
3682 slot_info.slot.pci.slot_capabilities = HPC_SLOT_64BITS;
3683
3684 if (schpc_use_legacy_apid)
3685 slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE;
3686 else
3687 slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE |
3688 HPC_SLOT_CREATE_DEVLINK;
3689
3690 (void) strcpy(slot_info.slot.pci.slot_logical_name,
3691 schpc_p->schpc_slot[slot].ap_id);
3692
3693 /*
3694 * Fill in the slot ops structure that tells
3695 * the Hot Plug Services what function we
3696 * support.
3697 */
3698 slot_ops->hpc_version = HPC_SLOT_OPS_VERSION;
3699 if (schpc_p->schpc_hotplugmodel ==
3700 SCHPC_HOTPLUGTYPE_CPCIHOTPLUG) {
3701 slot_ops->hpc_op_connect = schpc_connect;
3702 slot_ops->hpc_op_disconnect = schpc_disconnect;
3703 slot_ops->hpc_op_insert = NULL;
3704 slot_ops->hpc_op_remove = NULL;
3705 slot_ops->hpc_op_control = schpc_pci_control;
3706 } else {
3707 slot_ops->hpc_op_connect = NULL;
3708 slot_ops->hpc_op_disconnect = NULL;
3709 slot_ops->hpc_op_insert = NULL;
3710 slot_ops->hpc_op_remove = NULL;
3711 slot_ops->hpc_op_control = schpc_cpci_control;
3712 }
3713
3714 SCHPC_DEBUG5(D_ATTACH, "schpc_add_pci: Registering HPC "
3715 "- nexus =%s schpc_p=%p slot=%d pci number=%d ap_id=%s",
3716 schpc_p->schpc_slot[slot].nexus_path,
3717 (void *)schpc_p, SCHPC_SLOT_NUM(slot),
3718 slot_info.slot.pci.device_number,
3719 slot_info.slot.pci.slot_logical_name);
3720
3721 if (hpc_slot_register(schpc_p->schpc_devi,
3722 schpc_p->schpc_slot[slot].nexus_path, &slot_info,
3723 &schpc_p->schpc_slot[slot].slot_handle,
3724 slot_ops, (caddr_t)schpc_p, 0) != 0) {
3725
3726 /*
3727 * If the slot can not be registered,
3728 * then the slot_ops need to be freed.
3729 */
3730 cmn_err(CE_WARN, "schpc%d Unable to Register "
3731 "Slot %s", schpc_p->schpc_instance,
3732 slot_info.slot.pci.slot_logical_name);
3733
3734 hpc_free_slot_ops(schpc_p->schpc_slot[slot].slot_ops);
3735
3736 schpc_p->schpc_slot[slot].slot_ops = NULL;
3737
3738 return (DDI_FAILURE);
3739 }
3740
3741 /*
3742 * We are ready to take commands from the HPC Services.
3743 */
3744 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_HPCINITED;
3745 }
3746
3747 return (DDI_SUCCESS);
3748 }
3749
3750 /*
3751 * schpc_remove_pci
3752 *
3753 * Routine to remove attachments points associated with a pci node.
3754 * Can be call externally by DR when unconfiguring a PCI I/O Board.
3755 */
3756 int
schpc_remove_pci(dev_info_t * dip)3757 schpc_remove_pci(dev_info_t *dip)
3758 {
3759 int slot;
3760
3761 SCHPC_DEBUG1(D_DETACH, "schpc_remove_pci(dip=0x%p)", (void *)dip);
3762
3763 if (schpc_p == NULL) {
3764 /*
3765 * The schpc driver has not been attached yet.
3766 */
3767 return (DDI_SUCCESS);
3768 }
3769
3770 for (slot = 0; slot < schpc_p->schpc_number_of_slots; slot++) {
3771 if (schpc_p->schpc_slot[slot].devi == dip) {
3772
3773 if (schpc_p->schpc_slot[slot].slot_ops) {
3774 if (hpc_slot_unregister(
3775 &schpc_p->schpc_slot[slot].slot_handle)) {
3776 cmn_err(CE_WARN,
3777 "schpc_remove_pci(dip=0x%p) - "
3778 "unable to unregister pci slots\n",
3779 (void *)dip);
3780 return (DDI_FAILURE);
3781 } else {
3782 hpc_free_slot_ops(
3783 schpc_p->schpc_slot[slot].slot_ops);
3784
3785 schpc_p->schpc_slot[slot].slot_ops =
3786 NULL;
3787
3788 schpc_p->schpc_slot[slot].devi = NULL;
3789
3790 return (DDI_SUCCESS);
3791 }
3792 } else {
3793 schpc_p->schpc_slot[slot].devi = NULL;
3794
3795 return (DDI_SUCCESS);
3796 }
3797 }
3798 }
3799
3800 cmn_err(CE_WARN, "schpc_remove_pci(dip=0x%p) "
3801 "dip not found\n", (void *)dip);
3802
3803 return (DDI_SUCCESS);
3804 }
3805
3806 /*
3807 * schpc_match_dip
3808 *
3809 * Used by ddi_walk_devs to find PCI Nexus nodes associated with
3810 * Hot Plug Controllers.
3811 */
3812 static int
schpc_match_dip(dev_info_t * dip,void * arg)3813 schpc_match_dip(dev_info_t *dip, void *arg)
3814 {
3815 char *naddr;
3816 find_dev_t *find_dev = (find_dev_t *)arg;
3817
3818 if (strcmp(find_dev->cname, ddi_node_name(dip)) == 0 &&
3819 ((((naddr = ddi_get_name_addr(dip)) != NULL) &&
3820 (strcmp(find_dev->caddr, naddr) == 0)) ||
3821 ((naddr == NULL) && (strlen(find_dev->caddr) == 0)))) {
3822 /*
3823 * While ddi_walk_devs() holds dips when invoking this
3824 * callback, this dip is being saved and will be accessible
3825 * to the caller outside ddi_walk_devs(). Therefore it must be
3826 * held.
3827 */
3828 ndi_hold_devi(dip);
3829 find_dev->dip = dip;
3830
3831 SCHPC_DEBUG2(D_ATTACH,
3832 "schpc_match_dip: pci@%s FOUND dip=0x%p",
3833 find_dev->caddr, (void *)find_dev->dip);
3834
3835 return (DDI_WALK_TERMINATE);
3836 }
3837
3838 ASSERT(find_dev->dip == NULL);
3839 return (DDI_WALK_CONTINUE);
3840 }
3841
3842 /*
3843 * schpc_buildapid
3844 *
3845 * Takes a component address and translates it into a ap_id prefix.
3846 */
3847 static void
schpc_buildapid(dev_info_t * dip,int slot,char * ap_id)3848 schpc_buildapid(dev_info_t *dip, int slot, char *ap_id)
3849 {
3850 int r, pci_id_cnt, pci_id_bit;
3851 int slots_before, found;
3852 unsigned char *slot_names_data, *s;
3853 int slot_names_size;
3854 int slot_num;
3855 unsigned int bit_mask;
3856
3857 slot_num = SCHPC_SLOT_NUM(slot);
3858
3859 if (schpc_use_legacy_apid) {
3860 SCHPC_DEBUG1(D_APID, "Slot %d - Using Legacy ap-id", slot);
3861
3862 (void) sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip),
3863 schpc_getboard(dip), slot_num);
3864
3865 SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id);
3866
3867 return;
3868 }
3869
3870 r = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
3871 "slot-names", (caddr_t)&slot_names_data,
3872 &slot_names_size);
3873
3874 if (r == DDI_PROP_SUCCESS) {
3875
3876 /*
3877 * We can try to use the slot-names property to
3878 * build our ap-id.
3879 */
3880 bit_mask = slot_names_data[3] | (slot_names_data[2] << 8) |
3881 (slot_names_data[1] << 16) | (slot_names_data[0] << 24);
3882
3883 pci_id_bit = 1;
3884 pci_id_cnt = slots_before = found = 0;
3885
3886 SCHPC_DEBUG2(D_APID, "Slot %d - slot-names bitmask=%x",
3887 slot, bit_mask);
3888
3889 /*
3890 * Walk the bit mask until we find the bit that corresponds
3891 * to our slots device number. We count how many bits
3892 * we find before we find our slot's bit.
3893 */
3894 while (!found && (pci_id_cnt < 32)) {
3895
3896 while (schpc_p->schpc_slot[slot].pci_id
3897 != pci_id_cnt) {
3898
3899 /*
3900 * Find the next bit set.
3901 */
3902 while (!(bit_mask & pci_id_bit) &&
3903 (pci_id_cnt < 32)) {
3904 pci_id_bit = pci_id_bit << 1;
3905 pci_id_cnt++;
3906 }
3907
3908 if (schpc_p->schpc_slot[slot].pci_id !=
3909 pci_id_cnt)
3910 slots_before++;
3911 else
3912 found = 1;
3913 }
3914 }
3915
3916 if (pci_id_cnt < 32) {
3917
3918 /*
3919 * Set ptr to first string.
3920 */
3921 s = slot_names_data + 4;
3922
3923 /*
3924 * Increment past all the strings for the slots
3925 * before ours.
3926 */
3927 while (slots_before) {
3928 while (*s != NULL)
3929 s++;
3930 s++;
3931 slots_before--;
3932 }
3933
3934 /*
3935 * We should be at our string.
3936 */
3937
3938 (void) sprintf(ap_id, "IO%d_%s",
3939 schpc_getexpander(dip), s);
3940
3941 SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s",
3942 slot, ap_id);
3943
3944 kmem_free(slot_names_data, slot_names_size);
3945 return;
3946 }
3947
3948 SCHPC_DEBUG1(D_APID, "Slot %d - slot-names entry not found",
3949 slot);
3950
3951 kmem_free(slot_names_data, slot_names_size);
3952 } else
3953 SCHPC_DEBUG1(D_APID, "Slot %d - No slot-names prop found",
3954 slot);
3955
3956 /*
3957 * Build the ap-id using the legacy naming scheme.
3958 */
3959 (void) sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip),
3960 schpc_getboard(dip), slot_num);
3961
3962 SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id);
3963 }
3964
3965 /*
3966 * schpc_getexpander
3967 *
3968 * Returns the Expander Number (0-17) for the dip passed in. The Expander
3969 * Number is extracted from the portid property of the pci node. Portid
3970 * consists of <Expbrd#><1110x>, where x is the schizo number.
3971 */
3972 static int
schpc_getexpander(dev_info_t * dip)3973 schpc_getexpander(dev_info_t *dip)
3974 {
3975 int id;
3976
3977 id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "portid", -1);
3978
3979 if (id != -1)
3980 return (id >> 5);
3981 else {
3982 id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "expander", -1);
3983 return (id);
3984 }
3985 }
3986
3987 /*
3988 * schpc_getboard
3989 *
3990 * Returns the board number (0 or 1) for the dip passed in.
3991 */
3992 static int
schpc_getboard(dev_info_t * dip)3993 schpc_getboard(dev_info_t *dip)
3994 {
3995 _NOTE(ARGUNUSED(dip))
3996
3997 /*
3998 * Hot Pluggable PCI/cPCI slots are only available on
3999 * Board 1 (half-bandwidth slot).
4000 */
4001 return (1);
4002 }
4003
4004 /*ARGSUSED*/
4005 static int
schpc_get_slot_status(uint_t expander,uint_t board,uint_t slot)4006 schpc_get_slot_status(uint_t expander, uint_t board, uint_t slot)
4007 {
4008 gdcd_t *gdcd;
4009 int prd_slot, status, bus;
4010
4011 SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() "
4012 "exp=%d board=%d slot=%d", expander, board, slot);
4013
4014 if ((gdcd = (gdcd_t *)kmem_zalloc(sizeof (gdcd_t),
4015 KM_SLEEP)) == NULL) {
4016 return (RSV_UNDEFINED);
4017 }
4018
4019 /*
4020 * Get the Starcat Specific Global DCD Structure from the golden
4021 * IOSRAM.
4022 */
4023 if (iosram_rd(GDCD_MAGIC, 0, sizeof (gdcd_t), (caddr_t)gdcd)) {
4024 cmn_err(CE_WARN, "sc_gptwocfg: Unable To Read GDCD "
4025 "From IOSRAM\n");
4026 kmem_free(gdcd, sizeof (gdcd_t));
4027 return (RSV_UNDEFINED);
4028 }
4029
4030 if (gdcd->h.dcd_magic != GDCD_MAGIC) {
4031
4032 cmn_err(CE_WARN, "schpc: GDCD Bad Magic 0x%x\n",
4033 gdcd->h.dcd_magic);
4034
4035 kmem_free(gdcd, sizeof (gdcd_t));
4036 return (RSV_UNDEFINED);
4037 }
4038
4039 if (gdcd->h.dcd_version != DCD_VERSION) {
4040 cmn_err(CE_WARN, "schpc: GDCD Bad Version: "
4041 "GDCD Version 0x%x Expecting 0x%x\n",
4042 gdcd->h.dcd_version, DCD_VERSION);
4043
4044 kmem_free(gdcd, sizeof (gdcd_t));
4045 return (RSV_UNDEFINED);
4046 }
4047
4048 if (slot < 2)
4049 prd_slot = 4;
4050 else
4051 prd_slot = 5;
4052
4053 bus = slot & 0x1;
4054
4055 status = gdcd->dcd_prd[expander][prd_slot].prd_iocard_rsv[bus][0];
4056
4057 kmem_free(gdcd, sizeof (gdcd_t));
4058
4059 SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() "
4060 "prd_slot=%d bus=%d status=%d", prd_slot, bus, status);
4061
4062 return (status);
4063 }
4064
4065 #define LEAF_SAVE_END 0xff
4066
4067 typedef struct {
4068 int reg;
4069 int offset;
4070 int access_size;
4071 int number;
4072 } save_reg_list_t;
4073
4074 /*
4075 * Save List Array. Describes the leaf registers that need to
4076 * be restored after a leaf reset.
4077 *
4078 * Entry 1 - Reg Entry: 0=PCI Leaf CSRs, 2=PCI Config Space
4079 * Entry 2 - Offset Start
4080 * Entry 3 - Access Size: 8=64 bit, 4=32 bit, 2=16 bit, 1=8 bit
4081 * Entry 4 - # of registers to be saved starting at offset,
4082 */
4083 save_reg_list_t save_reg_list[] = { 0, 0x110, 8, 1,
4084 0, 0x200, 8, 2,
4085 0, 0x1000, 8, 0x18,
4086 0, 0x1a00, 8, 1,
4087 0, 0x2000, 8, 1,
4088 0, 0x2020, 8, 1,
4089 0, 0x2040, 8, 1,
4090 0, 0x2308, 8, 2,
4091 0, 0x2800, 8, 1,
4092 2, 0x04, 2, 1, /* Command */
4093 2, 0x0d, 1, 1, /* Latency */
4094 2, 0x40, 1, 1, /* Bus # */
4095 2, 0x41, 1, 1, /* Sub. Bus # */
4096 LEAF_SAVE_END, 0, 0, 0};
4097
4098 static int
schpc_save_leaf(int slot)4099 schpc_save_leaf(int slot)
4100 {
4101 int save_entry, list_entry, reg;
4102 caddr_t leaf_regs;
4103 ddi_device_acc_attr_t attr;
4104
4105 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot);
4106
4107 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
4108 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
4109 attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
4110
4111 /*
4112 * Map in the 3 addresses spaces defined for XMITS.
4113 */
4114 for (reg = 0; reg < 3; reg++) {
4115 if (ddi_regs_map_setup(schpc_p->schpc_slot[slot].devi, reg,
4116 &leaf_regs, 0, 0, &attr, &schpc_p->schpc_slot[slot].
4117 saved_handle[reg]) != DDI_SUCCESS) {
4118 cmn_err(CE_WARN, "Mapin failed\n");
4119 schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL;
4120 return (1);
4121 }
4122
4123 schpc_p->schpc_slot[slot].saved_regs_va[reg] = leaf_regs;
4124 }
4125
4126
4127 /*
4128 * Determine how many entries are in the list so we can
4129 * allocate the save space.
4130 */
4131 list_entry = 0;
4132 save_entry = 0;
4133 while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
4134 save_entry += save_reg_list[list_entry].number;
4135 list_entry++;
4136 }
4137
4138 schpc_p->schpc_slot[slot].saved_size = (save_entry * sizeof (uint64_t));
4139
4140 if (schpc_p->schpc_slot[slot].saved_size == 0)
4141 return (0);
4142
4143 schpc_p->schpc_slot[slot].saved_regs =
4144 (uint64_t *)kmem_zalloc(schpc_p->schpc_slot[slot].saved_size,
4145 KM_SLEEP);
4146
4147 /*
4148 * Walk through the register list and save contents.
4149 */
4150 list_entry = 0;
4151 save_entry = 0;
4152 while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
4153 schpc_save_entry(slot, list_entry, save_entry);
4154 save_entry += save_reg_list[list_entry].number;
4155 list_entry ++;
4156 }
4157
4158 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot);
4159
4160 return (0);
4161 }
4162
4163 static void
schpc_restore_leaf(int slot)4164 schpc_restore_leaf(int slot)
4165 {
4166 int save_entry, list_entry, reg;
4167
4168 if (schpc_p->schpc_slot[slot].saved_regs == NULL)
4169 return;
4170
4171 /*
4172 * Walk through the register list and restore contents.
4173 */
4174 list_entry = 0;
4175 save_entry = 0;
4176 while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
4177
4178 schpc_restore_entry(slot, list_entry, save_entry);
4179
4180 save_entry += save_reg_list[list_entry].number;
4181 list_entry ++;
4182 }
4183
4184 /*
4185 * Free the mapped in registers.
4186 */
4187 for (reg = 0; reg < 3; reg++) {
4188 if (schpc_p->schpc_slot[slot].saved_regs_va[reg]) {
4189
4190 ddi_regs_map_free(
4191 &schpc_p->schpc_slot[slot].saved_handle[reg]);
4192
4193 schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL;
4194 }
4195 }
4196
4197 kmem_free(schpc_p->schpc_slot[slot].saved_regs,
4198 schpc_p->schpc_slot[slot].saved_size);
4199
4200 schpc_p->schpc_slot[slot].saved_size = 0;
4201 schpc_p->schpc_slot[slot].saved_regs = NULL;
4202
4203 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Restored", slot);
4204 }
4205
4206 static void
schpc_save_entry(int slot,int list_entry,int save_entry)4207 schpc_save_entry(int slot, int list_entry, int save_entry)
4208 {
4209 int reg, reads = 0;
4210
4211 reg = save_reg_list[list_entry].reg;
4212
4213 while (reads < save_reg_list[list_entry].number) {
4214 switch (save_reg_list[list_entry].access_size) {
4215 case 8:
4216 schpc_p->schpc_slot[slot].saved_regs[save_entry] =
4217 ddi_get64(
4218 schpc_p->schpc_slot[slot].saved_handle[reg],
4219 (uint64_t *)(schpc_p->schpc_slot[slot].
4220 saved_regs_va[reg]
4221 + save_reg_list[list_entry].offset +
4222 (reads * sizeof (uint64_t))));
4223 #ifdef DEBUG
4224 if (schpc_dump_save_regs)
4225 cmn_err(CE_WARN, "Save 64 %x %lx %lx\n", reg,
4226 save_reg_list[list_entry].offset +
4227 (reads * sizeof (uint64_t)),
4228 schpc_p->schpc_slot[slot].
4229 saved_regs[save_entry]);
4230 #endif
4231
4232 break;
4233 case 4:
4234 schpc_p->schpc_slot[slot].saved_regs[save_entry] =
4235 ddi_get32(
4236 schpc_p->schpc_slot[slot].saved_handle[reg],
4237 (uint32_t *)(schpc_p->schpc_slot[slot].
4238 saved_regs_va[reg]
4239 + save_reg_list[list_entry].offset +
4240 (reads * sizeof (uint32_t))));
4241
4242 #ifdef DEBUG
4243 if (schpc_dump_save_regs)
4244 cmn_err(CE_WARN, "Save 32 %x %lx %lx\n", reg,
4245 save_reg_list[list_entry].offset +
4246 (reads * sizeof (uint32_t)),
4247 schpc_p->schpc_slot[slot].
4248 saved_regs[save_entry]);
4249 #endif
4250
4251 break;
4252 case 2:
4253 schpc_p->schpc_slot[slot].saved_regs[save_entry] =
4254 ddi_get16(
4255 schpc_p->schpc_slot[slot].saved_handle[reg],
4256 (uint16_t *)(schpc_p->schpc_slot[slot].
4257 saved_regs_va[reg]
4258 + save_reg_list[list_entry].offset +
4259 (reads * sizeof (uint16_t))));
4260
4261 #ifdef DEBUG
4262 if (schpc_dump_save_regs)
4263 cmn_err(CE_WARN, "Save 16 %x %lx %lx\n", reg,
4264 save_reg_list[list_entry].offset +
4265 (reads * sizeof (uint16_t)),
4266 schpc_p->schpc_slot[slot].
4267 saved_regs[save_entry]);
4268 #endif
4269
4270 break;
4271 case 1:
4272 schpc_p->schpc_slot[slot].saved_regs[save_entry] =
4273 ddi_get8(
4274 schpc_p->schpc_slot[slot].saved_handle[reg],
4275 (uint8_t *)(schpc_p->schpc_slot[slot].
4276 saved_regs_va[reg]
4277 + save_reg_list[list_entry].offset +
4278 (reads * sizeof (uint8_t))));
4279
4280 #ifdef DEBUG
4281 if (schpc_dump_save_regs)
4282 cmn_err(CE_WARN, "Save 8 %x %lx %lx\n", reg,
4283 save_reg_list[list_entry].offset +
4284 (reads * sizeof (uint8_t)),
4285 schpc_p->schpc_slot[slot].
4286 saved_regs[save_entry]);
4287 #endif
4288
4289 break;
4290 default:
4291 cmn_err(CE_WARN,
4292 "schpc: Illegal List Entry\n");
4293 }
4294 reads++;
4295 save_entry++;
4296 }
4297 }
4298
4299 static void
schpc_restore_entry(int slot,int list_entry,int save_entry)4300 schpc_restore_entry(int slot, int list_entry, int save_entry)
4301 {
4302 int reg, writes = 0;
4303
4304 reg = save_reg_list[list_entry].reg;
4305
4306 while (writes < save_reg_list[list_entry].number) {
4307 switch (save_reg_list[list_entry].access_size) {
4308 case 8:
4309 #ifdef DEBUG
4310 if (schpc_dump_save_regs)
4311 cmn_err(CE_WARN, "Restore 64 %x %lx %lx\n", reg,
4312 save_reg_list[list_entry].offset +
4313 (writes * sizeof (uint64_t)),
4314 schpc_p->schpc_slot[slot].
4315 saved_regs[save_entry]);
4316 #endif
4317
4318 ddi_put64(schpc_p->schpc_slot[slot].saved_handle[reg],
4319 (uint64_t *)(schpc_p->schpc_slot[slot].
4320 saved_regs_va[reg]
4321 + save_reg_list[list_entry].offset +
4322 (writes * sizeof (uint64_t))),
4323 schpc_p->schpc_slot[slot].saved_regs[save_entry]);
4324
4325 break;
4326 case 4:
4327 #ifdef DEBUG
4328 if (schpc_dump_save_regs)
4329 cmn_err(CE_WARN, "Restore 32 %x %lx %lx\n", reg,
4330 save_reg_list[list_entry].offset +
4331 (writes * sizeof (uint32_t)),
4332 schpc_p->schpc_slot[slot].
4333 saved_regs[save_entry]);
4334 #endif
4335
4336 ddi_put32(schpc_p->schpc_slot[slot].saved_handle[reg],
4337 (uint32_t *)(schpc_p->schpc_slot[slot].
4338 saved_regs_va[reg]
4339 + save_reg_list[list_entry].offset +
4340 (writes * sizeof (uint32_t))),
4341 schpc_p->schpc_slot[slot].saved_regs[save_entry]);
4342
4343 break;
4344 case 2:
4345 #ifdef DEBUG
4346 if (schpc_dump_save_regs)
4347 cmn_err(CE_WARN, "Restore 16 %x %lx %lx\n", reg,
4348 save_reg_list[list_entry].offset +
4349 (writes * sizeof (uint16_t)),
4350 schpc_p->schpc_slot[slot].
4351 saved_regs[save_entry]);
4352 #endif
4353
4354 ddi_put16(schpc_p->schpc_slot[slot].saved_handle[reg],
4355 (uint16_t *)(schpc_p->schpc_slot[slot].
4356 saved_regs_va[reg]
4357 + save_reg_list[list_entry].offset +
4358 (writes * sizeof (uint16_t))),
4359 schpc_p->schpc_slot[slot].saved_regs[save_entry]);
4360
4361 break;
4362 case 1:
4363 #ifdef DEBUG
4364 if (schpc_dump_save_regs)
4365 cmn_err(CE_WARN, "Restore 8 %x %lx %lx\n", reg,
4366 save_reg_list[list_entry].offset +
4367 (writes * sizeof (uint8_t)),
4368 schpc_p->schpc_slot[slot].
4369 saved_regs[save_entry]);
4370 #endif
4371
4372 ddi_put8(schpc_p->schpc_slot[slot].saved_handle[reg],
4373 (uint8_t *)(schpc_p->schpc_slot[slot].
4374 saved_regs_va[reg]
4375 + save_reg_list[list_entry].offset +
4376 (writes * sizeof (uint8_t))),
4377 schpc_p->schpc_slot[slot].saved_regs[save_entry]);
4378
4379 break;
4380 default:
4381 cmn_err(CE_WARN,
4382 "schpc: Illegal List Entry\n");
4383 }
4384 writes++;
4385 save_entry++;
4386 }
4387 }
4388
4389 /*
4390 * Returns TRUE if a leaf reset is required to change frequencies/mode.
4391 */
4392 static int
schpc_is_leaf_reset_required(int slot)4393 schpc_is_leaf_reset_required(int slot)
4394 {
4395 char *name;
4396 int32_t mod_rev;
4397
4398 /*
4399 * Only XMITS 3.0 and greater connected slots will require a
4400 * reset to switch frequency and/or mode.
4401 */
4402 name = ddi_binding_name(schpc_p->schpc_slot[slot].devi);
4403
4404 if (strcmp(name, "pci108e,8002") == 0) {
4405 mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY,
4406 schpc_p->schpc_slot[slot].devi,
4407 DDI_PROP_DONTPASS, "module-revision#", 0);
4408
4409 SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev);
4410
4411 /*
4412 * Check for XMITS 3.0 or greater.
4413 */
4414 if (mod_rev >= XMITS_30) {
4415
4416 /*
4417 * The leaf attached to C5V0 (slot 1) should
4418 * not be reset.
4419 */
4420 if ((slot & 3) == 1) {
4421
4422 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset "
4423 "Not Required - C5V0", slot);
4424
4425 return (0);
4426 }
4427
4428 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset "
4429 "Required", slot);
4430
4431 return (1);
4432 }
4433 }
4434 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset NOT Required", slot);
4435
4436 return (0);
4437 }
4438
4439 /*
4440 * Returns TRUE if the bus can change frequencies.
4441 */
4442 static int
schpc_is_freq_switchable(int slot)4443 schpc_is_freq_switchable(int slot)
4444 {
4445 char *name;
4446 int32_t mod_rev;
4447
4448 name = ddi_binding_name(schpc_p->schpc_slot[slot].devi);
4449
4450 if (strcmp(name, "pci108e,8002") == 0) {
4451 mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY,
4452 schpc_p->schpc_slot[slot].devi,
4453 DDI_PROP_DONTPASS, "module-revision#", 0);
4454
4455 SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev);
4456
4457 /*
4458 * We will only report back that XMITS 2.0 (mod_rev = 2)
4459 * or greater will have the ability to switch frequencies.
4460 */
4461 if (mod_rev >= XMITS_20) {
4462 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - "
4463 "Frequency is switchable", slot);
4464 return (1);
4465 }
4466 }
4467
4468 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Frequency is NOT switchable", slot);
4469 return (0);
4470 }
4471
4472 /*
4473 * schpc_slot_freq
4474 *
4475 * Convert the slot frequency setting to integer value.
4476 */
4477 static int
schpc_slot_freq(pci_getslot_t * getslotp)4478 schpc_slot_freq(pci_getslot_t *getslotp)
4479 {
4480 switch (getslotp->slot_freq_setting) {
4481 case PCIMSG_FREQ_33MHZ:
4482 return (SCHPC_33MHZ);
4483 case PCIMSG_FREQ_66MHZ:
4484 return (SCHPC_66MHZ);
4485 case PCIMSG_FREQ_90MHZ:
4486 return (SCHPC_90MHZ);
4487 case PCIMSG_FREQ_133MHZ:
4488 return (SCHPC_133MHZ);
4489 default:
4490 return (0);
4491 }
4492 }
4493
4494 /*
4495 * schpc_find_dip
4496 *
4497 * Used by ddi_walk_devs to find the dip which belongs
4498 * to a certain slot.
4499 *
4500 * When this function returns, the dip is held. It is the
4501 * responsibility of the caller to release the dip.
4502 */
4503 static int
schpc_find_dip(dev_info_t * dip,void * arg)4504 schpc_find_dip(dev_info_t *dip, void *arg)
4505 {
4506 find_dev_t *find_dev = (find_dev_t *)arg;
4507 char *pathname = find_dev->caddr;
4508
4509 (void) ddi_pathname(dip, pathname);
4510 if (strcmp(find_dev->cname, pathname) == 0) {
4511 ndi_hold_devi(dip);
4512 find_dev->dip = dip;
4513 return (DDI_WALK_TERMINATE);
4514 }
4515 return (DDI_WALK_CONTINUE);
4516 }
4517