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 }
2073
2074 if (slotstatus.slot_power_on) {
2075 schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON;
2076
2077 if (!slotstatus.slot_HEALTHY) {
2078 /*
2079 * cPCI Adapter is not asserting HEALTHY#.
2080 */
2081 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2082 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
2083 "PCI adapter not HEALTHY", expander, board,
2084 SCHPC_SLOT_NUM(slot),
2085 schpc_p->schpc_slot[slot].ap_id);
2086
2087 schpc_setslotled(expander, board, slot,
2088 (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
2089
2090 schpc_p->schpc_slot[slot].state &=
2091 ~SCHPC_SLOTSTATE_OCC_GOOD;
2092
2093 return;
2094 }
2095
2096 if (!slotstatus.slot_powergood) {
2097 /*
2098 * PCI Power Input is not good.
2099 */
2100 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2101 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
2102 "System Controller PCI Power Input Not Good",
2103 expander, board, SCHPC_SLOT_NUM(slot),
2104 schpc_p->schpc_slot[slot].ap_id);
2105
2106 schpc_setslotled(expander, board, slot,
2107 (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
2108
2109 schpc_p->schpc_slot[slot].state &=
2110 ~SCHPC_SLOTSTATE_OCC_GOOD;
2111
2112 return;
2113 }
2114
2115 if (slotstatus.slot_powerfault) {
2116 /*
2117 * PCI Power Fault.
2118 */
2119 cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
2120 "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
2121 "System Controller PCI Power Fault",
2122 expander, board, SCHPC_SLOT_NUM(slot),
2123 schpc_p->schpc_slot[slot].ap_id);
2124
2125 schpc_setslotled(expander, board, slot,
2126 (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
2127
2128 schpc_p->schpc_slot[slot].state &=
2129 ~SCHPC_SLOTSTATE_OCC_GOOD;
2130
2131 return;
2132 }
2133 }
2134
2135 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Test Successful - ret 0");
2136
2137 /*
2138 * Is the slot empty?
2139 */
2140 if (slotstatus.slot_empty) {
2141 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Empty");
2142
2143 schpc_p->schpc_slot[slot].state &=
2144 ~SCHPC_SLOTSTATE_PRESENT;
2145
2146 if (slotstatus.slot_power_on) {
2147
2148 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Empty Slot "
2149 "is powered ON");
2150
2151 /*
2152 * Tests will be retried once after powering off
2153 * an empty slot.
2154 */
2155 if (retry) {
2156
2157 /*
2158 * Turn off the slot and restart test.
2159 */
2160 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() "
2161 "Turning Empty Slot OFF");
2162
2163 schpc_init_setslot_message(&setslot);
2164 setslot.slot_power_off = PCIMSG_ON;
2165 (void) schpc_setslotstatus(
2166 expander, board, slot, &setslot);
2167
2168 retry = 0;
2169
2170 goto restart_test;
2171 }
2172 }
2173 } else {
2174 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Adapter Present");
2175
2176 if (!slotstatus.slot_power_on) {
2177 if (retry) {
2178 /*
2179 * If there is a cassette present and the
2180 * power is off, try turning the power on and
2181 * restart the test. This allows access to
2182 * the FRUID when an empty cassette is
2183 * installed.
2184 */
2185 SCHPC_DEBUG0(D_IOC_TEST,
2186 "schpc_test() Power On Adapter");
2187 schpc_init_setslot_message(&setslot);
2188 setslot.slot_power_on = PCIMSG_ON;
2189 (void) schpc_setslotstatus(
2190 expander, board, slot, &setslot);
2191 retry = 0;
2192 goto restart_test;
2193 }
2194 }
2195
2196 schpc_p->schpc_slot[slot].state |=
2197 SCHPC_SLOTSTATE_PRESENT;
2198 }
2199
2200 /*
2201 * Is the slot powered up?
2202 */
2203 schpc_init_setslot_message(&setslot);
2204
2205 if (slotstatus.slot_power_on) {
2206 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power On");
2207
2208 schpc_p->schpc_slot[slot].state |=
2209 SCHPC_SLOTSTATE_CONNECTED;
2210
2211 setslot.slot_led_power = PCIMSG_LED_ON;
2212 setslot.slot_led_service = PCIMSG_LED_OFF;
2213 setslot.slot_enable_ENUM = PCIMSG_ON;
2214 setslot.slot_enable_HEALTHY = PCIMSG_ON;
2215 } else {
2216 SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power Off");
2217
2218 schpc_p->schpc_slot[slot].state &=
2219 ~SCHPC_SLOTSTATE_CONNECTED;
2220
2221 setslot.slot_led_power = PCIMSG_LED_OFF;
2222 setslot.slot_led_service = PCIMSG_LED_ON;
2223 setslot.slot_disable_ENUM = PCIMSG_ON;
2224 setslot.slot_disable_HEALTHY = PCIMSG_ON;
2225 }
2226
2227 setslot.slot_led_fault = PCIMSG_LED_OFF;
2228
2229 (void) schpc_setslotstatus(expander, board, slot, &setslot);
2230
2231 /*
2232 * Save LED State.
2233 */
2234 switch (setslot.slot_led_power) {
2235 case PCIMSG_LED_ON:
2236 schpc_p->schpc_slot[slot].led.led_power = LED_ON;
2237 break;
2238 case PCIMSG_LED_OFF:
2239 schpc_p->schpc_slot[slot].led.led_power = LED_OFF;
2240 break;
2241 case PCIMSG_LED_FLASH:
2242 schpc_p->schpc_slot[slot].led.led_power = LED_FLASH;
2243 break;
2244 }
2245 switch (setslot.slot_led_service) {
2246 case PCIMSG_LED_ON:
2247 schpc_p->schpc_slot[slot].led.led_service = LED_ON;
2248 break;
2249 case PCIMSG_LED_OFF:
2250 schpc_p->schpc_slot[slot].led.led_service = LED_OFF;
2251 break;
2252 case PCIMSG_LED_FLASH:
2253 schpc_p->schpc_slot[slot].led.led_service = LED_FLASH;
2254 break;
2255 }
2256 switch (setslot.slot_led_fault) {
2257 case PCIMSG_LED_ON:
2258 schpc_p->schpc_slot[slot].led.led_fault = LED_ON;
2259 break;
2260 case PCIMSG_LED_OFF:
2261 schpc_p->schpc_slot[slot].led.led_fault = LED_OFF;
2262 break;
2263 case PCIMSG_LED_FLASH:
2264 schpc_p->schpc_slot[slot].led.led_fault = LED_FLASH;
2265 break;
2266 }
2267 }
2268
2269
2270 /*
2271 * schpc_event_handler
2272 *
2273 * Placed on the schpc_event_taskq by schpc_event_filter when an
2274 * unsolicited MBOXSC_MSG_EVENT is received from the SC. It handles
2275 * things like power insertion/removal, ENUM#, etc.
2276 */
2277 static void
schpc_event_handler(void * arg)2278 schpc_event_handler(void *arg)
2279 {
2280 pci_getslot_t slotstatus;
2281 uint8_t expander, board, slot;
2282 int rval;
2283 pcimsg_t *event = (pcimsg_t *)arg;
2284
2285 /*
2286 * OK, we got an event message. Since the event message only tells
2287 * us something has changed and not changed to what, we need to get
2288 * the current slot status to find how WHAT was change to WHAT.
2289 */
2290
2291 slot = event->pcimsg_slot;
2292 expander = event->pcimsg_node; /* get expander */
2293 board = event->pcimsg_board; /* get board */
2294
2295 SCHPC_DEBUG3(D_EVENT,
2296 "schpc_event_handler() - exp=%d board=%d slot=%d",
2297 expander, board, slot);
2298
2299 /* create a slot table index */
2300 slot = SCHPC_MAKE_SLOT_INDEX2(expander, slot);
2301
2302 SCHPC_DEBUG1(D_EVENT,
2303 "schpc_event_handler() - expanded slot %d", slot);
2304
2305 if (schpc_p == NULL) {
2306 cmn_err(CE_WARN, "schpc/Event Handler - Can not find schpc");
2307 kmem_free(event, sizeof (pcimsg_t));
2308 return;
2309 }
2310
2311 mutex_enter(&schpc_p->schpc_mutex);
2312
2313 if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
2314 SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - HPC Not Inited");
2315 mutex_exit(&schpc_p->schpc_mutex);
2316 kmem_free(event, sizeof (pcimsg_t));
2317 return;
2318 }
2319 /*
2320 * Block if another thread is executing a HPC command.
2321 */
2322 while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
2323 SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - Slot is busy");
2324 cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
2325 }
2326
2327 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
2328
2329 mutex_exit(&schpc_p->schpc_mutex);
2330
2331 rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
2332
2333 if (rval) {
2334 cmn_err(CE_WARN, "schpc/Event Handler - Can not get status "
2335 "for expander=%d board=%d slot=%d\n",
2336 expander, board, SCHPC_SLOT_NUM(slot));
2337
2338 mutex_enter(&schpc_p->schpc_mutex);
2339 schpc_p->schpc_slot[slot].state &=
2340 ~SCHPC_SLOTSTATE_EXECUTING;
2341 cv_signal(&schpc_p->schpc_cv);
2342 mutex_exit(&schpc_p->schpc_mutex);
2343 kmem_free(event, sizeof (pcimsg_t));
2344 return;
2345 }
2346
2347 if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
2348 cmn_err(CE_WARN, "schpc/Event Handler - Can not get good "
2349 "status for expander=%d board=%d slot=%d\n",
2350 expander, board, SCHPC_SLOT_NUM(slot));
2351
2352 mutex_enter(&schpc_p->schpc_mutex);
2353 schpc_p->schpc_slot[slot].state &=
2354 ~SCHPC_SLOTSTATE_EXECUTING;
2355 cv_signal(&schpc_p->schpc_cv);
2356 mutex_exit(&schpc_p->schpc_mutex);
2357
2358 kmem_free(event, sizeof (pcimsg_t));
2359 return;
2360 }
2361
2362 SCHPC_DEBUG3(D_EVENT, "Event Received - Expander %d Board %d Slot %d",
2363 expander, board, SCHPC_SLOT_NUM(slot));
2364
2365 if (schpc_p->schpc_slot[slot].slot_ops == NULL) {
2366 SCHPC_DEBUG3(D_EVENT, "schpc/Event Handler - Received event "
2367 "for unregistered slot for expander=%d board=%d slot=%d",
2368 expander, board, SCHPC_SLOT_NUM(slot));
2369
2370 mutex_enter(&schpc_p->schpc_mutex);
2371 schpc_p->schpc_slot[slot].state &=
2372 ~SCHPC_SLOTSTATE_EXECUTING;
2373 cv_signal(&schpc_p->schpc_cv);
2374 mutex_exit(&schpc_p->schpc_mutex);
2375
2376 kmem_free(event, sizeof (pcimsg_t));
2377 return;
2378 }
2379
2380 /* Slot Power Event */
2381
2382 if (event->pcimsg_type.pcimsg_slotevent.slot_power) {
2383 SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Event");
2384 /*
2385 * The SC may have changed to slot power status.
2386 */
2387 if (slotstatus.slot_power_on) {
2388 schpc_p->schpc_slot[slot].state |=
2389 SCHPC_SLOTSTATE_CONNECTED;
2390
2391 (void) hpc_slot_event_notify(
2392 schpc_p->schpc_slot[slot].slot_handle,
2393 HPC_EVENT_SLOT_POWER_ON, 0);
2394 } else {
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_OFF, 0);
2401 }
2402 }
2403
2404 /* Adapter Insertion/Removal Event */
2405
2406 if (event->pcimsg_type.pcimsg_slotevent.slot_presence) {
2407 if (slotstatus.slot_empty == PCIMSG_ON) {
2408
2409 /* Adapter Removed */
2410
2411 SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Removed");
2412
2413 if (schpc_p->schpc_slot[slot].state &
2414 SCHPC_SLOTSTATE_CONNECTED) {
2415 /*
2416 * If the adapter has been removed while
2417 * there the slot is connected, it could be
2418 * due to a ENUM handling.
2419 */
2420 cmn_err(CE_WARN, "Card removed from "
2421 "powered on slot at "
2422 "expander=%d board=%d slot=%d\n",
2423 expander, board, SCHPC_SLOT_NUM(slot));
2424
2425 schpc_p->schpc_slot[slot].state &=
2426 ~SCHPC_SLOTSTATE_EXECUTING;
2427 rval = schpc_disconnect((caddr_t)schpc_p,
2428 schpc_p->schpc_slot[slot].slot_handle,
2429 0, 0);
2430 mutex_enter(&schpc_p->schpc_mutex);
2431 while (schpc_p->schpc_slot[slot].state &
2432 SCHPC_SLOTSTATE_EXECUTING) {
2433 SCHPC_DEBUG0(D_EVENT,
2434 "schpc_event_handler - "
2435 "Slot is busy");
2436 cv_wait(&schpc_p->schpc_cv,
2437 &schpc_p->schpc_mutex);
2438 }
2439
2440 schpc_p->schpc_slot[slot].state |=
2441 SCHPC_SLOTSTATE_EXECUTING;
2442
2443 mutex_exit(&schpc_p->schpc_mutex);
2444 }
2445 schpc_p->schpc_slot[slot].state |=
2446 SCHPC_SLOTSTATE_OCC_GOOD;
2447
2448 schpc_p->schpc_slot[slot].state &=
2449 ~SCHPC_SLOTSTATE_PRESENT;
2450
2451 (void) hpc_slot_event_notify(
2452 schpc_p->schpc_slot[slot].slot_handle,
2453 HPC_EVENT_SLOT_REMOVAL, 0);
2454 } else {
2455
2456 /* Adapter Inserted */
2457
2458 SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Inserted");
2459
2460 if (schpc_p->schpc_slot[slot].state &
2461 SCHPC_SLOTSTATE_PRESENT) {
2462 /*
2463 * If the adapter is already present
2464 * throw the this event away.
2465 */
2466
2467 SCHPC_DEBUG0(D_EVENT,
2468 "Adapter is already present");
2469
2470 mutex_enter(&schpc_p->schpc_mutex);
2471 schpc_p->schpc_slot[slot].state &=
2472 ~SCHPC_SLOTSTATE_EXECUTING;
2473 cv_signal(&schpc_p->schpc_cv);
2474 mutex_exit(&schpc_p->schpc_mutex);
2475
2476 kmem_free(event, sizeof (pcimsg_t));
2477 return;
2478 }
2479
2480 schpc_p->schpc_slot[slot].state |=
2481 SCHPC_SLOTSTATE_PRESENT;
2482
2483 schpc_p->schpc_slot[slot].state &=
2484 ~SCHPC_SLOTSTATE_CONNECTED;
2485
2486 (void) hpc_slot_event_notify(
2487 schpc_p->schpc_slot[slot].slot_handle,
2488 HPC_EVENT_SLOT_INSERTION, 0);
2489
2490 if (schpc_p->schpc_slot[slot].state &
2491 SCHPC_SLOTSTATE_AUTOCFG_ENABLE) {
2492 SCHPC_DEBUG0(D_EVENT, "Auto Configuration "
2493 "(Connect/Configure) Started");
2494
2495 schpc_p->schpc_slot[slot].state &=
2496 ~SCHPC_SLOTSTATE_EXECUTING;
2497
2498 rval = schpc_connect((caddr_t)schpc_p,
2499 schpc_p->schpc_slot[slot].slot_handle,
2500 0, 0);
2501
2502 if (rval) {
2503 cmn_err(CE_WARN, "schpc/Event Handler -"
2504 " Can not connect");
2505
2506 mutex_enter(&schpc_p->schpc_mutex);
2507 schpc_p->schpc_slot[slot].state &=
2508 ~SCHPC_SLOTSTATE_EXECUTING;
2509 cv_signal(&schpc_p->schpc_cv);
2510 mutex_exit(&schpc_p->schpc_mutex);
2511
2512 kmem_free(event, sizeof (pcimsg_t));
2513 return;
2514 }
2515 mutex_enter(&schpc_p->schpc_mutex);
2516 while (schpc_p->schpc_slot[slot].state &
2517 SCHPC_SLOTSTATE_EXECUTING) {
2518 SCHPC_DEBUG0(D_EVENT,
2519 "schpc_event_handler - "
2520 "Slot is busy");
2521 cv_wait(&schpc_p->schpc_cv,
2522 &schpc_p->schpc_mutex);
2523 }
2524
2525 schpc_p->schpc_slot[slot].state |=
2526 SCHPC_SLOTSTATE_EXECUTING;
2527
2528 mutex_exit(&schpc_p->schpc_mutex);
2529
2530 (void) hpc_slot_event_notify(
2531 schpc_p->schpc_slot[slot].slot_handle,
2532 HPC_EVENT_SLOT_CONFIGURE, 0);
2533 } else {
2534 schpc_setslotled(expander, board, slot,
2535 SERVICE_LED_ON);
2536 }
2537 }
2538 }
2539
2540 /* ENUM# signal change event */
2541
2542 if (event->pcimsg_type.pcimsg_slotevent.slot_ENUM) {
2543 /*
2544 * ENUM should only be received to the adapter remove
2545 * procedure.
2546 */
2547
2548 SCHPC_DEBUG0(D_EVENT, "Event Type: ENUM Asserted");
2549
2550 schpc_setslotled(expander, board, slot, FAULT_LED_FLASH);
2551
2552 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_ENUM;
2553
2554 (void) hpc_slot_event_notify(
2555 schpc_p->schpc_slot[slot].slot_handle,
2556 HPC_EVENT_SLOT_ENUM, 0);
2557 }
2558
2559 /* HEALTHY# signal change event */
2560
2561 if (event->pcimsg_type.pcimsg_slotevent.slot_HEALTHY) {
2562
2563 if (!slotstatus.slot_HEALTHY) {
2564
2565 SCHPC_DEBUG0(D_EVENT, "Event Type: !HEALTHY ASSERTED");
2566
2567 schpc_p->schpc_slot[slot].state &=
2568 ~SCHPC_SLOTSTATE_OCC_GOOD;
2569
2570 (void) hpc_slot_event_notify(
2571 schpc_p->schpc_slot[slot].slot_handle,
2572 HPC_EVENT_SLOT_NOT_HEALTHY, 0);
2573
2574 schpc_setslotled(expander, board, slot, FAULT_LED_ON);
2575 } else {
2576 SCHPC_DEBUG0(D_EVENT, "Event Type: HEALTHY OK");
2577
2578 schpc_p->schpc_slot[slot].state |=
2579 SCHPC_SLOTSTATE_OCC_GOOD;
2580
2581 (void) hpc_slot_event_notify(
2582 schpc_p->schpc_slot[slot].slot_handle,
2583 HPC_EVENT_SLOT_HEALTHY_OK, 0);
2584
2585 schpc_setslotled(expander, board, slot,
2586 FAULT_LED_OFF);
2587 }
2588 }
2589
2590 /* Good Power change event */
2591
2592 if (event->pcimsg_type.pcimsg_slotevent.slot_powergood) {
2593 if (slotstatus.slot_powergood == PCIMSG_ON) {
2594
2595 SCHPC_DEBUG0(D_EVENT,
2596 "Event Type: Slot Power Good Detected");
2597
2598 schpc_p->schpc_slot[slot].state |=
2599 SCHPC_SLOTSTATE_OCC_GOOD;
2600
2601 (void) hpc_slot_event_notify(
2602 schpc_p->schpc_slot[slot].slot_handle,
2603 HPC_EVENT_SLOT_HEALTHY_OK, 0);
2604
2605 schpc_setslotled(expander, board, slot,
2606 FAULT_LED_OFF);
2607 } else {
2608 SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Not Good "
2609 "Detected");
2610
2611 if (schpc_p->schpc_slot[slot].state &
2612 SCHPC_SLOTSTATE_CONNECTED) {
2613
2614 SCHPC_DEBUG0(D_EVENT, "Slot Power Not Good: "
2615 "power failed");
2616
2617 schpc_p->schpc_slot[slot].state &=
2618 ~SCHPC_SLOTSTATE_OCC_GOOD;
2619
2620 (void) hpc_slot_event_notify(
2621 schpc_p->schpc_slot[slot].slot_handle,
2622 HPC_EVENT_SLOT_NOT_HEALTHY, 0);
2623
2624 schpc_setslotled(expander, board, slot,
2625 FAULT_LED_ON);
2626 }
2627 }
2628 }
2629
2630 /* Power Fault change event */
2631
2632 if (event->pcimsg_type.pcimsg_slotevent.slot_powerfault) {
2633 if (slotstatus.slot_powerfault == PCIMSG_ON) {
2634
2635 SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault "
2636 "Detected");
2637
2638 schpc_p->schpc_slot[slot].state &=
2639 ~SCHPC_SLOTSTATE_OCC_GOOD;
2640
2641 (void) hpc_slot_event_notify(
2642 schpc_p->schpc_slot[slot].slot_handle,
2643 HPC_EVENT_SLOT_NOT_HEALTHY, 0);
2644
2645 schpc_setslotled(expander, board, slot, FAULT_LED_ON);
2646 } else {
2647 SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault "
2648 "Cleared");
2649
2650 schpc_p->schpc_slot[slot].state |=
2651 SCHPC_SLOTSTATE_OCC_GOOD;
2652
2653 (void) hpc_slot_event_notify(
2654 schpc_p->schpc_slot[slot].slot_handle,
2655 HPC_EVENT_SLOT_HEALTHY_OK, 0);
2656
2657 schpc_setslotled(expander, board, slot,
2658 FAULT_LED_OFF);
2659 }
2660 }
2661 mutex_enter(&schpc_p->schpc_mutex);
2662 schpc_p->schpc_slot[slot].state &=
2663 ~SCHPC_SLOTSTATE_EXECUTING;
2664 cv_signal(&schpc_p->schpc_cv);
2665 mutex_exit(&schpc_p->schpc_mutex);
2666
2667 kmem_free(event, sizeof (pcimsg_t));
2668 }
2669
2670
2671 /*
2672 * schpc_event_filter
2673 *
2674 * The schpc_event_filter enqueues MBOXSC_MSG_EVENTs into the
2675 * schpc_event_taskq for processing by the schpc_event_handler _if_
2676 * hotpluggable pci slots have been registered; otherwise, the
2677 * MBOXSC_MSG_EVENTs are discarded in order to keep the incoming mailbox
2678 * open for future messages.
2679 */
2680 static void
schpc_event_filter(pcimsg_t * pmsg)2681 schpc_event_filter(pcimsg_t *pmsg)
2682 {
2683 if (slots_registered == B_TRUE) {
2684
2685 pcimsg_t *pevent;
2686
2687 /*
2688 * If hotpluggable pci slots have been registered then enqueue
2689 * the event onto the schpc_event_taskq for processing.
2690 */
2691
2692 SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
2693 "slots_registered = B_TRUE");
2694
2695 pevent = (pcimsg_t *)kmem_zalloc(sizeof (pcimsg_t), KM_SLEEP);
2696 bcopy(pmsg, pevent, sizeof (pcimsg_t));
2697
2698 SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
2699 "event alloc'd");
2700
2701 if (taskq_dispatch(schpc_event_taskq, schpc_event_handler,
2702 (void *)pevent, TQ_SLEEP) == NULL) {
2703 cmn_err(CE_WARN, "schpc: schpc_event_filter - "
2704 "taskq_dispatch failed to enqueue event");
2705 kmem_free(pevent, sizeof (pcimsg_t));
2706 return;
2707 }
2708
2709 SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
2710 "event was taskq_dispatch'ed to schpc_event_handler");
2711 } else {
2712 /*
2713 * Oops, schpc received an event _before_ the slots have been
2714 * registered. In that case there is no choice but to toss
2715 * the event.
2716 */
2717 cmn_err(CE_WARN, "schpc: schpc_event_filter - discarding "
2718 "premature event");
2719 }
2720 }
2721
2722
2723 /*
2724 * schpc_msg_thread
2725 * A stand-alone thread that monitors the incoming mailbox for
2726 * MBOXSC_MSG_REPLYs and MBOXSC_MSG_EVENTs, and removes them from
2727 * the mailbox for processing.
2728 *
2729 * MBOXSC_MSG_REPLYs are matched against outstanding REPLYs in the
2730 * schpc_replylist, and the waiting thread is notified that its REPLY
2731 * message has arrived; otherwise, if no REPLY match is found, then it is
2732 * discarded.
2733 *
2734 * MBOXSC_MSG_EVENTs are enqueued into the schpc_event_taskq and processed
2735 * by the schpc_event_handler.
2736 *
2737 * The schpc_msg_thread is started in _init().
2738 */
2739 void
schpc_msg_thread(void)2740 schpc_msg_thread(void)
2741 {
2742 int err;
2743 uint32_t type;
2744 uint32_t cmd;
2745 uint64_t transid;
2746 uint32_t length;
2747 pcimsg_t msg;
2748
2749 SCHPC_DEBUG0(D_THREAD, "schpc_msg_thread() running");
2750
2751 /* CONSTCOND */
2752 while (1) {
2753
2754 /* setup wildcard arguments */
2755 type = 0;
2756 cmd = 0;
2757 transid = 0;
2758 length = sizeof (pcimsg_t);
2759 bzero(&msg, sizeof (pcimsg_t));
2760
2761 err = mboxsc_getmsg(KEY_SCPC, &type, &cmd,
2762 &transid, &length, (void *)&msg,
2763 schpc_timeout_getmsg);
2764
2765 if (err) {
2766 switch (err) {
2767
2768 /*FALLTHROUGH*/
2769 case ETIMEDOUT:
2770 case EAGAIN:
2771 continue;
2772
2773 default:
2774 /*
2775 * unfortunately, we can't do very much here
2776 * because we're wildcarding mboxsc_getmsg
2777 * so if it encounters an error, we can't
2778 * identify which transid it belongs to.
2779 */
2780 cmn_err(CE_WARN,
2781 "schpc - mboxsc_getmsg failed, err=0x%x", err);
2782 delay(drv_usectohz(100000));
2783 continue;
2784 }
2785 }
2786
2787 if (msg.pcimsg_revision != PCIMSG_REVISION) {
2788 /*
2789 * This version of the schpc driver only understands
2790 * version 1.0 of the PCI Hot Plug Message format.
2791 */
2792 cmn_err(CE_WARN, " schpc: schpc_msg_thread - "
2793 "discarding event w/ unknown message version %x",
2794 msg.pcimsg_revision);
2795 continue;
2796 }
2797
2798 switch (type) {
2799
2800 case MBOXSC_MSG_EVENT:
2801 schpc_event_filter(&msg);
2802 break;
2803
2804 case MBOXSC_MSG_REPLY:
2805 schpc_reply_handler(&msg, type, cmd, transid, length);
2806 break;
2807
2808 default:
2809 cmn_err(CE_WARN,
2810 "schpc - mboxsc_getmsg unknown msg"
2811 " type=0x%x", type);
2812 break;
2813 }
2814 }
2815 /* this thread never exits */
2816 }
2817
2818
2819 void
schpc_reply_handler(pcimsg_t * pmsg,uint32_t type,uint32_t cmd,uint64_t transid,uint32_t length)2820 schpc_reply_handler(pcimsg_t *pmsg, uint32_t type, uint32_t cmd,
2821 uint64_t transid, uint32_t length)
2822 {
2823 schpc_replylist_t *entry;
2824
2825 mutex_enter(&schpc_replylist_mutex);
2826 entry = schpc_replylist_first;
2827 while (entry != NULL) {
2828 if (entry->transid == transid) {
2829 break;
2830 } else
2831 entry = entry->next;
2832 }
2833 if (entry) {
2834 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2835 "schpc_reply_handler() - 0x%lx transid reply "
2836 "received", transid);
2837
2838 mutex_enter(&entry->reply_lock);
2839 if (entry->reply_cexit == B_FALSE) {
2840 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2841 "schpc_reply_handler() - 0x%lx transid"
2842 " cv_signal waiting thread", transid);
2843
2844 /*
2845 * emulate mboxsc_getmsg by copying the reply
2846 */
2847 entry->type = type;
2848 entry->cmd = cmd;
2849 entry->transid = transid;
2850 entry->length = length;
2851 bcopy((caddr_t)pmsg, &entry->reply, length);
2852
2853 /* reply was received */
2854 entry->reply_recvd = B_TRUE;
2855
2856 /*
2857 * wake up thread waiting for reply with transid
2858 */
2859 cv_signal(&entry->reply_cv);
2860 }
2861 mutex_exit(&entry->reply_lock);
2862 } else {
2863 cmn_err(CE_WARN, "schpc - no match for transid 0x%lx",
2864 transid);
2865 }
2866 mutex_exit(&schpc_replylist_mutex);
2867 }
2868
2869
2870 /*
2871 * schpc_putrequest
2872 *
2873 * A wrapper around the synchronous call mboxsc_putmsg().
2874 */
2875 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)2876 schpc_putrequest(uint32_t key, uint32_t type, uint32_t cmd, uint64_t *transidp,
2877 uint32_t length, void *datap, clock_t timeout,
2878 schpc_replylist_t **entryp)
2879 {
2880 int rval;
2881
2882 /* add the request to replylist to keep track of outstanding requests */
2883 *entryp = schpc_replylist_link(cmd, *transidp, length);
2884
2885 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - "
2886 "0x%lx transid mboxsc_putmsg called", *transidp);
2887
2888 /* wait synchronously for request to be sent */
2889 rval = mboxsc_putmsg(key, type, cmd, transidp, length,
2890 (void *)datap, timeout);
2891
2892 SCHPC_DEBUG2(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - "
2893 "0x%lx transid mboxsc_putmsg returned 0x%x", *transidp, rval);
2894
2895 /* if problem is encountered then remove the request from replylist */
2896 if (rval)
2897 schpc_replylist_unlink(*entryp);
2898
2899 return (rval);
2900 }
2901
2902
2903 /*
2904 * schpc_getreply
2905 *
2906 * Wait for the schpc_msg_thread to respond that a matching reply has
2907 * arrived; otherwise, timeout and remove the entry from the schpc_replylist.
2908 */
2909 /*ARGSUSED*/
2910 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)2911 schpc_getreply(uint32_t key, uint32_t *typep, uint32_t *cmdp,
2912 uint64_t *transidp, uint32_t *lengthp, void *datap,
2913 clock_t timeout, schpc_replylist_t *listp)
2914 {
2915 int rc = 0;
2916
2917 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2918 "schpc_getreply() - 0x%lx transid waiting for reply",
2919 *transidp);
2920
2921 /*
2922 * wait here until schpc_msg_thread because it's always
2923 * looking for reply messages
2924 */
2925 mutex_enter(&listp->reply_lock);
2926
2927 while (listp->reply_recvd == B_FALSE) {
2928 /*
2929 * wait for reply or timeout
2930 */
2931 rc = cv_timedwait(&listp->reply_cv, &listp->reply_lock,
2932 ddi_get_lbolt() + drv_usectohz(timeout * 1000));
2933 switch (rc) {
2934 case -1: /* most likely a timeout, but check anyway */
2935
2936 /* message was received after all */
2937 if (listp->reply_recvd == B_TRUE)
2938 break;
2939
2940 /* no, it's really a timeout */
2941 listp->reply_cexit = B_TRUE;
2942 mutex_exit(&listp->reply_lock);
2943 cmn_err(CE_WARN,
2944 "schpc - 0x%lx transid reply timed out", *transidp);
2945 schpc_replylist_unlink(listp);
2946 return (ETIMEDOUT);
2947
2948 default:
2949 break;
2950 }
2951 }
2952
2953 *typep = listp->type;
2954 *cmdp = listp->cmd;
2955 *transidp = listp->transid;
2956 *lengthp = listp->length;
2957 bcopy((caddr_t)&listp->reply, datap, *lengthp);
2958 mutex_exit(&listp->reply_lock);
2959 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2960 "schpc_getreply() - 0x%lx transid received", *transidp);
2961 schpc_replylist_unlink(listp);
2962 return (0);
2963 }
2964
2965
2966 /*
2967 * schpc_replylist_unlink
2968 *
2969 * Deallocate a schpc_replylist_t element.
2970 */
2971 void
schpc_replylist_unlink(schpc_replylist_t * entry)2972 schpc_replylist_unlink(schpc_replylist_t *entry)
2973 {
2974 #if DEBUG
2975 schpc_replylist_t *dbg_entry;
2976 #endif /* DEBUG */
2977
2978 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
2979 "schpc_replylist_unlink() - 0x%lx transid deleted from replylist",
2980 entry->transid);
2981
2982 mutex_enter(&schpc_replylist_mutex);
2983 if (entry->prev) {
2984 entry->prev->next = entry->next;
2985 if (entry->next)
2986 entry->next->prev = entry->prev;
2987 } else {
2988 schpc_replylist_first = entry->next;
2989 if (entry->next)
2990 entry->next->prev = NULL;
2991 }
2992 if (entry == schpc_replylist_last) {
2993 schpc_replylist_last = entry->prev;
2994 }
2995 kmem_free(entry, sizeof (schpc_replylist_t));
2996 schpc_replylist_count--;
2997
2998 #if DEBUG
2999 if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) {
3000 dbg_entry = schpc_replylist_first;
3001 cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - replylist "
3002 "count = %d\n", schpc_replylist_count);
3003 while (dbg_entry != NULL) {
3004 cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - "
3005 "0x%lx transid\n", dbg_entry->transid);
3006 dbg_entry = dbg_entry->next;
3007 }
3008 }
3009 #endif /* DEBUG */
3010
3011 mutex_exit(&schpc_replylist_mutex);
3012 }
3013
3014
3015 /*
3016 * schpc_replylist_link
3017 *
3018 * Allocate and initialize a schpc_replylist_t element.
3019 */
3020 schpc_replylist_t *
schpc_replylist_link(uint32_t cmd,uint64_t transid,uint32_t length)3021 schpc_replylist_link(uint32_t cmd, uint64_t transid, uint32_t length)
3022 {
3023 schpc_replylist_t *entry;
3024 #if DEBUG
3025 schpc_replylist_t *dbg_entry;
3026 #endif /* DEBUG */
3027
3028 SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
3029 "schpc_replylist_link() - 0x%lx transid inserting into replylist",
3030 transid);
3031
3032 entry = kmem_zalloc(sizeof (schpc_replylist_t), KM_SLEEP);
3033 mutex_init(&entry->reply_lock, NULL, MUTEX_DRIVER, NULL);
3034 cv_init(&entry->reply_cv, NULL, CV_DRIVER, NULL);
3035 entry->type = MBOXSC_MSG_REPLY;
3036 entry->cmd = cmd;
3037 entry->transid = transid;
3038 entry->length = length;
3039 entry->reply_recvd = B_FALSE;
3040 entry->reply_cexit = B_FALSE;
3041
3042 mutex_enter(&schpc_replylist_mutex);
3043 if (schpc_replylist_last) {
3044 entry->prev = schpc_replylist_last;
3045 schpc_replylist_last->next = entry;
3046 schpc_replylist_last = entry;
3047 } else {
3048 schpc_replylist_last = schpc_replylist_first = entry;
3049 }
3050
3051 schpc_replylist_count++;
3052
3053 #if DEBUG
3054 if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) {
3055 dbg_entry = schpc_replylist_first;
3056 cmn_err(CE_CONT, "schpc: schpc_replylist_link() - replylist "
3057 "count = %d\n", schpc_replylist_count);
3058 while (dbg_entry != NULL) {
3059 cmn_err(CE_CONT, "schpc: schpc_replylist_link() - "
3060 "0x%lx transid\n", dbg_entry->transid);
3061 dbg_entry = dbg_entry->next;
3062 }
3063 }
3064 #endif /* DEBUG */
3065
3066 mutex_exit(&schpc_replylist_mutex);
3067
3068 return (entry);
3069 }
3070
3071
3072 /*
3073 * schpc_getslotstatus
3074 *
3075 * Issues a Get Slot Status command to the System Controller
3076 * for a specific slot.
3077 */
3078 static int
schpc_getslotstatus(uint32_t expander,uint32_t board,uint32_t slot,pci_getslot_t * slotstatus)3079 schpc_getslotstatus(uint32_t expander, uint32_t board, uint32_t slot,
3080 pci_getslot_t *slotstatus)
3081 {
3082 pcimsg_t request;
3083 pcimsg_t reply;
3084 int rval;
3085 uint32_t type, cmd, length;
3086 uint64_t transid;
3087 schpc_replylist_t *entry;
3088
3089 SCHPC_DEBUG4(D_GETSLOTSTATUS,
3090 "schpc_getslotstatus(expander=%d board=%d "
3091 "slot=%d slotstatus=0x%p", expander, board,
3092 SCHPC_SLOT_NUM(slot), (void *)slotstatus);
3093
3094 if (schpc_p == NULL) {
3095 return (1);
3096 }
3097
3098 bzero(&request, sizeof (pcimsg_t));
3099
3100 request.pcimsg_node = expander;
3101 request.pcimsg_board = board;
3102 request.pcimsg_slot = SCHPC_SLOT_NUM(slot);
3103 request.pcimsg_revision = PCIMSG_REVISION;
3104 request.pcimsg_command = PCIMSG_GETSLOTSTATUS;
3105
3106 type = MBOXSC_MSG_REQUEST;
3107 cmd = PCIMSG_GETSLOTSTATUS;
3108 transid = schpc_gettransid(schpc_p, slot);
3109 length = sizeof (pcimsg_t);
3110
3111 SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
3112 "0x%lx transid schpc_putrequest called", transid);
3113
3114 rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length,
3115 (void *)&request, schpc_timeout_putmsg, &entry);
3116
3117 SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
3118 "0x%lx transid schpc_putrequest returned 0x%x", transid, rval);
3119
3120 if (rval) {
3121 return (rval);
3122 }
3123
3124 bzero(&reply, sizeof (pcimsg_t));
3125 type = MBOXSC_MSG_REPLY;
3126
3127 SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
3128 "0x%lx transid schpc_getreply called", transid);
3129
3130 rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length,
3131 (void *)&reply, schpc_timeout_getmsg, entry);
3132
3133 SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
3134 "0x%lx transid schpc_getreply returned 0x%x", transid, rval);
3135
3136 if (rval == 0) {
3137 *slotstatus = reply.pcimsg_type.pcimsg_getslot;
3138
3139 SCHPC_DEBUG0(D_GETSLOTSTATUS, "schpc_getslotstatus()");
3140 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_power_on %x",
3141 reply.pcimsg_type.pcimsg_getslot.slot_power_on);
3142 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_powergood %x",
3143 reply.pcimsg_type.pcimsg_getslot.slot_powergood);
3144 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_powerfault %x",
3145 reply.pcimsg_type.pcimsg_getslot.slot_powerfault);
3146 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_empty %x",
3147 reply.pcimsg_type.pcimsg_getslot.slot_empty);
3148 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_freq_cap %x",
3149 reply.pcimsg_type.pcimsg_getslot.slot_freq_cap);
3150 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_freq_setting %x",
3151 reply.pcimsg_type.pcimsg_getslot.slot_freq_setting);
3152 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_condition %x",
3153 reply.pcimsg_type.pcimsg_getslot.slot_condition);
3154 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_HEALTHY %x",
3155 reply.pcimsg_type.pcimsg_getslot.slot_HEALTHY);
3156 SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_ENUM %x",
3157 reply.pcimsg_type.pcimsg_getslot.slot_ENUM);
3158 }
3159
3160 return (rval);
3161 }
3162
3163
3164 /*
3165 * schpc_setslotstatus
3166 *
3167 * Issues a Set Slot Status command to the System Controller
3168 * for a specific slot.
3169 */
3170 static int
schpc_setslotstatus(uint32_t expander,uint32_t board,uint32_t slot,pci_setslot_t * slotstatus)3171 schpc_setslotstatus(uint32_t expander, uint32_t board, uint32_t slot,
3172 pci_setslot_t *slotstatus)
3173 {
3174 pcimsg_t request;
3175 pcimsg_t reply;
3176 int rval;
3177 uint32_t type, cmd, length;
3178 uint64_t transid;
3179 schpc_replylist_t *entry;
3180
3181 SCHPC_DEBUG4(D_SETSLOTSTATUS,
3182 "schpc_setslotstatus(expander=%d board=%d "
3183 "slot=%d slotstatus=0x%p", expander, board,
3184 SCHPC_SLOT_NUM(slot), (void *)slotstatus);
3185
3186 bzero(&request, sizeof (pcimsg_t));
3187
3188 if (schpc_p == NULL) {
3189 return (1);
3190 }
3191
3192 request.pcimsg_node = expander;
3193 request.pcimsg_board = board;
3194 request.pcimsg_slot = SCHPC_SLOT_NUM(slot);
3195 request.pcimsg_revision = PCIMSG_REVISION;
3196 request.pcimsg_command = PCIMSG_SETSLOTSTATUS;
3197
3198 request.pcimsg_type.pcimsg_setslot = *slotstatus;
3199
3200 SCHPC_DEBUG0(D_IOC_LED, "schpc_setslotstatus() - LED state change");
3201 SCHPC_DEBUG3(D_IOC_LED, "LED Power %d Service %d Fault %d",
3202 slotstatus->slot_led_power,
3203 slotstatus->slot_led_service,
3204 slotstatus->slot_led_fault);
3205
3206 type = MBOXSC_MSG_REQUEST;
3207 cmd = PCIMSG_SETSLOTSTATUS;
3208 transid = schpc_gettransid(schpc_p, slot);
3209 length = sizeof (pcimsg_t);
3210
3211 SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
3212 "0x%lx transid schpc_putrequest called", transid);
3213
3214 rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length,
3215 (void *)&request, schpc_timeout_putmsg, &entry);
3216
3217 SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
3218 "0x%lx transid schpc_putrequest returned 0x%x", transid, rval);
3219
3220 if (rval) {
3221 return (rval);
3222 }
3223
3224 bzero(&reply, sizeof (pcimsg_t));
3225 type = MBOXSC_MSG_REPLY;
3226
3227 SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
3228 "0x%lx transid schpc_getreply called", transid);
3229
3230 rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length,
3231 (void *)&reply, schpc_timeout_getmsg, entry);
3232
3233 SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
3234 "0x%lx transid schpc_getreply returned 0x%x", transid, rval);
3235
3236 if (rval == 0) {
3237 slotstatus->slot_replystatus =
3238 reply.pcimsg_type.pcimsg_setslot.slot_replystatus;
3239 }
3240
3241 return (rval);
3242 }
3243
3244 /*
3245 * schpc_setslotled
3246 *
3247 * Changes the attention indicators for a given slot.
3248 */
3249 static void
schpc_setslotled(int expander,int board,int slot,uint32_t led_state)3250 schpc_setslotled(int expander, int board, int slot, uint32_t led_state)
3251 {
3252
3253 pci_setslot_t setslot;
3254
3255 if (schpc_p == NULL) {
3256 return;
3257 }
3258
3259 schpc_init_setslot_message(&setslot);
3260
3261 if (led_state & POWER_LED_ON) {
3262 schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON;
3263 }
3264 if (led_state & POWER_LED_OFF) {
3265 schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_OFF;
3266 }
3267 if (led_state & POWER_LED_FLASH) {
3268 schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_FLASH;
3269 }
3270 if (led_state & SERVICE_LED_ON) {
3271 schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_ON;
3272 }
3273 if (led_state & SERVICE_LED_OFF) {
3274 schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_OFF;
3275 }
3276 if (led_state & SERVICE_LED_FLASH) {
3277 schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_FLASH;
3278 }
3279 if (led_state & FAULT_LED_ON) {
3280 schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_ON;
3281 }
3282 if (led_state & FAULT_LED_OFF) {
3283 schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_OFF;
3284 }
3285 if (led_state & FAULT_LED_FLASH) {
3286 schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_FLASH;
3287 }
3288
3289 switch (schpc_p->schpc_slot[slot].led.led_power) {
3290 case PCIMSG_LED_ON:
3291 setslot.slot_led_power = PCIMSG_LED_ON;
3292 break;
3293 case PCIMSG_LED_OFF:
3294 setslot.slot_led_power = PCIMSG_LED_OFF;
3295 break;
3296 case PCIMSG_LED_FLASH:
3297 setslot.slot_led_power = PCIMSG_LED_FLASH;
3298 break;
3299 }
3300 switch (schpc_p->schpc_slot[slot].led.led_service) {
3301 case PCIMSG_LED_ON:
3302 setslot.slot_led_service = PCIMSG_LED_ON;
3303 break;
3304 case PCIMSG_LED_OFF:
3305 setslot.slot_led_service = PCIMSG_LED_OFF;
3306 break;
3307 case PCIMSG_LED_FLASH:
3308 setslot.slot_led_service = PCIMSG_LED_FLASH;
3309 break;
3310 }
3311 switch (schpc_p->schpc_slot[slot].led.led_fault) {
3312 case PCIMSG_LED_ON:
3313 setslot.slot_led_fault = PCIMSG_LED_ON;
3314 break;
3315 case PCIMSG_LED_OFF:
3316 setslot.slot_led_fault = PCIMSG_LED_OFF;
3317 break;
3318 case PCIMSG_LED_FLASH:
3319 setslot.slot_led_fault = PCIMSG_LED_FLASH;
3320 break;
3321 }
3322
3323 (void) schpc_setslotstatus(expander, board, slot, &setslot);
3324 }
3325
3326 /*
3327 * schpc_init_setslot_message
3328 *
3329 * Initialize Set Slot Message before using it.
3330 */
3331 static void
schpc_init_setslot_message(pci_setslot_t * setslot)3332 schpc_init_setslot_message(pci_setslot_t *setslot)
3333 {
3334 /*
3335 * Initialize Set Slot Command.
3336 */
3337 setslot->slot_power_on = PCIMSG_OFF;
3338 setslot->slot_power_off = PCIMSG_OFF;
3339 setslot->slot_led_power = PCIMSG_LED_OFF;
3340 setslot->slot_led_service = PCIMSG_LED_OFF;
3341 setslot->slot_led_fault = PCIMSG_LED_OFF;
3342 setslot->slot_disable_ENUM = PCIMSG_OFF;
3343 setslot->slot_enable_ENUM = PCIMSG_OFF;
3344 setslot->slot_disable_HEALTHY = PCIMSG_OFF;
3345 setslot->slot_enable_HEALTHY = PCIMSG_OFF;
3346 }
3347
3348 /*
3349 * schpc_gettransid
3350 *
3351 * Builds a unique transaction ID.
3352 */
3353 static uint64_t
schpc_gettransid(schpc_t * schpc_p,int slot)3354 schpc_gettransid(schpc_t *schpc_p, int slot)
3355 {
3356 uint64_t trans_id;
3357
3358 mutex_enter(&schpc_p->schpc_mutex);
3359
3360 if (++schpc_p->schpc_transid == 0)
3361 schpc_p->schpc_transid = 1;
3362
3363 trans_id = (schpc_p->schpc_slot[slot].expander<<24) |
3364 (schpc_p->schpc_slot[slot].board << 16) | schpc_p->schpc_transid;
3365
3366 mutex_exit(&schpc_p->schpc_mutex);
3367
3368 SCHPC_DEBUG1(D_TRANSID, "schpc_gettransid() - 0x%lx transid returning",
3369 trans_id);
3370
3371 return (trans_id);
3372 }
3373
3374 /*
3375 * schpc_slot_get_index
3376 *
3377 * get slot table index from the slot handle
3378 */
3379 static int
schpc_slot_get_index(schpc_t * schpc_p,hpc_slot_t slot)3380 schpc_slot_get_index(schpc_t *schpc_p, hpc_slot_t slot)
3381 {
3382 int i;
3383 int rval = -1;
3384
3385 ASSERT(MUTEX_HELD(&schpc_p->schpc_mutex));
3386
3387 for (i = 0; i < schpc_p->schpc_number_of_slots; i++) {
3388 if (schpc_p->schpc_slot[i].slot_handle == slot)
3389 return (i);
3390 }
3391
3392 return (rval);
3393 }
3394
3395 /*
3396 * schpc_register_all_slots
3397 *
3398 * Search device tree for pci nodes and register attachment points
3399 * for all hot pluggable slots.
3400 */
3401 /*ARGSUSED*/
3402 static void
schpc_register_all_slots(schpc_t * schpc_p)3403 schpc_register_all_slots(schpc_t *schpc_p)
3404 {
3405 int slot = 0;
3406 char caddr[64];
3407 dev_info_t *pci_dip = NULL;
3408 find_dev_t find_dev;
3409 int leaf, schizo, expander, portid, offset;
3410
3411 SCHPC_DEBUG1(D_ATTACH,
3412 "schpc_register_all_slots(schpc_p=%p)", (void *)schpc_p);
3413
3414 /*
3415 * Allow the event_handler to start processing unsolicited
3416 * events now that slots are about to be registered.
3417 */
3418 slots_registered = B_TRUE;
3419
3420 for (slot = 0; slot < STARCAT_MAX_SLOTS; slot++) {
3421
3422 leaf = SCHPC_SLOT_LEAF(slot);
3423 schizo = SCHPC_SLOT_SCHIZO(slot);
3424 expander = SCHPC_SLOT_EXPANDER(slot);
3425
3426 if (schizo == 0)
3427 portid = 0x1c;
3428 else
3429 portid = 0x1d;
3430
3431 if (leaf == 0)
3432 offset = 0x600000;
3433 else
3434 offset = 0x700000;
3435
3436 portid = (expander << 5) | portid;
3437
3438 (void) sprintf(caddr, "%x,%x", portid, offset);
3439
3440 SCHPC_DEBUG3(D_ATTACH,
3441 "schpc_register_all_slots: searching for pci@%s"
3442 " schizo=%d, leaf=%d", caddr, schizo, leaf);
3443
3444 find_dev.cname = "pci";
3445 find_dev.caddr = caddr;
3446 find_dev.schizo = schizo;
3447 find_dev.leaf = leaf;
3448 find_dev.dip = NULL;
3449
3450 /* root node doesn't have to be held */
3451 ddi_walk_devs(ddi_root_node(), schpc_match_dip,
3452 &find_dev);
3453
3454 pci_dip = find_dev.dip;
3455
3456 if (pci_dip == NULL) {
3457
3458 SCHPC_DEBUG1(D_ATTACH,
3459 "schpc_register_all_slots: pci@%s NOT FOUND",
3460 caddr);
3461
3462 continue;
3463 }
3464
3465 SCHPC_DEBUG2(D_ATTACH,
3466 "schpc_register_all_slots: pci@%s FOUND dip=0x%p",
3467 caddr, (void *)pci_dip);
3468
3469 (void) schpc_add_pci(pci_dip);
3470
3471 /*
3472 * Release hold acquired in schpc_match_dip()
3473 */
3474 ndi_rele_devi(pci_dip);
3475 }
3476
3477 SCHPC_DEBUG0(D_ATTACH, "schpc_register_all_slots: Thread Exit");
3478
3479 thread_exit();
3480 }
3481
3482 /*
3483 * schpc_add_pci
3484 *
3485 * Routine to add attachments points associated with a pci node.
3486 * Can be call externally by DR when configuring a PCI I/O Board.
3487 */
3488 int
schpc_add_pci(dev_info_t * bdip)3489 schpc_add_pci(dev_info_t *bdip)
3490 {
3491 int portid;
3492 int expander, board, schizo, leaf, slot, status;
3493 char ap_id[MAXNAMELEN];
3494 char caddr[64];
3495 char *naddr;
3496 hpc_slot_info_t slot_info;
3497 hpc_slot_ops_t *slot_ops;
3498 dev_info_t *sdip = bdip;
3499
3500 SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci(dip=0x%p)", (void *)sdip);
3501
3502 if (schpc_p == NULL) {
3503 /*
3504 * The schpc driver has not been attached yet.
3505 */
3506 return (DDI_SUCCESS);
3507 }
3508
3509 if ((portid = ddi_getprop(DDI_DEV_T_ANY, sdip, 0, "portid", -1)) < 0) {
3510 cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - no portid\n",
3511 (void *)sdip);
3512 return (DDI_FAILURE);
3513 }
3514
3515 expander = schpc_getexpander(sdip);
3516 board = schpc_getboard(sdip);
3517
3518 switch (portid & 0x1f) {
3519
3520 case 0x1c:
3521 schizo = 0;
3522 break;
3523 case 0x1d:
3524 schizo = 1;
3525 break;
3526 default:
3527 cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3528 "Invalid pci portid 0x%x\n", (void *)sdip, portid);
3529 return (DDI_FAILURE);
3530 }
3531
3532 naddr = ddi_get_name_addr(sdip);
3533 if (naddr == NULL) {
3534 SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci: ddi_get_name_addr"
3535 "(0x%p) returns null", (void *)sdip);
3536 return (DDI_FAILURE);
3537 }
3538
3539 (void) sprintf(caddr, "%x,600000", portid);
3540
3541 if (strcmp(caddr, naddr) == 0) {
3542 leaf = 0;
3543 } else {
3544 (void) sprintf(caddr, "%x,700000", portid);
3545 if (strcmp(caddr, naddr) == 0) {
3546 char *name;
3547
3548 leaf = 1;
3549 name = ddi_binding_name(sdip);
3550 if ((strcmp(name, "pci108e,8002") == 0) &&
3551 (schizo == 0)) {
3552 int circ;
3553 dev_info_t *cdip;
3554 /*
3555 * XMITS 0 Leaf B will have its hot
3556 * pluggable slot off a PCI-PCI bridge,
3557 * which is the only child.
3558 */
3559 ndi_devi_enter(sdip, &circ);
3560 cdip = ddi_get_child(sdip);
3561 if (cdip == NULL) {
3562 cmn_err(CE_WARN,
3563 "schpc_add_pci(dip=0x%p) - "
3564 "Invalid pci name addr %s\n",
3565 (void *)sdip, naddr);
3566 ndi_devi_exit(sdip, circ);
3567 return (DDI_FAILURE);
3568 }
3569 ndi_devi_exit(sdip, circ);
3570 sdip = cdip;
3571 }
3572 } else {
3573 cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3574 "Invalid pci name addr %s\n", (void *)sdip, naddr);
3575 return (DDI_FAILURE);
3576 }
3577 }
3578
3579 /* create a slot table index */
3580 slot = SCHPC_MAKE_SLOT_INDEX3(expander, schizo, leaf);
3581
3582 if (schpc_p->schpc_slot[slot].devi) {
3583 cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3584 "pci node already registered\n", (void *)sdip);
3585 return (DDI_FAILURE);
3586 }
3587
3588 /*
3589 * There is no need to hold the dip while saving it in
3590 * the devi field below. The dip is never dereferenced.
3591 * (If that changes, this code should be modified).
3592 * We want to avoid holding the dip here because it
3593 * prevents DR.
3594 *
3595 * NOTE: Even though the slot on XMITS0 Leaf-B
3596 * is connected to a pci_pci bridge, we will be saving
3597 * the busdip in this datastructure. This will make
3598 * it easier to identify the dip being removed in
3599 * schpc_remove_pci().
3600 */
3601 schpc_p->schpc_slot[slot].devi = bdip;
3602
3603 schpc_p->schpc_slot[slot].expander = expander;
3604 schpc_p->schpc_slot[slot].board = board;
3605 schpc_p->schpc_slot[slot].schizo = schizo;
3606 schpc_p->schpc_slot[slot].leaf = leaf;
3607
3608 /*
3609 * Starcat PCI slots are always PCI device 1.
3610 */
3611 schpc_p->schpc_slot[slot].pci_id = 1;
3612
3613 schpc_buildapid(sdip, slot, (char *)&ap_id);
3614
3615 (void) strcpy(schpc_p->schpc_slot[slot].ap_id, (char *)&ap_id);
3616
3617 /* safe to call ddi_pathname(): bdip is held */
3618 (void) ddi_pathname(sdip, schpc_p->schpc_slot[slot].nexus_path);
3619
3620 status = schpc_get_slot_status(expander, board, SCHPC_SLOT_NUM(slot));
3621 switch (status) {
3622 case RSV_UNKNOWN:
3623 case RSV_PRESENT:
3624 case RSV_MISS:
3625 case RSV_PASS:
3626 case RSV_EMPTY_CASSETTE:
3627
3628 /*
3629 * Test the condition of the slot.
3630 */
3631 schpc_test((caddr_t)schpc_p, slot, 0, 0);
3632 break;
3633 case RSV_BLACK:
3634 schpc_p->schpc_slot[slot].state = 0;
3635 cmn_err(CE_WARN, "schpc: PCI card blacklisted: "
3636 "expander=%d board=%d slot=%d\n", expander,
3637 board, SCHPC_SLOT_NUM(slot));
3638 break;
3639 default:
3640 schpc_p->schpc_slot[slot].state = 0;
3641 cmn_err(CE_WARN, "schpc: PCI card failed by POST: "
3642 "expander=%d board=%d slot=%d failure=0x%x\n",
3643 expander, board, SCHPC_SLOT_NUM(slot), status);
3644 break;
3645 }
3646
3647 if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_REC_GOOD) {
3648
3649 /* allocate slot ops */
3650
3651 slot_ops = hpc_alloc_slot_ops(KM_SLEEP);
3652 schpc_p->schpc_slot[slot].slot_ops = slot_ops;
3653
3654 /*
3655 * Default to Autoconfiguration disabled.
3656 */
3657 schpc_p->schpc_slot[slot].state &=
3658 ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
3659
3660 /*
3661 * Fill in the slot information structure that
3662 * describes the slot.
3663 */
3664 slot_info.version = HPC_SLOT_OPS_VERSION;
3665
3666 if (schpc_p->schpc_hotplugmodel ==
3667 SCHPC_HOTPLUGTYPE_CPCIHOTPLUG)
3668 slot_info.slot_type = HPC_SLOT_TYPE_PCI;
3669 else
3670 slot_info.slot_type = HPC_SLOT_TYPE_CPCI;
3671
3672 slot_info.slot.pci.device_number =
3673 schpc_p->schpc_slot[slot].pci_id;
3674
3675 slot_info.slot.pci.slot_capabilities = HPC_SLOT_64BITS;
3676
3677 if (schpc_use_legacy_apid)
3678 slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE;
3679 else
3680 slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE |
3681 HPC_SLOT_CREATE_DEVLINK;
3682
3683 (void) strcpy(slot_info.slot.pci.slot_logical_name,
3684 schpc_p->schpc_slot[slot].ap_id);
3685
3686 /*
3687 * Fill in the slot ops structure that tells
3688 * the Hot Plug Services what function we
3689 * support.
3690 */
3691 slot_ops->hpc_version = HPC_SLOT_OPS_VERSION;
3692 if (schpc_p->schpc_hotplugmodel ==
3693 SCHPC_HOTPLUGTYPE_CPCIHOTPLUG) {
3694 slot_ops->hpc_op_connect = schpc_connect;
3695 slot_ops->hpc_op_disconnect = schpc_disconnect;
3696 slot_ops->hpc_op_insert = NULL;
3697 slot_ops->hpc_op_remove = NULL;
3698 slot_ops->hpc_op_control = schpc_pci_control;
3699 } else {
3700 slot_ops->hpc_op_connect = NULL;
3701 slot_ops->hpc_op_disconnect = NULL;
3702 slot_ops->hpc_op_insert = NULL;
3703 slot_ops->hpc_op_remove = NULL;
3704 slot_ops->hpc_op_control = schpc_cpci_control;
3705 }
3706
3707 SCHPC_DEBUG5(D_ATTACH, "schpc_add_pci: Registering HPC "
3708 "- nexus =%s schpc_p=%p slot=%d pci number=%d ap_id=%s",
3709 schpc_p->schpc_slot[slot].nexus_path,
3710 (void *)schpc_p, SCHPC_SLOT_NUM(slot),
3711 slot_info.slot.pci.device_number,
3712 slot_info.slot.pci.slot_logical_name);
3713
3714 if (hpc_slot_register(schpc_p->schpc_devi,
3715 schpc_p->schpc_slot[slot].nexus_path, &slot_info,
3716 &schpc_p->schpc_slot[slot].slot_handle,
3717 slot_ops, (caddr_t)schpc_p, 0) != 0) {
3718
3719 /*
3720 * If the slot can not be registered,
3721 * then the slot_ops need to be freed.
3722 */
3723 cmn_err(CE_WARN, "schpc%d Unable to Register "
3724 "Slot %s", schpc_p->schpc_instance,
3725 slot_info.slot.pci.slot_logical_name);
3726
3727 hpc_free_slot_ops(schpc_p->schpc_slot[slot].slot_ops);
3728
3729 schpc_p->schpc_slot[slot].slot_ops = NULL;
3730
3731 return (DDI_FAILURE);
3732 }
3733
3734 /*
3735 * We are ready to take commands from the HPC Services.
3736 */
3737 schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_HPCINITED;
3738 }
3739
3740 return (DDI_SUCCESS);
3741 }
3742
3743 /*
3744 * schpc_remove_pci
3745 *
3746 * Routine to remove attachments points associated with a pci node.
3747 * Can be call externally by DR when unconfiguring a PCI I/O Board.
3748 */
3749 int
schpc_remove_pci(dev_info_t * dip)3750 schpc_remove_pci(dev_info_t *dip)
3751 {
3752 int slot;
3753
3754 SCHPC_DEBUG1(D_DETACH, "schpc_remove_pci(dip=0x%p)", (void *)dip);
3755
3756 if (schpc_p == NULL) {
3757 /*
3758 * The schpc driver has not been attached yet.
3759 */
3760 return (DDI_SUCCESS);
3761 }
3762
3763 for (slot = 0; slot < schpc_p->schpc_number_of_slots; slot++) {
3764 if (schpc_p->schpc_slot[slot].devi == dip) {
3765
3766 if (schpc_p->schpc_slot[slot].slot_ops) {
3767 if (hpc_slot_unregister(
3768 &schpc_p->schpc_slot[slot].slot_handle)) {
3769 cmn_err(CE_WARN,
3770 "schpc_remove_pci(dip=0x%p) - "
3771 "unable to unregister pci slots\n",
3772 (void *)dip);
3773 return (DDI_FAILURE);
3774 } else {
3775 hpc_free_slot_ops(
3776 schpc_p->schpc_slot[slot].slot_ops);
3777
3778 schpc_p->schpc_slot[slot].slot_ops =
3779 NULL;
3780
3781 schpc_p->schpc_slot[slot].devi = NULL;
3782
3783 return (DDI_SUCCESS);
3784 }
3785 } else {
3786 schpc_p->schpc_slot[slot].devi = NULL;
3787
3788 return (DDI_SUCCESS);
3789 }
3790 }
3791 }
3792
3793 cmn_err(CE_WARN, "schpc_remove_pci(dip=0x%p) "
3794 "dip not found\n", (void *)dip);
3795
3796 return (DDI_SUCCESS);
3797 }
3798
3799 /*
3800 * schpc_match_dip
3801 *
3802 * Used by ddi_walk_devs to find PCI Nexus nodes associated with
3803 * Hot Plug Controllers.
3804 */
3805 static int
schpc_match_dip(dev_info_t * dip,void * arg)3806 schpc_match_dip(dev_info_t *dip, void *arg)
3807 {
3808 char *naddr;
3809 find_dev_t *find_dev = (find_dev_t *)arg;
3810
3811 if (strcmp(find_dev->cname, ddi_node_name(dip)) == 0 &&
3812 ((((naddr = ddi_get_name_addr(dip)) != NULL) &&
3813 (strcmp(find_dev->caddr, naddr) == 0)) ||
3814 ((naddr == NULL) && (strlen(find_dev->caddr) == 0)))) {
3815 /*
3816 * While ddi_walk_devs() holds dips when invoking this
3817 * callback, this dip is being saved and will be accessible
3818 * to the caller outside ddi_walk_devs(). Therefore it must be
3819 * held.
3820 */
3821 ndi_hold_devi(dip);
3822 find_dev->dip = dip;
3823
3824 SCHPC_DEBUG2(D_ATTACH,
3825 "schpc_match_dip: pci@%s FOUND dip=0x%p",
3826 find_dev->caddr, (void *)find_dev->dip);
3827
3828 return (DDI_WALK_TERMINATE);
3829 }
3830
3831 ASSERT(find_dev->dip == NULL);
3832 return (DDI_WALK_CONTINUE);
3833 }
3834
3835 /*
3836 * schpc_buildapid
3837 *
3838 * Takes a component address and translates it into a ap_id prefix.
3839 */
3840 static void
schpc_buildapid(dev_info_t * dip,int slot,char * ap_id)3841 schpc_buildapid(dev_info_t *dip, int slot, char *ap_id)
3842 {
3843 int r, pci_id_cnt, pci_id_bit;
3844 int slots_before, found;
3845 unsigned char *slot_names_data, *s;
3846 int slot_names_size;
3847 int slot_num;
3848 unsigned int bit_mask;
3849
3850 slot_num = SCHPC_SLOT_NUM(slot);
3851
3852 if (schpc_use_legacy_apid) {
3853 SCHPC_DEBUG1(D_APID, "Slot %d - Using Legacy ap-id", slot);
3854
3855 (void) sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip),
3856 schpc_getboard(dip), slot_num);
3857
3858 SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id);
3859
3860 return;
3861 }
3862
3863 r = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
3864 "slot-names", (caddr_t)&slot_names_data,
3865 &slot_names_size);
3866
3867 if (r == DDI_PROP_SUCCESS) {
3868
3869 /*
3870 * We can try to use the slot-names property to
3871 * build our ap-id.
3872 */
3873 bit_mask = slot_names_data[3] | (slot_names_data[2] << 8) |
3874 (slot_names_data[1] << 16) | (slot_names_data[0] << 24);
3875
3876 pci_id_bit = 1;
3877 pci_id_cnt = slots_before = found = 0;
3878
3879 SCHPC_DEBUG2(D_APID, "Slot %d - slot-names bitmask=%x",
3880 slot, bit_mask);
3881
3882 /*
3883 * Walk the bit mask until we find the bit that corresponds
3884 * to our slots device number. We count how many bits
3885 * we find before we find our slot's bit.
3886 */
3887 while (!found && (pci_id_cnt < 32)) {
3888
3889 while (schpc_p->schpc_slot[slot].pci_id
3890 != pci_id_cnt) {
3891
3892 /*
3893 * Find the next bit set.
3894 */
3895 while (!(bit_mask & pci_id_bit) &&
3896 (pci_id_cnt < 32)) {
3897 pci_id_bit = pci_id_bit << 1;
3898 pci_id_cnt++;
3899 }
3900
3901 if (schpc_p->schpc_slot[slot].pci_id !=
3902 pci_id_cnt)
3903 slots_before++;
3904 else
3905 found = 1;
3906 }
3907 }
3908
3909 if (pci_id_cnt < 32) {
3910
3911 /*
3912 * Set ptr to first string.
3913 */
3914 s = slot_names_data + 4;
3915
3916 /*
3917 * Increment past all the strings for the slots
3918 * before ours.
3919 */
3920 while (slots_before) {
3921 while (*s != NULL)
3922 s++;
3923 s++;
3924 slots_before--;
3925 }
3926
3927 /*
3928 * We should be at our string.
3929 */
3930
3931 (void) sprintf(ap_id, "IO%d_%s",
3932 schpc_getexpander(dip), s);
3933
3934 SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s",
3935 slot, ap_id);
3936
3937 kmem_free(slot_names_data, slot_names_size);
3938 return;
3939 }
3940
3941 SCHPC_DEBUG1(D_APID, "Slot %d - slot-names entry not found",
3942 slot);
3943
3944 kmem_free(slot_names_data, slot_names_size);
3945 } else
3946 SCHPC_DEBUG1(D_APID, "Slot %d - No slot-names prop found",
3947 slot);
3948
3949 /*
3950 * Build the ap-id using the legacy naming scheme.
3951 */
3952 (void) sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip),
3953 schpc_getboard(dip), slot_num);
3954
3955 SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id);
3956 }
3957
3958 /*
3959 * schpc_getexpander
3960 *
3961 * Returns the Expander Number (0-17) for the dip passed in. The Expander
3962 * Number is extracted from the portid property of the pci node. Portid
3963 * consists of <Expbrd#><1110x>, where x is the schizo number.
3964 */
3965 static int
schpc_getexpander(dev_info_t * dip)3966 schpc_getexpander(dev_info_t *dip)
3967 {
3968 int id;
3969
3970 id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "portid", -1);
3971
3972 if (id != -1)
3973 return (id >> 5);
3974 else {
3975 id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "expander", -1);
3976 return (id);
3977 }
3978 }
3979
3980 /*
3981 * schpc_getboard
3982 *
3983 * Returns the board number (0 or 1) for the dip passed in.
3984 */
3985 static int
schpc_getboard(dev_info_t * dip)3986 schpc_getboard(dev_info_t *dip)
3987 {
3988 _NOTE(ARGUNUSED(dip))
3989
3990 /*
3991 * Hot Pluggable PCI/cPCI slots are only available on
3992 * Board 1 (half-bandwidth slot).
3993 */
3994 return (1);
3995 }
3996
3997 /*ARGSUSED*/
3998 static int
schpc_get_slot_status(uint_t expander,uint_t board,uint_t slot)3999 schpc_get_slot_status(uint_t expander, uint_t board, uint_t slot)
4000 {
4001 gdcd_t *gdcd;
4002 int prd_slot, status, bus;
4003
4004 SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() "
4005 "exp=%d board=%d slot=%d", expander, board, slot);
4006
4007 if ((gdcd = (gdcd_t *)kmem_zalloc(sizeof (gdcd_t),
4008 KM_SLEEP)) == NULL) {
4009 return (RSV_UNDEFINED);
4010 }
4011
4012 /*
4013 * Get the Starcat Specific Global DCD Structure from the golden
4014 * IOSRAM.
4015 */
4016 if (iosram_rd(GDCD_MAGIC, 0, sizeof (gdcd_t), (caddr_t)gdcd)) {
4017 cmn_err(CE_WARN, "sc_gptwocfg: Unable To Read GDCD "
4018 "From IOSRAM\n");
4019 kmem_free(gdcd, sizeof (gdcd_t));
4020 return (RSV_UNDEFINED);
4021 }
4022
4023 if (gdcd->h.dcd_magic != GDCD_MAGIC) {
4024
4025 cmn_err(CE_WARN, "schpc: GDCD Bad Magic 0x%x\n",
4026 gdcd->h.dcd_magic);
4027
4028 kmem_free(gdcd, sizeof (gdcd_t));
4029 return (RSV_UNDEFINED);
4030 }
4031
4032 if (gdcd->h.dcd_version != DCD_VERSION) {
4033 cmn_err(CE_WARN, "schpc: GDCD Bad Version: "
4034 "GDCD Version 0x%x Expecting 0x%x\n",
4035 gdcd->h.dcd_version, DCD_VERSION);
4036
4037 kmem_free(gdcd, sizeof (gdcd_t));
4038 return (RSV_UNDEFINED);
4039 }
4040
4041 if (slot < 2)
4042 prd_slot = 4;
4043 else
4044 prd_slot = 5;
4045
4046 bus = slot & 0x1;
4047
4048 status = gdcd->dcd_prd[expander][prd_slot].prd_iocard_rsv[bus][0];
4049
4050 kmem_free(gdcd, sizeof (gdcd_t));
4051
4052 SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() "
4053 "prd_slot=%d bus=%d status=%d", prd_slot, bus, status);
4054
4055 return (status);
4056 }
4057
4058 #define LEAF_SAVE_END 0xff
4059
4060 typedef struct {
4061 int reg;
4062 int offset;
4063 int access_size;
4064 int number;
4065 } save_reg_list_t;
4066
4067 /*
4068 * Save List Array. Describes the leaf registers that need to
4069 * be restored after a leaf reset.
4070 *
4071 * Entry 1 - Reg Entry: 0=PCI Leaf CSRs, 2=PCI Config Space
4072 * Entry 2 - Offset Start
4073 * Entry 3 - Access Size: 8=64 bit, 4=32 bit, 2=16 bit, 1=8 bit
4074 * Entry 4 - # of registers to be saved starting at offset,
4075 */
4076 save_reg_list_t save_reg_list[] = { 0, 0x110, 8, 1,
4077 0, 0x200, 8, 2,
4078 0, 0x1000, 8, 0x18,
4079 0, 0x1a00, 8, 1,
4080 0, 0x2000, 8, 1,
4081 0, 0x2020, 8, 1,
4082 0, 0x2040, 8, 1,
4083 0, 0x2308, 8, 2,
4084 0, 0x2800, 8, 1,
4085 2, 0x04, 2, 1, /* Command */
4086 2, 0x0d, 1, 1, /* Latency */
4087 2, 0x40, 1, 1, /* Bus # */
4088 2, 0x41, 1, 1, /* Sub. Bus # */
4089 LEAF_SAVE_END, 0, 0, 0};
4090
4091 static int
schpc_save_leaf(int slot)4092 schpc_save_leaf(int slot)
4093 {
4094 int save_entry, list_entry, reg;
4095 caddr_t leaf_regs;
4096 ddi_device_acc_attr_t attr;
4097
4098 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot);
4099
4100 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
4101 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
4102 attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
4103
4104 /*
4105 * Map in the 3 addresses spaces defined for XMITS.
4106 */
4107 for (reg = 0; reg < 3; reg++) {
4108 if (ddi_regs_map_setup(schpc_p->schpc_slot[slot].devi, reg,
4109 &leaf_regs, 0, 0, &attr, &schpc_p->schpc_slot[slot].
4110 saved_handle[reg]) != DDI_SUCCESS) {
4111 cmn_err(CE_WARN, "Mapin failed\n");
4112 schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL;
4113 return (1);
4114 }
4115
4116 schpc_p->schpc_slot[slot].saved_regs_va[reg] = leaf_regs;
4117 }
4118
4119
4120 /*
4121 * Determine how many entries are in the list so we can
4122 * allocate the save space.
4123 */
4124 list_entry = 0;
4125 save_entry = 0;
4126 while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
4127 save_entry += save_reg_list[list_entry].number;
4128 list_entry++;
4129 }
4130
4131 schpc_p->schpc_slot[slot].saved_size = (save_entry * sizeof (uint64_t));
4132
4133 if (schpc_p->schpc_slot[slot].saved_size == 0)
4134 return (0);
4135
4136 schpc_p->schpc_slot[slot].saved_regs =
4137 (uint64_t *)kmem_zalloc(schpc_p->schpc_slot[slot].saved_size,
4138 KM_SLEEP);
4139
4140 /*
4141 * Walk through the register list and save contents.
4142 */
4143 list_entry = 0;
4144 save_entry = 0;
4145 while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
4146 schpc_save_entry(slot, list_entry, save_entry);
4147 save_entry += save_reg_list[list_entry].number;
4148 list_entry ++;
4149 }
4150
4151 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot);
4152
4153 return (0);
4154 }
4155
4156 static void
schpc_restore_leaf(int slot)4157 schpc_restore_leaf(int slot)
4158 {
4159 int save_entry, list_entry, reg;
4160
4161 if (schpc_p->schpc_slot[slot].saved_regs == NULL)
4162 return;
4163
4164 /*
4165 * Walk through the register list and restore contents.
4166 */
4167 list_entry = 0;
4168 save_entry = 0;
4169 while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
4170
4171 schpc_restore_entry(slot, list_entry, save_entry);
4172
4173 save_entry += save_reg_list[list_entry].number;
4174 list_entry ++;
4175 }
4176
4177 /*
4178 * Free the mapped in registers.
4179 */
4180 for (reg = 0; reg < 3; reg++) {
4181 if (schpc_p->schpc_slot[slot].saved_regs_va[reg]) {
4182
4183 ddi_regs_map_free(
4184 &schpc_p->schpc_slot[slot].saved_handle[reg]);
4185
4186 schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL;
4187 }
4188 }
4189
4190 kmem_free(schpc_p->schpc_slot[slot].saved_regs,
4191 schpc_p->schpc_slot[slot].saved_size);
4192
4193 schpc_p->schpc_slot[slot].saved_size = 0;
4194 schpc_p->schpc_slot[slot].saved_regs = NULL;
4195
4196 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Restored", slot);
4197 }
4198
4199 static void
schpc_save_entry(int slot,int list_entry,int save_entry)4200 schpc_save_entry(int slot, int list_entry, int save_entry)
4201 {
4202 int reg, reads = 0;
4203
4204 reg = save_reg_list[list_entry].reg;
4205
4206 while (reads < save_reg_list[list_entry].number) {
4207 switch (save_reg_list[list_entry].access_size) {
4208 case 8:
4209 schpc_p->schpc_slot[slot].saved_regs[save_entry] =
4210 ddi_get64(
4211 schpc_p->schpc_slot[slot].saved_handle[reg],
4212 (uint64_t *)(schpc_p->schpc_slot[slot].
4213 saved_regs_va[reg]
4214 + save_reg_list[list_entry].offset +
4215 (reads * sizeof (uint64_t))));
4216 #ifdef DEBUG
4217 if (schpc_dump_save_regs)
4218 cmn_err(CE_WARN, "Save 64 %x %lx %lx\n", reg,
4219 save_reg_list[list_entry].offset +
4220 (reads * sizeof (uint64_t)),
4221 schpc_p->schpc_slot[slot].
4222 saved_regs[save_entry]);
4223 #endif
4224
4225 break;
4226 case 4:
4227 schpc_p->schpc_slot[slot].saved_regs[save_entry] =
4228 ddi_get32(
4229 schpc_p->schpc_slot[slot].saved_handle[reg],
4230 (uint32_t *)(schpc_p->schpc_slot[slot].
4231 saved_regs_va[reg]
4232 + save_reg_list[list_entry].offset +
4233 (reads * sizeof (uint32_t))));
4234
4235 #ifdef DEBUG
4236 if (schpc_dump_save_regs)
4237 cmn_err(CE_WARN, "Save 32 %x %lx %lx\n", reg,
4238 save_reg_list[list_entry].offset +
4239 (reads * sizeof (uint32_t)),
4240 schpc_p->schpc_slot[slot].
4241 saved_regs[save_entry]);
4242 #endif
4243
4244 break;
4245 case 2:
4246 schpc_p->schpc_slot[slot].saved_regs[save_entry] =
4247 ddi_get16(
4248 schpc_p->schpc_slot[slot].saved_handle[reg],
4249 (uint16_t *)(schpc_p->schpc_slot[slot].
4250 saved_regs_va[reg]
4251 + save_reg_list[list_entry].offset +
4252 (reads * sizeof (uint16_t))));
4253
4254 #ifdef DEBUG
4255 if (schpc_dump_save_regs)
4256 cmn_err(CE_WARN, "Save 16 %x %lx %lx\n", reg,
4257 save_reg_list[list_entry].offset +
4258 (reads * sizeof (uint16_t)),
4259 schpc_p->schpc_slot[slot].
4260 saved_regs[save_entry]);
4261 #endif
4262
4263 break;
4264 case 1:
4265 schpc_p->schpc_slot[slot].saved_regs[save_entry] =
4266 ddi_get8(
4267 schpc_p->schpc_slot[slot].saved_handle[reg],
4268 (uint8_t *)(schpc_p->schpc_slot[slot].
4269 saved_regs_va[reg]
4270 + save_reg_list[list_entry].offset +
4271 (reads * sizeof (uint8_t))));
4272
4273 #ifdef DEBUG
4274 if (schpc_dump_save_regs)
4275 cmn_err(CE_WARN, "Save 8 %x %lx %lx\n", reg,
4276 save_reg_list[list_entry].offset +
4277 (reads * sizeof (uint8_t)),
4278 schpc_p->schpc_slot[slot].
4279 saved_regs[save_entry]);
4280 #endif
4281
4282 break;
4283 default:
4284 cmn_err(CE_WARN,
4285 "schpc: Illegal List Entry\n");
4286 }
4287 reads++;
4288 save_entry++;
4289 }
4290 }
4291
4292 static void
schpc_restore_entry(int slot,int list_entry,int save_entry)4293 schpc_restore_entry(int slot, int list_entry, int save_entry)
4294 {
4295 int reg, writes = 0;
4296
4297 reg = save_reg_list[list_entry].reg;
4298
4299 while (writes < save_reg_list[list_entry].number) {
4300 switch (save_reg_list[list_entry].access_size) {
4301 case 8:
4302 #ifdef DEBUG
4303 if (schpc_dump_save_regs)
4304 cmn_err(CE_WARN, "Restore 64 %x %lx %lx\n", reg,
4305 save_reg_list[list_entry].offset +
4306 (writes * sizeof (uint64_t)),
4307 schpc_p->schpc_slot[slot].
4308 saved_regs[save_entry]);
4309 #endif
4310
4311 ddi_put64(schpc_p->schpc_slot[slot].saved_handle[reg],
4312 (uint64_t *)(schpc_p->schpc_slot[slot].
4313 saved_regs_va[reg]
4314 + save_reg_list[list_entry].offset +
4315 (writes * sizeof (uint64_t))),
4316 schpc_p->schpc_slot[slot].saved_regs[save_entry]);
4317
4318 break;
4319 case 4:
4320 #ifdef DEBUG
4321 if (schpc_dump_save_regs)
4322 cmn_err(CE_WARN, "Restore 32 %x %lx %lx\n", reg,
4323 save_reg_list[list_entry].offset +
4324 (writes * sizeof (uint32_t)),
4325 schpc_p->schpc_slot[slot].
4326 saved_regs[save_entry]);
4327 #endif
4328
4329 ddi_put32(schpc_p->schpc_slot[slot].saved_handle[reg],
4330 (uint32_t *)(schpc_p->schpc_slot[slot].
4331 saved_regs_va[reg]
4332 + save_reg_list[list_entry].offset +
4333 (writes * sizeof (uint32_t))),
4334 schpc_p->schpc_slot[slot].saved_regs[save_entry]);
4335
4336 break;
4337 case 2:
4338 #ifdef DEBUG
4339 if (schpc_dump_save_regs)
4340 cmn_err(CE_WARN, "Restore 16 %x %lx %lx\n", reg,
4341 save_reg_list[list_entry].offset +
4342 (writes * sizeof (uint16_t)),
4343 schpc_p->schpc_slot[slot].
4344 saved_regs[save_entry]);
4345 #endif
4346
4347 ddi_put16(schpc_p->schpc_slot[slot].saved_handle[reg],
4348 (uint16_t *)(schpc_p->schpc_slot[slot].
4349 saved_regs_va[reg]
4350 + save_reg_list[list_entry].offset +
4351 (writes * sizeof (uint16_t))),
4352 schpc_p->schpc_slot[slot].saved_regs[save_entry]);
4353
4354 break;
4355 case 1:
4356 #ifdef DEBUG
4357 if (schpc_dump_save_regs)
4358 cmn_err(CE_WARN, "Restore 8 %x %lx %lx\n", reg,
4359 save_reg_list[list_entry].offset +
4360 (writes * sizeof (uint8_t)),
4361 schpc_p->schpc_slot[slot].
4362 saved_regs[save_entry]);
4363 #endif
4364
4365 ddi_put8(schpc_p->schpc_slot[slot].saved_handle[reg],
4366 (uint8_t *)(schpc_p->schpc_slot[slot].
4367 saved_regs_va[reg]
4368 + save_reg_list[list_entry].offset +
4369 (writes * sizeof (uint8_t))),
4370 schpc_p->schpc_slot[slot].saved_regs[save_entry]);
4371
4372 break;
4373 default:
4374 cmn_err(CE_WARN,
4375 "schpc: Illegal List Entry\n");
4376 }
4377 writes++;
4378 save_entry++;
4379 }
4380 }
4381
4382 /*
4383 * Returns TRUE if a leaf reset is required to change frequencies/mode.
4384 */
4385 static int
schpc_is_leaf_reset_required(int slot)4386 schpc_is_leaf_reset_required(int slot)
4387 {
4388 char *name;
4389 int32_t mod_rev;
4390
4391 /*
4392 * Only XMITS 3.0 and greater connected slots will require a
4393 * reset to switch frequency and/or mode.
4394 */
4395 name = ddi_binding_name(schpc_p->schpc_slot[slot].devi);
4396
4397 if (strcmp(name, "pci108e,8002") == 0) {
4398 mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY,
4399 schpc_p->schpc_slot[slot].devi,
4400 DDI_PROP_DONTPASS, "module-revision#", 0);
4401
4402 SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev);
4403
4404 /*
4405 * Check for XMITS 3.0 or greater.
4406 */
4407 if (mod_rev >= XMITS_30) {
4408
4409 /*
4410 * The leaf attached to C5V0 (slot 1) should
4411 * not be reset.
4412 */
4413 if ((slot & 3) == 1) {
4414
4415 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset "
4416 "Not Required - C5V0", slot);
4417
4418 return (0);
4419 }
4420
4421 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset "
4422 "Required", slot);
4423
4424 return (1);
4425 }
4426 }
4427 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset NOT Required", slot);
4428
4429 return (0);
4430 }
4431
4432 /*
4433 * Returns TRUE if the bus can change frequencies.
4434 */
4435 static int
schpc_is_freq_switchable(int slot)4436 schpc_is_freq_switchable(int slot)
4437 {
4438 char *name;
4439 int32_t mod_rev;
4440
4441 name = ddi_binding_name(schpc_p->schpc_slot[slot].devi);
4442
4443 if (strcmp(name, "pci108e,8002") == 0) {
4444 mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY,
4445 schpc_p->schpc_slot[slot].devi,
4446 DDI_PROP_DONTPASS, "module-revision#", 0);
4447
4448 SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev);
4449
4450 /*
4451 * We will only report back that XMITS 2.0 (mod_rev = 2)
4452 * or greater will have the ability to switch frequencies.
4453 */
4454 if (mod_rev >= XMITS_20) {
4455 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - "
4456 "Frequency is switchable", slot);
4457 return (1);
4458 }
4459 }
4460
4461 SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Frequency is NOT switchable", slot);
4462 return (0);
4463 }
4464
4465 /*
4466 * schpc_slot_freq
4467 *
4468 * Convert the slot frequency setting to integer value.
4469 */
4470 static int
schpc_slot_freq(pci_getslot_t * getslotp)4471 schpc_slot_freq(pci_getslot_t *getslotp)
4472 {
4473 switch (getslotp->slot_freq_setting) {
4474 case PCIMSG_FREQ_33MHZ:
4475 return (SCHPC_33MHZ);
4476 case PCIMSG_FREQ_66MHZ:
4477 return (SCHPC_66MHZ);
4478 case PCIMSG_FREQ_90MHZ:
4479 return (SCHPC_90MHZ);
4480 case PCIMSG_FREQ_133MHZ:
4481 return (SCHPC_133MHZ);
4482 default:
4483 return (0);
4484 }
4485 }
4486
4487 /*
4488 * schpc_find_dip
4489 *
4490 * Used by ddi_walk_devs to find the dip which belongs
4491 * to a certain slot.
4492 *
4493 * When this function returns, the dip is held. It is the
4494 * responsibility of the caller to release the dip.
4495 */
4496 static int
schpc_find_dip(dev_info_t * dip,void * arg)4497 schpc_find_dip(dev_info_t *dip, void *arg)
4498 {
4499 find_dev_t *find_dev = (find_dev_t *)arg;
4500 char *pathname = find_dev->caddr;
4501
4502 (void) ddi_pathname(dip, pathname);
4503 if (strcmp(find_dev->cname, pathname) == 0) {
4504 ndi_hold_devi(dip);
4505 find_dev->dip = dip;
4506 return (DDI_WALK_TERMINATE);
4507 }
4508 return (DDI_WALK_CONTINUE);
4509 }
4510