dman_domain.c revision 1708:ea74d8598a3a
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29/*
30 * Domain specific portion of the Starcat Management Network Driver
31 */
32
33#include <sys/types.h>
34#include <sys/proc.h>
35#include <sys/kmem.h>
36#include <sys/stat.h>
37#include <sys/kstat.h>
38#include <sys/ksynch.h>
39#include <sys/stream.h>
40#include <sys/dlpi.h>
41#include <sys/stropts.h>
42#include <sys/strsubr.h>
43#include <sys/debug.h>
44#include <sys/conf.h>
45#include <sys/kstr.h>
46#include <sys/errno.h>
47#include <sys/ethernet.h>
48#include <sys/byteorder.h>
49#include <sys/ddi.h>
50#include <sys/sunddi.h>
51#include <sys/modctl.h>
52#include <sys/strsun.h>
53#include <sys/pci.h>
54#include <sys/callb.h>
55#include <sys/pci.h>
56#include <sys/iosramio.h>
57#include <sys/mboxsc.h>
58#include <netinet/in.h>
59#include <inet/common.h>
60#include <inet/mi.h>
61#include <inet/nd.h>
62#include <sys/socket.h>
63#include <netinet/igmp_var.h>
64#include <netinet/ip6.h>
65#include <netinet/icmp6.h>
66#include <inet/ip.h>
67#include <inet/ip6.h>
68#include <sys/dman.h>
69#include <sys/ddi_impldefs.h>
70#include <sys/sunndi.h>
71
72#define	MAN_SCHIZO_BINDING_NAME		"pci108e,8001"
73#define	MAN_XMITS_BINDING_NAME		"pci108e,8002"
74
75int	man_is_on_domain = TRUE;
76
77/*
78 * Domain side function prototypes.
79 */
80int	man_get_iosram(manc_t *);
81int	man_domain_configure(void);
82int	man_domain_deconfigure(void);
83int	man_path_discovery(void);
84int	man_dossc_switch(uint32_t);
85int	man_dr_attach(dev_info_t *);
86int	man_dr_detach(dev_info_t *);
87static int	man_dr_submit_work_wait(dev_info_t *, int);
88static int	man_find_devs(mi_path_t *, uchar_t);
89static int 	man_dip_is_schizoxmits0_pcib(dev_info_t *, int *, int *);
90static int	man_dip_is_eri(dev_info_t *, man_dev_t *);
91static int	man_dip_is_attached(dev_info_t *);
92static int 	man_get_eri_dev_info(dev_info_t *, man_dev_t *);
93static int	man_mbox_initialized = FALSE;
94
95/*
96 * Externs
97 */
98extern int	man_pg_cmd(mi_path_t *, man_work_t *);
99extern kmutex_t		man_lock;
100extern void		*man_softstate;
101extern man_work_t	*man_work_alloc(int, int);
102extern void		man_work_free(man_work_t *);
103extern void		man_work_add(man_workq_t *, man_work_t *);
104extern man_workq_t	*man_bwork_q;
105extern man_workq_t	*man_iwork_q;
106extern queue_t		*man_ctl_wq;
107
108#if defined(DEBUG)
109static void man_print_manc(manc_t *);
110extern uint32_t	man_debug;
111#endif  /* DEBUG */
112
113int
114man_domain_configure(void)
115{
116	int		status = 0;
117
118	/*
119	 * man_mbox_initialized is protected by inner perimiter lock.
120	 */
121	if (man_mbox_initialized == TRUE)
122		goto exit;
123
124	status = mboxsc_init(IOSRAM_KEY_SCMD, MBOXSC_MBOX_IN, NULL);
125
126	if (status != 0) {
127		cmn_err(CE_WARN, "man_domain_configure: failed to initialize"
128			" MBOXSC_MBOX_IN, errno = %d", status);
129		goto exit;
130	}
131
132	status = mboxsc_init(IOSRAM_KEY_MDSC, MBOXSC_MBOX_OUT, NULL);
133	if (status != 0) {
134		mboxsc_fini(IOSRAM_KEY_SCMD);
135		cmn_err(CE_WARN, "man_domain_configure: failed to initialize"
136			" MBOXSC_MBOX_OUT, errno = %d", status);
137		goto exit;
138	}
139
140	man_mbox_initialized = TRUE;
141
142	status = man_path_discovery();
143	if (status != 0) {
144		mboxsc_fini(IOSRAM_KEY_SCMD);
145		mboxsc_fini(IOSRAM_KEY_MDSC);
146		man_mbox_initialized = FALSE;
147	}
148
149exit:
150	return (status);
151}
152
153/*
154 * Build pathgroup connecting a domain to the SSC. Only called on domains
155 * at first man_open. On the SSC, pathgroups are built by IOCTL requests
156 * from the MAN daemon (see man_ioctl and mand(1M)).
157 *
158 * Locks held
159 *	- exclusive innerperim.
160 */
161int
162man_path_discovery(void)
163{
164	manc_t		manc;
165	mi_path_t	mpath;
166	int		num_devs;
167	int		status = 0;
168	int		i;
169
170	MAN_DBG(MAN_CONFIG, ("man_path_discovery:"));
171
172	if (status = man_get_iosram(&manc)) {
173		goto exit;
174	}
175
176	/*
177	 * If manc_ip_type indicates MAN network is not enabled
178	 * for this domain, then lets just bailout from here as if no
179	 * devices were found.
180	 */
181	if ((manc.manc_ip_type != AF_INET) &&
182			(manc.manc_ip_type != AF_INET6)) {
183		goto exit;
184	}
185
186	MAN_DBGCALL(MAN_CONFIG, man_print_manc(&manc));
187
188	/*
189	 * Extract SC ethernet address from IOSRAM.
190	 */
191	ether_copy(&manc.manc_sc_eaddr, &mpath.mip_eaddr);
192
193	mpath.mip_pg_id = 0;	/* SC is always pathgroup ID 0 */
194	mpath.mip_man_ppa = 0;	/* Domain only has one ppa, 0 */
195
196	/*
197	 * Get list of present devices, and update man_paths[] as needed.
198	 */
199	num_devs = man_find_devs(&mpath, MAN_MAX_EXPANDERS);
200	if (num_devs <= 0) {
201		status = ENODEV;
202		goto exit;
203	}
204
205	mpath.mip_cmd = MI_PATH_ASSIGN;
206
207	mutex_enter(&man_lock);
208	status = man_pg_cmd(&mpath, NULL);
209	if (status) {
210		mutex_exit(&man_lock);
211		goto exit;
212	}
213
214	/*
215	 * Now activate the ethernet on the golden io board.
216	 */
217	for (i = 0; i < num_devs; i++) {
218		if (mpath.mip_devs[i].mdev_exp_id == manc.manc_golden_iob)
219			mpath.mip_devs[0] = mpath.mip_devs[i];
220	}
221	mpath.mip_ndevs = 1;
222	mpath.mip_cmd = MI_PATH_ACTIVATE;
223	status = man_pg_cmd(&mpath, NULL);
224	mutex_exit(&man_lock);
225
226exit:
227	MAN_DBG(MAN_CONFIG, ("man_path_discovery: returns %d\n", status));
228
229	return (status);
230}
231
232int
233man_domain_deconfigure(void)
234{
235
236	mboxsc_fini(IOSRAM_KEY_SCMD);
237	mboxsc_fini(IOSRAM_KEY_MDSC);
238	/*
239	 * We are about to unload and know that there are no open
240	 * streams, so this change outside of the perimiter is ok.
241	 */
242	man_mbox_initialized = FALSE;
243
244	return (0);
245}
246
247/*
248 * Add a work request to the inner perimeter with the new eri device info.
249 */
250/* ARGSUSED */
251int
252man_dr_attach(dev_info_t *dip)
253{
254	man_t		*manp;
255	man_work_t	*wp;
256	int		status = 0;
257	man_dev_t	mdev;
258
259
260	mutex_enter(&man_lock);
261	manp = ddi_get_soft_state(man_softstate, 0);
262	if (manp == NULL || manp->man_pg == NULL) {
263		goto exit;
264	}
265
266	if (man_get_eri_dev_info(dip, &mdev) == FALSE) {
267		status = ENODEV;
268		goto exit;
269	}
270	MAN_DBG(MAN_DR, ("man_dr_attach: dip major = %d instance =%d",
271			mdev.mdev_major, mdev.mdev_ppa));
272	wp = man_work_alloc(MAN_WORK_DRATTACH, KM_NOSLEEP);
273	if (wp == NULL) {
274		status = ENOMEM;
275		goto exit;
276	}
277
278	wp->mw_arg.a_man_ppa = 0;	/* Domain only has one ppa, 0 */
279	wp->mw_arg.a_pg_id = 0;		/* SC is always pathgroup ID 0 */
280	wp->mw_arg.a_sf_dev = mdev;
281	wp->mw_flags = MAN_WFLAGS_NOWAITER;
282
283	man_work_add(man_iwork_q, wp);
284
285	if (man_ctl_wq)
286		qenable(man_ctl_wq);
287
288exit:
289	mutex_exit(&man_lock);
290
291	return (status);
292}
293
294int
295man_dr_detach(dev_info_t *dip)
296{
297	man_t		*manp;
298	int		status = 0;
299	int		retries = 0;
300
301
302	mutex_enter(&man_lock);
303	manp = ddi_get_soft_state(man_softstate, 0);
304	if (manp == NULL || manp->man_pg == NULL) {
305		mutex_exit(&man_lock);
306		goto exit;
307	}
308	mutex_exit(&man_lock);
309
310	/*
311	 * Arrange to have the detaching path switched if it is active.
312	 * We will cv_wait_sig for the switch to complete if it is needed.
313	 */
314again:
315	status = man_dr_submit_work_wait(dip, MAN_WORK_DRSWITCH);
316	if (status == EAGAIN && retries < manp->man_dr_retries) {
317		/*
318		 * Delay a bit and retry.
319		 */
320		MAN_DBG(MAN_DR,
321			("man_dr_detach(switch): EAGAIN - retrying..."));
322		retries++;
323		delay(drv_usectohz(manp->man_dr_delay));
324		goto again;
325	}
326
327	if (status)
328		goto exit;
329
330	retries = 0;
331
332	/*
333	 * Detaching device no longer in use, remove it from our
334	 * pathgroup.
335	 */
336	status = man_dr_submit_work_wait(dip, MAN_WORK_DRDETACH);
337	if (status == EAGAIN && retries < manp->man_dr_retries) {
338		MAN_DBG(MAN_DR,
339			("man_dr_detach(detach): EAGAIN - retrying..."));
340		retries++;
341		goto again;
342	}
343
344exit:
345	MAN_DBG(MAN_DR, ("man_dr_detach: returns %d", status));
346	return (status);
347}
348
349static int
350man_dr_submit_work_wait(dev_info_t *dip, int work_type)
351{
352	man_work_t	*wp;
353	int		status = 0;
354
355	wp = man_work_alloc(work_type, KM_NOSLEEP);
356	if (wp == NULL) {
357		status = ENOMEM;
358		goto exit;
359	}
360
361	wp->mw_arg.a_man_ppa = 0;
362	wp->mw_arg.a_pg_id = 0;
363	wp->mw_arg.a_sf_dev.mdev_major = ddi_name_to_major(ddi_get_name(dip));
364	wp->mw_arg.a_sf_dev.mdev_ppa = ddi_get_instance(dip);
365
366	mutex_enter(&man_lock);
367	wp->mw_flags = MAN_WFLAGS_CVWAITER;
368	man_work_add(man_iwork_q, wp);
369
370	/* TBD - change to ASSERT ? */
371	if (man_ctl_wq)
372		qenable(man_ctl_wq);
373
374	while (!(wp->mw_flags & MAN_WFLAGS_DONE)) {
375		if (!cv_wait_sig(&wp->mw_cv, &man_lock)) {
376			wp->mw_flags &= ~MAN_WFLAGS_CVWAITER;
377			status = EINTR;
378			break;
379		}
380	}
381
382	/*
383	 * Note that if cv_wait_sig() returns zero because a signal
384	 * was received, MAN_WFLAGS_DONE may not be set.
385	 * This will happen if man_dr_submit_work_wait() reacquires
386	 * man_lock before man_iwork() can acquire man_lock just before
387	 * signalling its work is complete.
388	 * In this case, it is not necessary to call man_work_free()
389	 * here because it will be called by man_iwork() because
390	 * MAN_WFLAGS_CVWAITER was cleared.
391	 * Should man_iwork() obtain man_lock to signal completion,
392	 * MAN_WFLAGS_DONE will be set which will ensure man_work_free()
393	 * is called here.
394	 */
395	if (wp->mw_flags & MAN_WFLAGS_DONE) {
396		status = wp->mw_status;
397		man_work_free(wp);
398	}
399
400	mutex_exit(&man_lock);
401
402exit:
403	return (status);
404}
405
406/*
407 * Notify SSC of switch request and wait for response.
408 */
409int
410man_dossc_switch(uint32_t exp_id)
411{
412	uint64_t	req_tid;
413	uint32_t	req_cmd;
414	uint64_t	resp_tid;
415	uint32_t	resp_cmd;
416	uint32_t	type;
417	man_mbox_msg_t	req;
418	man_mbox_msg_t	resp;
419	uint32_t	length;
420	int		status = 0;
421
422	/*
423	 *  There should be nothing in inbound mailbox.
424	 */
425	resp_tid = resp_cmd = type = 0;
426	length = sizeof (man_mbox_msg_t);
427	bzero((char *)&resp, sizeof (man_mbox_msg_t));
428	while (mboxsc_getmsg(IOSRAM_KEY_SCMD, &type, &resp_cmd, &resp_tid,
429		&length, &resp, 0) == 0) {
430
431		resp_tid = resp_cmd = type = 0;
432		length = sizeof (man_mbox_msg_t);
433		bzero((char *)&resp, sizeof (man_mbox_msg_t));
434
435		MAN_DBG(MAN_IOSRAM, ("man_dossc_switch: dumping message"));
436		MAN_DBG(MAN_IOSRAM, ("\tcommand = 0x%x", resp_cmd));
437	}
438
439	MAN_DBG(MAN_IOSRAM, ("man_dossc_switch: sending message"));
440
441	bzero((char *)&req, sizeof (man_mbox_msg_t));
442	req.mb_status = 0;
443	req.mb_exp_id = exp_id;
444	req_tid = 0;
445	req_cmd = MAN_WORK_SWITCH;
446
447	status = mboxsc_putmsg(IOSRAM_KEY_MDSC, MBOXSC_MSG_REQUEST,
448		req_cmd, &req_tid, sizeof (man_mbox_msg_t), &req,
449		MAN_IOSRAM_TIMEOUT);
450
451	if (status != 0) {
452		cmn_err(CE_WARN, "man_dossc_switch: mboxsc_putmsg failed,"
453			" errno = %d", status);
454		goto exit;
455	}
456
457	bzero((char *)&resp, sizeof (man_mbox_msg_t));
458
459	resp_tid = type = resp_cmd = 0;
460	length = sizeof (man_mbox_msg_t);
461	status = mboxsc_getmsg(IOSRAM_KEY_SCMD, &type, &resp_cmd, &resp_tid,
462		&length, (void *)&resp, MAN_IOSRAM_TIMEOUT);
463	if (status != 0) {
464		cmn_err(CE_WARN, "man_dossc_switch: mboxsc_getmsg failed,"
465			" errno = %d", status);
466		goto exit;
467	}
468
469	MAN_DBG(MAN_IOSRAM, ("man_dossc_switch: received message"));
470
471	if (req_cmd != resp_cmd || req_tid != resp_tid) {
472		cmn_err(CE_WARN, "man_dossc_switch: failed,"
473			" cmd/transid mismatch (%d, %d)/(%d, %d)",
474			req_cmd, resp_cmd, (int)req_tid, (int)resp_tid);
475		status = EINVAL;
476		goto exit;
477	}
478
479	status = resp.mb_status;
480	if (status != 0) {
481		cmn_err(CE_WARN, "man_dossc_switch: failed errno == %d",
482			status);
483	}
484exit:
485	return (status);
486}
487
488
489/*
490 *  Read IOSRAM info.
491 */
492int
493man_get_iosram(manc_t *mcp)
494{
495	int	status;
496
497	if (mcp == NULL)
498		return (EINVAL);
499
500	status = iosram_rd(IOSRAM_KEY_MANC, 0, sizeof (manc_t), (caddr_t)mcp);
501	if (status) {
502		cmn_err(CE_WARN, "man_get_iosram: iosram_rd failed"
503			" errno = %d\n", status);
504		return (status);
505	}
506
507	MAN_DBG(MAN_PATH, ("man_get_iosram:"));
508	MAN_DBGCALL(MAN_PATH, man_print_manc(mcp));
509
510	if (mcp->manc_magic != IOSRAM_KEY_MANC) {
511		cmn_err(CE_WARN, "man_get_iosram: bad magic - got(0x%x)"
512			" expected(0x%x)\n", mcp->manc_magic, IOSRAM_KEY_MANC);
513		status = EIO;
514	} else if (mcp->manc_version != MANC_VERSION) {
515		cmn_err(CE_WARN, "man_get_iosram: version mismatch -"
516			" got(0x%x) expected(0x%x)\n", mcp->manc_version,
517			MANC_VERSION);
518		status = EIO;
519	}
520
521	return (status);
522}
523
524#if defined(MAN_NO_IOSRAM)
525
526static manc_t	manc = {
527	IOSRAM_KEY_MANC,
528	MANC_VERSION,
529	0,
530	AF_INET,
531/*	0x10010102,		Two */
532	0x10010103,		/* Scot */
533	0xFF000000,		/* Scot netmask */
534	0x10010101,		/* SC 10.1.1.1 */
535	{0},	/* AF_INET6 addrs */
536	{0},	/* AF_INET6 addrs */
537	{0},
538/*	{0x8, 0x0, 0x20, 0x21, 0x44, 0x83},	Domain eaddr "two" */
539	{0x8, 0x0, 0x20, 0x8f, 0x84, 0x63},	/* Domain eaddr "scot" */
540	{0x8, 0x0, 0x20, 0x1f, 0xe3, 0x46},	/* SC eaddr "one" */
541	0x1,
542	0x1
543};
544
545
546/*
547 *  Get IOSRAM info or release it.
548 */
549int
550man_get_iosram(manc_t *mcp)
551{
552	int	status = 0;
553
554	if (mcp == NULL)
555		return (EINVAL);
556
557	*mcp = manc;
558
559	if (mcp->manc_magic != IOSRAM_KEY_MANC) {
560		cmn_err(CE_WARN, "man_get_iosram: bad magic - got(0x%x)"
561			" expected(0x%x)\n", mcp->manc_magic, IOSRAM_KEY_MANC);
562		status = EIO;
563	} else if (mcp->manc_version != MANC_VERSION) {
564		cmn_err(CE_WARN, "man_get_iosram: version mismatch -"
565			" got(0x%x) expected(0x%x)\n", mcp->manc_version,
566			MANC_VERSION);
567		status = EIO;
568	}
569
570	return (status);
571}
572#endif  /* MAN_NO_IOSRAM */
573
574/*
575 * Find all RIOs on the IO boards for the domain. We walk all the children
576 * of the root node looking for a PCI devinfo with a safari port ID of
577 * 0xDC that has a child with device ID of 3.  This is gauranteed to be
578 * the network portion of the RIO by virtue of the way Starcats are
579 * physically built.
580 */
581static int
582man_find_devs(mi_path_t *mipathp, uchar_t golden_iob)
583{
584	dev_info_t	*bus_dip;
585	dev_info_t	*eri_dip;
586	dev_info_t	*rdip, *pdip;
587	int		exp_id;
588	int		found = 0;
589	int		circ;
590	int		circ2;
591	man_dev_t	ndev;
592	int		xmits;
593
594	MAN_DBG(MAN_PATH, ("man_find_devs: mdevpp(0x%p) golden_iob(%d)\n",
595		(void *)(mipathp), golden_iob));
596
597	/*
598	 * Hold parent busy while walking its child list.
599	 */
600	rdip = ddi_root_node();
601	ndi_devi_enter(rdip, &circ);
602	bus_dip = ddi_get_child(rdip);
603
604	while (bus_dip != NULL) {
605		exp_id = -1;
606		xmits = 0;
607		if (man_dip_is_schizoxmits0_pcib(bus_dip, &exp_id, &xmits)) {
608			eri_dip = NULL;
609			pdip = bus_dip;
610			if (xmits) {
611				/*
612				 * If this is XMITS0 PCI_B leaf, then the
613				 * pci_pci bridge which is the only child,
614				 * is the parent to MAN RIO.
615				 */
616				pdip = ddi_get_child(bus_dip);
617				if (pdip == NULL) {
618					bus_dip = ddi_get_next_sibling(bus_dip);
619					continue;
620				}
621			}
622			ndi_devi_enter(pdip, &circ2);
623			eri_dip = ddi_get_child(pdip);
624			while (eri_dip != NULL) {
625				MAN_DBG(MAN_PATH, ("man_find_devs: "
626					"eri_dip %s\n",
627					ddi_binding_name(eri_dip)));
628				if (man_dip_is_eri(eri_dip, &ndev) &&
629					man_dip_is_attached(eri_dip)) {
630
631					ASSERT(exp_id != -1);
632					ndev.mdev_exp_id = exp_id;
633					ndev.mdev_state = MDEV_ASSIGNED;
634					mipathp->mip_devs[found] = ndev;
635					found++;
636
637					MAN_DBG(MAN_PATH,
638					    ("man_find_devs: found eri maj(%d) "
639					    "ppa(%d) on expander(%d)\n",
640					    ndev.mdev_major,
641					    ndev.mdev_ppa, exp_id));
642				}
643				eri_dip = ddi_get_next_sibling(eri_dip);
644			}
645			ndi_devi_exit(pdip, circ2);
646		}
647		bus_dip = ddi_get_next_sibling(bus_dip);
648	}
649	ndi_devi_exit(rdip, circ);
650
651	MAN_DBG(MAN_PATH, ("man_find_devs returns found = %d\n", found));
652
653	mipathp->mip_ndevs = found;
654	return (found);
655}
656
657/*
658 * Verify if the dip passed is an instance of 'eri' and set
659 * the device info in mdevp.
660 */
661static int
662man_get_eri_dev_info(dev_info_t *dip, man_dev_t *mdevp)
663{
664	dev_info_t	*parent_dip;
665	int		exp_id;
666	int		xmits;
667	char		*name;
668
669	ASSERT(dip != NULL);
670	/*
671	 * Verify if the parent is schizo(xmits)0 and pci B leaf.
672	 */
673	if (((parent_dip = ddi_get_parent(dip)) == NULL) ||
674		((name = ddi_binding_name(parent_dip)) == NULL))
675		return (FALSE);
676	if (strcmp(name, MAN_SCHIZO_BINDING_NAME) != 0) {
677		/*
678		 * This RIO could be on XMITS, so get the dip to
679		 * XMITS PCI Leaf.
680		 */
681		if ((parent_dip = ddi_get_parent(parent_dip)) == NULL)
682			return (FALSE);
683		if (((name = ddi_binding_name(parent_dip)) == NULL) ||
684			(strcmp(name, MAN_XMITS_BINDING_NAME) != 0)) {
685			return (FALSE);
686		}
687	}
688	if (man_dip_is_schizoxmits0_pcib(parent_dip, &exp_id, &xmits) == FALSE)
689		return (FALSE);
690
691	/*
692	 * Make sure it is attached.
693	 */
694	if (man_dip_is_attached(dip) == FALSE) {
695		MAN_DBG(MAN_DR, ("man_get_eri_dev_info: "
696				"dip 0x%p not attached\n", dip));
697		return (FALSE);
698	}
699	mdevp->mdev_exp_id = exp_id;
700	mdevp->mdev_ppa = ddi_get_instance(dip);
701	mdevp->mdev_major =
702		ddi_name_to_major(ddi_get_name(dip));
703	mdevp->mdev_state = MDEV_ASSIGNED;
704	return (TRUE);
705}
706
707/*
708 * MAN RIO is connected to SCHIZO/XMITS 0 and PCI_B Leaf.
709 * Incase of XMITS, it is actually connected to a PCI Bridge(21154)
710 * which is directly connected to the PCI_B leaf of XMITS0.
711 *
712 * This function verifies if the given dip is SCHIZO/XMITS 0 and
713 * PCI_B Leaf. This is done as follows:
714 *
715 * 	- Check the binding name to verify SCHIZO/XMITS.
716 * 	- Verify the Device type to be "pci".
717 *	- Verify the PortID to be ending with 0x1C
718 * 	- Verify the the CSR base to be 0x70.0000.
719 */
720static int
721man_dip_is_schizoxmits0_pcib(dev_info_t *dip, int *exp_id, int *xmits)
722{
723	char			dtype[MAN_DDI_BUFLEN];
724	int			portid;
725	uint_t			pci_csr_base;
726	struct pci_phys_spec	*regbuf = NULL;
727	int			length = MAN_DDI_BUFLEN;
728	char			*name;
729
730	ASSERT(dip != NULL);
731	*exp_id = -1;
732	if ((name = ddi_binding_name(dip)) == NULL)
733		return (FALSE);
734	if (strcmp(name, MAN_SCHIZO_BINDING_NAME) == 0) {
735		MAN_DBG(MAN_PATH, ("man_dip_is_schizoxmits0_pcib: "
736						"SCHIZO found 0x%p\n", dip));
737	} else if (strcmp(name, MAN_XMITS_BINDING_NAME) == 0) {
738		*xmits = TRUE;
739		MAN_DBG(MAN_PATH, ("man_dip_is_schizoxmits0_pcib: "
740						"XMITS found 0x%p\n", dip));
741	} else
742		return (FALSE);
743	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, MAN_DEVTYPE_PROP,
744		(caddr_t)dtype, &length) == DDI_PROP_SUCCESS) {
745
746		MAN_DBG(MAN_PATH, ("dtype: %s\n", dtype));
747		if (strncmp(dtype, MAN_DEVTYPE_PCI, 3) != 0)
748			goto notfound;
749
750		/*
751		 * Get safari ID (DDI port ID).
752		 */
753		if ((portid = (int)ddi_getprop(DDI_DEV_T_ANY, dip, 0,
754					MAN_PORTID_PROP, -1)) == -1) {
755
756			MAN_DBG(MAN_PATH, ("ddi_getpropp: failed\n"));
757			goto notfound;
758		}
759
760		/*
761		 * All schizo 0 safari IDs end in 0x1C.
762		 */
763		if ((portid & MAN_SCHIZO_MASK) != MAN_SCHIZO_0_ID)
764			goto notfound;
765
766		/*
767		 * All PCI nodes "B" are at configspace 0x70.0000
768		 */
769		if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
770				MAN_REG_PROP, (caddr_t)&regbuf,
771				&length) != DDI_PROP_SUCCESS) {
772
773			MAN_DBG(MAN_PATH, ("ddi_getlongprop_buf: failed"));
774			goto notfound;
775		}
776
777		pci_csr_base = regbuf[0].pci_phys_mid & PCI_CONF_ADDR_MASK;
778		kmem_free(regbuf, length);
779		if (pci_csr_base == MAN_PCI_B_CSR_BASE) {
780
781			MAN_DBG(MAN_PATH, ("man_dip_is_schizoxmits0_pcib:"
782				" found PCI B at dip(0x%p)\n", (void *)dip));
783
784			*exp_id = portid >> 5;
785			return (TRUE);
786		}
787	}
788
789notfound:
790	return (FALSE);
791}
792
793static int
794man_dip_is_eri(dev_info_t *dip, man_dev_t *ndevp)
795{
796	struct pci_phys_spec	*regbuf = NULL;
797	int			length = 0;
798	uint_t			pci_device;
799	uint_t			pci_function;
800
801	MAN_DBG(MAN_PATH, ("man_dip_is_eri: dip(0x%p) ndevp(0x%p)\n",
802		(void *)dip, (void *)ndevp));
803	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
804		MAN_REG_PROP, (caddr_t)&regbuf,
805		&length) == DDI_PROP_SUCCESS) {
806
807		pci_device = PCI_REG_DEV_G(regbuf->pci_phys_hi);
808		pci_function = PCI_REG_FUNC_G(regbuf->pci_phys_hi);
809		kmem_free(regbuf, length);
810
811		/*
812		 * The network function of the RIO ASIC will always
813		 * be device 3 and function 1 ("network@3,1").
814		 */
815		if (pci_device == 3 && pci_function == 1) {
816			ndevp->mdev_ppa = ddi_get_instance(dip);
817			ndevp->mdev_major =
818				ddi_name_to_major(ddi_get_name(dip));
819
820			MAN_DBG(MAN_PATH, ("man_dip_is_eri: found eri maj(%d)"
821			    " ppa(%d)\n", ndevp->mdev_major, ndevp->mdev_ppa));
822
823			return (TRUE);
824		}
825	}
826
827	MAN_DBG(MAN_PATH, ("man_dip_is_eri: returns FALSE\n"));
828
829	return (FALSE);
830}
831
832static int
833man_dip_is_attached(dev_info_t *dip)
834{
835	int state;
836
837	state = ddi_get_devstate(dip);
838	if (i_ddi_devi_attached(dip) || (state == DDI_DEVSTATE_UP)) {
839		/*
840		 * The instance info is more important for us,
841		 * so verify.
842		 */
843		if (ddi_get_instance(dip) >=  0) {
844			return (TRUE);
845		}
846		cmn_err(CE_WARN, "man_dip_is_attached: "
847				"eri 0x%p instance is not set yet", dip);
848
849	}
850	return (FALSE);
851}
852
853#if defined(DEBUG)
854static void
855man_print_manc(manc_t *mcp)
856{
857	cmn_err(CE_CONT, "\tmcp(0x%p)\n\n", (void *)mcp);
858
859	if (mcp == NULL)
860		return;
861
862	cmn_err(CE_CONT, "\tmagic: 0x%x\n", mcp->manc_magic);
863	cmn_err(CE_CONT, "\tversion: 0x%x\n", mcp->manc_version);
864	cmn_err(CE_CONT, "\tcsum: %d\n", mcp->manc_csum);
865	cmn_err(CE_CONT, "\tdom_eaddr: %s\n",
866		ether_sprintf(&mcp->manc_dom_eaddr));
867	cmn_err(CE_CONT, "\tsc_eaddr: %s\n",
868		ether_sprintf(&mcp->manc_sc_eaddr));
869	cmn_err(CE_CONT, "\tiob_bitmap: 0x%x\n", mcp->manc_iob_bitmap);
870	cmn_err(CE_CONT, "\tgolden_iob: %d\n", mcp->manc_golden_iob);
871
872}
873
874#endif  /* DEBUG */
875