11708Sstevel /*
21708Sstevel * CDDL HEADER START
31708Sstevel *
41708Sstevel * The contents of this file are subject to the terms of the
51708Sstevel * Common Development and Distribution License (the "License").
61708Sstevel * You may not use this file except in compliance with the License.
71708Sstevel *
81708Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel * or http://www.opensolaris.org/os/licensing.
101708Sstevel * See the License for the specific language governing permissions
111708Sstevel * and limitations under the License.
121708Sstevel *
131708Sstevel * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel *
191708Sstevel * CDDL HEADER END
201708Sstevel */
211708Sstevel
221708Sstevel /*
23*11311SSurya.Prakki@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
241708Sstevel * Use is subject to license terms.
251708Sstevel */
261708Sstevel
271708Sstevel /*
281708Sstevel * Domain specific portion of the Starcat Management Network Driver
291708Sstevel */
301708Sstevel
311708Sstevel #include <sys/types.h>
321708Sstevel #include <sys/proc.h>
331708Sstevel #include <sys/kmem.h>
341708Sstevel #include <sys/stat.h>
351708Sstevel #include <sys/kstat.h>
361708Sstevel #include <sys/ksynch.h>
371708Sstevel #include <sys/stream.h>
381708Sstevel #include <sys/dlpi.h>
391708Sstevel #include <sys/stropts.h>
401708Sstevel #include <sys/strsubr.h>
411708Sstevel #include <sys/debug.h>
421708Sstevel #include <sys/conf.h>
431708Sstevel #include <sys/kstr.h>
441708Sstevel #include <sys/errno.h>
451708Sstevel #include <sys/ethernet.h>
461708Sstevel #include <sys/byteorder.h>
471708Sstevel #include <sys/ddi.h>
481708Sstevel #include <sys/sunddi.h>
491708Sstevel #include <sys/modctl.h>
501708Sstevel #include <sys/strsun.h>
511708Sstevel #include <sys/pci.h>
521708Sstevel #include <sys/callb.h>
531708Sstevel #include <sys/pci.h>
541708Sstevel #include <sys/iosramio.h>
551708Sstevel #include <sys/mboxsc.h>
561708Sstevel #include <netinet/in.h>
571708Sstevel #include <inet/common.h>
581708Sstevel #include <inet/mi.h>
591708Sstevel #include <inet/nd.h>
601708Sstevel #include <sys/socket.h>
611708Sstevel #include <netinet/igmp_var.h>
621708Sstevel #include <netinet/ip6.h>
631708Sstevel #include <netinet/icmp6.h>
641708Sstevel #include <inet/ip.h>
651708Sstevel #include <inet/ip6.h>
661708Sstevel #include <sys/dman.h>
671708Sstevel #include <sys/ddi_impldefs.h>
681708Sstevel #include <sys/sunndi.h>
691708Sstevel
701708Sstevel #define MAN_SCHIZO_BINDING_NAME "pci108e,8001"
711708Sstevel #define MAN_XMITS_BINDING_NAME "pci108e,8002"
721708Sstevel
731708Sstevel int man_is_on_domain = TRUE;
741708Sstevel
751708Sstevel /*
761708Sstevel * Domain side function prototypes.
771708Sstevel */
781708Sstevel int man_get_iosram(manc_t *);
791708Sstevel int man_domain_configure(void);
801708Sstevel int man_domain_deconfigure(void);
811708Sstevel int man_path_discovery(void);
821708Sstevel int man_dossc_switch(uint32_t);
831708Sstevel int man_dr_attach(dev_info_t *);
841708Sstevel int man_dr_detach(dev_info_t *);
851708Sstevel static int man_dr_submit_work_wait(dev_info_t *, int);
861708Sstevel static int man_find_devs(mi_path_t *, uchar_t);
871708Sstevel static int man_dip_is_schizoxmits0_pcib(dev_info_t *, int *, int *);
881708Sstevel static int man_dip_is_eri(dev_info_t *, man_dev_t *);
891708Sstevel static int man_dip_is_attached(dev_info_t *);
901708Sstevel static int man_get_eri_dev_info(dev_info_t *, man_dev_t *);
911708Sstevel static int man_mbox_initialized = FALSE;
921708Sstevel
931708Sstevel /*
941708Sstevel * Externs
951708Sstevel */
961708Sstevel extern int man_pg_cmd(mi_path_t *, man_work_t *);
971708Sstevel extern kmutex_t man_lock;
981708Sstevel extern void *man_softstate;
991708Sstevel extern man_work_t *man_work_alloc(int, int);
1001708Sstevel extern void man_work_free(man_work_t *);
1011708Sstevel extern void man_work_add(man_workq_t *, man_work_t *);
1021708Sstevel extern man_workq_t *man_bwork_q;
1031708Sstevel extern man_workq_t *man_iwork_q;
1041708Sstevel extern queue_t *man_ctl_wq;
1051708Sstevel
1061708Sstevel #if defined(DEBUG)
1071708Sstevel static void man_print_manc(manc_t *);
1081708Sstevel extern uint32_t man_debug;
1091708Sstevel #endif /* DEBUG */
1101708Sstevel
1111708Sstevel int
man_domain_configure(void)1121708Sstevel man_domain_configure(void)
1131708Sstevel {
1141708Sstevel int status = 0;
1151708Sstevel
1161708Sstevel /*
1171708Sstevel * man_mbox_initialized is protected by inner perimiter lock.
1181708Sstevel */
1191708Sstevel if (man_mbox_initialized == TRUE)
1201708Sstevel goto exit;
1211708Sstevel
1221708Sstevel status = mboxsc_init(IOSRAM_KEY_SCMD, MBOXSC_MBOX_IN, NULL);
1231708Sstevel
1241708Sstevel if (status != 0) {
1251708Sstevel cmn_err(CE_WARN, "man_domain_configure: failed to initialize"
1268459SJerry.Gilliam@Sun.COM " MBOXSC_MBOX_IN, errno = %d", status);
1271708Sstevel goto exit;
1281708Sstevel }
1291708Sstevel
1301708Sstevel status = mboxsc_init(IOSRAM_KEY_MDSC, MBOXSC_MBOX_OUT, NULL);
1311708Sstevel if (status != 0) {
132*11311SSurya.Prakki@Sun.COM (void) mboxsc_fini(IOSRAM_KEY_SCMD);
1331708Sstevel cmn_err(CE_WARN, "man_domain_configure: failed to initialize"
1348459SJerry.Gilliam@Sun.COM " MBOXSC_MBOX_OUT, errno = %d", status);
1351708Sstevel goto exit;
1361708Sstevel }
1371708Sstevel
1381708Sstevel man_mbox_initialized = TRUE;
1391708Sstevel
1401708Sstevel status = man_path_discovery();
1411708Sstevel if (status != 0) {
142*11311SSurya.Prakki@Sun.COM (void) mboxsc_fini(IOSRAM_KEY_SCMD);
143*11311SSurya.Prakki@Sun.COM (void) mboxsc_fini(IOSRAM_KEY_MDSC);
1441708Sstevel man_mbox_initialized = FALSE;
1451708Sstevel }
1461708Sstevel
1471708Sstevel exit:
1481708Sstevel return (status);
1491708Sstevel }
1501708Sstevel
1511708Sstevel /*
1521708Sstevel * Build pathgroup connecting a domain to the SSC. Only called on domains
1531708Sstevel * at first man_open. On the SSC, pathgroups are built by IOCTL requests
1541708Sstevel * from the MAN daemon (see man_ioctl and mand(1M)).
1551708Sstevel *
1561708Sstevel * Locks held
1571708Sstevel * - exclusive innerperim.
1581708Sstevel */
1591708Sstevel int
man_path_discovery(void)1601708Sstevel man_path_discovery(void)
1611708Sstevel {
1621708Sstevel manc_t manc;
1631708Sstevel mi_path_t mpath;
1641708Sstevel int num_devs;
1651708Sstevel int status = 0;
1661708Sstevel int i;
1671708Sstevel
1681708Sstevel MAN_DBG(MAN_CONFIG, ("man_path_discovery:"));
1691708Sstevel
1701708Sstevel if (status = man_get_iosram(&manc)) {
1711708Sstevel goto exit;
1721708Sstevel }
1731708Sstevel
1741708Sstevel /*
1751708Sstevel * If manc_ip_type indicates MAN network is not enabled
1761708Sstevel * for this domain, then lets just bailout from here as if no
1771708Sstevel * devices were found.
1781708Sstevel */
1791708Sstevel if ((manc.manc_ip_type != AF_INET) &&
1808459SJerry.Gilliam@Sun.COM (manc.manc_ip_type != AF_INET6)) {
1811708Sstevel goto exit;
1821708Sstevel }
1831708Sstevel
1841708Sstevel MAN_DBGCALL(MAN_CONFIG, man_print_manc(&manc));
1851708Sstevel
1861708Sstevel /*
1871708Sstevel * Extract SC ethernet address from IOSRAM.
1881708Sstevel */
1891708Sstevel ether_copy(&manc.manc_sc_eaddr, &mpath.mip_eaddr);
1901708Sstevel
1911708Sstevel mpath.mip_pg_id = 0; /* SC is always pathgroup ID 0 */
1921708Sstevel mpath.mip_man_ppa = 0; /* Domain only has one ppa, 0 */
1931708Sstevel
1941708Sstevel /*
1951708Sstevel * Get list of present devices, and update man_paths[] as needed.
1961708Sstevel */
1971708Sstevel num_devs = man_find_devs(&mpath, MAN_MAX_EXPANDERS);
1981708Sstevel if (num_devs <= 0) {
1991708Sstevel status = ENODEV;
2001708Sstevel goto exit;
2011708Sstevel }
2021708Sstevel
2031708Sstevel mpath.mip_cmd = MI_PATH_ASSIGN;
2041708Sstevel
2051708Sstevel mutex_enter(&man_lock);
2061708Sstevel status = man_pg_cmd(&mpath, NULL);
2071708Sstevel if (status) {
2081708Sstevel mutex_exit(&man_lock);
2091708Sstevel goto exit;
2101708Sstevel }
2111708Sstevel
2121708Sstevel /*
2131708Sstevel * Now activate the ethernet on the golden io board.
2141708Sstevel */
2151708Sstevel for (i = 0; i < num_devs; i++) {
2161708Sstevel if (mpath.mip_devs[i].mdev_exp_id == manc.manc_golden_iob)
2171708Sstevel mpath.mip_devs[0] = mpath.mip_devs[i];
2181708Sstevel }
2191708Sstevel mpath.mip_ndevs = 1;
2201708Sstevel mpath.mip_cmd = MI_PATH_ACTIVATE;
2211708Sstevel status = man_pg_cmd(&mpath, NULL);
2221708Sstevel mutex_exit(&man_lock);
2231708Sstevel
2241708Sstevel exit:
2251708Sstevel MAN_DBG(MAN_CONFIG, ("man_path_discovery: returns %d\n", status));
2261708Sstevel
2271708Sstevel return (status);
2281708Sstevel }
2291708Sstevel
2301708Sstevel int
man_domain_deconfigure(void)2311708Sstevel man_domain_deconfigure(void)
2321708Sstevel {
2331708Sstevel
234*11311SSurya.Prakki@Sun.COM (void) mboxsc_fini(IOSRAM_KEY_SCMD);
235*11311SSurya.Prakki@Sun.COM (void) mboxsc_fini(IOSRAM_KEY_MDSC);
2361708Sstevel /*
2371708Sstevel * We are about to unload and know that there are no open
2381708Sstevel * streams, so this change outside of the perimiter is ok.
2391708Sstevel */
2401708Sstevel man_mbox_initialized = FALSE;
2411708Sstevel
2421708Sstevel return (0);
2431708Sstevel }
2441708Sstevel
2451708Sstevel /*
2461708Sstevel * Add a work request to the inner perimeter with the new eri device info.
2471708Sstevel */
2481708Sstevel /* ARGSUSED */
2491708Sstevel int
man_dr_attach(dev_info_t * dip)2501708Sstevel man_dr_attach(dev_info_t *dip)
2511708Sstevel {
2521708Sstevel man_t *manp;
2531708Sstevel man_work_t *wp;
2541708Sstevel int status = 0;
2551708Sstevel man_dev_t mdev;
2561708Sstevel
2571708Sstevel
2581708Sstevel mutex_enter(&man_lock);
2591708Sstevel manp = ddi_get_soft_state(man_softstate, 0);
2601708Sstevel if (manp == NULL || manp->man_pg == NULL) {
2611708Sstevel goto exit;
2621708Sstevel }
2631708Sstevel
2641708Sstevel if (man_get_eri_dev_info(dip, &mdev) == FALSE) {
2651708Sstevel status = ENODEV;
2661708Sstevel goto exit;
2671708Sstevel }
2681708Sstevel MAN_DBG(MAN_DR, ("man_dr_attach: dip major = %d instance =%d",
2698459SJerry.Gilliam@Sun.COM mdev.mdev_major, mdev.mdev_ppa));
2701708Sstevel wp = man_work_alloc(MAN_WORK_DRATTACH, KM_NOSLEEP);
2711708Sstevel if (wp == NULL) {
2721708Sstevel status = ENOMEM;
2731708Sstevel goto exit;
2741708Sstevel }
2751708Sstevel
2761708Sstevel wp->mw_arg.a_man_ppa = 0; /* Domain only has one ppa, 0 */
2771708Sstevel wp->mw_arg.a_pg_id = 0; /* SC is always pathgroup ID 0 */
2781708Sstevel wp->mw_arg.a_sf_dev = mdev;
2791708Sstevel wp->mw_flags = MAN_WFLAGS_NOWAITER;
2801708Sstevel
2811708Sstevel man_work_add(man_iwork_q, wp);
2821708Sstevel
2831708Sstevel if (man_ctl_wq)
2841708Sstevel qenable(man_ctl_wq);
2851708Sstevel
2861708Sstevel exit:
2871708Sstevel mutex_exit(&man_lock);
2881708Sstevel
2891708Sstevel return (status);
2901708Sstevel }
2911708Sstevel
2921708Sstevel int
man_dr_detach(dev_info_t * dip)2931708Sstevel man_dr_detach(dev_info_t *dip)
2941708Sstevel {
2951708Sstevel man_t *manp;
2961708Sstevel int status = 0;
2971708Sstevel int retries = 0;
2981708Sstevel
2991708Sstevel
3001708Sstevel mutex_enter(&man_lock);
3011708Sstevel manp = ddi_get_soft_state(man_softstate, 0);
3021708Sstevel if (manp == NULL || manp->man_pg == NULL) {
3031708Sstevel mutex_exit(&man_lock);
3041708Sstevel goto exit;
3051708Sstevel }
3061708Sstevel mutex_exit(&man_lock);
3071708Sstevel
3081708Sstevel /*
3091708Sstevel * Arrange to have the detaching path switched if it is active.
3101708Sstevel * We will cv_wait_sig for the switch to complete if it is needed.
3111708Sstevel */
3121708Sstevel again:
3131708Sstevel status = man_dr_submit_work_wait(dip, MAN_WORK_DRSWITCH);
3141708Sstevel if (status == EAGAIN && retries < manp->man_dr_retries) {
3151708Sstevel /*
3161708Sstevel * Delay a bit and retry.
3171708Sstevel */
3181708Sstevel MAN_DBG(MAN_DR,
3198459SJerry.Gilliam@Sun.COM ("man_dr_detach(switch): EAGAIN - retrying..."));
3201708Sstevel retries++;
3211708Sstevel delay(drv_usectohz(manp->man_dr_delay));
3221708Sstevel goto again;
3231708Sstevel }
3241708Sstevel
3251708Sstevel if (status)
3261708Sstevel goto exit;
3271708Sstevel
3281708Sstevel retries = 0;
3291708Sstevel
3301708Sstevel /*
3311708Sstevel * Detaching device no longer in use, remove it from our
3321708Sstevel * pathgroup.
3331708Sstevel */
3341708Sstevel status = man_dr_submit_work_wait(dip, MAN_WORK_DRDETACH);
3351708Sstevel if (status == EAGAIN && retries < manp->man_dr_retries) {
3361708Sstevel MAN_DBG(MAN_DR,
3378459SJerry.Gilliam@Sun.COM ("man_dr_detach(detach): EAGAIN - retrying..."));
3381708Sstevel retries++;
3391708Sstevel goto again;
3401708Sstevel }
3411708Sstevel
3421708Sstevel exit:
3431708Sstevel MAN_DBG(MAN_DR, ("man_dr_detach: returns %d", status));
3441708Sstevel return (status);
3451708Sstevel }
3461708Sstevel
3471708Sstevel static int
man_dr_submit_work_wait(dev_info_t * dip,int work_type)3481708Sstevel man_dr_submit_work_wait(dev_info_t *dip, int work_type)
3491708Sstevel {
3501708Sstevel man_work_t *wp;
3511708Sstevel int status = 0;
3521708Sstevel
3531708Sstevel wp = man_work_alloc(work_type, KM_NOSLEEP);
3541708Sstevel if (wp == NULL) {
3551708Sstevel status = ENOMEM;
3561708Sstevel goto exit;
3571708Sstevel }
3581708Sstevel
3591708Sstevel wp->mw_arg.a_man_ppa = 0;
3601708Sstevel wp->mw_arg.a_pg_id = 0;
3618459SJerry.Gilliam@Sun.COM wp->mw_arg.a_sf_dev.mdev_major = ddi_driver_major(dip);
3621708Sstevel wp->mw_arg.a_sf_dev.mdev_ppa = ddi_get_instance(dip);
3631708Sstevel
3641708Sstevel mutex_enter(&man_lock);
3651708Sstevel wp->mw_flags = MAN_WFLAGS_CVWAITER;
3661708Sstevel man_work_add(man_iwork_q, wp);
3671708Sstevel
3681708Sstevel /* TBD - change to ASSERT ? */
3691708Sstevel if (man_ctl_wq)
3701708Sstevel qenable(man_ctl_wq);
3711708Sstevel
3721708Sstevel while (!(wp->mw_flags & MAN_WFLAGS_DONE)) {
3731708Sstevel if (!cv_wait_sig(&wp->mw_cv, &man_lock)) {
3741708Sstevel wp->mw_flags &= ~MAN_WFLAGS_CVWAITER;
3751708Sstevel status = EINTR;
3761708Sstevel break;
3771708Sstevel }
3781708Sstevel }
3791708Sstevel
3801708Sstevel /*
3811708Sstevel * Note that if cv_wait_sig() returns zero because a signal
3821708Sstevel * was received, MAN_WFLAGS_DONE may not be set.
3831708Sstevel * This will happen if man_dr_submit_work_wait() reacquires
3841708Sstevel * man_lock before man_iwork() can acquire man_lock just before
3851708Sstevel * signalling its work is complete.
3861708Sstevel * In this case, it is not necessary to call man_work_free()
3871708Sstevel * here because it will be called by man_iwork() because
3881708Sstevel * MAN_WFLAGS_CVWAITER was cleared.
3891708Sstevel * Should man_iwork() obtain man_lock to signal completion,
3901708Sstevel * MAN_WFLAGS_DONE will be set which will ensure man_work_free()
3911708Sstevel * is called here.
3921708Sstevel */
3931708Sstevel if (wp->mw_flags & MAN_WFLAGS_DONE) {
3941708Sstevel status = wp->mw_status;
3951708Sstevel man_work_free(wp);
3961708Sstevel }
3971708Sstevel
3981708Sstevel mutex_exit(&man_lock);
3991708Sstevel
4001708Sstevel exit:
4011708Sstevel return (status);
4021708Sstevel }
4031708Sstevel
4041708Sstevel /*
4051708Sstevel * Notify SSC of switch request and wait for response.
4061708Sstevel */
4071708Sstevel int
man_dossc_switch(uint32_t exp_id)4081708Sstevel man_dossc_switch(uint32_t exp_id)
4091708Sstevel {
4101708Sstevel uint64_t req_tid;
4111708Sstevel uint32_t req_cmd;
4121708Sstevel uint64_t resp_tid;
4131708Sstevel uint32_t resp_cmd;
4141708Sstevel uint32_t type;
4151708Sstevel man_mbox_msg_t req;
4161708Sstevel man_mbox_msg_t resp;
4171708Sstevel uint32_t length;
4181708Sstevel int status = 0;
4191708Sstevel
4201708Sstevel /*
4211708Sstevel * There should be nothing in inbound mailbox.
4221708Sstevel */
4231708Sstevel resp_tid = resp_cmd = type = 0;
4241708Sstevel length = sizeof (man_mbox_msg_t);
4251708Sstevel bzero((char *)&resp, sizeof (man_mbox_msg_t));
4261708Sstevel while (mboxsc_getmsg(IOSRAM_KEY_SCMD, &type, &resp_cmd, &resp_tid,
4278459SJerry.Gilliam@Sun.COM &length, &resp, 0) == 0) {
4281708Sstevel
4291708Sstevel resp_tid = resp_cmd = type = 0;
4301708Sstevel length = sizeof (man_mbox_msg_t);
4311708Sstevel bzero((char *)&resp, sizeof (man_mbox_msg_t));
4321708Sstevel
4331708Sstevel MAN_DBG(MAN_IOSRAM, ("man_dossc_switch: dumping message"));
4341708Sstevel MAN_DBG(MAN_IOSRAM, ("\tcommand = 0x%x", resp_cmd));
4351708Sstevel }
4361708Sstevel
4371708Sstevel MAN_DBG(MAN_IOSRAM, ("man_dossc_switch: sending message"));
4381708Sstevel
4391708Sstevel bzero((char *)&req, sizeof (man_mbox_msg_t));
4401708Sstevel req.mb_status = 0;
4411708Sstevel req.mb_exp_id = exp_id;
4421708Sstevel req_tid = 0;
4431708Sstevel req_cmd = MAN_WORK_SWITCH;
4441708Sstevel
4451708Sstevel status = mboxsc_putmsg(IOSRAM_KEY_MDSC, MBOXSC_MSG_REQUEST,
4468459SJerry.Gilliam@Sun.COM req_cmd, &req_tid, sizeof (man_mbox_msg_t), &req,
4478459SJerry.Gilliam@Sun.COM MAN_IOSRAM_TIMEOUT);
4481708Sstevel
4491708Sstevel if (status != 0) {
4501708Sstevel cmn_err(CE_WARN, "man_dossc_switch: mboxsc_putmsg failed,"
4518459SJerry.Gilliam@Sun.COM " errno = %d", status);
4521708Sstevel goto exit;
4531708Sstevel }
4541708Sstevel
4551708Sstevel bzero((char *)&resp, sizeof (man_mbox_msg_t));
4561708Sstevel
4571708Sstevel resp_tid = type = resp_cmd = 0;
4581708Sstevel length = sizeof (man_mbox_msg_t);
4591708Sstevel status = mboxsc_getmsg(IOSRAM_KEY_SCMD, &type, &resp_cmd, &resp_tid,
4608459SJerry.Gilliam@Sun.COM &length, (void *)&resp, MAN_IOSRAM_TIMEOUT);
4611708Sstevel if (status != 0) {
4621708Sstevel cmn_err(CE_WARN, "man_dossc_switch: mboxsc_getmsg failed,"
4638459SJerry.Gilliam@Sun.COM " errno = %d", status);
4641708Sstevel goto exit;
4651708Sstevel }
4661708Sstevel
4671708Sstevel MAN_DBG(MAN_IOSRAM, ("man_dossc_switch: received message"));
4681708Sstevel
4691708Sstevel if (req_cmd != resp_cmd || req_tid != resp_tid) {
4701708Sstevel cmn_err(CE_WARN, "man_dossc_switch: failed,"
4718459SJerry.Gilliam@Sun.COM " cmd/transid mismatch (%d, %d)/(%d, %d)",
4728459SJerry.Gilliam@Sun.COM req_cmd, resp_cmd, (int)req_tid, (int)resp_tid);
4731708Sstevel status = EINVAL;
4741708Sstevel goto exit;
4751708Sstevel }
4761708Sstevel
4771708Sstevel status = resp.mb_status;
4781708Sstevel if (status != 0) {
4791708Sstevel cmn_err(CE_WARN, "man_dossc_switch: failed errno == %d",
4808459SJerry.Gilliam@Sun.COM status);
4811708Sstevel }
4821708Sstevel exit:
4831708Sstevel return (status);
4841708Sstevel }
4851708Sstevel
4861708Sstevel
4871708Sstevel /*
4881708Sstevel * Read IOSRAM info.
4891708Sstevel */
4901708Sstevel int
man_get_iosram(manc_t * mcp)4911708Sstevel man_get_iosram(manc_t *mcp)
4921708Sstevel {
4931708Sstevel int status;
4941708Sstevel
4951708Sstevel if (mcp == NULL)
4961708Sstevel return (EINVAL);
4971708Sstevel
4981708Sstevel status = iosram_rd(IOSRAM_KEY_MANC, 0, sizeof (manc_t), (caddr_t)mcp);
4991708Sstevel if (status) {
5001708Sstevel cmn_err(CE_WARN, "man_get_iosram: iosram_rd failed"
5018459SJerry.Gilliam@Sun.COM " errno = %d\n", status);
5021708Sstevel return (status);
5031708Sstevel }
5041708Sstevel
5051708Sstevel MAN_DBG(MAN_PATH, ("man_get_iosram:"));
5061708Sstevel MAN_DBGCALL(MAN_PATH, man_print_manc(mcp));
5071708Sstevel
5081708Sstevel if (mcp->manc_magic != IOSRAM_KEY_MANC) {
5091708Sstevel cmn_err(CE_WARN, "man_get_iosram: bad magic - got(0x%x)"
5108459SJerry.Gilliam@Sun.COM " expected(0x%x)\n", mcp->manc_magic, IOSRAM_KEY_MANC);
5111708Sstevel status = EIO;
5121708Sstevel } else if (mcp->manc_version != MANC_VERSION) {
5131708Sstevel cmn_err(CE_WARN, "man_get_iosram: version mismatch -"
5148459SJerry.Gilliam@Sun.COM " got(0x%x) expected(0x%x)\n", mcp->manc_version,
5158459SJerry.Gilliam@Sun.COM MANC_VERSION);
5161708Sstevel status = EIO;
5171708Sstevel }
5181708Sstevel
5191708Sstevel return (status);
5201708Sstevel }
5211708Sstevel
5221708Sstevel #if defined(MAN_NO_IOSRAM)
5231708Sstevel
5241708Sstevel static manc_t manc = {
5251708Sstevel IOSRAM_KEY_MANC,
5261708Sstevel MANC_VERSION,
5271708Sstevel 0,
5281708Sstevel AF_INET,
5291708Sstevel /* 0x10010102, Two */
5301708Sstevel 0x10010103, /* Scot */
5311708Sstevel 0xFF000000, /* Scot netmask */
5321708Sstevel 0x10010101, /* SC 10.1.1.1 */
5331708Sstevel {0}, /* AF_INET6 addrs */
5341708Sstevel {0}, /* AF_INET6 addrs */
5351708Sstevel {0},
5361708Sstevel /* {0x8, 0x0, 0x20, 0x21, 0x44, 0x83}, Domain eaddr "two" */
5371708Sstevel {0x8, 0x0, 0x20, 0x8f, 0x84, 0x63}, /* Domain eaddr "scot" */
5381708Sstevel {0x8, 0x0, 0x20, 0x1f, 0xe3, 0x46}, /* SC eaddr "one" */
5391708Sstevel 0x1,
5401708Sstevel 0x1
5411708Sstevel };
5421708Sstevel
5431708Sstevel
5441708Sstevel /*
5451708Sstevel * Get IOSRAM info or release it.
5461708Sstevel */
5471708Sstevel int
man_get_iosram(manc_t * mcp)5481708Sstevel man_get_iosram(manc_t *mcp)
5491708Sstevel {
5501708Sstevel int status = 0;
5511708Sstevel
5521708Sstevel if (mcp == NULL)
5531708Sstevel return (EINVAL);
5541708Sstevel
5551708Sstevel *mcp = manc;
5561708Sstevel
5571708Sstevel if (mcp->manc_magic != IOSRAM_KEY_MANC) {
5581708Sstevel cmn_err(CE_WARN, "man_get_iosram: bad magic - got(0x%x)"
5598459SJerry.Gilliam@Sun.COM " expected(0x%x)\n", mcp->manc_magic, IOSRAM_KEY_MANC);
5601708Sstevel status = EIO;
5611708Sstevel } else if (mcp->manc_version != MANC_VERSION) {
5621708Sstevel cmn_err(CE_WARN, "man_get_iosram: version mismatch -"
5638459SJerry.Gilliam@Sun.COM " got(0x%x) expected(0x%x)\n", mcp->manc_version,
5648459SJerry.Gilliam@Sun.COM MANC_VERSION);
5651708Sstevel status = EIO;
5661708Sstevel }
5671708Sstevel
5681708Sstevel return (status);
5691708Sstevel }
5701708Sstevel #endif /* MAN_NO_IOSRAM */
5711708Sstevel
5721708Sstevel /*
5731708Sstevel * Find all RIOs on the IO boards for the domain. We walk all the children
5741708Sstevel * of the root node looking for a PCI devinfo with a safari port ID of
5751708Sstevel * 0xDC that has a child with device ID of 3. This is gauranteed to be
5761708Sstevel * the network portion of the RIO by virtue of the way Starcats are
5771708Sstevel * physically built.
5781708Sstevel */
5791708Sstevel static int
man_find_devs(mi_path_t * mipathp,uchar_t golden_iob)5801708Sstevel man_find_devs(mi_path_t *mipathp, uchar_t golden_iob)
5811708Sstevel {
5821708Sstevel dev_info_t *bus_dip;
5831708Sstevel dev_info_t *eri_dip;
5841708Sstevel dev_info_t *rdip, *pdip;
5851708Sstevel int exp_id;
5861708Sstevel int found = 0;
5871708Sstevel int circ;
5881708Sstevel int circ2;
5891708Sstevel man_dev_t ndev;
5901708Sstevel int xmits;
5911708Sstevel
5921708Sstevel MAN_DBG(MAN_PATH, ("man_find_devs: mdevpp(0x%p) golden_iob(%d)\n",
5938459SJerry.Gilliam@Sun.COM (void *)(mipathp), golden_iob));
5941708Sstevel
5951708Sstevel /*
5961708Sstevel * Hold parent busy while walking its child list.
5971708Sstevel */
5981708Sstevel rdip = ddi_root_node();
5991708Sstevel ndi_devi_enter(rdip, &circ);
6001708Sstevel bus_dip = ddi_get_child(rdip);
6011708Sstevel
6021708Sstevel while (bus_dip != NULL) {
6031708Sstevel exp_id = -1;
6041708Sstevel xmits = 0;
6051708Sstevel if (man_dip_is_schizoxmits0_pcib(bus_dip, &exp_id, &xmits)) {
6061708Sstevel eri_dip = NULL;
6071708Sstevel pdip = bus_dip;
6081708Sstevel if (xmits) {
6091708Sstevel /*
6101708Sstevel * If this is XMITS0 PCI_B leaf, then the
6111708Sstevel * pci_pci bridge which is the only child,
6121708Sstevel * is the parent to MAN RIO.
6131708Sstevel */
6141708Sstevel pdip = ddi_get_child(bus_dip);
6151708Sstevel if (pdip == NULL) {
6161708Sstevel bus_dip = ddi_get_next_sibling(bus_dip);
6171708Sstevel continue;
6181708Sstevel }
6191708Sstevel }
6201708Sstevel ndi_devi_enter(pdip, &circ2);
6211708Sstevel eri_dip = ddi_get_child(pdip);
6221708Sstevel while (eri_dip != NULL) {
6231708Sstevel MAN_DBG(MAN_PATH, ("man_find_devs: "
6248459SJerry.Gilliam@Sun.COM "eri_dip %s\n",
6258459SJerry.Gilliam@Sun.COM ddi_binding_name(eri_dip)));
6261708Sstevel if (man_dip_is_eri(eri_dip, &ndev) &&
6278459SJerry.Gilliam@Sun.COM man_dip_is_attached(eri_dip)) {
6281708Sstevel
6291708Sstevel ASSERT(exp_id != -1);
6301708Sstevel ndev.mdev_exp_id = exp_id;
6311708Sstevel ndev.mdev_state = MDEV_ASSIGNED;
6321708Sstevel mipathp->mip_devs[found] = ndev;
6331708Sstevel found++;
6341708Sstevel
6351708Sstevel MAN_DBG(MAN_PATH,
6361708Sstevel ("man_find_devs: found eri maj(%d) "
6371708Sstevel "ppa(%d) on expander(%d)\n",
6381708Sstevel ndev.mdev_major,
6391708Sstevel ndev.mdev_ppa, exp_id));
6401708Sstevel }
6411708Sstevel eri_dip = ddi_get_next_sibling(eri_dip);
6421708Sstevel }
6431708Sstevel ndi_devi_exit(pdip, circ2);
6441708Sstevel }
6451708Sstevel bus_dip = ddi_get_next_sibling(bus_dip);
6461708Sstevel }
6471708Sstevel ndi_devi_exit(rdip, circ);
6481708Sstevel
6491708Sstevel MAN_DBG(MAN_PATH, ("man_find_devs returns found = %d\n", found));
6501708Sstevel
6511708Sstevel mipathp->mip_ndevs = found;
6521708Sstevel return (found);
6531708Sstevel }
6541708Sstevel
6551708Sstevel /*
6561708Sstevel * Verify if the dip passed is an instance of 'eri' and set
6571708Sstevel * the device info in mdevp.
6581708Sstevel */
6591708Sstevel static int
man_get_eri_dev_info(dev_info_t * dip,man_dev_t * mdevp)6601708Sstevel man_get_eri_dev_info(dev_info_t *dip, man_dev_t *mdevp)
6611708Sstevel {
6621708Sstevel dev_info_t *parent_dip;
6631708Sstevel int exp_id;
6641708Sstevel int xmits;
6651708Sstevel char *name;
6661708Sstevel
6671708Sstevel ASSERT(dip != NULL);
6681708Sstevel /*
6691708Sstevel * Verify if the parent is schizo(xmits)0 and pci B leaf.
6701708Sstevel */
6711708Sstevel if (((parent_dip = ddi_get_parent(dip)) == NULL) ||
6728459SJerry.Gilliam@Sun.COM ((name = ddi_binding_name(parent_dip)) == NULL))
6731708Sstevel return (FALSE);
6741708Sstevel if (strcmp(name, MAN_SCHIZO_BINDING_NAME) != 0) {
6751708Sstevel /*
6761708Sstevel * This RIO could be on XMITS, so get the dip to
6771708Sstevel * XMITS PCI Leaf.
6781708Sstevel */
6791708Sstevel if ((parent_dip = ddi_get_parent(parent_dip)) == NULL)
6801708Sstevel return (FALSE);
6811708Sstevel if (((name = ddi_binding_name(parent_dip)) == NULL) ||
6828459SJerry.Gilliam@Sun.COM (strcmp(name, MAN_XMITS_BINDING_NAME) != 0)) {
6831708Sstevel return (FALSE);
6841708Sstevel }
6851708Sstevel }
6861708Sstevel if (man_dip_is_schizoxmits0_pcib(parent_dip, &exp_id, &xmits) == FALSE)
6871708Sstevel return (FALSE);
6881708Sstevel
6891708Sstevel /*
6901708Sstevel * Make sure it is attached.
6911708Sstevel */
6921708Sstevel if (man_dip_is_attached(dip) == FALSE) {
6931708Sstevel MAN_DBG(MAN_DR, ("man_get_eri_dev_info: "
694*11311SSurya.Prakki@Sun.COM "dip 0x%p not attached\n", (void *)dip));
6951708Sstevel return (FALSE);
6961708Sstevel }
6971708Sstevel mdevp->mdev_exp_id = exp_id;
6981708Sstevel mdevp->mdev_ppa = ddi_get_instance(dip);
6998459SJerry.Gilliam@Sun.COM mdevp->mdev_major = ddi_driver_major(dip);
7001708Sstevel mdevp->mdev_state = MDEV_ASSIGNED;
7011708Sstevel return (TRUE);
7021708Sstevel }
7031708Sstevel
7041708Sstevel /*
7051708Sstevel * MAN RIO is connected to SCHIZO/XMITS 0 and PCI_B Leaf.
7061708Sstevel * Incase of XMITS, it is actually connected to a PCI Bridge(21154)
7071708Sstevel * which is directly connected to the PCI_B leaf of XMITS0.
7081708Sstevel *
7091708Sstevel * This function verifies if the given dip is SCHIZO/XMITS 0 and
7101708Sstevel * PCI_B Leaf. This is done as follows:
7111708Sstevel *
7121708Sstevel * - Check the binding name to verify SCHIZO/XMITS.
7131708Sstevel * - Verify the Device type to be "pci".
7141708Sstevel * - Verify the PortID to be ending with 0x1C
7151708Sstevel * - Verify the the CSR base to be 0x70.0000.
7161708Sstevel */
7171708Sstevel static int
man_dip_is_schizoxmits0_pcib(dev_info_t * dip,int * exp_id,int * xmits)7181708Sstevel man_dip_is_schizoxmits0_pcib(dev_info_t *dip, int *exp_id, int *xmits)
7191708Sstevel {
7201708Sstevel char dtype[MAN_DDI_BUFLEN];
7211708Sstevel int portid;
7221708Sstevel uint_t pci_csr_base;
7231708Sstevel struct pci_phys_spec *regbuf = NULL;
7241708Sstevel int length = MAN_DDI_BUFLEN;
7251708Sstevel char *name;
7261708Sstevel
7271708Sstevel ASSERT(dip != NULL);
7281708Sstevel *exp_id = -1;
7291708Sstevel if ((name = ddi_binding_name(dip)) == NULL)
7301708Sstevel return (FALSE);
7311708Sstevel if (strcmp(name, MAN_SCHIZO_BINDING_NAME) == 0) {
7321708Sstevel MAN_DBG(MAN_PATH, ("man_dip_is_schizoxmits0_pcib: "
733*11311SSurya.Prakki@Sun.COM "SCHIZO found 0x%p\n", (void *)dip));
7341708Sstevel } else if (strcmp(name, MAN_XMITS_BINDING_NAME) == 0) {
7351708Sstevel *xmits = TRUE;
7361708Sstevel MAN_DBG(MAN_PATH, ("man_dip_is_schizoxmits0_pcib: "
737*11311SSurya.Prakki@Sun.COM "XMITS found 0x%p\n", (void *)dip));
7381708Sstevel } else
7391708Sstevel return (FALSE);
7401708Sstevel if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, MAN_DEVTYPE_PROP,
7418459SJerry.Gilliam@Sun.COM (caddr_t)dtype, &length) == DDI_PROP_SUCCESS) {
7421708Sstevel
7431708Sstevel MAN_DBG(MAN_PATH, ("dtype: %s\n", dtype));
7441708Sstevel if (strncmp(dtype, MAN_DEVTYPE_PCI, 3) != 0)
7451708Sstevel goto notfound;
7461708Sstevel
7471708Sstevel /*
7481708Sstevel * Get safari ID (DDI port ID).
7491708Sstevel */
7501708Sstevel if ((portid = (int)ddi_getprop(DDI_DEV_T_ANY, dip, 0,
7518459SJerry.Gilliam@Sun.COM MAN_PORTID_PROP, -1)) == -1) {
7521708Sstevel
7531708Sstevel MAN_DBG(MAN_PATH, ("ddi_getpropp: failed\n"));
7541708Sstevel goto notfound;
7551708Sstevel }
7561708Sstevel
7571708Sstevel /*
7581708Sstevel * All schizo 0 safari IDs end in 0x1C.
7591708Sstevel */
7601708Sstevel if ((portid & MAN_SCHIZO_MASK) != MAN_SCHIZO_0_ID)
7611708Sstevel goto notfound;
7621708Sstevel
7631708Sstevel /*
7641708Sstevel * All PCI nodes "B" are at configspace 0x70.0000
7651708Sstevel */
7661708Sstevel if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
7678459SJerry.Gilliam@Sun.COM MAN_REG_PROP, (caddr_t)®buf,
7688459SJerry.Gilliam@Sun.COM &length) != DDI_PROP_SUCCESS) {
7691708Sstevel
7701708Sstevel MAN_DBG(MAN_PATH, ("ddi_getlongprop_buf: failed"));
7711708Sstevel goto notfound;
7721708Sstevel }
7731708Sstevel
7741708Sstevel pci_csr_base = regbuf[0].pci_phys_mid & PCI_CONF_ADDR_MASK;
7751708Sstevel kmem_free(regbuf, length);
7761708Sstevel if (pci_csr_base == MAN_PCI_B_CSR_BASE) {
7771708Sstevel
7781708Sstevel MAN_DBG(MAN_PATH, ("man_dip_is_schizoxmits0_pcib:"
7798459SJerry.Gilliam@Sun.COM " found PCI B at dip(0x%p)\n", (void *)dip));
7801708Sstevel
7811708Sstevel *exp_id = portid >> 5;
7821708Sstevel return (TRUE);
7831708Sstevel }
7841708Sstevel }
7851708Sstevel
7861708Sstevel notfound:
7871708Sstevel return (FALSE);
7881708Sstevel }
7891708Sstevel
7901708Sstevel static int
man_dip_is_eri(dev_info_t * dip,man_dev_t * ndevp)7911708Sstevel man_dip_is_eri(dev_info_t *dip, man_dev_t *ndevp)
7921708Sstevel {
7931708Sstevel struct pci_phys_spec *regbuf = NULL;
7941708Sstevel int length = 0;
7951708Sstevel uint_t pci_device;
7961708Sstevel uint_t pci_function;
7971708Sstevel
7981708Sstevel MAN_DBG(MAN_PATH, ("man_dip_is_eri: dip(0x%p) ndevp(0x%p)\n",
7998459SJerry.Gilliam@Sun.COM (void *)dip, (void *)ndevp));
8001708Sstevel if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
8018459SJerry.Gilliam@Sun.COM MAN_REG_PROP, (caddr_t)®buf,
8028459SJerry.Gilliam@Sun.COM &length) == DDI_PROP_SUCCESS) {
8031708Sstevel
8041708Sstevel pci_device = PCI_REG_DEV_G(regbuf->pci_phys_hi);
8051708Sstevel pci_function = PCI_REG_FUNC_G(regbuf->pci_phys_hi);
8061708Sstevel kmem_free(regbuf, length);
8071708Sstevel
8081708Sstevel /*
8091708Sstevel * The network function of the RIO ASIC will always
8101708Sstevel * be device 3 and function 1 ("network@3,1").
8111708Sstevel */
8121708Sstevel if (pci_device == 3 && pci_function == 1) {
8131708Sstevel ndevp->mdev_ppa = ddi_get_instance(dip);
8148459SJerry.Gilliam@Sun.COM ndevp->mdev_major = ddi_driver_major(dip);
8151708Sstevel
8161708Sstevel MAN_DBG(MAN_PATH, ("man_dip_is_eri: found eri maj(%d)"
8171708Sstevel " ppa(%d)\n", ndevp->mdev_major, ndevp->mdev_ppa));
8181708Sstevel
8191708Sstevel return (TRUE);
8201708Sstevel }
8211708Sstevel }
8221708Sstevel
8231708Sstevel MAN_DBG(MAN_PATH, ("man_dip_is_eri: returns FALSE\n"));
8241708Sstevel
8251708Sstevel return (FALSE);
8261708Sstevel }
8271708Sstevel
8281708Sstevel static int
man_dip_is_attached(dev_info_t * dip)8291708Sstevel man_dip_is_attached(dev_info_t *dip)
8301708Sstevel {
8311708Sstevel int state;
8321708Sstevel
8331708Sstevel state = ddi_get_devstate(dip);
8341708Sstevel if (i_ddi_devi_attached(dip) || (state == DDI_DEVSTATE_UP)) {
8351708Sstevel /*
8361708Sstevel * The instance info is more important for us,
8371708Sstevel * so verify.
8381708Sstevel */
8391708Sstevel if (ddi_get_instance(dip) >= 0) {
8401708Sstevel return (TRUE);
8411708Sstevel }
8421708Sstevel cmn_err(CE_WARN, "man_dip_is_attached: "
843*11311SSurya.Prakki@Sun.COM "eri 0x%p instance is not set yet", (void *)dip);
8441708Sstevel
8451708Sstevel }
8461708Sstevel return (FALSE);
8471708Sstevel }
8481708Sstevel
8491708Sstevel #if defined(DEBUG)
8501708Sstevel static void
man_print_manc(manc_t * mcp)8511708Sstevel man_print_manc(manc_t *mcp)
8521708Sstevel {
8531708Sstevel cmn_err(CE_CONT, "\tmcp(0x%p)\n\n", (void *)mcp);
8541708Sstevel
8551708Sstevel if (mcp == NULL)
8561708Sstevel return;
8571708Sstevel
8581708Sstevel cmn_err(CE_CONT, "\tmagic: 0x%x\n", mcp->manc_magic);
8591708Sstevel cmn_err(CE_CONT, "\tversion: 0x%x\n", mcp->manc_version);
8601708Sstevel cmn_err(CE_CONT, "\tcsum: %d\n", mcp->manc_csum);
8611708Sstevel cmn_err(CE_CONT, "\tdom_eaddr: %s\n",
8628459SJerry.Gilliam@Sun.COM ether_sprintf(&mcp->manc_dom_eaddr));
8631708Sstevel cmn_err(CE_CONT, "\tsc_eaddr: %s\n",
8648459SJerry.Gilliam@Sun.COM ether_sprintf(&mcp->manc_sc_eaddr));
8651708Sstevel cmn_err(CE_CONT, "\tiob_bitmap: 0x%x\n", mcp->manc_iob_bitmap);
8661708Sstevel cmn_err(CE_CONT, "\tgolden_iob: %d\n", mcp->manc_golden_iob);
8671708Sstevel
8681708Sstevel }
8691708Sstevel
8701708Sstevel #endif /* DEBUG */
871