103831d35Sstevel /*
203831d35Sstevel * CDDL HEADER START
303831d35Sstevel *
403831d35Sstevel * The contents of this file are subject to the terms of the
503831d35Sstevel * Common Development and Distribution License (the "License").
603831d35Sstevel * You may not use this file except in compliance with the License.
703831d35Sstevel *
803831d35Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel * See the License for the specific language governing permissions
1103831d35Sstevel * and limitations under the License.
1203831d35Sstevel *
1303831d35Sstevel * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel *
1903831d35Sstevel * CDDL HEADER END
2003831d35Sstevel */
2103831d35Sstevel
2203831d35Sstevel /*
23*07d06da5SSurya Prakki * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2403831d35Sstevel * Use is subject to license terms.
2503831d35Sstevel */
2603831d35Sstevel
2703831d35Sstevel
2803831d35Sstevel /*
2903831d35Sstevel * Starcat IOSRAM/Tunnel PCI Hot Plug Controller Driver
3003831d35Sstevel */
3103831d35Sstevel
3203831d35Sstevel #define CPCI_ENUM
3303831d35Sstevel
3403831d35Sstevel #include <sys/note.h>
3503831d35Sstevel #include <sys/types.h>
3603831d35Sstevel #include <sys/cmn_err.h>
3703831d35Sstevel #include <sys/kmem.h>
3803831d35Sstevel #include <sys/errno.h>
3903831d35Sstevel #include <sys/open.h>
4003831d35Sstevel #include <sys/stat.h>
4103831d35Sstevel #include <sys/conf.h>
4203831d35Sstevel #include <sys/ddi.h>
4303831d35Sstevel #include <sys/cmn_err.h>
4403831d35Sstevel #include <sys/sunddi.h>
4503831d35Sstevel #include <sys/sunndi.h>
4603831d35Sstevel #include <sys/ddi_impldefs.h>
4703831d35Sstevel #include <sys/ndi_impldefs.h>
4803831d35Sstevel #include <sys/modctl.h>
4903831d35Sstevel #include <sys/disp.h>
5003831d35Sstevel #include <sys/async.h>
5103831d35Sstevel #include <sys/hotplug/hpcsvc.h>
5203831d35Sstevel #include <sys/mboxsc.h>
5303831d35Sstevel #include <sys/schpc_msg.h>
5403831d35Sstevel #include <sys/schpc.h>
5503831d35Sstevel #include <post/scat_dcd.h>
5603831d35Sstevel #include <sys/taskq.h>
5703831d35Sstevel
5803831d35Sstevel #ifdef DEBUG
5903831d35Sstevel int schpc_dump_save_regs = 0;
6003831d35Sstevel static uint_t schpc_debug_flags = 0;
6103831d35Sstevel #define SCHPC_DEBUG0(f, s) if ((f)& schpc_debug_flags) \
6203831d35Sstevel cmn_err(CE_CONT, "schpc: " s "\n")
6303831d35Sstevel #define SCHPC_DEBUG1(f, s, a) if ((f)& schpc_debug_flags) \
6403831d35Sstevel cmn_err(CE_CONT, "schpc: " s "\n", a)
6503831d35Sstevel #define SCHPC_DEBUG2(f, s, a, b) if ((f)& schpc_debug_flags) \
6603831d35Sstevel cmn_err(CE_CONT, "schpc: " s "\n", a, b)
6703831d35Sstevel #define SCHPC_DEBUG3(f, s, a, b, c) if ((f)& schpc_debug_flags) \
6803831d35Sstevel cmn_err(CE_CONT, "schpc: " s "\n", a, b, c)
6903831d35Sstevel #define SCHPC_DEBUG4(f, s, a, b, c, d) if ((f)& schpc_debug_flags) \
7003831d35Sstevel cmn_err(CE_CONT, "schpc: " s "\n", a, b, c, d)
7103831d35Sstevel #define SCHPC_DEBUG5(f, s, a, b, c, d, e) if ((f)& schpc_debug_flags) \
7203831d35Sstevel cmn_err(CE_CONT, "schpc: " s "\n", a, b, c, d, e)
7303831d35Sstevel #define SCHPC_DEBUG6(f, s, a, b, c, d, e, ff) if ((f)& schpc_debug_flags) \
7403831d35Sstevel cmn_err(CE_CONT, "schpc: " s "\n", a, b, c, d, e, ff)
7503831d35Sstevel #else
7603831d35Sstevel
7703831d35Sstevel #define SCHPC_DEBUG0(f, s)
7803831d35Sstevel #define SCHPC_DEBUG1(f, s, a)
7903831d35Sstevel #define SCHPC_DEBUG2(f, s, a, b)
8003831d35Sstevel #define SCHPC_DEBUG3(f, s, a, b, c)
8103831d35Sstevel #define SCHPC_DEBUG4(f, s, a, b, c, d)
8203831d35Sstevel #define SCHPC_DEBUG5(f, s, a, b, c, d, e)
8303831d35Sstevel #define SCHPC_DEBUG6(f, s, a, b, c, d, e, ff)
8403831d35Sstevel
8503831d35Sstevel #endif
8603831d35Sstevel
8703831d35Sstevel #define D_IDENTIFY 0x00000001
8803831d35Sstevel #define D_ATTACH 0x00000002
8903831d35Sstevel #define D_DETACH 0x00000004
9003831d35Sstevel #define D_OPEN 0x00000008
9103831d35Sstevel #define D_GETSLOTSTATUS 0x00000010
9203831d35Sstevel #define D_SETSLOTSTATUS 0x00000020
9303831d35Sstevel #define D_IOCTL 0x00010000
9403831d35Sstevel #define D_IOC_CONNECT 0x00020000
9503831d35Sstevel #define D_IOC_CONTROL 0x00040000
9603831d35Sstevel #define D_IOC_CONFIG 0x00080000
9703831d35Sstevel #define D_IOC_STATUS 0x00100000
9803831d35Sstevel #define D_IOC_MSG 0x00200000
9903831d35Sstevel #define D_IOC_TEST 0x00400000
10003831d35Sstevel #define D_IOC_LED 0x00800000
10103831d35Sstevel #define D_EVENT 0x01000000
10203831d35Sstevel #define D_THREAD 0x02000000
10303831d35Sstevel #define D_TRANSID 0x04000000
10403831d35Sstevel #define D_SLOTTABLE 0x08000000
10503831d35Sstevel #define D_FREQCHG 0x10000000
10603831d35Sstevel #define D_APID 0x20000000
10703831d35Sstevel
10803831d35Sstevel /*
10903831d35Sstevel * driver global data:
11003831d35Sstevel */
11103831d35Sstevel static void *per_schpc_state; /* soft state head */
11203831d35Sstevel dev_info_t *schpc_devi;
11303831d35Sstevel static schpc_t *schpc_p;
11403831d35Sstevel
11503831d35Sstevel clock_t schpc_timeout_putmsg = 60 * 1000; /* 60 seconds */
11603831d35Sstevel clock_t schpc_timeout_getmsg = 60 * 1000; /* 60 seconds */
11703831d35Sstevel clock_t schpc_timeout_event = 60 * 5 * 1000; /* 5 minutes */
11803831d35Sstevel
11903831d35Sstevel int schpc_use_legacy_apid = 0;
12003831d35Sstevel
12103831d35Sstevel static mboxsc_timeout_range_t schpc_putmsg_timeout_range;
12203831d35Sstevel static mboxsc_timeout_range_t schpc_getmsg_timeout_range;
12303831d35Sstevel
12403831d35Sstevel static taskq_t *schpc_event_taskq = NULL;
12503831d35Sstevel
12603831d35Sstevel /*
12703831d35Sstevel * replies to mboxsc_getmsg() are handled asynchronously by the
12803831d35Sstevel * schpc_msg_thread using a linked list of schpc_replylist_t
12903831d35Sstevel * elements
13003831d35Sstevel */
13103831d35Sstevel typedef struct schpc_replylist {
13203831d35Sstevel struct schpc_replylist *prev; /* link to previous entry */
13303831d35Sstevel struct schpc_replylist *next; /* link to next entry */
13403831d35Sstevel kcondvar_t reply_cv; /* condvar for getting reply */
13503831d35Sstevel kmutex_t reply_lock; /* mutex for getting reply */
13603831d35Sstevel uint32_t type; /* mboxsc_xxxmsg() msg type */
13703831d35Sstevel uint32_t cmd; /* mboxsc_xxxmsg() cmd */
13803831d35Sstevel uint64_t transid; /* mboxsc_xxxmsg() trans id */
13903831d35Sstevel uint32_t length; /* mboxsc_xxxmsg() length */
14003831d35Sstevel pcimsg_t reply; /* mboxsc_xxxmsg() reply msg */
14103831d35Sstevel boolean_t reply_recvd; /* msg reply received */
14203831d35Sstevel boolean_t reply_cexit; /* client early exit */
14303831d35Sstevel } schpc_replylist_t;
14403831d35Sstevel
14503831d35Sstevel static kmutex_t schpc_replylist_mutex; /* replylist mutex */
14603831d35Sstevel static uint32_t schpc_replylist_count; /* replylist size */
14703831d35Sstevel static schpc_replylist_t *schpc_replylist_first; /* replylist 1st elem */
14803831d35Sstevel static schpc_replylist_t *schpc_replylist_last; /* replylist last elem */
14903831d35Sstevel static boolean_t slots_registered = B_FALSE; /* slots registered? */
15003831d35Sstevel
15103831d35Sstevel typedef struct {
15203831d35Sstevel char *cname;
15303831d35Sstevel char *caddr;
15403831d35Sstevel char schizo;
15503831d35Sstevel char leaf;
15603831d35Sstevel dev_info_t *dip;
15703831d35Sstevel } find_dev_t;
15803831d35Sstevel
15903831d35Sstevel /*
16003831d35Sstevel * Function prototypes for local functions
16103831d35Sstevel */
16203831d35Sstevel static int schpc_getexpander(dev_info_t *);
16303831d35Sstevel static int schpc_getboard(dev_info_t *);
16403831d35Sstevel static void schpc_event_handler(void *);
16503831d35Sstevel static void schpc_event_filter(pcimsg_t *msg);
16603831d35Sstevel static void schpc_reply_handler(pcimsg_t *pmsg, uint32_t type, uint32_t cmd,
16703831d35Sstevel uint64_t transid, uint32_t length);
16803831d35Sstevel static uint64_t schpc_gettransid(schpc_t *, int);
16903831d35Sstevel static int schpc_slot_get_index(schpc_t *, hpc_slot_t);
17003831d35Sstevel static void schpc_register_all_slots(schpc_t *);
17103831d35Sstevel static void schpc_setslotled(int, int, int, uint32_t);
17203831d35Sstevel static void schpc_init_setslot_message(pci_setslot_t *);
17303831d35Sstevel static void schpc_test(caddr_t, int, void *, uint_t);
17403831d35Sstevel static int schpc_getslotstatus(uint32_t, uint32_t, uint32_t, pci_getslot_t *);
17503831d35Sstevel static int schpc_setslotstatus(uint32_t, uint32_t, uint32_t, pci_setslot_t *);
17603831d35Sstevel static int schpc_match_dip(dev_info_t *, void *);
17703831d35Sstevel static void schpc_buildapid(dev_info_t *, int, char *);
17803831d35Sstevel static int schpc_get_slot_status(uint_t, uint_t, uint_t);
17903831d35Sstevel static void schpc_replylist_unlink(schpc_replylist_t *entry);
18003831d35Sstevel static schpc_replylist_t *schpc_replylist_link(uint32_t cmd, uint64_t transid,
18103831d35Sstevel uint32_t length);
18203831d35Sstevel static void schpc_msg_thread(void);
18303831d35Sstevel static int schpc_putrequest(uint32_t key, uint32_t type, uint32_t cmd,
18403831d35Sstevel uint64_t *transidp, uint32_t length,
18503831d35Sstevel void *datap, clock_t timeout,
18603831d35Sstevel schpc_replylist_t **entryp);
18703831d35Sstevel static int schpc_getreply(uint32_t key, uint32_t *typep, uint32_t *cmdp,
18803831d35Sstevel uint64_t *transidp, uint32_t *lengthp, void *datap,
18903831d35Sstevel clock_t timeout, schpc_replylist_t *listp);
19003831d35Sstevel
19103831d35Sstevel static int schpc_slot_freq(pci_getslot_t *);
19203831d35Sstevel static int schpc_find_dip(dev_info_t *, void *);
19303831d35Sstevel
19403831d35Sstevel static int schpc_save_leaf(int slot);
19503831d35Sstevel static void schpc_restore_leaf(int slot);
19603831d35Sstevel static int schpc_is_leaf_reset_required(int slot);
19703831d35Sstevel static int schpc_is_freq_switchable(int slot);
19803831d35Sstevel static void schpc_save_entry(int slot, int list_entry, int save_entry);
19903831d35Sstevel static void schpc_restore_entry(int slot, int list_entry, int save_entry);
20003831d35Sstevel
20103831d35Sstevel /*
20203831d35Sstevel * Function prototype for Hot Plug Services
20303831d35Sstevel */
20403831d35Sstevel static int schpc_connect(caddr_t, hpc_slot_t, void *, uint_t);
20503831d35Sstevel static int schpc_disconnect(caddr_t, hpc_slot_t, void *, uint_t);
20603831d35Sstevel static int schpc_cpci_control(caddr_t, hpc_slot_t, int, caddr_t);
20703831d35Sstevel static int schpc_pci_control(caddr_t, hpc_slot_t, int, caddr_t);
20803831d35Sstevel
20903831d35Sstevel extern int iosram_rd(uint32_t, uint32_t, uint32_t, caddr_t);
21003831d35Sstevel
21103831d35Sstevel /*
21203831d35Sstevel * cb_ops and dev_ops:
21303831d35Sstevel */
21403831d35Sstevel static struct cb_ops schpc_cb_ops = {
21503831d35Sstevel nodev, /* open */
21603831d35Sstevel nodev, /* close */
21703831d35Sstevel nodev, /* strategy */
21803831d35Sstevel nodev, /* print */
21903831d35Sstevel nodev, /* dump */
22003831d35Sstevel nodev, /* read */
22103831d35Sstevel nodev, /* write */
22203831d35Sstevel nodev, /* ioctl */
22303831d35Sstevel nodev, /* devmap */
22403831d35Sstevel nodev, /* mmap */
22503831d35Sstevel nodev, /* segmap */
22603831d35Sstevel nochpoll, /* poll */
22703831d35Sstevel ddi_prop_op, /* prop_op */
22803831d35Sstevel 0, /* streamtab */
22903831d35Sstevel D_NEW | D_MP | D_HOTPLUG /* Driver compatibility flag */
23003831d35Sstevel };
23103831d35Sstevel
23203831d35Sstevel /*
23303831d35Sstevel * Function prototype for dev_ops
23403831d35Sstevel */
23503831d35Sstevel static int schpc_attach(dev_info_t *, ddi_attach_cmd_t);
23603831d35Sstevel static int schpc_detach(dev_info_t *, ddi_detach_cmd_t);
23703831d35Sstevel static int schpc_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
23803831d35Sstevel
23903831d35Sstevel static struct dev_ops schpc_dev_ops = {
24003831d35Sstevel DEVO_REV, /* devo_rev, */
24103831d35Sstevel 0, /* refcnt */
24203831d35Sstevel schpc_info, /* get_dev_info */
24303831d35Sstevel nulldev, /* identify */
24403831d35Sstevel nulldev, /* probe */
24503831d35Sstevel schpc_attach, /* attach */
24603831d35Sstevel schpc_detach, /* detach */
24703831d35Sstevel nodev, /* reset */
24803831d35Sstevel &schpc_cb_ops, /* driver operations */
24919397407SSherry Moore (struct bus_ops *)0, /* no bus operations */
25019397407SSherry Moore NULL, /* power */
25119397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */
25203831d35Sstevel };
25303831d35Sstevel
25403831d35Sstevel /*
25503831d35Sstevel * loadable module declarations:
25603831d35Sstevel */
25703831d35Sstevel static struct modldrv modldrv = {
25803831d35Sstevel &mod_driverops,
25919397407SSherry Moore "PCI Hot Plug Controller Driver (schpc)",
26003831d35Sstevel &schpc_dev_ops,
26103831d35Sstevel };
26203831d35Sstevel
26303831d35Sstevel static struct modlinkage modlinkage = {
26403831d35Sstevel MODREV_1,
26503831d35Sstevel (void *)&modldrv,
26603831d35Sstevel NULL
26703831d35Sstevel };
26803831d35Sstevel
26903831d35Sstevel int
_init(void)27003831d35Sstevel _init(void)
27103831d35Sstevel {
27203831d35Sstevel int ret;
27303831d35Sstevel int rv;
27403831d35Sstevel
27503831d35Sstevel SCHPC_DEBUG0(D_ATTACH, "_init() installing module");
27603831d35Sstevel
27703831d35Sstevel ret = ddi_soft_state_init(&per_schpc_state, sizeof (schpc_t), 1);
27803831d35Sstevel if (ret != 0) {
27903831d35Sstevel return (ret);
28003831d35Sstevel }
28103831d35Sstevel
28203831d35Sstevel /*
28303831d35Sstevel * Initialize Outgoing Mailbox.
28403831d35Sstevel */
28503831d35Sstevel ret = mboxsc_init(KEY_PCSC, MBOXSC_MBOX_OUT, NULL);
28603831d35Sstevel
28703831d35Sstevel if (ret != 0) {
28803831d35Sstevel ddi_soft_state_fini(&per_schpc_state);
28903831d35Sstevel return (ret);
29003831d35Sstevel }
29103831d35Sstevel
29203831d35Sstevel ret = mboxsc_ctrl(KEY_PCSC, MBOXSC_CMD_PUTMSG_TIMEOUT_RANGE,
29303831d35Sstevel (void *) &schpc_putmsg_timeout_range);
29403831d35Sstevel
29503831d35Sstevel if (ret != 0) {
29603831d35Sstevel ddi_soft_state_fini(&per_schpc_state);
29703831d35Sstevel return (ret);
29803831d35Sstevel }
29903831d35Sstevel
30003831d35Sstevel if (schpc_timeout_putmsg < schpc_putmsg_timeout_range.min_timeout) {
30103831d35Sstevel schpc_timeout_putmsg = schpc_putmsg_timeout_range.min_timeout;
30203831d35Sstevel cmn_err(CE_WARN, " schpc: resetting putmsg timeout to %ld\n",
30303831d35Sstevel schpc_timeout_putmsg);
30403831d35Sstevel }
30503831d35Sstevel
30603831d35Sstevel if (schpc_timeout_putmsg > schpc_putmsg_timeout_range.max_timeout) {
30703831d35Sstevel schpc_timeout_putmsg = schpc_putmsg_timeout_range.max_timeout;
30803831d35Sstevel cmn_err(CE_WARN, " schpc: resetting putmsg timeout to %ld\n",
30903831d35Sstevel schpc_timeout_putmsg);
31003831d35Sstevel }
31103831d35Sstevel
31203831d35Sstevel /*
31303831d35Sstevel * Create the schpc_event_taskq for MBOXSC_MSG_EVENT processing.
31403831d35Sstevel */
31503831d35Sstevel schpc_event_taskq = taskq_create("schpc_event_taskq", 2,
31603831d35Sstevel minclsyspri, 4, 4, TASKQ_PREPOPULATE);
31703831d35Sstevel
31803831d35Sstevel /*
31903831d35Sstevel * Initialize Incoming Mailbox.
32003831d35Sstevel * NOTE: the callback is null because the schpc_msg_thread will
32103831d35Sstevel * handle all incoming MBOXSC_MSG_EVENT and MBOXSC_MSG_REPLY
32203831d35Sstevel * messages.
32303831d35Sstevel */
32403831d35Sstevel ret = mboxsc_init(KEY_SCPC, MBOXSC_MBOX_IN, NULL);
32503831d35Sstevel
32603831d35Sstevel if (ret != 0) {
32703831d35Sstevel cmn_err(CE_WARN, "schpc: can not initialize KEY_SCPC as "
32803831d35Sstevel "MBOXSC_MBOX_IN");
32903831d35Sstevel ddi_soft_state_fini(&per_schpc_state);
33003831d35Sstevel return (ret);
33103831d35Sstevel }
33203831d35Sstevel
33303831d35Sstevel ret = mboxsc_ctrl(KEY_SCPC, MBOXSC_CMD_GETMSG_TIMEOUT_RANGE,
33403831d35Sstevel (void *) &schpc_getmsg_timeout_range);
33503831d35Sstevel
33603831d35Sstevel if (ret != 0) {
33703831d35Sstevel ddi_soft_state_fini(&per_schpc_state);
33803831d35Sstevel return (ret);
33903831d35Sstevel }
34003831d35Sstevel
34103831d35Sstevel if (schpc_timeout_getmsg < schpc_getmsg_timeout_range.min_timeout) {
34203831d35Sstevel schpc_timeout_getmsg = schpc_getmsg_timeout_range.min_timeout;
34303831d35Sstevel cmn_err(CE_WARN, " schpc: resetting getmsg timeout to %ld\n",
34403831d35Sstevel schpc_timeout_getmsg);
34503831d35Sstevel }
34603831d35Sstevel
34703831d35Sstevel if (schpc_timeout_getmsg > schpc_getmsg_timeout_range.max_timeout) {
34803831d35Sstevel schpc_timeout_getmsg = schpc_getmsg_timeout_range.max_timeout;
34903831d35Sstevel cmn_err(CE_WARN, " schpc: resetting putmsg timeout to %ld\n",
35003831d35Sstevel schpc_timeout_putmsg);
35103831d35Sstevel }
35203831d35Sstevel
35303831d35Sstevel if (schpc_timeout_event < schpc_getmsg_timeout_range.min_timeout) {
35403831d35Sstevel schpc_timeout_event = schpc_getmsg_timeout_range.min_timeout;
35503831d35Sstevel cmn_err(CE_WARN, " schpc: resetting event timeout to %ld\n",
35603831d35Sstevel schpc_timeout_event);
35703831d35Sstevel }
35803831d35Sstevel
35903831d35Sstevel if (schpc_timeout_event > schpc_getmsg_timeout_range.max_timeout) {
36003831d35Sstevel schpc_timeout_event = schpc_getmsg_timeout_range.max_timeout;
36103831d35Sstevel cmn_err(CE_WARN, " schpc: resetting event timeout to %ld\n",
36203831d35Sstevel schpc_timeout_event);
36303831d35Sstevel }
36403831d35Sstevel
36503831d35Sstevel ret = mod_install(&modlinkage);
36603831d35Sstevel if (ret != 0) {
36703831d35Sstevel if ((rv = mboxsc_fini(KEY_PCSC)) != 0) {
36803831d35Sstevel cmn_err(CE_WARN, "schpc: _init() - "
36903831d35Sstevel "mboxsc_fini(KEY_PCSC) failed: 0x%x", rv);
37003831d35Sstevel }
37103831d35Sstevel if ((rv = mboxsc_fini(KEY_SCPC)) != 0) {
37203831d35Sstevel cmn_err(CE_WARN, "schpc: _init() - "
37303831d35Sstevel "mboxsc_fini(KEY_SCPC) failed: 0x%x", rv);
37403831d35Sstevel }
37503831d35Sstevel taskq_destroy(schpc_event_taskq);
37603831d35Sstevel ddi_soft_state_fini(&per_schpc_state);
37703831d35Sstevel return (ret);
37803831d35Sstevel }
37903831d35Sstevel
38003831d35Sstevel SCHPC_DEBUG0(D_ATTACH, "_init() module installed");
38103831d35Sstevel
38203831d35Sstevel /*
38303831d35Sstevel * Start the schpc_msg_thread to continuously monitor the
38403831d35Sstevel * MBOXSC_MBOX_IN mailbox for incoming MBOXSC_MSG_EVENTs and
38503831d35Sstevel * MBOXSC_MSG_REPLYs.
38603831d35Sstevel */
38703831d35Sstevel mutex_init(&schpc_replylist_mutex, NULL, MUTEX_DRIVER, NULL);
38803831d35Sstevel (void) thread_create(NULL, 0, schpc_msg_thread,
38903831d35Sstevel NULL, 0, &p0, TS_RUN, minclsyspri);
39003831d35Sstevel
39103831d35Sstevel SCHPC_DEBUG0(D_ATTACH, "_init() started schpc_msg_thread");
39203831d35Sstevel
39303831d35Sstevel return (ret);
39403831d35Sstevel }
39503831d35Sstevel
39603831d35Sstevel int
_fini(void)39703831d35Sstevel _fini(void)
39803831d35Sstevel {
39903831d35Sstevel SCHPC_DEBUG0(D_ATTACH, "_fini()");
40003831d35Sstevel
40103831d35Sstevel return (DDI_FAILURE);
40203831d35Sstevel }
40303831d35Sstevel
40403831d35Sstevel int
_info(struct modinfo * modinfop)40503831d35Sstevel _info(struct modinfo *modinfop)
40603831d35Sstevel {
40703831d35Sstevel SCHPC_DEBUG0(D_ATTACH, "_info() called.");
40803831d35Sstevel
40903831d35Sstevel return (mod_info(&modlinkage, modinfop));
41003831d35Sstevel }
41103831d35Sstevel
41203831d35Sstevel static int
schpc_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)41303831d35Sstevel schpc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
41403831d35Sstevel {
41503831d35Sstevel int instance = ddi_get_instance(devi);
41603831d35Sstevel int rval;
41703831d35Sstevel
41803831d35Sstevel SCHPC_DEBUG1(D_ATTACH, "attach(%x) ATTACH", instance);
41903831d35Sstevel
42003831d35Sstevel switch (cmd) {
42103831d35Sstevel case DDI_ATTACH:
42203831d35Sstevel
42303831d35Sstevel /*
42403831d35Sstevel * Allocate the soft state structure for this instance.
42503831d35Sstevel */
42603831d35Sstevel rval = ddi_soft_state_zalloc(per_schpc_state, instance);
42703831d35Sstevel
42803831d35Sstevel if (rval != DDI_SUCCESS) {
42903831d35Sstevel SCHPC_DEBUG1(D_ATTACH,
43003831d35Sstevel "schpc_attach(%x) Can not allocate "
43103831d35Sstevel "soft state structure", instance);
43203831d35Sstevel return (DDI_FAILURE);
43303831d35Sstevel }
43403831d35Sstevel
43503831d35Sstevel schpc_p = (schpc_t *)ddi_get_soft_state(per_schpc_state,
43603831d35Sstevel instance);
43703831d35Sstevel
43803831d35Sstevel if (schpc_p == NULL) {
43903831d35Sstevel return (DDI_FAILURE);
44003831d35Sstevel }
44103831d35Sstevel
44203831d35Sstevel mutex_init(&schpc_p->schpc_mutex, NULL, MUTEX_DRIVER, NULL);
44303831d35Sstevel cv_init(&schpc_p->schpc_cv, NULL, CV_DRIVER, NULL);
44403831d35Sstevel
44503831d35Sstevel /*
44603831d35Sstevel * Put schpc structure on global linked list.
44703831d35Sstevel */
44803831d35Sstevel
44903831d35Sstevel /*
45003831d35Sstevel * Initialize starting transaction ID.
45103831d35Sstevel */
45203831d35Sstevel schpc_p->schpc_transid = 0;
45303831d35Sstevel
45403831d35Sstevel schpc_p->schpc_number_of_slots = STARCAT_MAX_SLOTS;
45503831d35Sstevel
45603831d35Sstevel SCHPC_DEBUG2(D_ATTACH, "schpc_attach(%x) slot-table property "
45703831d35Sstevel "describes %d slots", instance,
45803831d35Sstevel schpc_p->schpc_number_of_slots);
45903831d35Sstevel
46003831d35Sstevel schpc_p->schpc_hotplugmodel = ddi_getprop(DDI_DEV_T_ANY,
46103831d35Sstevel devi, 0, "hot-plug-model", SCHPC_HOTPLUGTYPE_CPCIHOTPLUG);
46203831d35Sstevel
46303831d35Sstevel SCHPC_DEBUG2(D_ATTACH, "attach(%x) ATTACH - Hot Plug Model=%x",
46403831d35Sstevel instance, schpc_p->schpc_hotplugmodel);
46503831d35Sstevel
46603831d35Sstevel /*
46703831d35Sstevel * What type of hot plug do these slots support? The only
46803831d35Sstevel * types of slots we support is the cPCI Hot Plug Model
46903831d35Sstevel * and Not Hot Pluggable.
47003831d35Sstevel */
47103831d35Sstevel if (schpc_p->schpc_hotplugmodel !=
47203831d35Sstevel SCHPC_HOTPLUGTYPE_CPCIHOTPLUG) {
47303831d35Sstevel schpc_p->schpc_hotplugmodel =
47403831d35Sstevel SCHPC_HOTPLUGTYPE_NOTHOTPLUGGABLE;
47503831d35Sstevel }
47603831d35Sstevel
47703831d35Sstevel schpc_p->schpc_slot = (schpc_slot_t *)kmem_zalloc((size_t)
47803831d35Sstevel (schpc_p->schpc_number_of_slots * sizeof (schpc_slot_t)),
47903831d35Sstevel KM_SLEEP);
48003831d35Sstevel
48103831d35Sstevel schpc_p->schpc_devi = devi;
48203831d35Sstevel schpc_p->schpc_instance = instance;
48303831d35Sstevel
48403831d35Sstevel /*
48503831d35Sstevel * Start thread to search the device tree and register
48603831d35Sstevel * all found pci slots.
48703831d35Sstevel */
48803831d35Sstevel (void) thread_create(NULL, 0, schpc_register_all_slots,
48903831d35Sstevel (void *)schpc_p, 0, &p0, TS_RUN, minclsyspri);
49003831d35Sstevel
49103831d35Sstevel break;
49203831d35Sstevel
49303831d35Sstevel case DDI_PM_RESUME:
49403831d35Sstevel case DDI_RESUME:
49503831d35Sstevel return (DDI_SUCCESS);
49603831d35Sstevel default:
49703831d35Sstevel cmn_err(CE_WARN, "schpc%d: Cmd != DDI_ATTACH/DDI_RESUME",
49803831d35Sstevel instance);
49903831d35Sstevel
50003831d35Sstevel return (DDI_FAILURE);
50103831d35Sstevel }
50203831d35Sstevel
50303831d35Sstevel SCHPC_DEBUG1(D_ATTACH,
50403831d35Sstevel "schpc_attach(%x) Attach - DDI_SUCCESS", instance);
50503831d35Sstevel
50603831d35Sstevel return (DDI_SUCCESS);
50703831d35Sstevel }
50803831d35Sstevel
50903831d35Sstevel /*ARGSUSED*/
51003831d35Sstevel static int
schpc_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)51103831d35Sstevel schpc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
51203831d35Sstevel {
51303831d35Sstevel int instance = ddi_get_instance(devi);
51403831d35Sstevel
51503831d35Sstevel SCHPC_DEBUG1(D_DETACH, "detach(%x) DETACH", instance);
51603831d35Sstevel
51703831d35Sstevel return (DDI_FAILURE);
51803831d35Sstevel }
51903831d35Sstevel
52003831d35Sstevel /*ARGSUSED*/
52103831d35Sstevel static int
schpc_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)52203831d35Sstevel schpc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
52303831d35Sstevel void **result)
52403831d35Sstevel {
52503831d35Sstevel int error;
52603831d35Sstevel
52703831d35Sstevel switch (infocmd) {
52803831d35Sstevel case DDI_INFO_DEVT2DEVINFO:
52903831d35Sstevel *result = (void *)schpc_devi;
53003831d35Sstevel error = DDI_SUCCESS;
53103831d35Sstevel break;
53203831d35Sstevel case DDI_INFO_DEVT2INSTANCE:
53303831d35Sstevel *result = (void *)0;
53403831d35Sstevel error = DDI_SUCCESS;
53503831d35Sstevel break;
53603831d35Sstevel default:
53703831d35Sstevel error = DDI_FAILURE;
53803831d35Sstevel }
53903831d35Sstevel return (error);
54003831d35Sstevel }
54103831d35Sstevel
54203831d35Sstevel /*
54303831d35Sstevel * schpc_connect()
54403831d35Sstevel *
54503831d35Sstevel * Called by Hot Plug Services to connect a slot to the bus.
54603831d35Sstevel */
54703831d35Sstevel
54803831d35Sstevel /*ARGSUSED*/
54903831d35Sstevel static int
schpc_connect(caddr_t ops_arg,hpc_slot_t slot_hdl,void * data,uint_t flags)55003831d35Sstevel schpc_connect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data, uint_t flags)
55103831d35Sstevel {
55203831d35Sstevel int rval;
55303831d35Sstevel int expander, board;
55403831d35Sstevel pci_setslot_t setslot;
55503831d35Sstevel pci_getslot_t getslot;
55603831d35Sstevel int slot;
55703831d35Sstevel
55803831d35Sstevel SCHPC_DEBUG2(D_IOC_CONNECT, "schpc_connect( ops_arg=%p slot_hdl=%p)",
559*07d06da5SSurya Prakki (void *)ops_arg, (void *)slot_hdl);
56003831d35Sstevel
56103831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
56203831d35Sstevel
56303831d35Sstevel slot = schpc_slot_get_index(schpc_p, slot_hdl);
56403831d35Sstevel
56503831d35Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
56603831d35Sstevel SCHPC_DEBUG0(D_IOC_CONNECT, "schpc_connect - HPC Not Inited");
56703831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
56803831d35Sstevel return (HPC_ERR_FAILED);
56903831d35Sstevel }
57003831d35Sstevel
57103831d35Sstevel /*
57203831d35Sstevel * Check to see if the slot is already connected.
57303831d35Sstevel */
57403831d35Sstevel if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_CONNECTED) {
57503831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
57603831d35Sstevel return (0);
57703831d35Sstevel }
57803831d35Sstevel
57903831d35Sstevel /*
58003831d35Sstevel * Block if another thread is executing a HPC command.
58103831d35Sstevel */
58203831d35Sstevel while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
58303831d35Sstevel cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
58403831d35Sstevel }
58503831d35Sstevel
58603831d35Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
58703831d35Sstevel
58803831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
58903831d35Sstevel
59003831d35Sstevel expander = schpc_p->schpc_slot[slot].expander; /* get expander */
59103831d35Sstevel board = schpc_p->schpc_slot[slot].board; /* get board */
59203831d35Sstevel
59303831d35Sstevel SCHPC_DEBUG3(D_IOC_CONNECT,
59403831d35Sstevel "schpc_connect Expander=%x Board=%x Slot=%x",
59503831d35Sstevel expander, board, SCHPC_SLOT_NUM(slot));
59603831d35Sstevel
59703831d35Sstevel
59803831d35Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_OCC_GOOD)) {
59903831d35Sstevel cmn_err(CE_WARN, "schpc: Hot Plug - Unable to complete "
60003831d35Sstevel "connection on Expander %d Board %d Slot %d - "
60103831d35Sstevel "Ap_Id=%s : Occupant is in failed state",
60203831d35Sstevel expander, board, SCHPC_SLOT_NUM(slot),
60303831d35Sstevel schpc_p->schpc_slot[slot].ap_id);
60403831d35Sstevel
60503831d35Sstevel /* Fault LED should already be illuminated */
60603831d35Sstevel
60703831d35Sstevel goto failed;
60803831d35Sstevel }
60903831d35Sstevel
61003831d35Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_REC_GOOD)) {
61103831d35Sstevel cmn_err(CE_WARN, "schpc: Hot Plug - Unable to complete "
61203831d35Sstevel "connection on Expander %d Board %d Slot %d - "
61303831d35Sstevel "Ap_Id=%s : Receptacle is in failed state",
61403831d35Sstevel expander, board, SCHPC_SLOT_NUM(slot),
61503831d35Sstevel schpc_p->schpc_slot[slot].ap_id);
61603831d35Sstevel
61703831d35Sstevel /* Fault LED should already be illuminated */
61803831d35Sstevel
61903831d35Sstevel goto failed;
62003831d35Sstevel }
62103831d35Sstevel
62203831d35Sstevel rval = schpc_getslotstatus(expander, board, slot, &getslot);
62303831d35Sstevel
62403831d35Sstevel if (rval) {
62503831d35Sstevel /*
62603831d35Sstevel * System Controller/Mailbox failure.
62703831d35Sstevel */
62803831d35Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on "
62903831d35Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
63003831d35Sstevel "Communicate with System Controller", expander, board,
63103831d35Sstevel SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
63203831d35Sstevel
63303831d35Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
63403831d35Sstevel
63503831d35Sstevel goto failed;
63603831d35Sstevel }
63703831d35Sstevel
63803831d35Sstevel if (getslot.slot_replystatus != PCIMSG_REPLY_GOOD) {
63903831d35Sstevel
64003831d35Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on "
64103831d35Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
64203831d35Sstevel "Read Slot Status", expander, board,
64303831d35Sstevel SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
64403831d35Sstevel
64503831d35Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
64603831d35Sstevel
64703831d35Sstevel goto failed;
64803831d35Sstevel }
64903831d35Sstevel
65003831d35Sstevel if (getslot.slot_empty) {
65103831d35Sstevel /*
65203831d35Sstevel * If the slot is empty - fail the connection request.
65303831d35Sstevel */
65403831d35Sstevel goto failed;
65503831d35Sstevel }
65603831d35Sstevel
65703831d35Sstevel SCHPC_DEBUG3(D_FREQCHG, "Slot %d - slot_freq_setting %d "
65803831d35Sstevel "slot_freq_cap %d", slot, getslot.slot_freq_setting,
65903831d35Sstevel getslot.slot_freq_cap);
66003831d35Sstevel
66103831d35Sstevel if (!schpc_is_freq_switchable(slot) &&
66203831d35Sstevel (getslot.slot_freq_setting > getslot.slot_freq_cap)) {
66303831d35Sstevel
66403831d35Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
66503831d35Sstevel "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
66603831d35Sstevel "Bus Speed Mismatch", expander,
66703831d35Sstevel board, SCHPC_SLOT_NUM(slot),
66803831d35Sstevel schpc_p->schpc_slot[slot].ap_id);
66903831d35Sstevel
67003831d35Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
67103831d35Sstevel
67203831d35Sstevel goto failed;
67303831d35Sstevel }
67403831d35Sstevel
67503831d35Sstevel if (schpc_is_leaf_reset_required(slot) &&
67603831d35Sstevel (schpc_p->schpc_slot[slot].saved_regs == NULL)) {
67703831d35Sstevel
67803831d35Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Save Regs before connect",
67903831d35Sstevel slot);
68003831d35Sstevel
68103831d35Sstevel /*
68203831d35Sstevel * A prior disconnect had not saved off the leaf so lets
68303831d35Sstevel * save it now. This is probably due to the domain being
68403831d35Sstevel * booted with a slot with no cassette.
68503831d35Sstevel */
68603831d35Sstevel if (schpc_save_leaf(slot) != 0) {
68703831d35Sstevel cmn_err(CE_WARN, "schpc - Unable to save leaf regs on "
68803831d35Sstevel
68903831d35Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : ",
69003831d35Sstevel expander, board, slot & 3,
69103831d35Sstevel schpc_p->schpc_slot[slot].ap_id);
69203831d35Sstevel
69303831d35Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
69403831d35Sstevel
69503831d35Sstevel goto failed;
69603831d35Sstevel }
69703831d35Sstevel }
69803831d35Sstevel
69903831d35Sstevel /*
70003831d35Sstevel * Initialize Set Slot Command.
70103831d35Sstevel */
70203831d35Sstevel schpc_init_setslot_message(&setslot);
70303831d35Sstevel
70403831d35Sstevel setslot.slot_power_on = PCIMSG_ON; /* Turn slot power on */
70503831d35Sstevel
70603831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH; /* Flash Fault LED */
70703831d35Sstevel
70803831d35Sstevel rval = schpc_setslotstatus(expander, board, slot, &setslot);
70903831d35Sstevel
71003831d35Sstevel if (rval != 0) {
71103831d35Sstevel /*
71203831d35Sstevel * System Controller/Mailbox failure.
71303831d35Sstevel */
71403831d35Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on "
71503831d35Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
71603831d35Sstevel "Communicate with System Controller", expander, board,
71703831d35Sstevel SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
71803831d35Sstevel
71903831d35Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
72003831d35Sstevel
72103831d35Sstevel goto failed;
72203831d35Sstevel }
72303831d35Sstevel
72403831d35Sstevel if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) {
72503831d35Sstevel
72603831d35Sstevel /*
72703831d35Sstevel * The Request was successfully completed.
72803831d35Sstevel */
72903831d35Sstevel
73003831d35Sstevel SCHPC_DEBUG0(D_IOC_CONNECT, "schpc_connect() - setslotstatus "
73103831d35Sstevel "succeeded");
73203831d35Sstevel
73303831d35Sstevel /*
73403831d35Sstevel * Need to check HEALTHY# signal.
73503831d35Sstevel */
73603831d35Sstevel rval = schpc_getslotstatus(expander, board, slot, &getslot);
73703831d35Sstevel
73803831d35Sstevel if (rval) {
73903831d35Sstevel /*
74003831d35Sstevel * System Controller/Mailbox failure.
74103831d35Sstevel */
74203831d35Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
74303831d35Sstevel "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
74403831d35Sstevel "Unable to Communicate with System Controller",
74503831d35Sstevel expander, board, SCHPC_SLOT_NUM(slot),
74603831d35Sstevel schpc_p->schpc_slot[slot].ap_id);
74703831d35Sstevel
74803831d35Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
74903831d35Sstevel
75003831d35Sstevel goto failed;
75103831d35Sstevel }
75203831d35Sstevel
75303831d35Sstevel if (getslot.slot_replystatus != PCIMSG_REPLY_GOOD) {
75403831d35Sstevel
75503831d35Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
75603831d35Sstevel "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
75703831d35Sstevel "Unable to Read Slot Status", expander, board,
75803831d35Sstevel SCHPC_SLOT_NUM(slot),
75903831d35Sstevel schpc_p->schpc_slot[slot].ap_id);
76003831d35Sstevel
76103831d35Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
76203831d35Sstevel
76303831d35Sstevel goto failed;
76403831d35Sstevel }
76503831d35Sstevel
76603831d35Sstevel if ((getslot.slot_powergood != PCIMSG_ON) ||
76703831d35Sstevel (getslot.slot_powerfault == PCIMSG_ON)) {
76803831d35Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
76903831d35Sstevel "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
77003831d35Sstevel "Power failure detected", expander, board,
77103831d35Sstevel SCHPC_SLOT_NUM(slot),
77203831d35Sstevel schpc_p->schpc_slot[slot].ap_id);
77303831d35Sstevel
77403831d35Sstevel /*
77503831d35Sstevel * Initialize Set Slot Command.
77603831d35Sstevel */
77703831d35Sstevel schpc_init_setslot_message(&setslot);
77803831d35Sstevel
77903831d35Sstevel /*
78003831d35Sstevel * Turn slot power off.
78103831d35Sstevel */
78203831d35Sstevel setslot.slot_power_off = PCIMSG_ON;
78303831d35Sstevel
78403831d35Sstevel (void) schpc_setslotstatus(expander, board,
78503831d35Sstevel slot, &setslot);
78603831d35Sstevel
78703831d35Sstevel schpc_setslotled(expander, board, slot,
78803831d35Sstevel (SERVICE_LED_ON | FAULT_LED_ON));
78903831d35Sstevel
79003831d35Sstevel goto failed;
79103831d35Sstevel }
79203831d35Sstevel
79303831d35Sstevel if (!getslot.slot_HEALTHY) {
79403831d35Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
79503831d35Sstevel "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
79603831d35Sstevel "Adapter did not assert HEALTHY#", expander, board,
79703831d35Sstevel SCHPC_SLOT_NUM(slot),
79803831d35Sstevel schpc_p->schpc_slot[slot].ap_id);
79903831d35Sstevel
80003831d35Sstevel /*
80103831d35Sstevel * Initialize Set Slot Command.
80203831d35Sstevel */
80303831d35Sstevel schpc_init_setslot_message(&setslot);
80403831d35Sstevel
80503831d35Sstevel /*
80603831d35Sstevel * Turn slot power off.
80703831d35Sstevel */
80803831d35Sstevel setslot.slot_power_off = PCIMSG_ON;
80903831d35Sstevel
81003831d35Sstevel (void) schpc_setslotstatus(expander, board, slot,
81103831d35Sstevel &setslot);
81203831d35Sstevel
81303831d35Sstevel schpc_setslotled(expander, board, slot,
81403831d35Sstevel (SERVICE_LED_ON | FAULT_LED_ON));
81503831d35Sstevel
81603831d35Sstevel goto failed;
81703831d35Sstevel }
81803831d35Sstevel
81903831d35Sstevel /*
82003831d35Sstevel * Initialize Set Slot Command.
82103831d35Sstevel */
82203831d35Sstevel schpc_init_setslot_message(&setslot);
82303831d35Sstevel
82403831d35Sstevel /*
82503831d35Sstevel * Start monitoring ENUM# and HEALTHY#
82603831d35Sstevel */
82703831d35Sstevel setslot.slot_enable_HEALTHY = PCIMSG_ON;
82803831d35Sstevel setslot.slot_enable_ENUM = PCIMSG_ON;
82903831d35Sstevel
83003831d35Sstevel rval = schpc_setslotstatus(expander, board, slot, &setslot);
83103831d35Sstevel
83203831d35Sstevel if (rval != 0) {
83303831d35Sstevel /*
83403831d35Sstevel * System Controller/Mailbox failure.
83503831d35Sstevel */
83603831d35Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
83703831d35Sstevel "on Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
83803831d35Sstevel "Unable to Communicate with System Controller",
83903831d35Sstevel expander, board, SCHPC_SLOT_NUM(slot),
84003831d35Sstevel schpc_p->schpc_slot[slot].ap_id);
84103831d35Sstevel
84203831d35Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
84303831d35Sstevel
84403831d35Sstevel goto failed;
84503831d35Sstevel }
84603831d35Sstevel if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) {
84703831d35Sstevel
84803831d35Sstevel int freq;
84903831d35Sstevel find_dev_t find_dev;
85003831d35Sstevel
85103831d35Sstevel /*
85203831d35Sstevel * The Request was successfully completed.
85303831d35Sstevel */
85403831d35Sstevel
85503831d35Sstevel SCHPC_DEBUG0(D_IOC_CONNECT,
85603831d35Sstevel "schpc_connect() - setslotstatus succeeded");
85703831d35Sstevel
85803831d35Sstevel schpc_p->schpc_slot[slot].state |=
85903831d35Sstevel SCHPC_SLOTSTATE_CONNECTED;
86003831d35Sstevel
86103831d35Sstevel schpc_setslotled(expander, board, slot,
86203831d35Sstevel (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_OFF));
86303831d35Sstevel
86403831d35Sstevel find_dev.cname = schpc_p->schpc_slot[slot].nexus_path;
86503831d35Sstevel find_dev.caddr = (char *)kmem_alloc(MAXPATHLEN,
86603831d35Sstevel KM_SLEEP);
86703831d35Sstevel find_dev.dip = NULL;
86803831d35Sstevel
86903831d35Sstevel /* root node doesn't have to be held */
87003831d35Sstevel ddi_walk_devs(ddi_root_node(), schpc_find_dip,
87103831d35Sstevel &find_dev);
87203831d35Sstevel if (find_dev.dip != NULL) {
87303831d35Sstevel /*
87403831d35Sstevel * Update the clock-frequency property to
87503831d35Sstevel * reflect the new slot-frequency.
87603831d35Sstevel */
87703831d35Sstevel freq = schpc_slot_freq(&getslot);
87803831d35Sstevel SCHPC_DEBUG2(D_FREQCHG,
87903831d35Sstevel "schpc_connect: updating dip=%p freq=%dHZ",
880*07d06da5SSurya Prakki (void *)find_dev.dip, freq);
88103831d35Sstevel if (ndi_prop_update_int(DDI_DEV_T_NONE,
88203831d35Sstevel find_dev.dip, "clock-frequency", freq)
88303831d35Sstevel != DDI_SUCCESS) {
88403831d35Sstevel cmn_err(CE_WARN,
88503831d35Sstevel "schpc: - failed to update "
88603831d35Sstevel "clock-frequency property for %s",
88703831d35Sstevel find_dev.cname);
88803831d35Sstevel }
88903831d35Sstevel ndi_rele_devi(find_dev.dip);
89003831d35Sstevel } else {
89103831d35Sstevel cmn_err(CE_WARN,
89203831d35Sstevel "schpc: couldn't find dip for %s ",
89303831d35Sstevel find_dev.cname);
89403831d35Sstevel }
89503831d35Sstevel kmem_free(find_dev.caddr, MAXPATHLEN);
89603831d35Sstevel
89703831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
89803831d35Sstevel schpc_p->schpc_slot[slot].state &=
89903831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
90003831d35Sstevel
90103831d35Sstevel /*
90203831d35Sstevel * If leaf registers were saved off, then they
90303831d35Sstevel * need to be restored.
90403831d35Sstevel */
90503831d35Sstevel schpc_restore_leaf(slot);
90603831d35Sstevel
90703831d35Sstevel /*
90803831d35Sstevel * Since the device saw a PCI Reset, we need to
90903831d35Sstevel * wait 2^25 clock cycles before the first
91003831d35Sstevel * Configuration access. The worst case is 33MHz,
91103831d35Sstevel * which is a 1 second wait.
91203831d35Sstevel */
91303831d35Sstevel drv_usecwait(1000000);
91403831d35Sstevel
91503831d35Sstevel cv_signal(&schpc_p->schpc_cv);
91603831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
91703831d35Sstevel
91803831d35Sstevel return (0);
91903831d35Sstevel } else {
92003831d35Sstevel /*
92103831d35Sstevel * The System Controller Rejected the
92203831d35Sstevel * connection request.
92303831d35Sstevel */
92403831d35Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed "
92503831d35Sstevel "on Expander %d Board %d PCI Slot %d - Ap_Id=%s :"
92603831d35Sstevel "System Controller failed connection request",
92703831d35Sstevel expander, board, SCHPC_SLOT_NUM(slot),
92803831d35Sstevel schpc_p->schpc_slot[slot].ap_id);
92903831d35Sstevel
93003831d35Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
93103831d35Sstevel
93203831d35Sstevel goto failed;
93303831d35Sstevel }
93403831d35Sstevel }
93503831d35Sstevel
93603831d35Sstevel /*
93703831d35Sstevel * The System Controller Rejected the connection request.
93803831d35Sstevel */
93903831d35Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Connection Failed on "
94003831d35Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : System Controller "
94103831d35Sstevel "failed connection request", expander, board, SCHPC_SLOT_NUM(slot),
94203831d35Sstevel schpc_p->schpc_slot[slot].ap_id);
94303831d35Sstevel
94403831d35Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
94503831d35Sstevel
94603831d35Sstevel failed:
94703831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
94803831d35Sstevel schpc_p->schpc_slot[slot].state &=
94903831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
95003831d35Sstevel cv_signal(&schpc_p->schpc_cv);
95103831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
95203831d35Sstevel
95303831d35Sstevel return (HPC_ERR_FAILED);
95403831d35Sstevel }
95503831d35Sstevel
95603831d35Sstevel /*
95703831d35Sstevel * schpc_disconnect()
95803831d35Sstevel *
95903831d35Sstevel * Called by Hot Plug Services to disconnect a slot to the bus.
96003831d35Sstevel */
96103831d35Sstevel
96203831d35Sstevel /*ARGSUSED*/
96303831d35Sstevel static int
schpc_disconnect(caddr_t ops_arg,hpc_slot_t slot_hdl,void * data,uint_t flags)96403831d35Sstevel schpc_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl, void *data,
96503831d35Sstevel uint_t flags)
96603831d35Sstevel {
96703831d35Sstevel int rval;
96803831d35Sstevel int expander, board, slot;
96903831d35Sstevel pci_setslot_t setslot;
97003831d35Sstevel
97103831d35Sstevel SCHPC_DEBUG2(D_IOC_CONNECT,
972*07d06da5SSurya Prakki "schpc_disconnect( ops_arg=%p slot_hdl=%p)", (void *)ops_arg,
973*07d06da5SSurya Prakki slot_hdl);
97403831d35Sstevel
97503831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
97603831d35Sstevel
97703831d35Sstevel slot = schpc_slot_get_index(schpc_p, slot_hdl);
97803831d35Sstevel
97903831d35Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
98003831d35Sstevel SCHPC_DEBUG0(D_IOC_CONNECT,
98103831d35Sstevel "schpc_disconnect - HPC Not Inited");
98203831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
98303831d35Sstevel return (HPC_ERR_FAILED);
98403831d35Sstevel }
98503831d35Sstevel
98603831d35Sstevel /*
98703831d35Sstevel * Check to see if we are already disconnected.
98803831d35Sstevel */
98903831d35Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_CONNECTED)) {
99003831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
99103831d35Sstevel return (0);
99203831d35Sstevel }
99303831d35Sstevel
99403831d35Sstevel /*
99503831d35Sstevel * Block if another thread is executing a HPC command.
99603831d35Sstevel */
99703831d35Sstevel while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
99803831d35Sstevel cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
99903831d35Sstevel }
100003831d35Sstevel
100103831d35Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
100203831d35Sstevel
100303831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
100403831d35Sstevel
100503831d35Sstevel expander = schpc_p->schpc_slot[slot].expander; /* get expander */
100603831d35Sstevel board = schpc_p->schpc_slot[slot].board; /* get board */
100703831d35Sstevel
100803831d35Sstevel /*
100903831d35Sstevel * If a leaf reset is going to be asserted due to a mode/freq.
101003831d35Sstevel * change, then the leaf registers of the XMITS bridge will need
101103831d35Sstevel * to be saved off prior to the connect.
101203831d35Sstevel */
101303831d35Sstevel if (schpc_is_leaf_reset_required(slot)) {
101403831d35Sstevel if (schpc_save_leaf(slot) != 0) {
101503831d35Sstevel
101603831d35Sstevel cmn_err(CE_WARN, "schpc - Unable to save leaf regs on "
101703831d35Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : ",
101803831d35Sstevel expander, board, slot & 3,
101903831d35Sstevel schpc_p->schpc_slot[slot].ap_id);
102003831d35Sstevel
102103831d35Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
102203831d35Sstevel
102303831d35Sstevel goto failed;
102403831d35Sstevel }
102503831d35Sstevel }
102603831d35Sstevel
102703831d35Sstevel /*
102803831d35Sstevel * Initialize Set Slot Command.
102903831d35Sstevel */
103003831d35Sstevel schpc_init_setslot_message(&setslot);
103103831d35Sstevel
103203831d35Sstevel setslot.slot_power_off = PCIMSG_ON; /* Turn Power Off */
103303831d35Sstevel
103403831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH; /* Flash the Fault LED */
103503831d35Sstevel
103603831d35Sstevel setslot.slot_disable_ENUM = PCIMSG_ON; /* Mask the ENUM# signal */
103703831d35Sstevel setslot.slot_disable_HEALTHY = PCIMSG_ON; /* Mask the HEALTHY# sig */
103803831d35Sstevel
103903831d35Sstevel rval = schpc_setslotstatus(expander, board, slot, &setslot);
104003831d35Sstevel
104103831d35Sstevel SCHPC_DEBUG1(D_IOC_CONNECT, "schpc_disconnect() - "
104203831d35Sstevel "setslotstatus returned 0x%x", rval);
104303831d35Sstevel
104403831d35Sstevel if (rval != 0) {
104503831d35Sstevel /*
104603831d35Sstevel * System Controller/Mailbox failure.
104703831d35Sstevel */
104803831d35Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Disconnection Failed on "
104903831d35Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
105003831d35Sstevel "Communicate with System Controller", expander, board,
105103831d35Sstevel SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
105203831d35Sstevel
105303831d35Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
105403831d35Sstevel
105503831d35Sstevel goto failed;
105603831d35Sstevel }
105703831d35Sstevel
105803831d35Sstevel SCHPC_DEBUG1(D_IOC_CONNECT, "schpc_disconnect() - "
105903831d35Sstevel "slot_replystatus returned 0x%x", setslot.slot_replystatus);
106003831d35Sstevel
106103831d35Sstevel if (setslot.slot_replystatus == PCIMSG_REPLY_GOOD) {
106203831d35Sstevel
106303831d35Sstevel /*
106403831d35Sstevel * The Request was successfully completed.
106503831d35Sstevel */
106603831d35Sstevel schpc_p->schpc_slot[slot].state &=
106703831d35Sstevel ~SCHPC_SLOTSTATE_CONNECTED;
106803831d35Sstevel
106903831d35Sstevel schpc_setslotled(expander, board, slot,
107003831d35Sstevel (POWER_LED_OFF | SERVICE_LED_ON | FAULT_LED_OFF));
107103831d35Sstevel
107203831d35Sstevel SCHPC_DEBUG0(D_IOC_CONNECT,
107303831d35Sstevel "schpc_disconnect() - setslotstatus succeeded");
107403831d35Sstevel
107503831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
107603831d35Sstevel schpc_p->schpc_slot[slot].state &=
107703831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
107803831d35Sstevel cv_signal(&schpc_p->schpc_cv);
107903831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
108003831d35Sstevel
108103831d35Sstevel return (0);
108203831d35Sstevel }
108303831d35Sstevel /*
108403831d35Sstevel * System Controller/Mailbox failure.
108503831d35Sstevel */
108603831d35Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Disconnection Failed on "
108703831d35Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : System Controller "
108803831d35Sstevel "failed disconnection request", expander, board,
108903831d35Sstevel SCHPC_SLOT_NUM(slot),
109003831d35Sstevel schpc_p->schpc_slot[slot].ap_id);
109103831d35Sstevel
109203831d35Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
109303831d35Sstevel
109403831d35Sstevel failed:
109503831d35Sstevel schpc_restore_leaf(slot);
109603831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
109703831d35Sstevel schpc_p->schpc_slot[slot].state &=
109803831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
109903831d35Sstevel cv_signal(&schpc_p->schpc_cv);
110003831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
110103831d35Sstevel
110203831d35Sstevel return (HPC_ERR_FAILED);
110303831d35Sstevel }
110403831d35Sstevel
110503831d35Sstevel /*
110603831d35Sstevel * schpc_cpci_control
110703831d35Sstevel *
110803831d35Sstevel * Called by Hot Plug Services to perform a attachment point specific
110903831d35Sstevel * on a Hot Pluggable Compact PCI Slot.
111003831d35Sstevel */
111103831d35Sstevel /*ARGSUSED*/
111203831d35Sstevel static int
schpc_cpci_control(caddr_t ops_arg,hpc_slot_t slot_hdl,int request,caddr_t arg)111303831d35Sstevel schpc_cpci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request,
111403831d35Sstevel caddr_t arg)
111503831d35Sstevel {
111603831d35Sstevel int rval;
111703831d35Sstevel int expander, board, slot;
111803831d35Sstevel pci_setslot_t setslot;
111903831d35Sstevel pci_getslot_t slotstatus;
112003831d35Sstevel hpc_led_info_t *hpc_led_info;
112103831d35Sstevel
112203831d35Sstevel SCHPC_DEBUG3(D_IOC_CONTROL,
112303831d35Sstevel "schpc_cpci_control(op_args=%p slot_hdl=%p request=%x)",
1124*07d06da5SSurya Prakki (void *)ops_arg, (void *)slot_hdl, request);
112503831d35Sstevel
112603831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
112703831d35Sstevel
112803831d35Sstevel slot = schpc_slot_get_index(schpc_p, slot_hdl);
112903831d35Sstevel
113003831d35Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
113103831d35Sstevel SCHPC_DEBUG0(D_IOC_CONNECT,
113203831d35Sstevel "schpc_disconnect - HPC Not Inited");
113303831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
113403831d35Sstevel return (HPC_ERR_FAILED);
113503831d35Sstevel }
113603831d35Sstevel
113703831d35Sstevel /*
113803831d35Sstevel * Block if another thread is executing a HPC command.
113903831d35Sstevel */
114003831d35Sstevel while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
114103831d35Sstevel cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
114203831d35Sstevel }
114303831d35Sstevel
114403831d35Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
114503831d35Sstevel
114603831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
114703831d35Sstevel
114803831d35Sstevel expander = schpc_p->schpc_slot[slot].expander; /* get expander */
114903831d35Sstevel board = schpc_p->schpc_slot[slot].board; /* get board */
115003831d35Sstevel
115103831d35Sstevel /*
115203831d35Sstevel * Initialize Set Slot Command.
115303831d35Sstevel */
115403831d35Sstevel schpc_init_setslot_message(&setslot);
115503831d35Sstevel
115603831d35Sstevel /*
115703831d35Sstevel * Initialize LED to last know state.
115803831d35Sstevel */
115903831d35Sstevel switch (schpc_p->schpc_slot[slot].led.led_power) {
116003831d35Sstevel case LED_ON:
116103831d35Sstevel setslot.slot_led_power = PCIMSG_LED_ON;
116203831d35Sstevel break;
116303831d35Sstevel case LED_OFF:
116403831d35Sstevel setslot.slot_led_power = PCIMSG_LED_OFF;
116503831d35Sstevel break;
116603831d35Sstevel case LED_FLASH:
116703831d35Sstevel setslot.slot_led_power = PCIMSG_LED_FLASH;
116803831d35Sstevel break;
116903831d35Sstevel }
117003831d35Sstevel
117103831d35Sstevel switch (schpc_p->schpc_slot[slot].led.led_service) {
117203831d35Sstevel case LED_ON:
117303831d35Sstevel setslot.slot_led_service = PCIMSG_LED_ON;
117403831d35Sstevel break;
117503831d35Sstevel case LED_OFF:
117603831d35Sstevel setslot.slot_led_service = PCIMSG_LED_OFF;
117703831d35Sstevel break;
117803831d35Sstevel case LED_FLASH:
117903831d35Sstevel setslot.slot_led_service = PCIMSG_LED_FLASH;
118003831d35Sstevel break;
118103831d35Sstevel }
118203831d35Sstevel
118303831d35Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) {
118403831d35Sstevel case LED_ON:
118503831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_ON;
118603831d35Sstevel break;
118703831d35Sstevel case LED_OFF:
118803831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF;
118903831d35Sstevel break;
119003831d35Sstevel case LED_FLASH:
119103831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH;
119203831d35Sstevel break;
119303831d35Sstevel }
119403831d35Sstevel
119503831d35Sstevel switch (request) {
119603831d35Sstevel
119703831d35Sstevel case HPC_CTRL_GET_LED_STATE:
119803831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
119903831d35Sstevel "HPC_CTRL_GET_LED_STATE");
120003831d35Sstevel hpc_led_info = (hpc_led_info_t *)arg;
120103831d35Sstevel
120203831d35Sstevel switch (hpc_led_info->led) {
120303831d35Sstevel case HPC_FAULT_LED:
120403831d35Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) {
120503831d35Sstevel case LED_OFF:
120603831d35Sstevel hpc_led_info->state = HPC_LED_OFF;
120703831d35Sstevel break;
120803831d35Sstevel case LED_ON:
120903831d35Sstevel hpc_led_info->state = HPC_LED_ON;
121003831d35Sstevel break;
121103831d35Sstevel case LED_FLASH:
121203831d35Sstevel hpc_led_info->state = HPC_LED_BLINK;
121303831d35Sstevel break;
121403831d35Sstevel }
121503831d35Sstevel break;
121603831d35Sstevel
121703831d35Sstevel case HPC_POWER_LED:
121803831d35Sstevel switch (schpc_p->schpc_slot[slot].led.led_power) {
121903831d35Sstevel case LED_OFF:
122003831d35Sstevel hpc_led_info->state = HPC_LED_OFF;
122103831d35Sstevel break;
122203831d35Sstevel case LED_ON:
122303831d35Sstevel hpc_led_info->state = HPC_LED_ON;
122403831d35Sstevel break;
122503831d35Sstevel case LED_FLASH:
122603831d35Sstevel hpc_led_info->state = HPC_LED_BLINK;
122703831d35Sstevel break;
122803831d35Sstevel }
122903831d35Sstevel break;
123003831d35Sstevel case HPC_ATTN_LED:
123103831d35Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) {
123203831d35Sstevel case LED_OFF:
123303831d35Sstevel hpc_led_info->state = HPC_LED_OFF;
123403831d35Sstevel break;
123503831d35Sstevel case LED_ON:
123603831d35Sstevel hpc_led_info->state = HPC_LED_OFF;
123703831d35Sstevel break;
123803831d35Sstevel case LED_FLASH:
123903831d35Sstevel hpc_led_info->state = HPC_LED_ON;
124003831d35Sstevel break;
124103831d35Sstevel }
124203831d35Sstevel break;
124303831d35Sstevel case HPC_ACTIVE_LED:
124403831d35Sstevel switch (schpc_p->schpc_slot[slot].led.led_service) {
124503831d35Sstevel case LED_OFF:
124603831d35Sstevel hpc_led_info->state = HPC_LED_OFF;
124703831d35Sstevel break;
124803831d35Sstevel case LED_ON:
124903831d35Sstevel hpc_led_info->state = HPC_LED_ON;
125003831d35Sstevel break;
125103831d35Sstevel case LED_FLASH:
125203831d35Sstevel hpc_led_info->state = HPC_LED_BLINK;
125303831d35Sstevel break;
125403831d35Sstevel }
125503831d35Sstevel break;
125603831d35Sstevel default:
125703831d35Sstevel SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - "
125803831d35Sstevel "Invalid LED %x", hpc_led_info->led);
125903831d35Sstevel
126003831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
126103831d35Sstevel schpc_p->schpc_slot[slot].state &=
126203831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
126303831d35Sstevel cv_signal(&schpc_p->schpc_cv);
126403831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
126503831d35Sstevel
126603831d35Sstevel return (HPC_ERR_FAILED);
126703831d35Sstevel }
126803831d35Sstevel
126903831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
127003831d35Sstevel schpc_p->schpc_slot[slot].state &=
127103831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
127203831d35Sstevel cv_signal(&schpc_p->schpc_cv);
127303831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
127403831d35Sstevel
127503831d35Sstevel return (0);
127603831d35Sstevel
127703831d35Sstevel case HPC_CTRL_SET_LED_STATE:
127803831d35Sstevel hpc_led_info = (hpc_led_info_t *)arg;
127903831d35Sstevel
128003831d35Sstevel SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - "
1281*07d06da5SSurya Prakki "HPC_CTRL_SET_LED_STATE hpc_led_info=%p",
1282*07d06da5SSurya Prakki (void *)hpc_led_info);
128303831d35Sstevel
128403831d35Sstevel switch (hpc_led_info->led) {
128503831d35Sstevel case HPC_FAULT_LED:
128603831d35Sstevel switch (hpc_led_info->state) {
128703831d35Sstevel case HPC_LED_OFF:
128803831d35Sstevel schpc_p->schpc_slot[slot].led.led_fault =
128903831d35Sstevel LED_OFF;
129003831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF;
129103831d35Sstevel break;
129203831d35Sstevel case HPC_LED_ON:
129303831d35Sstevel schpc_p->schpc_slot[slot].led.led_fault =
129403831d35Sstevel LED_ON;
129503831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_ON;
129603831d35Sstevel break;
129703831d35Sstevel case HPC_LED_BLINK:
129803831d35Sstevel schpc_p->schpc_slot[slot].led.led_fault =
129903831d35Sstevel LED_FLASH;
130003831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH;
130103831d35Sstevel break;
130203831d35Sstevel }
130303831d35Sstevel break;
130403831d35Sstevel case HPC_POWER_LED:
130503831d35Sstevel switch (hpc_led_info->state) {
130603831d35Sstevel case HPC_LED_OFF:
130703831d35Sstevel schpc_p->schpc_slot[slot].led.led_power =
130803831d35Sstevel LED_OFF;
130903831d35Sstevel setslot.slot_led_power = PCIMSG_LED_OFF;
131003831d35Sstevel break;
131103831d35Sstevel case HPC_LED_ON:
131203831d35Sstevel schpc_p->schpc_slot[slot].led.led_power =
131303831d35Sstevel LED_ON;
131403831d35Sstevel setslot.slot_led_power = PCIMSG_LED_ON;
131503831d35Sstevel break;
131603831d35Sstevel case HPC_LED_BLINK:
131703831d35Sstevel schpc_p->schpc_slot[slot].led.led_power =
131803831d35Sstevel LED_FLASH;
131903831d35Sstevel setslot.slot_led_power = PCIMSG_LED_FLASH;
132003831d35Sstevel break;
132103831d35Sstevel }
132203831d35Sstevel break;
132303831d35Sstevel case HPC_ATTN_LED:
132403831d35Sstevel switch (hpc_led_info->state) {
132503831d35Sstevel case HPC_LED_OFF:
132603831d35Sstevel schpc_p->schpc_slot[slot].led.led_fault =
132703831d35Sstevel LED_OFF;
132803831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF;
132903831d35Sstevel break;
133003831d35Sstevel case HPC_LED_ON:
133103831d35Sstevel schpc_p->schpc_slot[slot].led.led_fault =
133203831d35Sstevel LED_FLASH;
133303831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH;
133403831d35Sstevel break;
133503831d35Sstevel case HPC_LED_BLINK:
133603831d35Sstevel schpc_p->schpc_slot[slot].led.led_fault =
133703831d35Sstevel LED_FLASH;
133803831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH;
133903831d35Sstevel break;
134003831d35Sstevel }
134103831d35Sstevel break;
134203831d35Sstevel case HPC_ACTIVE_LED:
134303831d35Sstevel switch (hpc_led_info->state) {
134403831d35Sstevel case HPC_LED_OFF:
134503831d35Sstevel schpc_p->schpc_slot[slot].led.led_service =
134603831d35Sstevel LED_OFF;
134703831d35Sstevel setslot.slot_led_service = PCIMSG_LED_OFF;
134803831d35Sstevel break;
134903831d35Sstevel case HPC_LED_ON:
135003831d35Sstevel schpc_p->schpc_slot[slot].led.led_service =
135103831d35Sstevel LED_ON;
135203831d35Sstevel setslot.slot_led_service = PCIMSG_LED_ON;
135303831d35Sstevel break;
135403831d35Sstevel case HPC_LED_BLINK:
135503831d35Sstevel schpc_p->schpc_slot[slot].led.led_service =
135603831d35Sstevel LED_FLASH;
135703831d35Sstevel setslot.slot_led_service = PCIMSG_LED_FLASH;
135803831d35Sstevel break;
135903831d35Sstevel }
136003831d35Sstevel break;
136103831d35Sstevel default:
136203831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
136303831d35Sstevel schpc_p->schpc_slot[slot].state &=
136403831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
136503831d35Sstevel cv_signal(&schpc_p->schpc_cv);
136603831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
136703831d35Sstevel
136803831d35Sstevel return (0);
136903831d35Sstevel }
137003831d35Sstevel
137103831d35Sstevel (void) schpc_setslotstatus(expander, board, slot, &setslot);
137203831d35Sstevel
137303831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
137403831d35Sstevel schpc_p->schpc_slot[slot].state &=
137503831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
137603831d35Sstevel cv_signal(&schpc_p->schpc_cv);
137703831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
137803831d35Sstevel
137903831d35Sstevel return (0);
138003831d35Sstevel
138103831d35Sstevel case HPC_CTRL_GET_SLOT_STATE: {
138203831d35Sstevel hpc_slot_state_t *hpc_slot_state;
138303831d35Sstevel
138403831d35Sstevel hpc_slot_state = (hpc_slot_state_t *)arg;
138503831d35Sstevel
138603831d35Sstevel SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_cpci_control() - "
138703831d35Sstevel "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=%p",
1388*07d06da5SSurya Prakki (void *)hpc_slot_state);
138903831d35Sstevel
139003831d35Sstevel rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
139103831d35Sstevel
139203831d35Sstevel if (!rval) {
139303831d35Sstevel
139403831d35Sstevel if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
139503831d35Sstevel return (HPC_ERR_FAILED);
139603831d35Sstevel }
139703831d35Sstevel
139803831d35Sstevel if (slotstatus.slot_empty == PCIMSG_ON) {
139903831d35Sstevel *hpc_slot_state = HPC_SLOT_EMPTY;
140003831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Empty");
140103831d35Sstevel } else if (slotstatus.slot_power_on == PCIMSG_ON) {
140203831d35Sstevel *hpc_slot_state = HPC_SLOT_CONNECTED;
140303831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Connected");
140403831d35Sstevel schpc_p->schpc_slot[slot].state |=
140503831d35Sstevel SCHPC_SLOTSTATE_CONNECTED;
140603831d35Sstevel } else {
140703831d35Sstevel *hpc_slot_state = HPC_SLOT_DISCONNECTED;
140803831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL,
140903831d35Sstevel "Slot Disconnected");
141003831d35Sstevel schpc_p->schpc_slot[slot].state &=
141103831d35Sstevel ~SCHPC_SLOTSTATE_CONNECTED;
141203831d35Sstevel }
141303831d35Sstevel } else {
141403831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "Mailbox Command failed");
141503831d35Sstevel
141603831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
141703831d35Sstevel schpc_p->schpc_slot[slot].state &=
141803831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
141903831d35Sstevel cv_signal(&schpc_p->schpc_cv);
142003831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
142103831d35Sstevel
142203831d35Sstevel return (HPC_ERR_FAILED);
142303831d35Sstevel }
142403831d35Sstevel
142503831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
142603831d35Sstevel schpc_p->schpc_slot[slot].state &=
142703831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
142803831d35Sstevel cv_signal(&schpc_p->schpc_cv);
142903831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
143003831d35Sstevel
143103831d35Sstevel return (0);
143203831d35Sstevel }
143303831d35Sstevel case HPC_CTRL_GET_BOARD_TYPE: {
143403831d35Sstevel hpc_board_type_t *hpc_board_type;
143503831d35Sstevel
143603831d35Sstevel hpc_board_type = (hpc_board_type_t *)arg;
143703831d35Sstevel
143803831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
143903831d35Sstevel "HPC_CTRL_GET_BOARD_TYPE");
144003831d35Sstevel
144103831d35Sstevel /*
144203831d35Sstevel * The HPC driver does not know what board type
144303831d35Sstevel * is plugged in.
144403831d35Sstevel */
144503831d35Sstevel *hpc_board_type = HPC_BOARD_CPCI_HS;
144603831d35Sstevel
144703831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
144803831d35Sstevel schpc_p->schpc_slot[slot].state &=
144903831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
145003831d35Sstevel cv_signal(&schpc_p->schpc_cv);
145103831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
145203831d35Sstevel
145303831d35Sstevel return (0);
145403831d35Sstevel
145503831d35Sstevel }
145603831d35Sstevel case HPC_CTRL_DEV_CONFIGURED:
145703831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
145803831d35Sstevel "HPC_CTRL_DEV_CONFIGURED");
145903831d35Sstevel
146003831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
146103831d35Sstevel schpc_p->schpc_slot[slot].state &=
146203831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
146303831d35Sstevel cv_signal(&schpc_p->schpc_cv);
146403831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
146503831d35Sstevel
146603831d35Sstevel return (0);
146703831d35Sstevel
146803831d35Sstevel case HPC_CTRL_DEV_UNCONFIGURED:
146903831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
147003831d35Sstevel "HPC_CTRL_DEV_UNCONFIGURED");
147103831d35Sstevel
147203831d35Sstevel if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_ENUM) {
147303831d35Sstevel /*
147403831d35Sstevel * When the occupant is unconfigured, power
147503831d35Sstevel * down the slot.
147603831d35Sstevel */
147703831d35Sstevel rval = schpc_disconnect((caddr_t)schpc_p,
147803831d35Sstevel schpc_p->schpc_slot[slot].slot_handle,
147903831d35Sstevel 0, 0);
148003831d35Sstevel
148103831d35Sstevel schpc_p->schpc_slot[slot].state &=
148203831d35Sstevel ~SCHPC_SLOTSTATE_ENUM;
148303831d35Sstevel }
148403831d35Sstevel
148503831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
148603831d35Sstevel schpc_p->schpc_slot[slot].state &=
148703831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
148803831d35Sstevel cv_signal(&schpc_p->schpc_cv);
148903831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
149003831d35Sstevel
149103831d35Sstevel return (0);
149203831d35Sstevel
149303831d35Sstevel case HPC_CTRL_ENABLE_AUTOCFG:
149403831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
149503831d35Sstevel "HPC_CTRL_ENABLE_AUTOCFG");
149603831d35Sstevel
149703831d35Sstevel schpc_p->schpc_slot[slot].state |=
149803831d35Sstevel SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
149903831d35Sstevel
150003831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
150103831d35Sstevel schpc_p->schpc_slot[slot].state &=
150203831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
150303831d35Sstevel cv_signal(&schpc_p->schpc_cv);
150403831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
150503831d35Sstevel
150603831d35Sstevel return (0);
150703831d35Sstevel
150803831d35Sstevel case HPC_CTRL_DISABLE_AUTOCFG:
150903831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
151003831d35Sstevel "HPC_CTRL_DISABLE_AUTOCFG");
151103831d35Sstevel schpc_p->schpc_slot[slot].state &=
151203831d35Sstevel ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
151303831d35Sstevel
151403831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
151503831d35Sstevel schpc_p->schpc_slot[slot].state &=
151603831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
151703831d35Sstevel cv_signal(&schpc_p->schpc_cv);
151803831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
151903831d35Sstevel
152003831d35Sstevel return (0);
152103831d35Sstevel
152203831d35Sstevel case HPC_CTRL_DISABLE_ENUM:
152303831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
152403831d35Sstevel "HPC_CTRL_DISABLE_ENUM");
152503831d35Sstevel
152603831d35Sstevel setslot.slot_disable_ENUM = PCIMSG_ON;
152703831d35Sstevel
152803831d35Sstevel rval = schpc_setslotstatus(expander, board, slot, &setslot);
152903831d35Sstevel
153003831d35Sstevel if (rval)
153103831d35Sstevel rval = HPC_ERR_FAILED;
153203831d35Sstevel
153303831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
153403831d35Sstevel schpc_p->schpc_slot[slot].state &=
153503831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
153603831d35Sstevel cv_signal(&schpc_p->schpc_cv);
153703831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
153803831d35Sstevel
153903831d35Sstevel return (rval);
154003831d35Sstevel
154103831d35Sstevel case HPC_CTRL_ENABLE_ENUM:
154203831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
154303831d35Sstevel "HPC_CTRL_ENABLE_ENUM");
154403831d35Sstevel
154503831d35Sstevel setslot.slot_enable_ENUM = PCIMSG_ON;
154603831d35Sstevel
154703831d35Sstevel rval = schpc_setslotstatus(expander, board, slot, &setslot);
154803831d35Sstevel
154903831d35Sstevel if (rval)
155003831d35Sstevel rval = HPC_ERR_FAILED;
155103831d35Sstevel
155203831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
155303831d35Sstevel schpc_p->schpc_slot[slot].state &=
155403831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
155503831d35Sstevel cv_signal(&schpc_p->schpc_cv);
155603831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
155703831d35Sstevel
155803831d35Sstevel return (rval);
155903831d35Sstevel
156003831d35Sstevel default:
156103831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_cpci_control() - "
156203831d35Sstevel "****NOT SUPPORTED CONTROL CMD");
156303831d35Sstevel
156403831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
156503831d35Sstevel schpc_p->schpc_slot[slot].state &=
156603831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
156703831d35Sstevel cv_signal(&schpc_p->schpc_cv);
156803831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
156903831d35Sstevel
157003831d35Sstevel return (HPC_ERR_NOTSUPPORTED);
157103831d35Sstevel }
157203831d35Sstevel }
157303831d35Sstevel
157403831d35Sstevel /*
157503831d35Sstevel * schpc_pci_control
157603831d35Sstevel *
157703831d35Sstevel * Called by Hot Plug Services to perform a attachment point specific
157803831d35Sstevel * on a Hot Pluggable Standard PCI Slot.
157903831d35Sstevel */
158003831d35Sstevel /*ARGSUSED*/
158103831d35Sstevel static int
schpc_pci_control(caddr_t ops_arg,hpc_slot_t slot_hdl,int request,caddr_t arg)158203831d35Sstevel schpc_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request,
158303831d35Sstevel caddr_t arg)
158403831d35Sstevel {
158503831d35Sstevel int rval;
158603831d35Sstevel int expander, board, slot;
158703831d35Sstevel pci_setslot_t setslot;
158803831d35Sstevel pci_getslot_t slotstatus;
158903831d35Sstevel hpc_led_info_t *hpc_led_info;
159003831d35Sstevel
159103831d35Sstevel SCHPC_DEBUG3(D_IOC_CONTROL,
159203831d35Sstevel "schpc_pci_control(op_args=%p slot_hdl=%p request=%x)",
1593*07d06da5SSurya Prakki (void *)ops_arg, (void *)slot_hdl, request);
159403831d35Sstevel
159503831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
159603831d35Sstevel
159703831d35Sstevel slot = schpc_slot_get_index(schpc_p, slot_hdl);
159803831d35Sstevel
159903831d35Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
160003831d35Sstevel SCHPC_DEBUG0(D_IOC_CONNECT,
160103831d35Sstevel "schpc_disconnect - HPC Not Inited");
160203831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
160303831d35Sstevel return (HPC_ERR_FAILED);
160403831d35Sstevel }
160503831d35Sstevel
160603831d35Sstevel /*
160703831d35Sstevel * Block if another thread is executing a HPC command.
160803831d35Sstevel */
160903831d35Sstevel while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
161003831d35Sstevel cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
161103831d35Sstevel }
161203831d35Sstevel
161303831d35Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
161403831d35Sstevel
161503831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
161603831d35Sstevel
161703831d35Sstevel expander = schpc_p->schpc_slot[slot].expander; /* get expander */
161803831d35Sstevel board = schpc_p->schpc_slot[slot].board; /* get board */
161903831d35Sstevel
162003831d35Sstevel /*
162103831d35Sstevel * Initialize Set Slot Command.
162203831d35Sstevel */
162303831d35Sstevel schpc_init_setslot_message(&setslot);
162403831d35Sstevel
162503831d35Sstevel /*
162603831d35Sstevel * Initialize LED to last know state.
162703831d35Sstevel */
162803831d35Sstevel switch (schpc_p->schpc_slot[slot].led.led_power) {
162903831d35Sstevel case LED_ON:
163003831d35Sstevel setslot.slot_led_power = PCIMSG_LED_ON;
163103831d35Sstevel break;
163203831d35Sstevel case LED_OFF:
163303831d35Sstevel setslot.slot_led_power = PCIMSG_LED_OFF;
163403831d35Sstevel break;
163503831d35Sstevel case LED_FLASH:
163603831d35Sstevel setslot.slot_led_power = PCIMSG_LED_FLASH;
163703831d35Sstevel break;
163803831d35Sstevel }
163903831d35Sstevel
164003831d35Sstevel switch (schpc_p->schpc_slot[slot].led.led_service) {
164103831d35Sstevel case LED_ON:
164203831d35Sstevel setslot.slot_led_service = PCIMSG_LED_ON;
164303831d35Sstevel break;
164403831d35Sstevel case LED_OFF:
164503831d35Sstevel setslot.slot_led_service = PCIMSG_LED_OFF;
164603831d35Sstevel break;
164703831d35Sstevel case LED_FLASH:
164803831d35Sstevel setslot.slot_led_service = PCIMSG_LED_FLASH;
164903831d35Sstevel break;
165003831d35Sstevel }
165103831d35Sstevel
165203831d35Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) {
165303831d35Sstevel case LED_ON:
165403831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_ON;
165503831d35Sstevel break;
165603831d35Sstevel case LED_OFF:
165703831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF;
165803831d35Sstevel break;
165903831d35Sstevel case LED_FLASH:
166003831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH;
166103831d35Sstevel break;
166203831d35Sstevel }
166303831d35Sstevel
166403831d35Sstevel switch (request) {
166503831d35Sstevel
166603831d35Sstevel
166703831d35Sstevel case HPC_CTRL_GET_SLOT_STATE: {
166803831d35Sstevel hpc_slot_state_t *hpc_slot_state;
166903831d35Sstevel
167003831d35Sstevel hpc_slot_state = (hpc_slot_state_t *)arg;
167103831d35Sstevel
167203831d35Sstevel SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - "
167303831d35Sstevel "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=%p",
1674*07d06da5SSurya Prakki (void *)hpc_slot_state);
167503831d35Sstevel
167603831d35Sstevel rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
167703831d35Sstevel
167803831d35Sstevel if (!rval) {
167903831d35Sstevel
168003831d35Sstevel if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
168103831d35Sstevel
168203831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
168303831d35Sstevel schpc_p->schpc_slot[slot].state &=
168403831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
168503831d35Sstevel cv_signal(&schpc_p->schpc_cv);
168603831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
168703831d35Sstevel
168803831d35Sstevel return (HPC_ERR_FAILED);
168903831d35Sstevel }
169003831d35Sstevel
169103831d35Sstevel if (slotstatus.slot_empty == PCIMSG_ON) {
169203831d35Sstevel *hpc_slot_state = HPC_SLOT_EMPTY;
169303831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Empty");
169403831d35Sstevel } else if (slotstatus.slot_power_on == PCIMSG_ON) {
169503831d35Sstevel *hpc_slot_state = HPC_SLOT_CONNECTED;
169603831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "Slot Connected");
169703831d35Sstevel schpc_p->schpc_slot[slot].state |=
169803831d35Sstevel SCHPC_SLOTSTATE_CONNECTED;
169903831d35Sstevel } else {
170003831d35Sstevel *hpc_slot_state = HPC_SLOT_DISCONNECTED;
170103831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL,
170203831d35Sstevel "Slot Disconnected");
170303831d35Sstevel schpc_p->schpc_slot[slot].state &=
170403831d35Sstevel ~SCHPC_SLOTSTATE_CONNECTED;
170503831d35Sstevel }
170603831d35Sstevel } else {
170703831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "Mailbox Command failed");
170803831d35Sstevel
170903831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
171003831d35Sstevel schpc_p->schpc_slot[slot].state &=
171103831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
171203831d35Sstevel cv_signal(&schpc_p->schpc_cv);
171303831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
171403831d35Sstevel
171503831d35Sstevel return (HPC_ERR_FAILED);
171603831d35Sstevel }
171703831d35Sstevel
171803831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
171903831d35Sstevel schpc_p->schpc_slot[slot].state &=
172003831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
172103831d35Sstevel cv_signal(&schpc_p->schpc_cv);
172203831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
172303831d35Sstevel
172403831d35Sstevel return (0);
172503831d35Sstevel }
172603831d35Sstevel case HPC_CTRL_GET_BOARD_TYPE: {
172703831d35Sstevel hpc_board_type_t *hpc_board_type;
172803831d35Sstevel
172903831d35Sstevel hpc_board_type = (hpc_board_type_t *)arg;
173003831d35Sstevel
173103831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
173203831d35Sstevel "HPC_CTRL_GET_BOARD_TYPE");
173303831d35Sstevel
173403831d35Sstevel
173503831d35Sstevel /*
173603831d35Sstevel * The HPC driver does not know what board type
173703831d35Sstevel * is plugged in.
173803831d35Sstevel */
173903831d35Sstevel *hpc_board_type = HPC_BOARD_PCI_HOTPLUG;
174003831d35Sstevel
174103831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
174203831d35Sstevel schpc_p->schpc_slot[slot].state &=
174303831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
174403831d35Sstevel cv_signal(&schpc_p->schpc_cv);
174503831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
174603831d35Sstevel
174703831d35Sstevel return (0);
174803831d35Sstevel
174903831d35Sstevel }
175003831d35Sstevel case HPC_CTRL_DEV_UNCONFIG_START:
175103831d35Sstevel case HPC_CTRL_DEV_CONFIG_START:
175203831d35Sstevel case HPC_CTRL_DEV_CONFIGURED:
175303831d35Sstevel case HPC_CTRL_DEV_UNCONFIGURED:
175403831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
175503831d35Sstevel schpc_p->schpc_slot[slot].state &=
175603831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
175703831d35Sstevel cv_signal(&schpc_p->schpc_cv);
175803831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
175903831d35Sstevel
176003831d35Sstevel return (0);
176103831d35Sstevel
176203831d35Sstevel case HPC_CTRL_GET_LED_STATE:
176303831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
176403831d35Sstevel "HPC_CTRL_GET_LED_STATE");
176503831d35Sstevel hpc_led_info = (hpc_led_info_t *)arg;
176603831d35Sstevel
176703831d35Sstevel switch (hpc_led_info->led) {
176803831d35Sstevel case HPC_FAULT_LED:
176903831d35Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) {
177003831d35Sstevel case LED_OFF:
177103831d35Sstevel hpc_led_info->state = HPC_LED_OFF;
177203831d35Sstevel break;
177303831d35Sstevel case LED_ON:
177403831d35Sstevel hpc_led_info->state = HPC_LED_ON;
177503831d35Sstevel break;
177603831d35Sstevel case LED_FLASH:
177703831d35Sstevel hpc_led_info->state = HPC_LED_BLINK;
177803831d35Sstevel break;
177903831d35Sstevel }
178003831d35Sstevel break;
178103831d35Sstevel
178203831d35Sstevel case HPC_POWER_LED:
178303831d35Sstevel switch (schpc_p->schpc_slot[slot].led.led_power) {
178403831d35Sstevel case LED_OFF:
178503831d35Sstevel hpc_led_info->state = HPC_LED_OFF;
178603831d35Sstevel break;
178703831d35Sstevel case LED_ON:
178803831d35Sstevel hpc_led_info->state = HPC_LED_ON;
178903831d35Sstevel break;
179003831d35Sstevel case LED_FLASH:
179103831d35Sstevel hpc_led_info->state = HPC_LED_BLINK;
179203831d35Sstevel break;
179303831d35Sstevel }
179403831d35Sstevel break;
179503831d35Sstevel case HPC_ATTN_LED:
179603831d35Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) {
179703831d35Sstevel case LED_OFF:
179803831d35Sstevel hpc_led_info->state = HPC_LED_OFF;
179903831d35Sstevel break;
180003831d35Sstevel case LED_ON:
180103831d35Sstevel hpc_led_info->state = HPC_LED_OFF;
180203831d35Sstevel break;
180303831d35Sstevel case LED_FLASH:
180403831d35Sstevel hpc_led_info->state = HPC_LED_ON;
180503831d35Sstevel break;
180603831d35Sstevel }
180703831d35Sstevel break;
180803831d35Sstevel case HPC_ACTIVE_LED:
180903831d35Sstevel switch (schpc_p->schpc_slot[slot].led.led_service) {
181003831d35Sstevel case LED_OFF:
181103831d35Sstevel hpc_led_info->state = HPC_LED_OFF;
181203831d35Sstevel break;
181303831d35Sstevel case LED_ON:
181403831d35Sstevel hpc_led_info->state = HPC_LED_ON;
181503831d35Sstevel break;
181603831d35Sstevel case LED_FLASH:
181703831d35Sstevel hpc_led_info->state = HPC_LED_BLINK;
181803831d35Sstevel break;
181903831d35Sstevel }
182003831d35Sstevel break;
182103831d35Sstevel default:
182203831d35Sstevel SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - "
182303831d35Sstevel "Invalid LED %x", hpc_led_info->led);
182403831d35Sstevel
182503831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
182603831d35Sstevel schpc_p->schpc_slot[slot].state &=
182703831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
182803831d35Sstevel cv_signal(&schpc_p->schpc_cv);
182903831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
183003831d35Sstevel
183103831d35Sstevel return (HPC_ERR_FAILED);
183203831d35Sstevel }
183303831d35Sstevel
183403831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
183503831d35Sstevel schpc_p->schpc_slot[slot].state &=
183603831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
183703831d35Sstevel cv_signal(&schpc_p->schpc_cv);
183803831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
183903831d35Sstevel
184003831d35Sstevel return (0);
184103831d35Sstevel
184203831d35Sstevel case HPC_CTRL_SET_LED_STATE:
184303831d35Sstevel hpc_led_info = (hpc_led_info_t *)arg;
184403831d35Sstevel
184503831d35Sstevel SCHPC_DEBUG1(D_IOC_CONTROL, "schpc_pci_control() - "
1846*07d06da5SSurya Prakki "HPC_CTRL_SET_LED_STATE hpc_led_info=%p",
1847*07d06da5SSurya Prakki (void *)hpc_led_info);
184803831d35Sstevel
184903831d35Sstevel switch (hpc_led_info->led) {
185003831d35Sstevel case HPC_FAULT_LED:
185103831d35Sstevel switch (hpc_led_info->state) {
185203831d35Sstevel case HPC_LED_OFF:
185303831d35Sstevel schpc_p->schpc_slot[slot].led.led_fault =
185403831d35Sstevel LED_OFF;
185503831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF;
185603831d35Sstevel break;
185703831d35Sstevel case HPC_LED_ON:
185803831d35Sstevel schpc_p->schpc_slot[slot].led.led_fault =
185903831d35Sstevel LED_ON;
186003831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_ON;
186103831d35Sstevel break;
186203831d35Sstevel case HPC_LED_BLINK:
186303831d35Sstevel schpc_p->schpc_slot[slot].led.led_fault =
186403831d35Sstevel LED_FLASH;
186503831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH;
186603831d35Sstevel break;
186703831d35Sstevel }
186803831d35Sstevel break;
186903831d35Sstevel case HPC_POWER_LED:
187003831d35Sstevel switch (hpc_led_info->state) {
187103831d35Sstevel case HPC_LED_OFF:
187203831d35Sstevel schpc_p->schpc_slot[slot].led.led_power =
187303831d35Sstevel LED_OFF;
187403831d35Sstevel setslot.slot_led_power = PCIMSG_LED_OFF;
187503831d35Sstevel break;
187603831d35Sstevel case HPC_LED_ON:
187703831d35Sstevel schpc_p->schpc_slot[slot].led.led_power =
187803831d35Sstevel LED_ON;
187903831d35Sstevel setslot.slot_led_power = PCIMSG_LED_ON;
188003831d35Sstevel break;
188103831d35Sstevel case HPC_LED_BLINK:
188203831d35Sstevel schpc_p->schpc_slot[slot].led.led_power =
188303831d35Sstevel LED_FLASH;
188403831d35Sstevel setslot.slot_led_power = PCIMSG_LED_FLASH;
188503831d35Sstevel break;
188603831d35Sstevel }
188703831d35Sstevel break;
188803831d35Sstevel case HPC_ATTN_LED:
188903831d35Sstevel switch (hpc_led_info->state) {
189003831d35Sstevel case HPC_LED_OFF:
189103831d35Sstevel schpc_p->schpc_slot[slot].led.led_fault =
189203831d35Sstevel LED_OFF;
189303831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF;
189403831d35Sstevel break;
189503831d35Sstevel case HPC_LED_ON:
189603831d35Sstevel schpc_p->schpc_slot[slot].led.led_fault =
189703831d35Sstevel LED_FLASH;
189803831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH;
189903831d35Sstevel break;
190003831d35Sstevel case HPC_LED_BLINK:
190103831d35Sstevel schpc_p->schpc_slot[slot].led.led_fault =
190203831d35Sstevel LED_FLASH;
190303831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH;
190403831d35Sstevel break;
190503831d35Sstevel }
190603831d35Sstevel break;
190703831d35Sstevel case HPC_ACTIVE_LED:
190803831d35Sstevel switch (hpc_led_info->state) {
190903831d35Sstevel case HPC_LED_OFF:
191003831d35Sstevel schpc_p->schpc_slot[slot].led.led_service =
191103831d35Sstevel LED_OFF;
191203831d35Sstevel setslot.slot_led_service = PCIMSG_LED_OFF;
191303831d35Sstevel break;
191403831d35Sstevel case HPC_LED_ON:
191503831d35Sstevel schpc_p->schpc_slot[slot].led.led_service =
191603831d35Sstevel LED_ON;
191703831d35Sstevel setslot.slot_led_service = PCIMSG_LED_ON;
191803831d35Sstevel break;
191903831d35Sstevel case HPC_LED_BLINK:
192003831d35Sstevel schpc_p->schpc_slot[slot].led.led_service =
192103831d35Sstevel LED_FLASH;
192203831d35Sstevel setslot.slot_led_service = PCIMSG_LED_FLASH;
192303831d35Sstevel break;
192403831d35Sstevel }
192503831d35Sstevel break;
192603831d35Sstevel default:
192703831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
192803831d35Sstevel schpc_p->schpc_slot[slot].state &=
192903831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
193003831d35Sstevel cv_signal(&schpc_p->schpc_cv);
193103831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
193203831d35Sstevel
193303831d35Sstevel return (0);
193403831d35Sstevel }
193503831d35Sstevel
193603831d35Sstevel (void) schpc_setslotstatus(expander, board, slot, &setslot);
193703831d35Sstevel
193803831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
193903831d35Sstevel schpc_p->schpc_slot[slot].state &=
194003831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
194103831d35Sstevel cv_signal(&schpc_p->schpc_cv);
194203831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
194303831d35Sstevel
194403831d35Sstevel return (0);
194503831d35Sstevel
194603831d35Sstevel case HPC_CTRL_ENABLE_AUTOCFG:
194703831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
194803831d35Sstevel "HPC_CTRL_ENABLE_AUTOCFG");
194903831d35Sstevel
195003831d35Sstevel schpc_p->schpc_slot[slot].state |=
195103831d35Sstevel SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
195203831d35Sstevel
195303831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
195403831d35Sstevel schpc_p->schpc_slot[slot].state &=
195503831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
195603831d35Sstevel cv_signal(&schpc_p->schpc_cv);
195703831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
195803831d35Sstevel
195903831d35Sstevel return (0);
196003831d35Sstevel
196103831d35Sstevel case HPC_CTRL_DISABLE_AUTOCFG:
196203831d35Sstevel SCHPC_DEBUG0(D_IOC_CONTROL, "schpc_pci_control() - "
196303831d35Sstevel "HPC_CTRL_DISABLE_AUTOCFG");
196403831d35Sstevel schpc_p->schpc_slot[slot].state &=
196503831d35Sstevel ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
196603831d35Sstevel
196703831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
196803831d35Sstevel schpc_p->schpc_slot[slot].state &=
196903831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
197003831d35Sstevel cv_signal(&schpc_p->schpc_cv);
197103831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
197203831d35Sstevel
197303831d35Sstevel return (0);
197403831d35Sstevel
197503831d35Sstevel case HPC_CTRL_DISABLE_ENUM:
197603831d35Sstevel case HPC_CTRL_ENABLE_ENUM:
197703831d35Sstevel default:
197803831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
197903831d35Sstevel schpc_p->schpc_slot[slot].state &=
198003831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
198103831d35Sstevel cv_signal(&schpc_p->schpc_cv);
198203831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
198303831d35Sstevel
198403831d35Sstevel return (HPC_ERR_NOTSUPPORTED);
198503831d35Sstevel }
198603831d35Sstevel }
198703831d35Sstevel
198803831d35Sstevel /*
198903831d35Sstevel * schpc_test
199003831d35Sstevel *
199103831d35Sstevel * Tests the slot.
199203831d35Sstevel */
199303831d35Sstevel /*ARGSUSED*/
199403831d35Sstevel static void
schpc_test(caddr_t ops_arg,int slot,void * data,uint_t flags)199503831d35Sstevel schpc_test(caddr_t ops_arg, int slot, void *data, uint_t flags)
199603831d35Sstevel {
199703831d35Sstevel pci_getslot_t slotstatus;
199803831d35Sstevel pci_setslot_t setslot;
199903831d35Sstevel int expander, board;
200003831d35Sstevel int rval;
200103831d35Sstevel int retry = 1;
200203831d35Sstevel
200303831d35Sstevel SCHPC_DEBUG2(D_IOC_TEST, "schpc_test(op_args=%p slot=%x)",
2004*07d06da5SSurya Prakki (void *)ops_arg, SCHPC_SLOT_NUM(slot));
200503831d35Sstevel
200603831d35Sstevel SCHPC_DEBUG3(D_IOC_TEST,
200703831d35Sstevel " schpc_test() Expander=%d Board=%d Slot=%d",
200803831d35Sstevel schpc_p->schpc_slot[slot].expander,
200903831d35Sstevel schpc_p->schpc_slot[slot].board, SCHPC_SLOT_NUM(slot));
201003831d35Sstevel
201103831d35Sstevel expander = schpc_p->schpc_slot[slot].expander;
201203831d35Sstevel board = schpc_p->schpc_slot[slot].board;
201303831d35Sstevel
201403831d35Sstevel restart_test:
201503831d35Sstevel /*
201603831d35Sstevel * Initial the slot with its occupant and receptacle in good condition.
201703831d35Sstevel */
201803831d35Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_REC_GOOD;
201903831d35Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_OCC_GOOD;
202003831d35Sstevel
202103831d35Sstevel
202203831d35Sstevel rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
202303831d35Sstevel
202403831d35Sstevel if (rval) {
202503831d35Sstevel /*
202603831d35Sstevel * System Controller/Mailbox failure.
202703831d35Sstevel */
202803831d35Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
202903831d35Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : Unable to "
203003831d35Sstevel "Communicate with System Controller", expander, board,
203103831d35Sstevel SCHPC_SLOT_NUM(slot), schpc_p->schpc_slot[slot].ap_id);
203203831d35Sstevel
203303831d35Sstevel schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD;
203403831d35Sstevel return;
203503831d35Sstevel }
203603831d35Sstevel
203703831d35Sstevel if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
203803831d35Sstevel
203903831d35Sstevel cmn_err(CE_WARN, "schpc - Expander %d Board %d PCI Slot %d "
204003831d35Sstevel "is not hot pluggable\n", expander, board,
204103831d35Sstevel SCHPC_SLOT_NUM(slot));
204203831d35Sstevel
204303831d35Sstevel schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD;
204403831d35Sstevel return;
204503831d35Sstevel }
204603831d35Sstevel
204703831d35Sstevel switch (slotstatus.slot_condition) {
204803831d35Sstevel case PCIMSG_SLOTCOND_OCC_FAIL:
204903831d35Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
205003831d35Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
205103831d35Sstevel "System Controller/Occupant Failed",
205203831d35Sstevel expander, board, SCHPC_SLOT_NUM(slot),
205303831d35Sstevel schpc_p->schpc_slot[slot].ap_id);
205403831d35Sstevel
205503831d35Sstevel schpc_setslotled(expander, board, slot,
205603831d35Sstevel (POWER_LED_OFF | SERVICE_LED_ON | FAULT_LED_ON));
205703831d35Sstevel
205803831d35Sstevel schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_OCC_GOOD;
205903831d35Sstevel return;
206003831d35Sstevel case PCIMSG_SLOTCOND_REC_FAIL:
206103831d35Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
206203831d35Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
206303831d35Sstevel "System Controller/Receptacle Failed",
206403831d35Sstevel expander, board, SCHPC_SLOT_NUM(slot),
206503831d35Sstevel schpc_p->schpc_slot[slot].ap_id);
206603831d35Sstevel
206703831d35Sstevel schpc_setslotled(expander, board, slot,
206803831d35Sstevel (POWER_LED_OFF | SERVICE_LED_OFF | FAULT_LED_ON));
206903831d35Sstevel
207003831d35Sstevel schpc_p->schpc_slot[slot].state &= ~SCHPC_SLOTSTATE_REC_GOOD;
207103831d35Sstevel return;
207203831d35Sstevel }
207303831d35Sstevel
207403831d35Sstevel if (slotstatus.slot_power_on) {
207503831d35Sstevel schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON;
207603831d35Sstevel
207703831d35Sstevel if (!slotstatus.slot_HEALTHY) {
207803831d35Sstevel /*
207903831d35Sstevel * cPCI Adapter is not asserting HEALTHY#.
208003831d35Sstevel */
208103831d35Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
208203831d35Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
208303831d35Sstevel "PCI adapter not HEALTHY", expander, board,
208403831d35Sstevel SCHPC_SLOT_NUM(slot),
208503831d35Sstevel schpc_p->schpc_slot[slot].ap_id);
208603831d35Sstevel
208703831d35Sstevel schpc_setslotled(expander, board, slot,
208803831d35Sstevel (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
208903831d35Sstevel
209003831d35Sstevel schpc_p->schpc_slot[slot].state &=
209103831d35Sstevel ~SCHPC_SLOTSTATE_OCC_GOOD;
209203831d35Sstevel
209303831d35Sstevel return;
209403831d35Sstevel }
209503831d35Sstevel
209603831d35Sstevel if (!slotstatus.slot_powergood) {
209703831d35Sstevel /*
209803831d35Sstevel * PCI Power Input is not good.
209903831d35Sstevel */
210003831d35Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
210103831d35Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
210203831d35Sstevel "System Controller PCI Power Input Not Good",
210303831d35Sstevel expander, board, SCHPC_SLOT_NUM(slot),
210403831d35Sstevel schpc_p->schpc_slot[slot].ap_id);
210503831d35Sstevel
210603831d35Sstevel schpc_setslotled(expander, board, slot,
210703831d35Sstevel (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
210803831d35Sstevel
210903831d35Sstevel schpc_p->schpc_slot[slot].state &=
211003831d35Sstevel ~SCHPC_SLOTSTATE_OCC_GOOD;
211103831d35Sstevel
211203831d35Sstevel return;
211303831d35Sstevel }
211403831d35Sstevel
211503831d35Sstevel if (slotstatus.slot_powerfault) {
211603831d35Sstevel /*
211703831d35Sstevel * PCI Power Fault.
211803831d35Sstevel */
211903831d35Sstevel cmn_err(CE_WARN, "schpc - Hot Plug Slot Test Failed on "
212003831d35Sstevel "Expander %d Board %d PCI Slot %d - Ap_Id=%s : "
212103831d35Sstevel "System Controller PCI Power Fault",
212203831d35Sstevel expander, board, SCHPC_SLOT_NUM(slot),
212303831d35Sstevel schpc_p->schpc_slot[slot].ap_id);
212403831d35Sstevel
212503831d35Sstevel schpc_setslotled(expander, board, slot,
212603831d35Sstevel (POWER_LED_ON | SERVICE_LED_OFF | FAULT_LED_ON));
212703831d35Sstevel
212803831d35Sstevel schpc_p->schpc_slot[slot].state &=
212903831d35Sstevel ~SCHPC_SLOTSTATE_OCC_GOOD;
213003831d35Sstevel
213103831d35Sstevel return;
213203831d35Sstevel }
213303831d35Sstevel }
213403831d35Sstevel
213503831d35Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Test Successful - ret 0");
213603831d35Sstevel
213703831d35Sstevel /*
213803831d35Sstevel * Is the slot empty?
213903831d35Sstevel */
214003831d35Sstevel if (slotstatus.slot_empty) {
214103831d35Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Empty");
214203831d35Sstevel
214303831d35Sstevel schpc_p->schpc_slot[slot].state &=
214403831d35Sstevel ~SCHPC_SLOTSTATE_PRESENT;
214503831d35Sstevel
214603831d35Sstevel if (slotstatus.slot_power_on) {
214703831d35Sstevel
214803831d35Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Empty Slot "
214903831d35Sstevel "is powered ON");
215003831d35Sstevel
215103831d35Sstevel /*
215203831d35Sstevel * Tests will be retried once after powering off
215303831d35Sstevel * an empty slot.
215403831d35Sstevel */
215503831d35Sstevel if (retry) {
215603831d35Sstevel
215703831d35Sstevel /*
215803831d35Sstevel * Turn off the slot and restart test.
215903831d35Sstevel */
216003831d35Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() "
216103831d35Sstevel "Turning Empty Slot OFF");
216203831d35Sstevel
216303831d35Sstevel schpc_init_setslot_message(&setslot);
216403831d35Sstevel setslot.slot_power_off = PCIMSG_ON;
216503831d35Sstevel (void) schpc_setslotstatus(
216603831d35Sstevel expander, board, slot, &setslot);
216703831d35Sstevel
216803831d35Sstevel retry = 0;
216903831d35Sstevel
217003831d35Sstevel goto restart_test;
217103831d35Sstevel }
217203831d35Sstevel }
217303831d35Sstevel } else {
217403831d35Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Adapter Present");
217503831d35Sstevel
217603831d35Sstevel if (!slotstatus.slot_power_on) {
217703831d35Sstevel if (retry) {
217803831d35Sstevel /*
217903831d35Sstevel * If there is a cassette present and the
218003831d35Sstevel * power is off, try turning the power on and
218103831d35Sstevel * restart the test. This allows access to
218203831d35Sstevel * the FRUID when an empty cassette is
218303831d35Sstevel * installed.
218403831d35Sstevel */
218503831d35Sstevel SCHPC_DEBUG0(D_IOC_TEST,
218603831d35Sstevel "schpc_test() Power On Adapter");
218703831d35Sstevel schpc_init_setslot_message(&setslot);
218803831d35Sstevel setslot.slot_power_on = PCIMSG_ON;
218903831d35Sstevel (void) schpc_setslotstatus(
219003831d35Sstevel expander, board, slot, &setslot);
219103831d35Sstevel retry = 0;
219203831d35Sstevel goto restart_test;
219303831d35Sstevel }
219403831d35Sstevel }
219503831d35Sstevel
219603831d35Sstevel schpc_p->schpc_slot[slot].state |=
219703831d35Sstevel SCHPC_SLOTSTATE_PRESENT;
219803831d35Sstevel }
219903831d35Sstevel
220003831d35Sstevel /*
220103831d35Sstevel * Is the slot powered up?
220203831d35Sstevel */
220303831d35Sstevel schpc_init_setslot_message(&setslot);
220403831d35Sstevel
220503831d35Sstevel if (slotstatus.slot_power_on) {
220603831d35Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power On");
220703831d35Sstevel
220803831d35Sstevel schpc_p->schpc_slot[slot].state |=
220903831d35Sstevel SCHPC_SLOTSTATE_CONNECTED;
221003831d35Sstevel
221103831d35Sstevel setslot.slot_led_power = PCIMSG_LED_ON;
221203831d35Sstevel setslot.slot_led_service = PCIMSG_LED_OFF;
221303831d35Sstevel setslot.slot_enable_ENUM = PCIMSG_ON;
221403831d35Sstevel setslot.slot_enable_HEALTHY = PCIMSG_ON;
221503831d35Sstevel } else {
221603831d35Sstevel SCHPC_DEBUG0(D_IOC_TEST, "schpc_test() Slot Power Off");
221703831d35Sstevel
221803831d35Sstevel schpc_p->schpc_slot[slot].state &=
221903831d35Sstevel ~SCHPC_SLOTSTATE_CONNECTED;
222003831d35Sstevel
222103831d35Sstevel setslot.slot_led_power = PCIMSG_LED_OFF;
222203831d35Sstevel setslot.slot_led_service = PCIMSG_LED_ON;
222303831d35Sstevel setslot.slot_disable_ENUM = PCIMSG_ON;
222403831d35Sstevel setslot.slot_disable_HEALTHY = PCIMSG_ON;
222503831d35Sstevel }
222603831d35Sstevel
222703831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF;
222803831d35Sstevel
222903831d35Sstevel (void) schpc_setslotstatus(expander, board, slot, &setslot);
223003831d35Sstevel
223103831d35Sstevel /*
223203831d35Sstevel * Save LED State.
223303831d35Sstevel */
223403831d35Sstevel switch (setslot.slot_led_power) {
223503831d35Sstevel case PCIMSG_LED_ON:
223603831d35Sstevel schpc_p->schpc_slot[slot].led.led_power = LED_ON;
223703831d35Sstevel break;
223803831d35Sstevel case PCIMSG_LED_OFF:
223903831d35Sstevel schpc_p->schpc_slot[slot].led.led_power = LED_OFF;
224003831d35Sstevel break;
224103831d35Sstevel case PCIMSG_LED_FLASH:
224203831d35Sstevel schpc_p->schpc_slot[slot].led.led_power = LED_FLASH;
224303831d35Sstevel break;
224403831d35Sstevel }
224503831d35Sstevel switch (setslot.slot_led_service) {
224603831d35Sstevel case PCIMSG_LED_ON:
224703831d35Sstevel schpc_p->schpc_slot[slot].led.led_service = LED_ON;
224803831d35Sstevel break;
224903831d35Sstevel case PCIMSG_LED_OFF:
225003831d35Sstevel schpc_p->schpc_slot[slot].led.led_service = LED_OFF;
225103831d35Sstevel break;
225203831d35Sstevel case PCIMSG_LED_FLASH:
225303831d35Sstevel schpc_p->schpc_slot[slot].led.led_service = LED_FLASH;
225403831d35Sstevel break;
225503831d35Sstevel }
225603831d35Sstevel switch (setslot.slot_led_fault) {
225703831d35Sstevel case PCIMSG_LED_ON:
225803831d35Sstevel schpc_p->schpc_slot[slot].led.led_fault = LED_ON;
225903831d35Sstevel break;
226003831d35Sstevel case PCIMSG_LED_OFF:
226103831d35Sstevel schpc_p->schpc_slot[slot].led.led_fault = LED_OFF;
226203831d35Sstevel break;
226303831d35Sstevel case PCIMSG_LED_FLASH:
226403831d35Sstevel schpc_p->schpc_slot[slot].led.led_fault = LED_FLASH;
226503831d35Sstevel break;
226603831d35Sstevel }
226703831d35Sstevel }
226803831d35Sstevel
226903831d35Sstevel
227003831d35Sstevel /*
227103831d35Sstevel * schpc_event_handler
227203831d35Sstevel *
227303831d35Sstevel * Placed on the schpc_event_taskq by schpc_event_filter when an
227403831d35Sstevel * unsolicited MBOXSC_MSG_EVENT is received from the SC. It handles
227503831d35Sstevel * things like power insertion/removal, ENUM#, etc.
227603831d35Sstevel */
227703831d35Sstevel static void
schpc_event_handler(void * arg)227803831d35Sstevel schpc_event_handler(void *arg)
227903831d35Sstevel {
228003831d35Sstevel pci_getslot_t slotstatus;
228103831d35Sstevel uint8_t expander, board, slot;
228203831d35Sstevel int rval;
228303831d35Sstevel pcimsg_t *event = (pcimsg_t *)arg;
228403831d35Sstevel
228503831d35Sstevel /*
228603831d35Sstevel * OK, we got an event message. Since the event message only tells
228703831d35Sstevel * us something has changed and not changed to what, we need to get
228803831d35Sstevel * the current slot status to find how WHAT was change to WHAT.
228903831d35Sstevel */
229003831d35Sstevel
229103831d35Sstevel slot = event->pcimsg_slot;
229203831d35Sstevel expander = event->pcimsg_node; /* get expander */
229303831d35Sstevel board = event->pcimsg_board; /* get board */
229403831d35Sstevel
229503831d35Sstevel SCHPC_DEBUG3(D_EVENT,
229603831d35Sstevel "schpc_event_handler() - exp=%d board=%d slot=%d",
229703831d35Sstevel expander, board, slot);
229803831d35Sstevel
229903831d35Sstevel /* create a slot table index */
230003831d35Sstevel slot = SCHPC_MAKE_SLOT_INDEX2(expander, slot);
230103831d35Sstevel
230203831d35Sstevel SCHPC_DEBUG1(D_EVENT,
230303831d35Sstevel "schpc_event_handler() - expanded slot %d", slot);
230403831d35Sstevel
230503831d35Sstevel if (schpc_p == NULL) {
230603831d35Sstevel cmn_err(CE_WARN, "schpc/Event Handler - Can not find schpc");
230703831d35Sstevel kmem_free(event, sizeof (pcimsg_t));
230803831d35Sstevel return;
230903831d35Sstevel }
231003831d35Sstevel
231103831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
231203831d35Sstevel
231303831d35Sstevel if (!(schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_HPCINITED)) {
231403831d35Sstevel SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - HPC Not Inited");
231503831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
231603831d35Sstevel kmem_free(event, sizeof (pcimsg_t));
231703831d35Sstevel return;
231803831d35Sstevel }
231903831d35Sstevel /*
232003831d35Sstevel * Block if another thread is executing a HPC command.
232103831d35Sstevel */
232203831d35Sstevel while (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_EXECUTING) {
232303831d35Sstevel SCHPC_DEBUG0(D_EVENT, "schpc_event_handler - Slot is busy");
232403831d35Sstevel cv_wait(&schpc_p->schpc_cv, &schpc_p->schpc_mutex);
232503831d35Sstevel }
232603831d35Sstevel
232703831d35Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_EXECUTING;
232803831d35Sstevel
232903831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
233003831d35Sstevel
233103831d35Sstevel rval = schpc_getslotstatus(expander, board, slot, &slotstatus);
233203831d35Sstevel
233303831d35Sstevel if (rval) {
233403831d35Sstevel cmn_err(CE_WARN, "schpc/Event Handler - Can not get status "
233503831d35Sstevel "for expander=%d board=%d slot=%d\n",
233603831d35Sstevel expander, board, SCHPC_SLOT_NUM(slot));
233703831d35Sstevel
233803831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
233903831d35Sstevel schpc_p->schpc_slot[slot].state &=
234003831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
234103831d35Sstevel cv_signal(&schpc_p->schpc_cv);
234203831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
234303831d35Sstevel kmem_free(event, sizeof (pcimsg_t));
234403831d35Sstevel return;
234503831d35Sstevel }
234603831d35Sstevel
234703831d35Sstevel if (slotstatus.slot_replystatus != PCIMSG_REPLY_GOOD) {
234803831d35Sstevel cmn_err(CE_WARN, "schpc/Event Handler - Can not get good "
234903831d35Sstevel "status for expander=%d board=%d slot=%d\n",
235003831d35Sstevel expander, board, SCHPC_SLOT_NUM(slot));
235103831d35Sstevel
235203831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
235303831d35Sstevel schpc_p->schpc_slot[slot].state &=
235403831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
235503831d35Sstevel cv_signal(&schpc_p->schpc_cv);
235603831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
235703831d35Sstevel
235803831d35Sstevel kmem_free(event, sizeof (pcimsg_t));
235903831d35Sstevel return;
236003831d35Sstevel }
236103831d35Sstevel
236203831d35Sstevel SCHPC_DEBUG3(D_EVENT, "Event Received - Expander %d Board %d Slot %d",
236303831d35Sstevel expander, board, SCHPC_SLOT_NUM(slot));
236403831d35Sstevel
236503831d35Sstevel if (schpc_p->schpc_slot[slot].slot_ops == NULL) {
236603831d35Sstevel SCHPC_DEBUG3(D_EVENT, "schpc/Event Handler - Received event "
236703831d35Sstevel "for unregistered slot for expander=%d board=%d slot=%d",
236803831d35Sstevel expander, board, SCHPC_SLOT_NUM(slot));
236903831d35Sstevel
237003831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
237103831d35Sstevel schpc_p->schpc_slot[slot].state &=
237203831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
237303831d35Sstevel cv_signal(&schpc_p->schpc_cv);
237403831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
237503831d35Sstevel
237603831d35Sstevel kmem_free(event, sizeof (pcimsg_t));
237703831d35Sstevel return;
237803831d35Sstevel }
237903831d35Sstevel
238003831d35Sstevel /* Slot Power Event */
238103831d35Sstevel
238203831d35Sstevel if (event->pcimsg_type.pcimsg_slotevent.slot_power) {
238303831d35Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Event");
238403831d35Sstevel /*
238503831d35Sstevel * The SC may have changed to slot power status.
238603831d35Sstevel */
238703831d35Sstevel if (slotstatus.slot_power_on) {
238803831d35Sstevel schpc_p->schpc_slot[slot].state |=
238903831d35Sstevel SCHPC_SLOTSTATE_CONNECTED;
239003831d35Sstevel
2391*07d06da5SSurya Prakki (void) hpc_slot_event_notify(
239203831d35Sstevel schpc_p->schpc_slot[slot].slot_handle,
239303831d35Sstevel HPC_EVENT_SLOT_POWER_ON, 0);
239403831d35Sstevel } else {
239503831d35Sstevel schpc_p->schpc_slot[slot].state &=
239603831d35Sstevel ~SCHPC_SLOTSTATE_CONNECTED;
239703831d35Sstevel
2398*07d06da5SSurya Prakki (void) hpc_slot_event_notify(
239903831d35Sstevel schpc_p->schpc_slot[slot].slot_handle,
240003831d35Sstevel HPC_EVENT_SLOT_POWER_OFF, 0);
240103831d35Sstevel }
240203831d35Sstevel }
240303831d35Sstevel
240403831d35Sstevel /* Adapter Insertion/Removal Event */
240503831d35Sstevel
240603831d35Sstevel if (event->pcimsg_type.pcimsg_slotevent.slot_presence) {
240703831d35Sstevel if (slotstatus.slot_empty == PCIMSG_ON) {
240803831d35Sstevel
240903831d35Sstevel /* Adapter Removed */
241003831d35Sstevel
241103831d35Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Removed");
241203831d35Sstevel
241303831d35Sstevel if (schpc_p->schpc_slot[slot].state &
241403831d35Sstevel SCHPC_SLOTSTATE_CONNECTED) {
241503831d35Sstevel /*
241603831d35Sstevel * If the adapter has been removed while
241703831d35Sstevel * there the slot is connected, it could be
241803831d35Sstevel * due to a ENUM handling.
241903831d35Sstevel */
242003831d35Sstevel cmn_err(CE_WARN, "Card removed from "
242103831d35Sstevel "powered on slot at "
242203831d35Sstevel "expander=%d board=%d slot=%d\n",
242303831d35Sstevel expander, board, SCHPC_SLOT_NUM(slot));
242403831d35Sstevel
242503831d35Sstevel schpc_p->schpc_slot[slot].state &=
242603831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
242703831d35Sstevel rval = schpc_disconnect((caddr_t)schpc_p,
242803831d35Sstevel schpc_p->schpc_slot[slot].slot_handle,
242903831d35Sstevel 0, 0);
243003831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
243103831d35Sstevel while (schpc_p->schpc_slot[slot].state &
243203831d35Sstevel SCHPC_SLOTSTATE_EXECUTING) {
243303831d35Sstevel SCHPC_DEBUG0(D_EVENT,
243403831d35Sstevel "schpc_event_handler - "
243503831d35Sstevel "Slot is busy");
243603831d35Sstevel cv_wait(&schpc_p->schpc_cv,
243703831d35Sstevel &schpc_p->schpc_mutex);
243803831d35Sstevel }
243903831d35Sstevel
244003831d35Sstevel schpc_p->schpc_slot[slot].state |=
244103831d35Sstevel SCHPC_SLOTSTATE_EXECUTING;
244203831d35Sstevel
244303831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
244403831d35Sstevel }
244503831d35Sstevel schpc_p->schpc_slot[slot].state |=
244603831d35Sstevel SCHPC_SLOTSTATE_OCC_GOOD;
244703831d35Sstevel
244803831d35Sstevel schpc_p->schpc_slot[slot].state &=
244903831d35Sstevel ~SCHPC_SLOTSTATE_PRESENT;
245003831d35Sstevel
2451*07d06da5SSurya Prakki (void) hpc_slot_event_notify(
245203831d35Sstevel schpc_p->schpc_slot[slot].slot_handle,
245303831d35Sstevel HPC_EVENT_SLOT_REMOVAL, 0);
245403831d35Sstevel } else {
245503831d35Sstevel
245603831d35Sstevel /* Adapter Inserted */
245703831d35Sstevel
245803831d35Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: Adapter Inserted");
245903831d35Sstevel
246003831d35Sstevel if (schpc_p->schpc_slot[slot].state &
246103831d35Sstevel SCHPC_SLOTSTATE_PRESENT) {
246203831d35Sstevel /*
246303831d35Sstevel * If the adapter is already present
246403831d35Sstevel * throw the this event away.
246503831d35Sstevel */
246603831d35Sstevel
246703831d35Sstevel SCHPC_DEBUG0(D_EVENT,
246803831d35Sstevel "Adapter is already present");
246903831d35Sstevel
247003831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
247103831d35Sstevel schpc_p->schpc_slot[slot].state &=
247203831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
247303831d35Sstevel cv_signal(&schpc_p->schpc_cv);
247403831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
247503831d35Sstevel
247603831d35Sstevel kmem_free(event, sizeof (pcimsg_t));
247703831d35Sstevel return;
247803831d35Sstevel }
247903831d35Sstevel
248003831d35Sstevel schpc_p->schpc_slot[slot].state |=
248103831d35Sstevel SCHPC_SLOTSTATE_PRESENT;
248203831d35Sstevel
248303831d35Sstevel schpc_p->schpc_slot[slot].state &=
248403831d35Sstevel ~SCHPC_SLOTSTATE_CONNECTED;
248503831d35Sstevel
2486*07d06da5SSurya Prakki (void) hpc_slot_event_notify(
248703831d35Sstevel schpc_p->schpc_slot[slot].slot_handle,
248803831d35Sstevel HPC_EVENT_SLOT_INSERTION, 0);
248903831d35Sstevel
249003831d35Sstevel if (schpc_p->schpc_slot[slot].state &
249103831d35Sstevel SCHPC_SLOTSTATE_AUTOCFG_ENABLE) {
249203831d35Sstevel SCHPC_DEBUG0(D_EVENT, "Auto Configuration "
249303831d35Sstevel "(Connect/Configure) Started");
249403831d35Sstevel
249503831d35Sstevel schpc_p->schpc_slot[slot].state &=
249603831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
249703831d35Sstevel
249803831d35Sstevel rval = schpc_connect((caddr_t)schpc_p,
249903831d35Sstevel schpc_p->schpc_slot[slot].slot_handle,
250003831d35Sstevel 0, 0);
250103831d35Sstevel
250203831d35Sstevel if (rval) {
250303831d35Sstevel cmn_err(CE_WARN, "schpc/Event Handler -"
250403831d35Sstevel " Can not connect");
250503831d35Sstevel
250603831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
250703831d35Sstevel schpc_p->schpc_slot[slot].state &=
250803831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
250903831d35Sstevel cv_signal(&schpc_p->schpc_cv);
251003831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
251103831d35Sstevel
251203831d35Sstevel kmem_free(event, sizeof (pcimsg_t));
251303831d35Sstevel return;
251403831d35Sstevel }
251503831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
251603831d35Sstevel while (schpc_p->schpc_slot[slot].state &
251703831d35Sstevel SCHPC_SLOTSTATE_EXECUTING) {
251803831d35Sstevel SCHPC_DEBUG0(D_EVENT,
251903831d35Sstevel "schpc_event_handler - "
252003831d35Sstevel "Slot is busy");
252103831d35Sstevel cv_wait(&schpc_p->schpc_cv,
252203831d35Sstevel &schpc_p->schpc_mutex);
252303831d35Sstevel }
252403831d35Sstevel
252503831d35Sstevel schpc_p->schpc_slot[slot].state |=
252603831d35Sstevel SCHPC_SLOTSTATE_EXECUTING;
252703831d35Sstevel
252803831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
252903831d35Sstevel
2530*07d06da5SSurya Prakki (void) hpc_slot_event_notify(
253103831d35Sstevel schpc_p->schpc_slot[slot].slot_handle,
253203831d35Sstevel HPC_EVENT_SLOT_CONFIGURE, 0);
253303831d35Sstevel } else {
253403831d35Sstevel schpc_setslotled(expander, board, slot,
253503831d35Sstevel SERVICE_LED_ON);
253603831d35Sstevel }
253703831d35Sstevel }
253803831d35Sstevel }
253903831d35Sstevel
254003831d35Sstevel /* ENUM# signal change event */
254103831d35Sstevel
254203831d35Sstevel if (event->pcimsg_type.pcimsg_slotevent.slot_ENUM) {
254303831d35Sstevel /*
254403831d35Sstevel * ENUM should only be received to the adapter remove
254503831d35Sstevel * procedure.
254603831d35Sstevel */
254703831d35Sstevel
254803831d35Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: ENUM Asserted");
254903831d35Sstevel
255003831d35Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_FLASH);
255103831d35Sstevel
255203831d35Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_ENUM;
255303831d35Sstevel
2554*07d06da5SSurya Prakki (void) hpc_slot_event_notify(
255503831d35Sstevel schpc_p->schpc_slot[slot].slot_handle,
255603831d35Sstevel HPC_EVENT_SLOT_ENUM, 0);
255703831d35Sstevel }
255803831d35Sstevel
255903831d35Sstevel /* HEALTHY# signal change event */
256003831d35Sstevel
256103831d35Sstevel if (event->pcimsg_type.pcimsg_slotevent.slot_HEALTHY) {
256203831d35Sstevel
256303831d35Sstevel if (!slotstatus.slot_HEALTHY) {
256403831d35Sstevel
256503831d35Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: !HEALTHY ASSERTED");
256603831d35Sstevel
256703831d35Sstevel schpc_p->schpc_slot[slot].state &=
256803831d35Sstevel ~SCHPC_SLOTSTATE_OCC_GOOD;
256903831d35Sstevel
2570*07d06da5SSurya Prakki (void) hpc_slot_event_notify(
257103831d35Sstevel schpc_p->schpc_slot[slot].slot_handle,
257203831d35Sstevel HPC_EVENT_SLOT_NOT_HEALTHY, 0);
257303831d35Sstevel
257403831d35Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
257503831d35Sstevel } else {
257603831d35Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: HEALTHY OK");
257703831d35Sstevel
257803831d35Sstevel schpc_p->schpc_slot[slot].state |=
257903831d35Sstevel SCHPC_SLOTSTATE_OCC_GOOD;
258003831d35Sstevel
2581*07d06da5SSurya Prakki (void) hpc_slot_event_notify(
258203831d35Sstevel schpc_p->schpc_slot[slot].slot_handle,
258303831d35Sstevel HPC_EVENT_SLOT_HEALTHY_OK, 0);
258403831d35Sstevel
258503831d35Sstevel schpc_setslotled(expander, board, slot,
258603831d35Sstevel FAULT_LED_OFF);
258703831d35Sstevel }
258803831d35Sstevel }
258903831d35Sstevel
259003831d35Sstevel /* Good Power change event */
259103831d35Sstevel
259203831d35Sstevel if (event->pcimsg_type.pcimsg_slotevent.slot_powergood) {
259303831d35Sstevel if (slotstatus.slot_powergood == PCIMSG_ON) {
259403831d35Sstevel
259503831d35Sstevel SCHPC_DEBUG0(D_EVENT,
259603831d35Sstevel "Event Type: Slot Power Good Detected");
259703831d35Sstevel
259803831d35Sstevel schpc_p->schpc_slot[slot].state |=
259903831d35Sstevel SCHPC_SLOTSTATE_OCC_GOOD;
260003831d35Sstevel
2601*07d06da5SSurya Prakki (void) hpc_slot_event_notify(
260203831d35Sstevel schpc_p->schpc_slot[slot].slot_handle,
260303831d35Sstevel HPC_EVENT_SLOT_HEALTHY_OK, 0);
260403831d35Sstevel
260503831d35Sstevel schpc_setslotled(expander, board, slot,
260603831d35Sstevel FAULT_LED_OFF);
260703831d35Sstevel } else {
260803831d35Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Not Good "
260903831d35Sstevel "Detected");
261003831d35Sstevel
261103831d35Sstevel if (schpc_p->schpc_slot[slot].state &
261203831d35Sstevel SCHPC_SLOTSTATE_CONNECTED) {
261303831d35Sstevel
261403831d35Sstevel SCHPC_DEBUG0(D_EVENT, "Slot Power Not Good: "
261503831d35Sstevel "power failed");
261603831d35Sstevel
261703831d35Sstevel schpc_p->schpc_slot[slot].state &=
261803831d35Sstevel ~SCHPC_SLOTSTATE_OCC_GOOD;
261903831d35Sstevel
2620*07d06da5SSurya Prakki (void) hpc_slot_event_notify(
262103831d35Sstevel schpc_p->schpc_slot[slot].slot_handle,
262203831d35Sstevel HPC_EVENT_SLOT_NOT_HEALTHY, 0);
262303831d35Sstevel
262403831d35Sstevel schpc_setslotled(expander, board, slot,
262503831d35Sstevel FAULT_LED_ON);
262603831d35Sstevel }
262703831d35Sstevel }
262803831d35Sstevel }
262903831d35Sstevel
263003831d35Sstevel /* Power Fault change event */
263103831d35Sstevel
263203831d35Sstevel if (event->pcimsg_type.pcimsg_slotevent.slot_powerfault) {
263303831d35Sstevel if (slotstatus.slot_powerfault == PCIMSG_ON) {
263403831d35Sstevel
263503831d35Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault "
263603831d35Sstevel "Detected");
263703831d35Sstevel
263803831d35Sstevel schpc_p->schpc_slot[slot].state &=
263903831d35Sstevel ~SCHPC_SLOTSTATE_OCC_GOOD;
264003831d35Sstevel
2641*07d06da5SSurya Prakki (void) hpc_slot_event_notify(
264203831d35Sstevel schpc_p->schpc_slot[slot].slot_handle,
264303831d35Sstevel HPC_EVENT_SLOT_NOT_HEALTHY, 0);
264403831d35Sstevel
264503831d35Sstevel schpc_setslotled(expander, board, slot, FAULT_LED_ON);
264603831d35Sstevel } else {
264703831d35Sstevel SCHPC_DEBUG0(D_EVENT, "Event Type: Slot Power Fault "
264803831d35Sstevel "Cleared");
264903831d35Sstevel
265003831d35Sstevel schpc_p->schpc_slot[slot].state |=
265103831d35Sstevel SCHPC_SLOTSTATE_OCC_GOOD;
265203831d35Sstevel
2653*07d06da5SSurya Prakki (void) hpc_slot_event_notify(
265403831d35Sstevel schpc_p->schpc_slot[slot].slot_handle,
265503831d35Sstevel HPC_EVENT_SLOT_HEALTHY_OK, 0);
265603831d35Sstevel
265703831d35Sstevel schpc_setslotled(expander, board, slot,
265803831d35Sstevel FAULT_LED_OFF);
265903831d35Sstevel }
266003831d35Sstevel }
266103831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
266203831d35Sstevel schpc_p->schpc_slot[slot].state &=
266303831d35Sstevel ~SCHPC_SLOTSTATE_EXECUTING;
266403831d35Sstevel cv_signal(&schpc_p->schpc_cv);
266503831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
266603831d35Sstevel
266703831d35Sstevel kmem_free(event, sizeof (pcimsg_t));
266803831d35Sstevel }
266903831d35Sstevel
267003831d35Sstevel
267103831d35Sstevel /*
267203831d35Sstevel * schpc_event_filter
267303831d35Sstevel *
267403831d35Sstevel * The schpc_event_filter enqueues MBOXSC_MSG_EVENTs into the
267503831d35Sstevel * schpc_event_taskq for processing by the schpc_event_handler _if_
267603831d35Sstevel * hotpluggable pci slots have been registered; otherwise, the
267703831d35Sstevel * MBOXSC_MSG_EVENTs are discarded in order to keep the incoming mailbox
267803831d35Sstevel * open for future messages.
267903831d35Sstevel */
268003831d35Sstevel static void
schpc_event_filter(pcimsg_t * pmsg)268103831d35Sstevel schpc_event_filter(pcimsg_t *pmsg)
268203831d35Sstevel {
268303831d35Sstevel if (slots_registered == B_TRUE) {
268403831d35Sstevel
268503831d35Sstevel pcimsg_t *pevent;
268603831d35Sstevel
268703831d35Sstevel /*
268803831d35Sstevel * If hotpluggable pci slots have been registered then enqueue
268903831d35Sstevel * the event onto the schpc_event_taskq for processing.
269003831d35Sstevel */
269103831d35Sstevel
269203831d35Sstevel SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
269303831d35Sstevel "slots_registered = B_TRUE");
269403831d35Sstevel
269503831d35Sstevel pevent = (pcimsg_t *)kmem_zalloc(sizeof (pcimsg_t), KM_SLEEP);
269603831d35Sstevel bcopy(pmsg, pevent, sizeof (pcimsg_t));
269703831d35Sstevel
269803831d35Sstevel SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
269903831d35Sstevel "event alloc'd");
270003831d35Sstevel
270103831d35Sstevel if (taskq_dispatch(schpc_event_taskq, schpc_event_handler,
270203831d35Sstevel (void *)pevent, TQ_SLEEP) == NULL) {
270303831d35Sstevel cmn_err(CE_WARN, "schpc: schpc_event_filter - "
270403831d35Sstevel "taskq_dispatch failed to enqueue event");
270503831d35Sstevel kmem_free(pevent, sizeof (pcimsg_t));
270603831d35Sstevel return;
270703831d35Sstevel }
270803831d35Sstevel
270903831d35Sstevel SCHPC_DEBUG0(D_EVENT, "schpc_event_filter() - "
271003831d35Sstevel "event was taskq_dispatch'ed to schpc_event_handler");
271103831d35Sstevel } else {
271203831d35Sstevel /*
271303831d35Sstevel * Oops, schpc received an event _before_ the slots have been
271403831d35Sstevel * registered. In that case there is no choice but to toss
271503831d35Sstevel * the event.
271603831d35Sstevel */
271703831d35Sstevel cmn_err(CE_WARN, "schpc: schpc_event_filter - discarding "
271803831d35Sstevel "premature event");
271903831d35Sstevel }
272003831d35Sstevel }
272103831d35Sstevel
272203831d35Sstevel
272303831d35Sstevel /*
272403831d35Sstevel * schpc_msg_thread
272503831d35Sstevel * A stand-alone thread that monitors the incoming mailbox for
272603831d35Sstevel * MBOXSC_MSG_REPLYs and MBOXSC_MSG_EVENTs, and removes them from
272703831d35Sstevel * the mailbox for processing.
272803831d35Sstevel *
272903831d35Sstevel * MBOXSC_MSG_REPLYs are matched against outstanding REPLYs in the
273003831d35Sstevel * schpc_replylist, and the waiting thread is notified that its REPLY
273103831d35Sstevel * message has arrived; otherwise, if no REPLY match is found, then it is
273203831d35Sstevel * discarded.
273303831d35Sstevel *
273403831d35Sstevel * MBOXSC_MSG_EVENTs are enqueued into the schpc_event_taskq and processed
273503831d35Sstevel * by the schpc_event_handler.
273603831d35Sstevel *
273703831d35Sstevel * The schpc_msg_thread is started in _init().
273803831d35Sstevel */
273903831d35Sstevel void
schpc_msg_thread(void)274003831d35Sstevel schpc_msg_thread(void)
274103831d35Sstevel {
274203831d35Sstevel int err;
274303831d35Sstevel uint32_t type;
274403831d35Sstevel uint32_t cmd;
274503831d35Sstevel uint64_t transid;
274603831d35Sstevel uint32_t length;
274703831d35Sstevel pcimsg_t msg;
274803831d35Sstevel
274903831d35Sstevel SCHPC_DEBUG0(D_THREAD, "schpc_msg_thread() running");
275003831d35Sstevel
275103831d35Sstevel /* CONSTCOND */
275203831d35Sstevel while (1) {
275303831d35Sstevel
275403831d35Sstevel /* setup wildcard arguments */
275503831d35Sstevel type = 0;
275603831d35Sstevel cmd = 0;
275703831d35Sstevel transid = 0;
275803831d35Sstevel length = sizeof (pcimsg_t);
275903831d35Sstevel bzero(&msg, sizeof (pcimsg_t));
276003831d35Sstevel
276103831d35Sstevel err = mboxsc_getmsg(KEY_SCPC, &type, &cmd,
276203831d35Sstevel &transid, &length, (void *)&msg,
276303831d35Sstevel schpc_timeout_getmsg);
276403831d35Sstevel
276503831d35Sstevel if (err) {
276603831d35Sstevel switch (err) {
276703831d35Sstevel
276803831d35Sstevel /*FALLTHROUGH*/
276903831d35Sstevel case ETIMEDOUT:
277003831d35Sstevel case EAGAIN:
277103831d35Sstevel continue;
277203831d35Sstevel
277303831d35Sstevel default:
277403831d35Sstevel /*
277503831d35Sstevel * unfortunately, we can't do very much here
277603831d35Sstevel * because we're wildcarding mboxsc_getmsg
277703831d35Sstevel * so if it encounters an error, we can't
277803831d35Sstevel * identify which transid it belongs to.
277903831d35Sstevel */
278003831d35Sstevel cmn_err(CE_WARN,
278103831d35Sstevel "schpc - mboxsc_getmsg failed, err=0x%x", err);
278203831d35Sstevel delay(drv_usectohz(100000));
278303831d35Sstevel continue;
278403831d35Sstevel }
278503831d35Sstevel }
278603831d35Sstevel
278703831d35Sstevel if (msg.pcimsg_revision != PCIMSG_REVISION) {
278803831d35Sstevel /*
278903831d35Sstevel * This version of the schpc driver only understands
279003831d35Sstevel * version 1.0 of the PCI Hot Plug Message format.
279103831d35Sstevel */
279203831d35Sstevel cmn_err(CE_WARN, " schpc: schpc_msg_thread - "
279303831d35Sstevel "discarding event w/ unknown message version %x",
279403831d35Sstevel msg.pcimsg_revision);
279503831d35Sstevel continue;
279603831d35Sstevel }
279703831d35Sstevel
279803831d35Sstevel switch (type) {
279903831d35Sstevel
280003831d35Sstevel case MBOXSC_MSG_EVENT:
280103831d35Sstevel schpc_event_filter(&msg);
280203831d35Sstevel break;
280303831d35Sstevel
280403831d35Sstevel case MBOXSC_MSG_REPLY:
280503831d35Sstevel schpc_reply_handler(&msg, type, cmd, transid, length);
280603831d35Sstevel break;
280703831d35Sstevel
280803831d35Sstevel default:
280903831d35Sstevel cmn_err(CE_WARN,
281003831d35Sstevel "schpc - mboxsc_getmsg unknown msg"
281103831d35Sstevel " type=0x%x", type);
281203831d35Sstevel break;
281303831d35Sstevel }
281403831d35Sstevel }
281503831d35Sstevel /* this thread never exits */
281603831d35Sstevel }
281703831d35Sstevel
281803831d35Sstevel
281903831d35Sstevel void
schpc_reply_handler(pcimsg_t * pmsg,uint32_t type,uint32_t cmd,uint64_t transid,uint32_t length)282003831d35Sstevel schpc_reply_handler(pcimsg_t *pmsg, uint32_t type, uint32_t cmd,
282103831d35Sstevel uint64_t transid, uint32_t length)
282203831d35Sstevel {
282303831d35Sstevel schpc_replylist_t *entry;
282403831d35Sstevel
282503831d35Sstevel mutex_enter(&schpc_replylist_mutex);
282603831d35Sstevel entry = schpc_replylist_first;
282703831d35Sstevel while (entry != NULL) {
282803831d35Sstevel if (entry->transid == transid) {
282903831d35Sstevel break;
283003831d35Sstevel } else
283103831d35Sstevel entry = entry->next;
283203831d35Sstevel }
283303831d35Sstevel if (entry) {
283403831d35Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
283503831d35Sstevel "schpc_reply_handler() - 0x%lx transid reply "
283603831d35Sstevel "received", transid);
283703831d35Sstevel
283803831d35Sstevel mutex_enter(&entry->reply_lock);
283903831d35Sstevel if (entry->reply_cexit == B_FALSE) {
284003831d35Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
284103831d35Sstevel "schpc_reply_handler() - 0x%lx transid"
284203831d35Sstevel " cv_signal waiting thread", transid);
284303831d35Sstevel
284403831d35Sstevel /*
284503831d35Sstevel * emulate mboxsc_getmsg by copying the reply
284603831d35Sstevel */
284703831d35Sstevel entry->type = type;
284803831d35Sstevel entry->cmd = cmd;
284903831d35Sstevel entry->transid = transid;
285003831d35Sstevel entry->length = length;
285103831d35Sstevel bcopy((caddr_t)pmsg, &entry->reply, length);
285203831d35Sstevel
285303831d35Sstevel /* reply was received */
285403831d35Sstevel entry->reply_recvd = B_TRUE;
285503831d35Sstevel
285603831d35Sstevel /*
285703831d35Sstevel * wake up thread waiting for reply with transid
285803831d35Sstevel */
285903831d35Sstevel cv_signal(&entry->reply_cv);
286003831d35Sstevel }
286103831d35Sstevel mutex_exit(&entry->reply_lock);
286203831d35Sstevel } else {
286303831d35Sstevel cmn_err(CE_WARN, "schpc - no match for transid 0x%lx",
286403831d35Sstevel transid);
286503831d35Sstevel }
286603831d35Sstevel mutex_exit(&schpc_replylist_mutex);
286703831d35Sstevel }
286803831d35Sstevel
286903831d35Sstevel
287003831d35Sstevel /*
287103831d35Sstevel * schpc_putrequest
287203831d35Sstevel *
287303831d35Sstevel * A wrapper around the synchronous call mboxsc_putmsg().
287403831d35Sstevel */
287503831d35Sstevel 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)287603831d35Sstevel schpc_putrequest(uint32_t key, uint32_t type, uint32_t cmd, uint64_t *transidp,
287703831d35Sstevel uint32_t length, void *datap, clock_t timeout,
287803831d35Sstevel schpc_replylist_t **entryp)
287903831d35Sstevel {
288003831d35Sstevel int rval;
288103831d35Sstevel
288203831d35Sstevel /* add the request to replylist to keep track of outstanding requests */
288303831d35Sstevel *entryp = schpc_replylist_link(cmd, *transidp, length);
288403831d35Sstevel
288503831d35Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - "
288603831d35Sstevel "0x%lx transid mboxsc_putmsg called", *transidp);
288703831d35Sstevel
288803831d35Sstevel /* wait synchronously for request to be sent */
288903831d35Sstevel rval = mboxsc_putmsg(key, type, cmd, transidp, length,
289003831d35Sstevel (void *)datap, timeout);
289103831d35Sstevel
289203831d35Sstevel SCHPC_DEBUG2(D_GETSLOTSTATUS|D_SETSLOTSTATUS, "schpc_putrequest() - "
289303831d35Sstevel "0x%lx transid mboxsc_putmsg returned 0x%x", *transidp, rval);
289403831d35Sstevel
289503831d35Sstevel /* if problem is encountered then remove the request from replylist */
289603831d35Sstevel if (rval)
289703831d35Sstevel schpc_replylist_unlink(*entryp);
289803831d35Sstevel
289903831d35Sstevel return (rval);
290003831d35Sstevel }
290103831d35Sstevel
290203831d35Sstevel
290303831d35Sstevel /*
290403831d35Sstevel * schpc_getreply
290503831d35Sstevel *
290603831d35Sstevel * Wait for the schpc_msg_thread to respond that a matching reply has
290703831d35Sstevel * arrived; otherwise, timeout and remove the entry from the schpc_replylist.
290803831d35Sstevel */
290903831d35Sstevel /*ARGSUSED*/
291003831d35Sstevel 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)291103831d35Sstevel schpc_getreply(uint32_t key, uint32_t *typep, uint32_t *cmdp,
291203831d35Sstevel uint64_t *transidp, uint32_t *lengthp, void *datap,
291303831d35Sstevel clock_t timeout, schpc_replylist_t *listp)
291403831d35Sstevel {
291503831d35Sstevel int rc = 0;
291603831d35Sstevel
291703831d35Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
291803831d35Sstevel "schpc_getreply() - 0x%lx transid waiting for reply",
291903831d35Sstevel *transidp);
292003831d35Sstevel
292103831d35Sstevel /*
292203831d35Sstevel * wait here until schpc_msg_thread because it's always
292303831d35Sstevel * looking for reply messages
292403831d35Sstevel */
292503831d35Sstevel mutex_enter(&listp->reply_lock);
292603831d35Sstevel
292703831d35Sstevel while (listp->reply_recvd == B_FALSE) {
292803831d35Sstevel /*
292903831d35Sstevel * wait for reply or timeout
293003831d35Sstevel */
293103831d35Sstevel rc = cv_timedwait(&listp->reply_cv, &listp->reply_lock,
293203831d35Sstevel ddi_get_lbolt() + drv_usectohz(timeout * 1000));
293303831d35Sstevel switch (rc) {
293403831d35Sstevel case -1: /* most likely a timeout, but check anyway */
293503831d35Sstevel
293603831d35Sstevel /* message was received after all */
293703831d35Sstevel if (listp->reply_recvd == B_TRUE)
293803831d35Sstevel break;
293903831d35Sstevel
294003831d35Sstevel /* no, it's really a timeout */
294103831d35Sstevel listp->reply_cexit = B_TRUE;
294203831d35Sstevel mutex_exit(&listp->reply_lock);
294303831d35Sstevel cmn_err(CE_WARN,
294403831d35Sstevel "schpc - 0x%lx transid reply timed out", *transidp);
294503831d35Sstevel schpc_replylist_unlink(listp);
294603831d35Sstevel return (ETIMEDOUT);
294703831d35Sstevel
294803831d35Sstevel default:
294903831d35Sstevel break;
295003831d35Sstevel }
295103831d35Sstevel }
295203831d35Sstevel
295303831d35Sstevel *typep = listp->type;
295403831d35Sstevel *cmdp = listp->cmd;
295503831d35Sstevel *transidp = listp->transid;
295603831d35Sstevel *lengthp = listp->length;
295703831d35Sstevel bcopy((caddr_t)&listp->reply, datap, *lengthp);
295803831d35Sstevel mutex_exit(&listp->reply_lock);
295903831d35Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
296003831d35Sstevel "schpc_getreply() - 0x%lx transid received", *transidp);
296103831d35Sstevel schpc_replylist_unlink(listp);
296203831d35Sstevel return (0);
296303831d35Sstevel }
296403831d35Sstevel
296503831d35Sstevel
296603831d35Sstevel /*
296703831d35Sstevel * schpc_replylist_unlink
296803831d35Sstevel *
296903831d35Sstevel * Deallocate a schpc_replylist_t element.
297003831d35Sstevel */
297103831d35Sstevel void
schpc_replylist_unlink(schpc_replylist_t * entry)297203831d35Sstevel schpc_replylist_unlink(schpc_replylist_t *entry)
297303831d35Sstevel {
297403831d35Sstevel #if DEBUG
297503831d35Sstevel schpc_replylist_t *dbg_entry;
297603831d35Sstevel #endif /* DEBUG */
297703831d35Sstevel
297803831d35Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
297903831d35Sstevel "schpc_replylist_unlink() - 0x%lx transid deleted from replylist",
298003831d35Sstevel entry->transid);
298103831d35Sstevel
298203831d35Sstevel mutex_enter(&schpc_replylist_mutex);
298303831d35Sstevel if (entry->prev) {
298403831d35Sstevel entry->prev->next = entry->next;
298503831d35Sstevel if (entry->next)
298603831d35Sstevel entry->next->prev = entry->prev;
298703831d35Sstevel } else {
298803831d35Sstevel schpc_replylist_first = entry->next;
298903831d35Sstevel if (entry->next)
299003831d35Sstevel entry->next->prev = NULL;
299103831d35Sstevel }
299203831d35Sstevel if (entry == schpc_replylist_last) {
299303831d35Sstevel schpc_replylist_last = entry->prev;
299403831d35Sstevel }
299503831d35Sstevel kmem_free(entry, sizeof (schpc_replylist_t));
299603831d35Sstevel schpc_replylist_count--;
299703831d35Sstevel
299803831d35Sstevel #if DEBUG
299903831d35Sstevel if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) {
300003831d35Sstevel dbg_entry = schpc_replylist_first;
300103831d35Sstevel cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - replylist "
300203831d35Sstevel "count = %d\n", schpc_replylist_count);
300303831d35Sstevel while (dbg_entry != NULL) {
300403831d35Sstevel cmn_err(CE_CONT, "schpc: schpc_replylist_unlink() - "
300503831d35Sstevel "0x%lx transid\n", dbg_entry->transid);
300603831d35Sstevel dbg_entry = dbg_entry->next;
300703831d35Sstevel }
300803831d35Sstevel }
300903831d35Sstevel #endif /* DEBUG */
301003831d35Sstevel
301103831d35Sstevel mutex_exit(&schpc_replylist_mutex);
301203831d35Sstevel }
301303831d35Sstevel
301403831d35Sstevel
301503831d35Sstevel /*
301603831d35Sstevel * schpc_replylist_link
301703831d35Sstevel *
301803831d35Sstevel * Allocate and initialize a schpc_replylist_t element.
301903831d35Sstevel */
302003831d35Sstevel schpc_replylist_t *
schpc_replylist_link(uint32_t cmd,uint64_t transid,uint32_t length)302103831d35Sstevel schpc_replylist_link(uint32_t cmd, uint64_t transid, uint32_t length)
302203831d35Sstevel {
302303831d35Sstevel schpc_replylist_t *entry;
302403831d35Sstevel #if DEBUG
302503831d35Sstevel schpc_replylist_t *dbg_entry;
302603831d35Sstevel #endif /* DEBUG */
302703831d35Sstevel
302803831d35Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS|D_SETSLOTSTATUS,
302903831d35Sstevel "schpc_replylist_link() - 0x%lx transid inserting into replylist",
303003831d35Sstevel transid);
303103831d35Sstevel
303203831d35Sstevel entry = kmem_zalloc(sizeof (schpc_replylist_t), KM_SLEEP);
303303831d35Sstevel mutex_init(&entry->reply_lock, NULL, MUTEX_DRIVER, NULL);
303403831d35Sstevel cv_init(&entry->reply_cv, NULL, CV_DRIVER, NULL);
303503831d35Sstevel entry->type = MBOXSC_MSG_REPLY;
303603831d35Sstevel entry->cmd = cmd;
303703831d35Sstevel entry->transid = transid;
303803831d35Sstevel entry->length = length;
303903831d35Sstevel entry->reply_recvd = B_FALSE;
304003831d35Sstevel entry->reply_cexit = B_FALSE;
304103831d35Sstevel
304203831d35Sstevel mutex_enter(&schpc_replylist_mutex);
304303831d35Sstevel if (schpc_replylist_last) {
304403831d35Sstevel entry->prev = schpc_replylist_last;
304503831d35Sstevel schpc_replylist_last->next = entry;
304603831d35Sstevel schpc_replylist_last = entry;
304703831d35Sstevel } else {
304803831d35Sstevel schpc_replylist_last = schpc_replylist_first = entry;
304903831d35Sstevel }
305003831d35Sstevel
305103831d35Sstevel schpc_replylist_count++;
305203831d35Sstevel
305303831d35Sstevel #if DEBUG
305403831d35Sstevel if (schpc_debug_flags & (D_GETSLOTSTATUS|D_SETSLOTSTATUS)) {
305503831d35Sstevel dbg_entry = schpc_replylist_first;
305603831d35Sstevel cmn_err(CE_CONT, "schpc: schpc_replylist_link() - replylist "
305703831d35Sstevel "count = %d\n", schpc_replylist_count);
305803831d35Sstevel while (dbg_entry != NULL) {
305903831d35Sstevel cmn_err(CE_CONT, "schpc: schpc_replylist_link() - "
306003831d35Sstevel "0x%lx transid\n", dbg_entry->transid);
306103831d35Sstevel dbg_entry = dbg_entry->next;
306203831d35Sstevel }
306303831d35Sstevel }
306403831d35Sstevel #endif /* DEBUG */
306503831d35Sstevel
306603831d35Sstevel mutex_exit(&schpc_replylist_mutex);
306703831d35Sstevel
306803831d35Sstevel return (entry);
306903831d35Sstevel }
307003831d35Sstevel
307103831d35Sstevel
307203831d35Sstevel /*
307303831d35Sstevel * schpc_getslotstatus
307403831d35Sstevel *
307503831d35Sstevel * Issues a Get Slot Status command to the System Controller
307603831d35Sstevel * for a specific slot.
307703831d35Sstevel */
307803831d35Sstevel static int
schpc_getslotstatus(uint32_t expander,uint32_t board,uint32_t slot,pci_getslot_t * slotstatus)307903831d35Sstevel schpc_getslotstatus(uint32_t expander, uint32_t board, uint32_t slot,
308003831d35Sstevel pci_getslot_t *slotstatus)
308103831d35Sstevel {
308203831d35Sstevel pcimsg_t request;
308303831d35Sstevel pcimsg_t reply;
308403831d35Sstevel int rval;
308503831d35Sstevel uint32_t type, cmd, length;
308603831d35Sstevel uint64_t transid;
308703831d35Sstevel schpc_replylist_t *entry;
308803831d35Sstevel
308903831d35Sstevel SCHPC_DEBUG4(D_GETSLOTSTATUS,
309003831d35Sstevel "schpc_getslotstatus(expander=%d board=%d "
309103831d35Sstevel "slot=%d slotstatus=0x%p", expander, board,
3092*07d06da5SSurya Prakki SCHPC_SLOT_NUM(slot), (void *)slotstatus);
309303831d35Sstevel
309403831d35Sstevel if (schpc_p == NULL) {
309503831d35Sstevel return (1);
309603831d35Sstevel }
309703831d35Sstevel
309803831d35Sstevel bzero(&request, sizeof (pcimsg_t));
309903831d35Sstevel
310003831d35Sstevel request.pcimsg_node = expander;
310103831d35Sstevel request.pcimsg_board = board;
310203831d35Sstevel request.pcimsg_slot = SCHPC_SLOT_NUM(slot);
310303831d35Sstevel request.pcimsg_revision = PCIMSG_REVISION;
310403831d35Sstevel request.pcimsg_command = PCIMSG_GETSLOTSTATUS;
310503831d35Sstevel
310603831d35Sstevel type = MBOXSC_MSG_REQUEST;
310703831d35Sstevel cmd = PCIMSG_GETSLOTSTATUS;
310803831d35Sstevel transid = schpc_gettransid(schpc_p, slot);
310903831d35Sstevel length = sizeof (pcimsg_t);
311003831d35Sstevel
311103831d35Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
311203831d35Sstevel "0x%lx transid schpc_putrequest called", transid);
311303831d35Sstevel
311403831d35Sstevel rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length,
311503831d35Sstevel (void *)&request, schpc_timeout_putmsg, &entry);
311603831d35Sstevel
311703831d35Sstevel SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
311803831d35Sstevel "0x%lx transid schpc_putrequest returned 0x%x", transid, rval);
311903831d35Sstevel
312003831d35Sstevel if (rval) {
312103831d35Sstevel return (rval);
312203831d35Sstevel }
312303831d35Sstevel
312403831d35Sstevel bzero(&reply, sizeof (pcimsg_t));
312503831d35Sstevel type = MBOXSC_MSG_REPLY;
312603831d35Sstevel
312703831d35Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
312803831d35Sstevel "0x%lx transid schpc_getreply called", transid);
312903831d35Sstevel
313003831d35Sstevel rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length,
313103831d35Sstevel (void *)&reply, schpc_timeout_getmsg, entry);
313203831d35Sstevel
313303831d35Sstevel SCHPC_DEBUG2(D_GETSLOTSTATUS, "schpc_getslotstatus() - "
313403831d35Sstevel "0x%lx transid schpc_getreply returned 0x%x", transid, rval);
313503831d35Sstevel
313603831d35Sstevel if (rval == 0) {
313703831d35Sstevel *slotstatus = reply.pcimsg_type.pcimsg_getslot;
313803831d35Sstevel
313903831d35Sstevel SCHPC_DEBUG0(D_GETSLOTSTATUS, "schpc_getslotstatus()");
314003831d35Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_power_on %x",
314103831d35Sstevel reply.pcimsg_type.pcimsg_getslot.slot_power_on);
314203831d35Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_powergood %x",
314303831d35Sstevel reply.pcimsg_type.pcimsg_getslot.slot_powergood);
314403831d35Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_powerfault %x",
314503831d35Sstevel reply.pcimsg_type.pcimsg_getslot.slot_powerfault);
314603831d35Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_empty %x",
314703831d35Sstevel reply.pcimsg_type.pcimsg_getslot.slot_empty);
314803831d35Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_freq_cap %x",
314903831d35Sstevel reply.pcimsg_type.pcimsg_getslot.slot_freq_cap);
315003831d35Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_freq_setting %x",
315103831d35Sstevel reply.pcimsg_type.pcimsg_getslot.slot_freq_setting);
315203831d35Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_condition %x",
315303831d35Sstevel reply.pcimsg_type.pcimsg_getslot.slot_condition);
315403831d35Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_HEALTHY %x",
315503831d35Sstevel reply.pcimsg_type.pcimsg_getslot.slot_HEALTHY);
315603831d35Sstevel SCHPC_DEBUG1(D_GETSLOTSTATUS, " slot_ENUM %x",
315703831d35Sstevel reply.pcimsg_type.pcimsg_getslot.slot_ENUM);
315803831d35Sstevel }
315903831d35Sstevel
316003831d35Sstevel return (rval);
316103831d35Sstevel }
316203831d35Sstevel
316303831d35Sstevel
316403831d35Sstevel /*
316503831d35Sstevel * schpc_setslotstatus
316603831d35Sstevel *
316703831d35Sstevel * Issues a Set Slot Status command to the System Controller
316803831d35Sstevel * for a specific slot.
316903831d35Sstevel */
317003831d35Sstevel static int
schpc_setslotstatus(uint32_t expander,uint32_t board,uint32_t slot,pci_setslot_t * slotstatus)317103831d35Sstevel schpc_setslotstatus(uint32_t expander, uint32_t board, uint32_t slot,
317203831d35Sstevel pci_setslot_t *slotstatus)
317303831d35Sstevel {
317403831d35Sstevel pcimsg_t request;
317503831d35Sstevel pcimsg_t reply;
317603831d35Sstevel int rval;
317703831d35Sstevel uint32_t type, cmd, length;
317803831d35Sstevel uint64_t transid;
317903831d35Sstevel schpc_replylist_t *entry;
318003831d35Sstevel
318103831d35Sstevel SCHPC_DEBUG4(D_SETSLOTSTATUS,
318203831d35Sstevel "schpc_setslotstatus(expander=%d board=%d "
318303831d35Sstevel "slot=%d slotstatus=0x%p", expander, board,
3184*07d06da5SSurya Prakki SCHPC_SLOT_NUM(slot), (void *)slotstatus);
318503831d35Sstevel
318603831d35Sstevel bzero(&request, sizeof (pcimsg_t));
318703831d35Sstevel
318803831d35Sstevel if (schpc_p == NULL) {
318903831d35Sstevel return (1);
319003831d35Sstevel }
319103831d35Sstevel
319203831d35Sstevel request.pcimsg_node = expander;
319303831d35Sstevel request.pcimsg_board = board;
319403831d35Sstevel request.pcimsg_slot = SCHPC_SLOT_NUM(slot);
319503831d35Sstevel request.pcimsg_revision = PCIMSG_REVISION;
319603831d35Sstevel request.pcimsg_command = PCIMSG_SETSLOTSTATUS;
319703831d35Sstevel
319803831d35Sstevel request.pcimsg_type.pcimsg_setslot = *slotstatus;
319903831d35Sstevel
320003831d35Sstevel SCHPC_DEBUG0(D_IOC_LED, "schpc_setslotstatus() - LED state change");
320103831d35Sstevel SCHPC_DEBUG3(D_IOC_LED, "LED Power %d Service %d Fault %d",
320203831d35Sstevel slotstatus->slot_led_power,
320303831d35Sstevel slotstatus->slot_led_service,
320403831d35Sstevel slotstatus->slot_led_fault);
320503831d35Sstevel
320603831d35Sstevel type = MBOXSC_MSG_REQUEST;
320703831d35Sstevel cmd = PCIMSG_SETSLOTSTATUS;
320803831d35Sstevel transid = schpc_gettransid(schpc_p, slot);
320903831d35Sstevel length = sizeof (pcimsg_t);
321003831d35Sstevel
321103831d35Sstevel SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
321203831d35Sstevel "0x%lx transid schpc_putrequest called", transid);
321303831d35Sstevel
321403831d35Sstevel rval = schpc_putrequest(KEY_PCSC, type, cmd, &transid, length,
321503831d35Sstevel (void *)&request, schpc_timeout_putmsg, &entry);
321603831d35Sstevel
321703831d35Sstevel SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
321803831d35Sstevel "0x%lx transid schpc_putrequest returned 0x%x", transid, rval);
321903831d35Sstevel
322003831d35Sstevel if (rval) {
322103831d35Sstevel return (rval);
322203831d35Sstevel }
322303831d35Sstevel
322403831d35Sstevel bzero(&reply, sizeof (pcimsg_t));
322503831d35Sstevel type = MBOXSC_MSG_REPLY;
322603831d35Sstevel
322703831d35Sstevel SCHPC_DEBUG1(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
322803831d35Sstevel "0x%lx transid schpc_getreply called", transid);
322903831d35Sstevel
323003831d35Sstevel rval = schpc_getreply(KEY_SCPC, &type, &cmd, &transid, &length,
323103831d35Sstevel (void *)&reply, schpc_timeout_getmsg, entry);
323203831d35Sstevel
323303831d35Sstevel SCHPC_DEBUG2(D_SETSLOTSTATUS, "schpc_setslotstatus() - "
323403831d35Sstevel "0x%lx transid schpc_getreply returned 0x%x", transid, rval);
323503831d35Sstevel
323603831d35Sstevel if (rval == 0) {
323703831d35Sstevel slotstatus->slot_replystatus =
323803831d35Sstevel reply.pcimsg_type.pcimsg_setslot.slot_replystatus;
323903831d35Sstevel }
324003831d35Sstevel
324103831d35Sstevel return (rval);
324203831d35Sstevel }
324303831d35Sstevel
324403831d35Sstevel /*
324503831d35Sstevel * schpc_setslotled
324603831d35Sstevel *
324703831d35Sstevel * Changes the attention indicators for a given slot.
324803831d35Sstevel */
324903831d35Sstevel static void
schpc_setslotled(int expander,int board,int slot,uint32_t led_state)325003831d35Sstevel schpc_setslotled(int expander, int board, int slot, uint32_t led_state)
325103831d35Sstevel {
325203831d35Sstevel
325303831d35Sstevel pci_setslot_t setslot;
325403831d35Sstevel
325503831d35Sstevel if (schpc_p == NULL) {
325603831d35Sstevel return;
325703831d35Sstevel }
325803831d35Sstevel
325903831d35Sstevel schpc_init_setslot_message(&setslot);
326003831d35Sstevel
326103831d35Sstevel if (led_state & POWER_LED_ON) {
326203831d35Sstevel schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_ON;
326303831d35Sstevel }
326403831d35Sstevel if (led_state & POWER_LED_OFF) {
326503831d35Sstevel schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_OFF;
326603831d35Sstevel }
326703831d35Sstevel if (led_state & POWER_LED_FLASH) {
326803831d35Sstevel schpc_p->schpc_slot[slot].led.led_power = PCIMSG_LED_FLASH;
326903831d35Sstevel }
327003831d35Sstevel if (led_state & SERVICE_LED_ON) {
327103831d35Sstevel schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_ON;
327203831d35Sstevel }
327303831d35Sstevel if (led_state & SERVICE_LED_OFF) {
327403831d35Sstevel schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_OFF;
327503831d35Sstevel }
327603831d35Sstevel if (led_state & SERVICE_LED_FLASH) {
327703831d35Sstevel schpc_p->schpc_slot[slot].led.led_service = PCIMSG_LED_FLASH;
327803831d35Sstevel }
327903831d35Sstevel if (led_state & FAULT_LED_ON) {
328003831d35Sstevel schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_ON;
328103831d35Sstevel }
328203831d35Sstevel if (led_state & FAULT_LED_OFF) {
328303831d35Sstevel schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_OFF;
328403831d35Sstevel }
328503831d35Sstevel if (led_state & FAULT_LED_FLASH) {
328603831d35Sstevel schpc_p->schpc_slot[slot].led.led_fault = PCIMSG_LED_FLASH;
328703831d35Sstevel }
328803831d35Sstevel
328903831d35Sstevel switch (schpc_p->schpc_slot[slot].led.led_power) {
329003831d35Sstevel case PCIMSG_LED_ON:
329103831d35Sstevel setslot.slot_led_power = PCIMSG_LED_ON;
329203831d35Sstevel break;
329303831d35Sstevel case PCIMSG_LED_OFF:
329403831d35Sstevel setslot.slot_led_power = PCIMSG_LED_OFF;
329503831d35Sstevel break;
329603831d35Sstevel case PCIMSG_LED_FLASH:
329703831d35Sstevel setslot.slot_led_power = PCIMSG_LED_FLASH;
329803831d35Sstevel break;
329903831d35Sstevel }
330003831d35Sstevel switch (schpc_p->schpc_slot[slot].led.led_service) {
330103831d35Sstevel case PCIMSG_LED_ON:
330203831d35Sstevel setslot.slot_led_service = PCIMSG_LED_ON;
330303831d35Sstevel break;
330403831d35Sstevel case PCIMSG_LED_OFF:
330503831d35Sstevel setslot.slot_led_service = PCIMSG_LED_OFF;
330603831d35Sstevel break;
330703831d35Sstevel case PCIMSG_LED_FLASH:
330803831d35Sstevel setslot.slot_led_service = PCIMSG_LED_FLASH;
330903831d35Sstevel break;
331003831d35Sstevel }
331103831d35Sstevel switch (schpc_p->schpc_slot[slot].led.led_fault) {
331203831d35Sstevel case PCIMSG_LED_ON:
331303831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_ON;
331403831d35Sstevel break;
331503831d35Sstevel case PCIMSG_LED_OFF:
331603831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_OFF;
331703831d35Sstevel break;
331803831d35Sstevel case PCIMSG_LED_FLASH:
331903831d35Sstevel setslot.slot_led_fault = PCIMSG_LED_FLASH;
332003831d35Sstevel break;
332103831d35Sstevel }
332203831d35Sstevel
332303831d35Sstevel (void) schpc_setslotstatus(expander, board, slot, &setslot);
332403831d35Sstevel }
332503831d35Sstevel
332603831d35Sstevel /*
332703831d35Sstevel * schpc_init_setslot_message
332803831d35Sstevel *
332903831d35Sstevel * Initialize Set Slot Message before using it.
333003831d35Sstevel */
333103831d35Sstevel static void
schpc_init_setslot_message(pci_setslot_t * setslot)333203831d35Sstevel schpc_init_setslot_message(pci_setslot_t *setslot)
333303831d35Sstevel {
333403831d35Sstevel /*
333503831d35Sstevel * Initialize Set Slot Command.
333603831d35Sstevel */
333703831d35Sstevel setslot->slot_power_on = PCIMSG_OFF;
333803831d35Sstevel setslot->slot_power_off = PCIMSG_OFF;
333903831d35Sstevel setslot->slot_led_power = PCIMSG_LED_OFF;
334003831d35Sstevel setslot->slot_led_service = PCIMSG_LED_OFF;
334103831d35Sstevel setslot->slot_led_fault = PCIMSG_LED_OFF;
334203831d35Sstevel setslot->slot_disable_ENUM = PCIMSG_OFF;
334303831d35Sstevel setslot->slot_enable_ENUM = PCIMSG_OFF;
334403831d35Sstevel setslot->slot_disable_HEALTHY = PCIMSG_OFF;
334503831d35Sstevel setslot->slot_enable_HEALTHY = PCIMSG_OFF;
334603831d35Sstevel }
334703831d35Sstevel
334803831d35Sstevel /*
334903831d35Sstevel * schpc_gettransid
335003831d35Sstevel *
335103831d35Sstevel * Builds a unique transaction ID.
335203831d35Sstevel */
335303831d35Sstevel static uint64_t
schpc_gettransid(schpc_t * schpc_p,int slot)335403831d35Sstevel schpc_gettransid(schpc_t *schpc_p, int slot)
335503831d35Sstevel {
335603831d35Sstevel uint64_t trans_id;
335703831d35Sstevel
335803831d35Sstevel mutex_enter(&schpc_p->schpc_mutex);
335903831d35Sstevel
336003831d35Sstevel if (++schpc_p->schpc_transid == 0)
336103831d35Sstevel schpc_p->schpc_transid = 1;
336203831d35Sstevel
336303831d35Sstevel trans_id = (schpc_p->schpc_slot[slot].expander<<24) |
336403831d35Sstevel (schpc_p->schpc_slot[slot].board << 16) | schpc_p->schpc_transid;
336503831d35Sstevel
336603831d35Sstevel mutex_exit(&schpc_p->schpc_mutex);
336703831d35Sstevel
336803831d35Sstevel SCHPC_DEBUG1(D_TRANSID, "schpc_gettransid() - 0x%lx transid returning",
336903831d35Sstevel trans_id);
337003831d35Sstevel
337103831d35Sstevel return (trans_id);
337203831d35Sstevel }
337303831d35Sstevel
337403831d35Sstevel /*
337503831d35Sstevel * schpc_slot_get_index
337603831d35Sstevel *
337703831d35Sstevel * get slot table index from the slot handle
337803831d35Sstevel */
337903831d35Sstevel static int
schpc_slot_get_index(schpc_t * schpc_p,hpc_slot_t slot)338003831d35Sstevel schpc_slot_get_index(schpc_t *schpc_p, hpc_slot_t slot)
338103831d35Sstevel {
338203831d35Sstevel int i;
338303831d35Sstevel int rval = -1;
338403831d35Sstevel
338503831d35Sstevel ASSERT(MUTEX_HELD(&schpc_p->schpc_mutex));
338603831d35Sstevel
338703831d35Sstevel for (i = 0; i < schpc_p->schpc_number_of_slots; i++) {
338803831d35Sstevel if (schpc_p->schpc_slot[i].slot_handle == slot)
338903831d35Sstevel return (i);
339003831d35Sstevel }
339103831d35Sstevel
339203831d35Sstevel return (rval);
339303831d35Sstevel }
339403831d35Sstevel
339503831d35Sstevel /*
339603831d35Sstevel * schpc_register_all_slots
339703831d35Sstevel *
339803831d35Sstevel * Search device tree for pci nodes and register attachment points
339903831d35Sstevel * for all hot pluggable slots.
340003831d35Sstevel */
340103831d35Sstevel /*ARGSUSED*/
340203831d35Sstevel static void
schpc_register_all_slots(schpc_t * schpc_p)340303831d35Sstevel schpc_register_all_slots(schpc_t *schpc_p)
340403831d35Sstevel {
340503831d35Sstevel int slot = 0;
340603831d35Sstevel char caddr[64];
340703831d35Sstevel dev_info_t *pci_dip = NULL;
340803831d35Sstevel find_dev_t find_dev;
340903831d35Sstevel int leaf, schizo, expander, portid, offset;
341003831d35Sstevel
341103831d35Sstevel SCHPC_DEBUG1(D_ATTACH,
3412*07d06da5SSurya Prakki "schpc_register_all_slots(schpc_p=%p)", (void *)schpc_p);
341303831d35Sstevel
341403831d35Sstevel /*
341503831d35Sstevel * Allow the event_handler to start processing unsolicited
341603831d35Sstevel * events now that slots are about to be registered.
341703831d35Sstevel */
341803831d35Sstevel slots_registered = B_TRUE;
341903831d35Sstevel
342003831d35Sstevel for (slot = 0; slot < STARCAT_MAX_SLOTS; slot++) {
342103831d35Sstevel
342203831d35Sstevel leaf = SCHPC_SLOT_LEAF(slot);
342303831d35Sstevel schizo = SCHPC_SLOT_SCHIZO(slot);
342403831d35Sstevel expander = SCHPC_SLOT_EXPANDER(slot);
342503831d35Sstevel
342603831d35Sstevel if (schizo == 0)
342703831d35Sstevel portid = 0x1c;
342803831d35Sstevel else
342903831d35Sstevel portid = 0x1d;
343003831d35Sstevel
343103831d35Sstevel if (leaf == 0)
343203831d35Sstevel offset = 0x600000;
343303831d35Sstevel else
343403831d35Sstevel offset = 0x700000;
343503831d35Sstevel
343603831d35Sstevel portid = (expander << 5) | portid;
343703831d35Sstevel
343803831d35Sstevel (void) sprintf(caddr, "%x,%x", portid, offset);
343903831d35Sstevel
344003831d35Sstevel SCHPC_DEBUG3(D_ATTACH,
344103831d35Sstevel "schpc_register_all_slots: searching for pci@%s"
344203831d35Sstevel " schizo=%d, leaf=%d", caddr, schizo, leaf);
344303831d35Sstevel
344403831d35Sstevel find_dev.cname = "pci";
344503831d35Sstevel find_dev.caddr = caddr;
344603831d35Sstevel find_dev.schizo = schizo;
344703831d35Sstevel find_dev.leaf = leaf;
344803831d35Sstevel find_dev.dip = NULL;
344903831d35Sstevel
345003831d35Sstevel /* root node doesn't have to be held */
345103831d35Sstevel ddi_walk_devs(ddi_root_node(), schpc_match_dip,
345203831d35Sstevel &find_dev);
345303831d35Sstevel
345403831d35Sstevel pci_dip = find_dev.dip;
345503831d35Sstevel
345603831d35Sstevel if (pci_dip == NULL) {
345703831d35Sstevel
345803831d35Sstevel SCHPC_DEBUG1(D_ATTACH,
345903831d35Sstevel "schpc_register_all_slots: pci@%s NOT FOUND",
346003831d35Sstevel caddr);
346103831d35Sstevel
346203831d35Sstevel continue;
346303831d35Sstevel }
346403831d35Sstevel
346503831d35Sstevel SCHPC_DEBUG2(D_ATTACH,
346603831d35Sstevel "schpc_register_all_slots: pci@%s FOUND dip=0x%p",
3467*07d06da5SSurya Prakki caddr, (void *)pci_dip);
346803831d35Sstevel
346903831d35Sstevel (void) schpc_add_pci(pci_dip);
347003831d35Sstevel
347103831d35Sstevel /*
347203831d35Sstevel * Release hold acquired in schpc_match_dip()
347303831d35Sstevel */
347403831d35Sstevel ndi_rele_devi(pci_dip);
347503831d35Sstevel }
347603831d35Sstevel
347703831d35Sstevel SCHPC_DEBUG0(D_ATTACH, "schpc_register_all_slots: Thread Exit");
347803831d35Sstevel
347903831d35Sstevel thread_exit();
348003831d35Sstevel }
348103831d35Sstevel
348203831d35Sstevel /*
348303831d35Sstevel * schpc_add_pci
348403831d35Sstevel *
348503831d35Sstevel * Routine to add attachments points associated with a pci node.
348603831d35Sstevel * Can be call externally by DR when configuring a PCI I/O Board.
348703831d35Sstevel */
348803831d35Sstevel int
schpc_add_pci(dev_info_t * bdip)348903831d35Sstevel schpc_add_pci(dev_info_t *bdip)
349003831d35Sstevel {
349103831d35Sstevel int portid;
349203831d35Sstevel int expander, board, schizo, leaf, slot, status;
349303831d35Sstevel char ap_id[MAXNAMELEN];
349403831d35Sstevel char caddr[64];
349503831d35Sstevel char *naddr;
349603831d35Sstevel hpc_slot_info_t slot_info;
349703831d35Sstevel hpc_slot_ops_t *slot_ops;
349803831d35Sstevel dev_info_t *sdip = bdip;
349903831d35Sstevel
3500*07d06da5SSurya Prakki SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci(dip=0x%p)", (void *)sdip);
350103831d35Sstevel
350203831d35Sstevel if (schpc_p == NULL) {
350303831d35Sstevel /*
350403831d35Sstevel * The schpc driver has not been attached yet.
350503831d35Sstevel */
350603831d35Sstevel return (DDI_SUCCESS);
350703831d35Sstevel }
350803831d35Sstevel
350903831d35Sstevel if ((portid = ddi_getprop(DDI_DEV_T_ANY, sdip, 0, "portid", -1)) < 0) {
3510*07d06da5SSurya Prakki cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - no portid\n",
3511*07d06da5SSurya Prakki (void *)sdip);
351203831d35Sstevel return (DDI_FAILURE);
351303831d35Sstevel }
351403831d35Sstevel
351503831d35Sstevel expander = schpc_getexpander(sdip);
351603831d35Sstevel board = schpc_getboard(sdip);
351703831d35Sstevel
351803831d35Sstevel switch (portid & 0x1f) {
351903831d35Sstevel
352003831d35Sstevel case 0x1c:
352103831d35Sstevel schizo = 0;
352203831d35Sstevel break;
352303831d35Sstevel case 0x1d:
352403831d35Sstevel schizo = 1;
352503831d35Sstevel break;
352603831d35Sstevel default:
352703831d35Sstevel cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3528*07d06da5SSurya Prakki "Invalid pci portid 0x%x\n", (void *)sdip, portid);
352903831d35Sstevel return (DDI_FAILURE);
353003831d35Sstevel }
353103831d35Sstevel
353203831d35Sstevel naddr = ddi_get_name_addr(sdip);
353303831d35Sstevel if (naddr == NULL) {
353403831d35Sstevel SCHPC_DEBUG1(D_ATTACH, "schpc_add_pci: ddi_get_name_addr"
3535*07d06da5SSurya Prakki "(0x%p) returns null", (void *)sdip);
353603831d35Sstevel return (DDI_FAILURE);
353703831d35Sstevel }
353803831d35Sstevel
353903831d35Sstevel (void) sprintf(caddr, "%x,600000", portid);
354003831d35Sstevel
354103831d35Sstevel if (strcmp(caddr, naddr) == 0) {
354203831d35Sstevel leaf = 0;
354303831d35Sstevel } else {
354403831d35Sstevel (void) sprintf(caddr, "%x,700000", portid);
354503831d35Sstevel if (strcmp(caddr, naddr) == 0) {
354603831d35Sstevel char *name;
354703831d35Sstevel
354803831d35Sstevel leaf = 1;
354903831d35Sstevel name = ddi_binding_name(sdip);
355003831d35Sstevel if ((strcmp(name, "pci108e,8002") == 0) &&
355103831d35Sstevel (schizo == 0)) {
355203831d35Sstevel int circ;
355303831d35Sstevel dev_info_t *cdip;
355403831d35Sstevel /*
355503831d35Sstevel * XMITS 0 Leaf B will have its hot
355603831d35Sstevel * pluggable slot off a PCI-PCI bridge,
355703831d35Sstevel * which is the only child.
355803831d35Sstevel */
355903831d35Sstevel ndi_devi_enter(sdip, &circ);
356003831d35Sstevel cdip = ddi_get_child(sdip);
356103831d35Sstevel if (cdip == NULL) {
356203831d35Sstevel cmn_err(CE_WARN,
356303831d35Sstevel "schpc_add_pci(dip=0x%p) - "
356403831d35Sstevel "Invalid pci name addr %s\n",
3565*07d06da5SSurya Prakki (void *)sdip, naddr);
356603831d35Sstevel ndi_devi_exit(sdip, circ);
356703831d35Sstevel return (DDI_FAILURE);
356803831d35Sstevel }
356903831d35Sstevel ndi_devi_exit(sdip, circ);
357003831d35Sstevel sdip = cdip;
357103831d35Sstevel }
357203831d35Sstevel } else {
357303831d35Sstevel cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3574*07d06da5SSurya Prakki "Invalid pci name addr %s\n", (void *)sdip, naddr);
357503831d35Sstevel return (DDI_FAILURE);
357603831d35Sstevel }
357703831d35Sstevel }
357803831d35Sstevel
357903831d35Sstevel /* create a slot table index */
358003831d35Sstevel slot = SCHPC_MAKE_SLOT_INDEX3(expander, schizo, leaf);
358103831d35Sstevel
358203831d35Sstevel if (schpc_p->schpc_slot[slot].devi) {
358303831d35Sstevel cmn_err(CE_WARN, "schpc_add_pci(dip=0x%p) - "
3584*07d06da5SSurya Prakki "pci node already registered\n", (void *)sdip);
358503831d35Sstevel return (DDI_FAILURE);
358603831d35Sstevel }
358703831d35Sstevel
358803831d35Sstevel /*
358903831d35Sstevel * There is no need to hold the dip while saving it in
359003831d35Sstevel * the devi field below. The dip is never dereferenced.
359103831d35Sstevel * (If that changes, this code should be modified).
359203831d35Sstevel * We want to avoid holding the dip here because it
359303831d35Sstevel * prevents DR.
359403831d35Sstevel *
359503831d35Sstevel * NOTE: Even though the slot on XMITS0 Leaf-B
359603831d35Sstevel * is connected to a pci_pci bridge, we will be saving
359703831d35Sstevel * the busdip in this datastructure. This will make
359803831d35Sstevel * it easier to identify the dip being removed in
359903831d35Sstevel * schpc_remove_pci().
360003831d35Sstevel */
360103831d35Sstevel schpc_p->schpc_slot[slot].devi = bdip;
360203831d35Sstevel
360303831d35Sstevel schpc_p->schpc_slot[slot].expander = expander;
360403831d35Sstevel schpc_p->schpc_slot[slot].board = board;
360503831d35Sstevel schpc_p->schpc_slot[slot].schizo = schizo;
360603831d35Sstevel schpc_p->schpc_slot[slot].leaf = leaf;
360703831d35Sstevel
360803831d35Sstevel /*
360903831d35Sstevel * Starcat PCI slots are always PCI device 1.
361003831d35Sstevel */
361103831d35Sstevel schpc_p->schpc_slot[slot].pci_id = 1;
361203831d35Sstevel
361303831d35Sstevel schpc_buildapid(sdip, slot, (char *)&ap_id);
361403831d35Sstevel
361503831d35Sstevel (void) strcpy(schpc_p->schpc_slot[slot].ap_id, (char *)&ap_id);
361603831d35Sstevel
361703831d35Sstevel /* safe to call ddi_pathname(): bdip is held */
361803831d35Sstevel (void) ddi_pathname(sdip, schpc_p->schpc_slot[slot].nexus_path);
361903831d35Sstevel
362003831d35Sstevel status = schpc_get_slot_status(expander, board, SCHPC_SLOT_NUM(slot));
362103831d35Sstevel switch (status) {
362203831d35Sstevel case RSV_UNKNOWN:
362303831d35Sstevel case RSV_PRESENT:
362403831d35Sstevel case RSV_MISS:
362503831d35Sstevel case RSV_PASS:
362603831d35Sstevel case RSV_EMPTY_CASSETTE:
362703831d35Sstevel
362803831d35Sstevel /*
362903831d35Sstevel * Test the condition of the slot.
363003831d35Sstevel */
363103831d35Sstevel schpc_test((caddr_t)schpc_p, slot, 0, 0);
363203831d35Sstevel break;
363303831d35Sstevel case RSV_BLACK:
363403831d35Sstevel schpc_p->schpc_slot[slot].state = 0;
363503831d35Sstevel cmn_err(CE_WARN, "schpc: PCI card blacklisted: "
363603831d35Sstevel "expander=%d board=%d slot=%d\n", expander,
363703831d35Sstevel board, SCHPC_SLOT_NUM(slot));
363803831d35Sstevel break;
363903831d35Sstevel default:
364003831d35Sstevel schpc_p->schpc_slot[slot].state = 0;
364103831d35Sstevel cmn_err(CE_WARN, "schpc: PCI card failed by POST: "
364203831d35Sstevel "expander=%d board=%d slot=%d failure=0x%x\n",
364303831d35Sstevel expander, board, SCHPC_SLOT_NUM(slot), status);
364403831d35Sstevel break;
364503831d35Sstevel }
364603831d35Sstevel
364703831d35Sstevel if (schpc_p->schpc_slot[slot].state & SCHPC_SLOTSTATE_REC_GOOD) {
364803831d35Sstevel
364903831d35Sstevel /* allocate slot ops */
365003831d35Sstevel
365103831d35Sstevel slot_ops = hpc_alloc_slot_ops(KM_SLEEP);
365203831d35Sstevel schpc_p->schpc_slot[slot].slot_ops = slot_ops;
365303831d35Sstevel
365403831d35Sstevel /*
365503831d35Sstevel * Default to Autoconfiguration disabled.
365603831d35Sstevel */
365703831d35Sstevel schpc_p->schpc_slot[slot].state &=
365803831d35Sstevel ~SCHPC_SLOTSTATE_AUTOCFG_ENABLE;
365903831d35Sstevel
366003831d35Sstevel /*
366103831d35Sstevel * Fill in the slot information structure that
366203831d35Sstevel * describes the slot.
366303831d35Sstevel */
366403831d35Sstevel slot_info.version = HPC_SLOT_OPS_VERSION;
366503831d35Sstevel
366603831d35Sstevel if (schpc_p->schpc_hotplugmodel ==
366703831d35Sstevel SCHPC_HOTPLUGTYPE_CPCIHOTPLUG)
366803831d35Sstevel slot_info.slot_type = HPC_SLOT_TYPE_PCI;
366903831d35Sstevel else
367003831d35Sstevel slot_info.slot_type = HPC_SLOT_TYPE_CPCI;
367103831d35Sstevel
367203831d35Sstevel slot_info.slot.pci.device_number =
367303831d35Sstevel schpc_p->schpc_slot[slot].pci_id;
367403831d35Sstevel
367503831d35Sstevel slot_info.slot.pci.slot_capabilities = HPC_SLOT_64BITS;
367603831d35Sstevel
367703831d35Sstevel if (schpc_use_legacy_apid)
367803831d35Sstevel slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE;
367903831d35Sstevel else
368003831d35Sstevel slot_info.slot_flags = HPC_SLOT_NO_AUTO_ENABLE |
368103831d35Sstevel HPC_SLOT_CREATE_DEVLINK;
368203831d35Sstevel
3683*07d06da5SSurya Prakki (void) strcpy(slot_info.slot.pci.slot_logical_name,
368403831d35Sstevel schpc_p->schpc_slot[slot].ap_id);
368503831d35Sstevel
368603831d35Sstevel /*
368703831d35Sstevel * Fill in the slot ops structure that tells
368803831d35Sstevel * the Hot Plug Services what function we
368903831d35Sstevel * support.
369003831d35Sstevel */
369103831d35Sstevel slot_ops->hpc_version = HPC_SLOT_OPS_VERSION;
369203831d35Sstevel if (schpc_p->schpc_hotplugmodel ==
369303831d35Sstevel SCHPC_HOTPLUGTYPE_CPCIHOTPLUG) {
369403831d35Sstevel slot_ops->hpc_op_connect = schpc_connect;
369503831d35Sstevel slot_ops->hpc_op_disconnect = schpc_disconnect;
369603831d35Sstevel slot_ops->hpc_op_insert = NULL;
369703831d35Sstevel slot_ops->hpc_op_remove = NULL;
369803831d35Sstevel slot_ops->hpc_op_control = schpc_pci_control;
369903831d35Sstevel } else {
370003831d35Sstevel slot_ops->hpc_op_connect = NULL;
370103831d35Sstevel slot_ops->hpc_op_disconnect = NULL;
370203831d35Sstevel slot_ops->hpc_op_insert = NULL;
370303831d35Sstevel slot_ops->hpc_op_remove = NULL;
370403831d35Sstevel slot_ops->hpc_op_control = schpc_cpci_control;
370503831d35Sstevel }
370603831d35Sstevel
370703831d35Sstevel SCHPC_DEBUG5(D_ATTACH, "schpc_add_pci: Registering HPC "
370803831d35Sstevel "- nexus =%s schpc_p=%p slot=%d pci number=%d ap_id=%s",
370903831d35Sstevel schpc_p->schpc_slot[slot].nexus_path,
3710*07d06da5SSurya Prakki (void *)schpc_p, SCHPC_SLOT_NUM(slot),
371103831d35Sstevel slot_info.slot.pci.device_number,
371203831d35Sstevel slot_info.slot.pci.slot_logical_name);
371303831d35Sstevel
371403831d35Sstevel if (hpc_slot_register(schpc_p->schpc_devi,
371503831d35Sstevel schpc_p->schpc_slot[slot].nexus_path, &slot_info,
371603831d35Sstevel &schpc_p->schpc_slot[slot].slot_handle,
371703831d35Sstevel slot_ops, (caddr_t)schpc_p, 0) != 0) {
371803831d35Sstevel
371903831d35Sstevel /*
372003831d35Sstevel * If the slot can not be registered,
372103831d35Sstevel * then the slot_ops need to be freed.
372203831d35Sstevel */
372303831d35Sstevel cmn_err(CE_WARN, "schpc%d Unable to Register "
372403831d35Sstevel "Slot %s", schpc_p->schpc_instance,
372503831d35Sstevel slot_info.slot.pci.slot_logical_name);
372603831d35Sstevel
372703831d35Sstevel hpc_free_slot_ops(schpc_p->schpc_slot[slot].slot_ops);
372803831d35Sstevel
372903831d35Sstevel schpc_p->schpc_slot[slot].slot_ops = NULL;
373003831d35Sstevel
373103831d35Sstevel return (DDI_FAILURE);
373203831d35Sstevel }
373303831d35Sstevel
373403831d35Sstevel /*
373503831d35Sstevel * We are ready to take commands from the HPC Services.
373603831d35Sstevel */
373703831d35Sstevel schpc_p->schpc_slot[slot].state |= SCHPC_SLOTSTATE_HPCINITED;
373803831d35Sstevel }
373903831d35Sstevel
374003831d35Sstevel return (DDI_SUCCESS);
374103831d35Sstevel }
374203831d35Sstevel
374303831d35Sstevel /*
374403831d35Sstevel * schpc_remove_pci
374503831d35Sstevel *
374603831d35Sstevel * Routine to remove attachments points associated with a pci node.
374703831d35Sstevel * Can be call externally by DR when unconfiguring a PCI I/O Board.
374803831d35Sstevel */
374903831d35Sstevel int
schpc_remove_pci(dev_info_t * dip)375003831d35Sstevel schpc_remove_pci(dev_info_t *dip)
375103831d35Sstevel {
375203831d35Sstevel int slot;
375303831d35Sstevel
3754*07d06da5SSurya Prakki SCHPC_DEBUG1(D_DETACH, "schpc_remove_pci(dip=0x%p)", (void *)dip);
375503831d35Sstevel
375603831d35Sstevel if (schpc_p == NULL) {
375703831d35Sstevel /*
375803831d35Sstevel * The schpc driver has not been attached yet.
375903831d35Sstevel */
376003831d35Sstevel return (DDI_SUCCESS);
376103831d35Sstevel }
376203831d35Sstevel
376303831d35Sstevel for (slot = 0; slot < schpc_p->schpc_number_of_slots; slot++) {
376403831d35Sstevel if (schpc_p->schpc_slot[slot].devi == dip) {
376503831d35Sstevel
376603831d35Sstevel if (schpc_p->schpc_slot[slot].slot_ops) {
376703831d35Sstevel if (hpc_slot_unregister(
376803831d35Sstevel &schpc_p->schpc_slot[slot].slot_handle)) {
376903831d35Sstevel cmn_err(CE_WARN,
377003831d35Sstevel "schpc_remove_pci(dip=0x%p) - "
377103831d35Sstevel "unable to unregister pci slots\n",
3772*07d06da5SSurya Prakki (void *)dip);
377303831d35Sstevel return (DDI_FAILURE);
377403831d35Sstevel } else {
377503831d35Sstevel hpc_free_slot_ops(
377603831d35Sstevel schpc_p->schpc_slot[slot].slot_ops);
377703831d35Sstevel
377803831d35Sstevel schpc_p->schpc_slot[slot].slot_ops =
377903831d35Sstevel NULL;
378003831d35Sstevel
378103831d35Sstevel schpc_p->schpc_slot[slot].devi = NULL;
378203831d35Sstevel
378303831d35Sstevel return (DDI_SUCCESS);
378403831d35Sstevel }
378503831d35Sstevel } else {
378603831d35Sstevel schpc_p->schpc_slot[slot].devi = NULL;
378703831d35Sstevel
378803831d35Sstevel return (DDI_SUCCESS);
378903831d35Sstevel }
379003831d35Sstevel }
379103831d35Sstevel }
379203831d35Sstevel
379303831d35Sstevel cmn_err(CE_WARN, "schpc_remove_pci(dip=0x%p) "
3794*07d06da5SSurya Prakki "dip not found\n", (void *)dip);
379503831d35Sstevel
379603831d35Sstevel return (DDI_SUCCESS);
379703831d35Sstevel }
379803831d35Sstevel
379903831d35Sstevel /*
380003831d35Sstevel * schpc_match_dip
380103831d35Sstevel *
380203831d35Sstevel * Used by ddi_walk_devs to find PCI Nexus nodes associated with
380303831d35Sstevel * Hot Plug Controllers.
380403831d35Sstevel */
380503831d35Sstevel static int
schpc_match_dip(dev_info_t * dip,void * arg)380603831d35Sstevel schpc_match_dip(dev_info_t *dip, void *arg)
380703831d35Sstevel {
380803831d35Sstevel char *naddr;
380903831d35Sstevel find_dev_t *find_dev = (find_dev_t *)arg;
381003831d35Sstevel
381103831d35Sstevel if (strcmp(find_dev->cname, ddi_node_name(dip)) == 0 &&
381203831d35Sstevel ((((naddr = ddi_get_name_addr(dip)) != NULL) &&
381303831d35Sstevel (strcmp(find_dev->caddr, naddr) == 0)) ||
381403831d35Sstevel ((naddr == NULL) && (strlen(find_dev->caddr) == 0)))) {
381503831d35Sstevel /*
381603831d35Sstevel * While ddi_walk_devs() holds dips when invoking this
381703831d35Sstevel * callback, this dip is being saved and will be accessible
381803831d35Sstevel * to the caller outside ddi_walk_devs(). Therefore it must be
381903831d35Sstevel * held.
382003831d35Sstevel */
382103831d35Sstevel ndi_hold_devi(dip);
382203831d35Sstevel find_dev->dip = dip;
382303831d35Sstevel
382403831d35Sstevel SCHPC_DEBUG2(D_ATTACH,
382503831d35Sstevel "schpc_match_dip: pci@%s FOUND dip=0x%p",
3826*07d06da5SSurya Prakki find_dev->caddr, (void *)find_dev->dip);
382703831d35Sstevel
382803831d35Sstevel return (DDI_WALK_TERMINATE);
382903831d35Sstevel }
383003831d35Sstevel
383103831d35Sstevel ASSERT(find_dev->dip == NULL);
383203831d35Sstevel return (DDI_WALK_CONTINUE);
383303831d35Sstevel }
383403831d35Sstevel
383503831d35Sstevel /*
383603831d35Sstevel * schpc_buildapid
383703831d35Sstevel *
383803831d35Sstevel * Takes a component address and translates it into a ap_id prefix.
383903831d35Sstevel */
384003831d35Sstevel static void
schpc_buildapid(dev_info_t * dip,int slot,char * ap_id)384103831d35Sstevel schpc_buildapid(dev_info_t *dip, int slot, char *ap_id)
384203831d35Sstevel {
384303831d35Sstevel int r, pci_id_cnt, pci_id_bit;
384403831d35Sstevel int slots_before, found;
384503831d35Sstevel unsigned char *slot_names_data, *s;
384603831d35Sstevel int slot_names_size;
384703831d35Sstevel int slot_num;
384803831d35Sstevel unsigned int bit_mask;
384903831d35Sstevel
385003831d35Sstevel slot_num = SCHPC_SLOT_NUM(slot);
385103831d35Sstevel
385203831d35Sstevel if (schpc_use_legacy_apid) {
385303831d35Sstevel SCHPC_DEBUG1(D_APID, "Slot %d - Using Legacy ap-id", slot);
385403831d35Sstevel
3855*07d06da5SSurya Prakki (void) sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip),
385603831d35Sstevel schpc_getboard(dip), slot_num);
385703831d35Sstevel
385803831d35Sstevel SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id);
385903831d35Sstevel
386003831d35Sstevel return;
386103831d35Sstevel }
386203831d35Sstevel
386303831d35Sstevel r = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
386403831d35Sstevel "slot-names", (caddr_t)&slot_names_data,
386503831d35Sstevel &slot_names_size);
386603831d35Sstevel
386703831d35Sstevel if (r == DDI_PROP_SUCCESS) {
386803831d35Sstevel
386903831d35Sstevel /*
387003831d35Sstevel * We can try to use the slot-names property to
387103831d35Sstevel * build our ap-id.
387203831d35Sstevel */
387303831d35Sstevel bit_mask = slot_names_data[3] | (slot_names_data[2] << 8) |
387403831d35Sstevel (slot_names_data[1] << 16) | (slot_names_data[0] << 24);
387503831d35Sstevel
387603831d35Sstevel pci_id_bit = 1;
387703831d35Sstevel pci_id_cnt = slots_before = found = 0;
387803831d35Sstevel
387903831d35Sstevel SCHPC_DEBUG2(D_APID, "Slot %d - slot-names bitmask=%x",
388003831d35Sstevel slot, bit_mask);
388103831d35Sstevel
388203831d35Sstevel /*
388303831d35Sstevel * Walk the bit mask until we find the bit that corresponds
388403831d35Sstevel * to our slots device number. We count how many bits
388503831d35Sstevel * we find before we find our slot's bit.
388603831d35Sstevel */
388703831d35Sstevel while (!found && (pci_id_cnt < 32)) {
388803831d35Sstevel
388903831d35Sstevel while (schpc_p->schpc_slot[slot].pci_id
389003831d35Sstevel != pci_id_cnt) {
389103831d35Sstevel
389203831d35Sstevel /*
389303831d35Sstevel * Find the next bit set.
389403831d35Sstevel */
389503831d35Sstevel while (!(bit_mask & pci_id_bit) &&
389603831d35Sstevel (pci_id_cnt < 32)) {
389703831d35Sstevel pci_id_bit = pci_id_bit << 1;
389803831d35Sstevel pci_id_cnt++;
389903831d35Sstevel }
390003831d35Sstevel
390103831d35Sstevel if (schpc_p->schpc_slot[slot].pci_id !=
390203831d35Sstevel pci_id_cnt)
390303831d35Sstevel slots_before++;
390403831d35Sstevel else
390503831d35Sstevel found = 1;
390603831d35Sstevel }
390703831d35Sstevel }
390803831d35Sstevel
390903831d35Sstevel if (pci_id_cnt < 32) {
391003831d35Sstevel
391103831d35Sstevel /*
391203831d35Sstevel * Set ptr to first string.
391303831d35Sstevel */
391403831d35Sstevel s = slot_names_data + 4;
391503831d35Sstevel
391603831d35Sstevel /*
391703831d35Sstevel * Increment past all the strings for the slots
391803831d35Sstevel * before ours.
391903831d35Sstevel */
392003831d35Sstevel while (slots_before) {
392103831d35Sstevel while (*s != NULL)
392203831d35Sstevel s++;
392303831d35Sstevel s++;
392403831d35Sstevel slots_before--;
392503831d35Sstevel }
392603831d35Sstevel
392703831d35Sstevel /*
392803831d35Sstevel * We should be at our string.
392903831d35Sstevel */
393003831d35Sstevel
3931*07d06da5SSurya Prakki (void) sprintf(ap_id, "IO%d_%s",
3932*07d06da5SSurya Prakki schpc_getexpander(dip), s);
393303831d35Sstevel
393403831d35Sstevel SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s",
393503831d35Sstevel slot, ap_id);
393603831d35Sstevel
393703831d35Sstevel kmem_free(slot_names_data, slot_names_size);
393803831d35Sstevel return;
393903831d35Sstevel }
394003831d35Sstevel
394103831d35Sstevel SCHPC_DEBUG1(D_APID, "Slot %d - slot-names entry not found",
394203831d35Sstevel slot);
394303831d35Sstevel
394403831d35Sstevel kmem_free(slot_names_data, slot_names_size);
394503831d35Sstevel } else
394603831d35Sstevel SCHPC_DEBUG1(D_APID, "Slot %d - No slot-names prop found",
394703831d35Sstevel slot);
394803831d35Sstevel
394903831d35Sstevel /*
395003831d35Sstevel * Build the ap-id using the legacy naming scheme.
395103831d35Sstevel */
3952*07d06da5SSurya Prakki (void) sprintf(ap_id, "e%02db%dslot%d", schpc_getexpander(dip),
395303831d35Sstevel schpc_getboard(dip), slot_num);
395403831d35Sstevel
395503831d35Sstevel SCHPC_DEBUG2(D_APID, "Slot %d - ap-id=%s", slot, ap_id);
395603831d35Sstevel }
395703831d35Sstevel
395803831d35Sstevel /*
395903831d35Sstevel * schpc_getexpander
396003831d35Sstevel *
396103831d35Sstevel * Returns the Expander Number (0-17) for the dip passed in. The Expander
396203831d35Sstevel * Number is extracted from the portid property of the pci node. Portid
396303831d35Sstevel * consists of <Expbrd#><1110x>, where x is the schizo number.
396403831d35Sstevel */
396503831d35Sstevel static int
schpc_getexpander(dev_info_t * dip)396603831d35Sstevel schpc_getexpander(dev_info_t *dip)
396703831d35Sstevel {
396803831d35Sstevel int id;
396903831d35Sstevel
397003831d35Sstevel id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "portid", -1);
397103831d35Sstevel
397203831d35Sstevel if (id != -1)
397303831d35Sstevel return (id >> 5);
397403831d35Sstevel else {
397503831d35Sstevel id = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "expander", -1);
397603831d35Sstevel return (id);
397703831d35Sstevel }
397803831d35Sstevel }
397903831d35Sstevel
398003831d35Sstevel /*
398103831d35Sstevel * schpc_getboard
398203831d35Sstevel *
398303831d35Sstevel * Returns the board number (0 or 1) for the dip passed in.
398403831d35Sstevel */
398503831d35Sstevel static int
schpc_getboard(dev_info_t * dip)398603831d35Sstevel schpc_getboard(dev_info_t *dip)
398703831d35Sstevel {
398803831d35Sstevel _NOTE(ARGUNUSED(dip))
398903831d35Sstevel
399003831d35Sstevel /*
399103831d35Sstevel * Hot Pluggable PCI/cPCI slots are only available on
399203831d35Sstevel * Board 1 (half-bandwidth slot).
399303831d35Sstevel */
399403831d35Sstevel return (1);
399503831d35Sstevel }
399603831d35Sstevel
399703831d35Sstevel /*ARGSUSED*/
399803831d35Sstevel static int
schpc_get_slot_status(uint_t expander,uint_t board,uint_t slot)399903831d35Sstevel schpc_get_slot_status(uint_t expander, uint_t board, uint_t slot)
400003831d35Sstevel {
400103831d35Sstevel gdcd_t *gdcd;
400203831d35Sstevel int prd_slot, status, bus;
400303831d35Sstevel
400403831d35Sstevel SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() "
400503831d35Sstevel "exp=%d board=%d slot=%d", expander, board, slot);
400603831d35Sstevel
400703831d35Sstevel if ((gdcd = (gdcd_t *)kmem_zalloc(sizeof (gdcd_t),
400803831d35Sstevel KM_SLEEP)) == NULL) {
400903831d35Sstevel return (RSV_UNDEFINED);
401003831d35Sstevel }
401103831d35Sstevel
401203831d35Sstevel /*
401303831d35Sstevel * Get the Starcat Specific Global DCD Structure from the golden
401403831d35Sstevel * IOSRAM.
401503831d35Sstevel */
401603831d35Sstevel if (iosram_rd(GDCD_MAGIC, 0, sizeof (gdcd_t), (caddr_t)gdcd)) {
401703831d35Sstevel cmn_err(CE_WARN, "sc_gptwocfg: Unable To Read GDCD "
401803831d35Sstevel "From IOSRAM\n");
401903831d35Sstevel kmem_free(gdcd, sizeof (gdcd_t));
402003831d35Sstevel return (RSV_UNDEFINED);
402103831d35Sstevel }
402203831d35Sstevel
402303831d35Sstevel if (gdcd->h.dcd_magic != GDCD_MAGIC) {
402403831d35Sstevel
402503831d35Sstevel cmn_err(CE_WARN, "schpc: GDCD Bad Magic 0x%x\n",
402603831d35Sstevel gdcd->h.dcd_magic);
402703831d35Sstevel
402803831d35Sstevel kmem_free(gdcd, sizeof (gdcd_t));
402903831d35Sstevel return (RSV_UNDEFINED);
403003831d35Sstevel }
403103831d35Sstevel
403203831d35Sstevel if (gdcd->h.dcd_version != DCD_VERSION) {
403303831d35Sstevel cmn_err(CE_WARN, "schpc: GDCD Bad Version: "
403403831d35Sstevel "GDCD Version 0x%x Expecting 0x%x\n",
403503831d35Sstevel gdcd->h.dcd_version, DCD_VERSION);
403603831d35Sstevel
403703831d35Sstevel kmem_free(gdcd, sizeof (gdcd_t));
403803831d35Sstevel return (RSV_UNDEFINED);
403903831d35Sstevel }
404003831d35Sstevel
404103831d35Sstevel if (slot < 2)
404203831d35Sstevel prd_slot = 4;
404303831d35Sstevel else
404403831d35Sstevel prd_slot = 5;
404503831d35Sstevel
404603831d35Sstevel bus = slot & 0x1;
404703831d35Sstevel
404803831d35Sstevel status = gdcd->dcd_prd[expander][prd_slot].prd_iocard_rsv[bus][0];
404903831d35Sstevel
405003831d35Sstevel kmem_free(gdcd, sizeof (gdcd_t));
405103831d35Sstevel
405203831d35Sstevel SCHPC_DEBUG3(D_ATTACH, "schpc_get_slot_status() "
405303831d35Sstevel "prd_slot=%d bus=%d status=%d", prd_slot, bus, status);
405403831d35Sstevel
405503831d35Sstevel return (status);
405603831d35Sstevel }
405703831d35Sstevel
405803831d35Sstevel #define LEAF_SAVE_END 0xff
405903831d35Sstevel
406003831d35Sstevel typedef struct {
406103831d35Sstevel int reg;
406203831d35Sstevel int offset;
406303831d35Sstevel int access_size;
406403831d35Sstevel int number;
406503831d35Sstevel } save_reg_list_t;
406603831d35Sstevel
406703831d35Sstevel /*
406803831d35Sstevel * Save List Array. Describes the leaf registers that need to
406903831d35Sstevel * be restored after a leaf reset.
407003831d35Sstevel *
407103831d35Sstevel * Entry 1 - Reg Entry: 0=PCI Leaf CSRs, 2=PCI Config Space
407203831d35Sstevel * Entry 2 - Offset Start
407303831d35Sstevel * Entry 3 - Access Size: 8=64 bit, 4=32 bit, 2=16 bit, 1=8 bit
407403831d35Sstevel * Entry 4 - # of registers to be saved starting at offset,
407503831d35Sstevel */
407603831d35Sstevel save_reg_list_t save_reg_list[] = { 0, 0x110, 8, 1,
407703831d35Sstevel 0, 0x200, 8, 2,
407803831d35Sstevel 0, 0x1000, 8, 0x18,
407903831d35Sstevel 0, 0x1a00, 8, 1,
408003831d35Sstevel 0, 0x2000, 8, 1,
408103831d35Sstevel 0, 0x2020, 8, 1,
408203831d35Sstevel 0, 0x2040, 8, 1,
408303831d35Sstevel 0, 0x2308, 8, 2,
408403831d35Sstevel 0, 0x2800, 8, 1,
408503831d35Sstevel 2, 0x04, 2, 1, /* Command */
408603831d35Sstevel 2, 0x0d, 1, 1, /* Latency */
408703831d35Sstevel 2, 0x40, 1, 1, /* Bus # */
408803831d35Sstevel 2, 0x41, 1, 1, /* Sub. Bus # */
408903831d35Sstevel LEAF_SAVE_END, 0, 0, 0};
409003831d35Sstevel
409103831d35Sstevel static int
schpc_save_leaf(int slot)409203831d35Sstevel schpc_save_leaf(int slot)
409303831d35Sstevel {
409403831d35Sstevel int save_entry, list_entry, reg;
409503831d35Sstevel caddr_t leaf_regs;
409603831d35Sstevel ddi_device_acc_attr_t attr;
409703831d35Sstevel
409803831d35Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot);
409903831d35Sstevel
410003831d35Sstevel attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
410103831d35Sstevel attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
410203831d35Sstevel attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
410303831d35Sstevel
410403831d35Sstevel /*
410503831d35Sstevel * Map in the 3 addresses spaces defined for XMITS.
410603831d35Sstevel */
410703831d35Sstevel for (reg = 0; reg < 3; reg++) {
410803831d35Sstevel if (ddi_regs_map_setup(schpc_p->schpc_slot[slot].devi, reg,
410903831d35Sstevel &leaf_regs, 0, 0, &attr, &schpc_p->schpc_slot[slot].
411003831d35Sstevel saved_handle[reg]) != DDI_SUCCESS) {
411103831d35Sstevel cmn_err(CE_WARN, "Mapin failed\n");
411203831d35Sstevel schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL;
411303831d35Sstevel return (1);
411403831d35Sstevel }
411503831d35Sstevel
411603831d35Sstevel schpc_p->schpc_slot[slot].saved_regs_va[reg] = leaf_regs;
411703831d35Sstevel }
411803831d35Sstevel
411903831d35Sstevel
412003831d35Sstevel /*
412103831d35Sstevel * Determine how many entries are in the list so we can
412203831d35Sstevel * allocate the save space.
412303831d35Sstevel */
412403831d35Sstevel list_entry = 0;
412503831d35Sstevel save_entry = 0;
412603831d35Sstevel while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
412703831d35Sstevel save_entry += save_reg_list[list_entry].number;
412803831d35Sstevel list_entry++;
412903831d35Sstevel }
413003831d35Sstevel
413103831d35Sstevel schpc_p->schpc_slot[slot].saved_size = (save_entry * sizeof (uint64_t));
413203831d35Sstevel
413303831d35Sstevel if (schpc_p->schpc_slot[slot].saved_size == 0)
413403831d35Sstevel return (0);
413503831d35Sstevel
413603831d35Sstevel schpc_p->schpc_slot[slot].saved_regs =
413703831d35Sstevel (uint64_t *)kmem_zalloc(schpc_p->schpc_slot[slot].saved_size,
413803831d35Sstevel KM_SLEEP);
413903831d35Sstevel
414003831d35Sstevel /*
414103831d35Sstevel * Walk through the register list and save contents.
414203831d35Sstevel */
414303831d35Sstevel list_entry = 0;
414403831d35Sstevel save_entry = 0;
414503831d35Sstevel while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
414603831d35Sstevel schpc_save_entry(slot, list_entry, save_entry);
414703831d35Sstevel save_entry += save_reg_list[list_entry].number;
414803831d35Sstevel list_entry ++;
414903831d35Sstevel }
415003831d35Sstevel
415103831d35Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Saved", slot);
415203831d35Sstevel
415303831d35Sstevel return (0);
415403831d35Sstevel }
415503831d35Sstevel
415603831d35Sstevel static void
schpc_restore_leaf(int slot)415703831d35Sstevel schpc_restore_leaf(int slot)
415803831d35Sstevel {
415903831d35Sstevel int save_entry, list_entry, reg;
416003831d35Sstevel
416103831d35Sstevel if (schpc_p->schpc_slot[slot].saved_regs == NULL)
416203831d35Sstevel return;
416303831d35Sstevel
416403831d35Sstevel /*
416503831d35Sstevel * Walk through the register list and restore contents.
416603831d35Sstevel */
416703831d35Sstevel list_entry = 0;
416803831d35Sstevel save_entry = 0;
416903831d35Sstevel while (save_reg_list[list_entry].reg != LEAF_SAVE_END) {
417003831d35Sstevel
417103831d35Sstevel schpc_restore_entry(slot, list_entry, save_entry);
417203831d35Sstevel
417303831d35Sstevel save_entry += save_reg_list[list_entry].number;
417403831d35Sstevel list_entry ++;
417503831d35Sstevel }
417603831d35Sstevel
417703831d35Sstevel /*
417803831d35Sstevel * Free the mapped in registers.
417903831d35Sstevel */
418003831d35Sstevel for (reg = 0; reg < 3; reg++) {
418103831d35Sstevel if (schpc_p->schpc_slot[slot].saved_regs_va[reg]) {
418203831d35Sstevel
418303831d35Sstevel ddi_regs_map_free(
418403831d35Sstevel &schpc_p->schpc_slot[slot].saved_handle[reg]);
418503831d35Sstevel
418603831d35Sstevel schpc_p->schpc_slot[slot].saved_regs_va[reg] = NULL;
418703831d35Sstevel }
418803831d35Sstevel }
418903831d35Sstevel
419003831d35Sstevel kmem_free(schpc_p->schpc_slot[slot].saved_regs,
419103831d35Sstevel schpc_p->schpc_slot[slot].saved_size);
419203831d35Sstevel
419303831d35Sstevel schpc_p->schpc_slot[slot].saved_size = 0;
419403831d35Sstevel schpc_p->schpc_slot[slot].saved_regs = NULL;
419503831d35Sstevel
419603831d35Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Registers Restored", slot);
419703831d35Sstevel }
419803831d35Sstevel
419903831d35Sstevel static void
schpc_save_entry(int slot,int list_entry,int save_entry)420003831d35Sstevel schpc_save_entry(int slot, int list_entry, int save_entry)
420103831d35Sstevel {
420203831d35Sstevel int reg, reads = 0;
420303831d35Sstevel
420403831d35Sstevel reg = save_reg_list[list_entry].reg;
420503831d35Sstevel
420603831d35Sstevel while (reads < save_reg_list[list_entry].number) {
420703831d35Sstevel switch (save_reg_list[list_entry].access_size) {
420803831d35Sstevel case 8:
420903831d35Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry] =
421003831d35Sstevel ddi_get64(
421103831d35Sstevel schpc_p->schpc_slot[slot].saved_handle[reg],
421203831d35Sstevel (uint64_t *)(schpc_p->schpc_slot[slot].
421303831d35Sstevel saved_regs_va[reg]
421403831d35Sstevel + save_reg_list[list_entry].offset +
421503831d35Sstevel (reads * sizeof (uint64_t))));
421603831d35Sstevel #ifdef DEBUG
421703831d35Sstevel if (schpc_dump_save_regs)
421803831d35Sstevel cmn_err(CE_WARN, "Save 64 %x %lx %lx\n", reg,
421903831d35Sstevel save_reg_list[list_entry].offset +
422003831d35Sstevel (reads * sizeof (uint64_t)),
422103831d35Sstevel schpc_p->schpc_slot[slot].
422203831d35Sstevel saved_regs[save_entry]);
422303831d35Sstevel #endif
422403831d35Sstevel
422503831d35Sstevel break;
422603831d35Sstevel case 4:
422703831d35Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry] =
422803831d35Sstevel ddi_get32(
422903831d35Sstevel schpc_p->schpc_slot[slot].saved_handle[reg],
423003831d35Sstevel (uint32_t *)(schpc_p->schpc_slot[slot].
423103831d35Sstevel saved_regs_va[reg]
423203831d35Sstevel + save_reg_list[list_entry].offset +
423303831d35Sstevel (reads * sizeof (uint32_t))));
423403831d35Sstevel
423503831d35Sstevel #ifdef DEBUG
423603831d35Sstevel if (schpc_dump_save_regs)
423703831d35Sstevel cmn_err(CE_WARN, "Save 32 %x %lx %lx\n", reg,
423803831d35Sstevel save_reg_list[list_entry].offset +
423903831d35Sstevel (reads * sizeof (uint32_t)),
424003831d35Sstevel schpc_p->schpc_slot[slot].
424103831d35Sstevel saved_regs[save_entry]);
424203831d35Sstevel #endif
424303831d35Sstevel
424403831d35Sstevel break;
424503831d35Sstevel case 2:
424603831d35Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry] =
424703831d35Sstevel ddi_get16(
424803831d35Sstevel schpc_p->schpc_slot[slot].saved_handle[reg],
424903831d35Sstevel (uint16_t *)(schpc_p->schpc_slot[slot].
425003831d35Sstevel saved_regs_va[reg]
425103831d35Sstevel + save_reg_list[list_entry].offset +
425203831d35Sstevel (reads * sizeof (uint16_t))));
425303831d35Sstevel
425403831d35Sstevel #ifdef DEBUG
425503831d35Sstevel if (schpc_dump_save_regs)
425603831d35Sstevel cmn_err(CE_WARN, "Save 16 %x %lx %lx\n", reg,
425703831d35Sstevel save_reg_list[list_entry].offset +
425803831d35Sstevel (reads * sizeof (uint16_t)),
425903831d35Sstevel schpc_p->schpc_slot[slot].
426003831d35Sstevel saved_regs[save_entry]);
426103831d35Sstevel #endif
426203831d35Sstevel
426303831d35Sstevel break;
426403831d35Sstevel case 1:
426503831d35Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry] =
426603831d35Sstevel ddi_get8(
426703831d35Sstevel schpc_p->schpc_slot[slot].saved_handle[reg],
426803831d35Sstevel (uint8_t *)(schpc_p->schpc_slot[slot].
426903831d35Sstevel saved_regs_va[reg]
427003831d35Sstevel + save_reg_list[list_entry].offset +
427103831d35Sstevel (reads * sizeof (uint8_t))));
427203831d35Sstevel
427303831d35Sstevel #ifdef DEBUG
427403831d35Sstevel if (schpc_dump_save_regs)
427503831d35Sstevel cmn_err(CE_WARN, "Save 8 %x %lx %lx\n", reg,
427603831d35Sstevel save_reg_list[list_entry].offset +
427703831d35Sstevel (reads * sizeof (uint8_t)),
427803831d35Sstevel schpc_p->schpc_slot[slot].
427903831d35Sstevel saved_regs[save_entry]);
428003831d35Sstevel #endif
428103831d35Sstevel
428203831d35Sstevel break;
428303831d35Sstevel default:
428403831d35Sstevel cmn_err(CE_WARN,
428503831d35Sstevel "schpc: Illegal List Entry\n");
428603831d35Sstevel }
428703831d35Sstevel reads++;
428803831d35Sstevel save_entry++;
428903831d35Sstevel }
429003831d35Sstevel }
429103831d35Sstevel
429203831d35Sstevel static void
schpc_restore_entry(int slot,int list_entry,int save_entry)429303831d35Sstevel schpc_restore_entry(int slot, int list_entry, int save_entry)
429403831d35Sstevel {
429503831d35Sstevel int reg, writes = 0;
429603831d35Sstevel
429703831d35Sstevel reg = save_reg_list[list_entry].reg;
429803831d35Sstevel
429903831d35Sstevel while (writes < save_reg_list[list_entry].number) {
430003831d35Sstevel switch (save_reg_list[list_entry].access_size) {
430103831d35Sstevel case 8:
430203831d35Sstevel #ifdef DEBUG
430303831d35Sstevel if (schpc_dump_save_regs)
430403831d35Sstevel cmn_err(CE_WARN, "Restore 64 %x %lx %lx\n", reg,
430503831d35Sstevel save_reg_list[list_entry].offset +
430603831d35Sstevel (writes * sizeof (uint64_t)),
430703831d35Sstevel schpc_p->schpc_slot[slot].
430803831d35Sstevel saved_regs[save_entry]);
430903831d35Sstevel #endif
431003831d35Sstevel
431103831d35Sstevel ddi_put64(schpc_p->schpc_slot[slot].saved_handle[reg],
431203831d35Sstevel (uint64_t *)(schpc_p->schpc_slot[slot].
431303831d35Sstevel saved_regs_va[reg]
431403831d35Sstevel + save_reg_list[list_entry].offset +
431503831d35Sstevel (writes * sizeof (uint64_t))),
431603831d35Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry]);
431703831d35Sstevel
431803831d35Sstevel break;
431903831d35Sstevel case 4:
432003831d35Sstevel #ifdef DEBUG
432103831d35Sstevel if (schpc_dump_save_regs)
432203831d35Sstevel cmn_err(CE_WARN, "Restore 32 %x %lx %lx\n", reg,
432303831d35Sstevel save_reg_list[list_entry].offset +
432403831d35Sstevel (writes * sizeof (uint32_t)),
432503831d35Sstevel schpc_p->schpc_slot[slot].
432603831d35Sstevel saved_regs[save_entry]);
432703831d35Sstevel #endif
432803831d35Sstevel
432903831d35Sstevel ddi_put32(schpc_p->schpc_slot[slot].saved_handle[reg],
433003831d35Sstevel (uint32_t *)(schpc_p->schpc_slot[slot].
433103831d35Sstevel saved_regs_va[reg]
433203831d35Sstevel + save_reg_list[list_entry].offset +
433303831d35Sstevel (writes * sizeof (uint32_t))),
433403831d35Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry]);
433503831d35Sstevel
433603831d35Sstevel break;
433703831d35Sstevel case 2:
433803831d35Sstevel #ifdef DEBUG
433903831d35Sstevel if (schpc_dump_save_regs)
434003831d35Sstevel cmn_err(CE_WARN, "Restore 16 %x %lx %lx\n", reg,
434103831d35Sstevel save_reg_list[list_entry].offset +
434203831d35Sstevel (writes * sizeof (uint16_t)),
434303831d35Sstevel schpc_p->schpc_slot[slot].
434403831d35Sstevel saved_regs[save_entry]);
434503831d35Sstevel #endif
434603831d35Sstevel
434703831d35Sstevel ddi_put16(schpc_p->schpc_slot[slot].saved_handle[reg],
434803831d35Sstevel (uint16_t *)(schpc_p->schpc_slot[slot].
434903831d35Sstevel saved_regs_va[reg]
435003831d35Sstevel + save_reg_list[list_entry].offset +
435103831d35Sstevel (writes * sizeof (uint16_t))),
435203831d35Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry]);
435303831d35Sstevel
435403831d35Sstevel break;
435503831d35Sstevel case 1:
435603831d35Sstevel #ifdef DEBUG
435703831d35Sstevel if (schpc_dump_save_regs)
435803831d35Sstevel cmn_err(CE_WARN, "Restore 8 %x %lx %lx\n", reg,
435903831d35Sstevel save_reg_list[list_entry].offset +
436003831d35Sstevel (writes * sizeof (uint8_t)),
436103831d35Sstevel schpc_p->schpc_slot[slot].
436203831d35Sstevel saved_regs[save_entry]);
436303831d35Sstevel #endif
436403831d35Sstevel
436503831d35Sstevel ddi_put8(schpc_p->schpc_slot[slot].saved_handle[reg],
436603831d35Sstevel (uint8_t *)(schpc_p->schpc_slot[slot].
436703831d35Sstevel saved_regs_va[reg]
436803831d35Sstevel + save_reg_list[list_entry].offset +
436903831d35Sstevel (writes * sizeof (uint8_t))),
437003831d35Sstevel schpc_p->schpc_slot[slot].saved_regs[save_entry]);
437103831d35Sstevel
437203831d35Sstevel break;
437303831d35Sstevel default:
437403831d35Sstevel cmn_err(CE_WARN,
437503831d35Sstevel "schpc: Illegal List Entry\n");
437603831d35Sstevel }
437703831d35Sstevel writes++;
437803831d35Sstevel save_entry++;
437903831d35Sstevel }
438003831d35Sstevel }
438103831d35Sstevel
438203831d35Sstevel /*
438303831d35Sstevel * Returns TRUE if a leaf reset is required to change frequencies/mode.
438403831d35Sstevel */
438503831d35Sstevel static int
schpc_is_leaf_reset_required(int slot)438603831d35Sstevel schpc_is_leaf_reset_required(int slot)
438703831d35Sstevel {
438803831d35Sstevel char *name;
438903831d35Sstevel int32_t mod_rev;
439003831d35Sstevel
439103831d35Sstevel /*
439203831d35Sstevel * Only XMITS 3.0 and greater connected slots will require a
439303831d35Sstevel * reset to switch frequency and/or mode.
439403831d35Sstevel */
439503831d35Sstevel name = ddi_binding_name(schpc_p->schpc_slot[slot].devi);
439603831d35Sstevel
439703831d35Sstevel if (strcmp(name, "pci108e,8002") == 0) {
439803831d35Sstevel mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY,
439903831d35Sstevel schpc_p->schpc_slot[slot].devi,
440003831d35Sstevel DDI_PROP_DONTPASS, "module-revision#", 0);
440103831d35Sstevel
440203831d35Sstevel SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev);
440303831d35Sstevel
440403831d35Sstevel /*
440503831d35Sstevel * Check for XMITS 3.0 or greater.
440603831d35Sstevel */
440703831d35Sstevel if (mod_rev >= XMITS_30) {
440803831d35Sstevel
440903831d35Sstevel /*
441003831d35Sstevel * The leaf attached to C5V0 (slot 1) should
441103831d35Sstevel * not be reset.
441203831d35Sstevel */
441303831d35Sstevel if ((slot & 3) == 1) {
441403831d35Sstevel
441503831d35Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset "
441603831d35Sstevel "Not Required - C5V0", slot);
441703831d35Sstevel
441803831d35Sstevel return (0);
441903831d35Sstevel }
442003831d35Sstevel
442103831d35Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset "
442203831d35Sstevel "Required", slot);
442303831d35Sstevel
442403831d35Sstevel return (1);
442503831d35Sstevel }
442603831d35Sstevel }
442703831d35Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Leaf Reset NOT Required", slot);
442803831d35Sstevel
442903831d35Sstevel return (0);
443003831d35Sstevel }
443103831d35Sstevel
443203831d35Sstevel /*
443303831d35Sstevel * Returns TRUE if the bus can change frequencies.
443403831d35Sstevel */
443503831d35Sstevel static int
schpc_is_freq_switchable(int slot)443603831d35Sstevel schpc_is_freq_switchable(int slot)
443703831d35Sstevel {
443803831d35Sstevel char *name;
443903831d35Sstevel int32_t mod_rev;
444003831d35Sstevel
444103831d35Sstevel name = ddi_binding_name(schpc_p->schpc_slot[slot].devi);
444203831d35Sstevel
444303831d35Sstevel if (strcmp(name, "pci108e,8002") == 0) {
444403831d35Sstevel mod_rev = ddi_prop_get_int(DDI_DEV_T_ANY,
444503831d35Sstevel schpc_p->schpc_slot[slot].devi,
444603831d35Sstevel DDI_PROP_DONTPASS, "module-revision#", 0);
444703831d35Sstevel
444803831d35Sstevel SCHPC_DEBUG2(D_FREQCHG, "Slot %d - mod_rev=%x", slot, mod_rev);
444903831d35Sstevel
445003831d35Sstevel /*
445103831d35Sstevel * We will only report back that XMITS 2.0 (mod_rev = 2)
445203831d35Sstevel * or greater will have the ability to switch frequencies.
445303831d35Sstevel */
445403831d35Sstevel if (mod_rev >= XMITS_20) {
445503831d35Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - "
445603831d35Sstevel "Frequency is switchable", slot);
445703831d35Sstevel return (1);
445803831d35Sstevel }
445903831d35Sstevel }
446003831d35Sstevel
446103831d35Sstevel SCHPC_DEBUG1(D_FREQCHG, "Slot %d - Frequency is NOT switchable", slot);
446203831d35Sstevel return (0);
446303831d35Sstevel }
446403831d35Sstevel
446503831d35Sstevel /*
446603831d35Sstevel * schpc_slot_freq
446703831d35Sstevel *
446803831d35Sstevel * Convert the slot frequency setting to integer value.
446903831d35Sstevel */
447003831d35Sstevel static int
schpc_slot_freq(pci_getslot_t * getslotp)447103831d35Sstevel schpc_slot_freq(pci_getslot_t *getslotp)
447203831d35Sstevel {
447303831d35Sstevel switch (getslotp->slot_freq_setting) {
447403831d35Sstevel case PCIMSG_FREQ_33MHZ:
447503831d35Sstevel return (SCHPC_33MHZ);
447603831d35Sstevel case PCIMSG_FREQ_66MHZ:
447703831d35Sstevel return (SCHPC_66MHZ);
447803831d35Sstevel case PCIMSG_FREQ_90MHZ:
447903831d35Sstevel return (SCHPC_90MHZ);
448003831d35Sstevel case PCIMSG_FREQ_133MHZ:
448103831d35Sstevel return (SCHPC_133MHZ);
448203831d35Sstevel default:
448303831d35Sstevel return (0);
448403831d35Sstevel }
448503831d35Sstevel }
448603831d35Sstevel
448703831d35Sstevel /*
448803831d35Sstevel * schpc_find_dip
448903831d35Sstevel *
449003831d35Sstevel * Used by ddi_walk_devs to find the dip which belongs
449103831d35Sstevel * to a certain slot.
449203831d35Sstevel *
449303831d35Sstevel * When this function returns, the dip is held. It is the
449403831d35Sstevel * responsibility of the caller to release the dip.
449503831d35Sstevel */
449603831d35Sstevel static int
schpc_find_dip(dev_info_t * dip,void * arg)449703831d35Sstevel schpc_find_dip(dev_info_t *dip, void *arg)
449803831d35Sstevel {
449903831d35Sstevel find_dev_t *find_dev = (find_dev_t *)arg;
450003831d35Sstevel char *pathname = find_dev->caddr;
450103831d35Sstevel
450203831d35Sstevel (void) ddi_pathname(dip, pathname);
450303831d35Sstevel if (strcmp(find_dev->cname, pathname) == 0) {
450403831d35Sstevel ndi_hold_devi(dip);
450503831d35Sstevel find_dev->dip = dip;
450603831d35Sstevel return (DDI_WALK_TERMINATE);
450703831d35Sstevel }
450803831d35Sstevel return (DDI_WALK_CONTINUE);
450903831d35Sstevel }
4510