xref: /titanic_51/usr/src/uts/sun4u/starcat/io/dman_domain.c (revision 80feccabd0bc0fca1df2b60bfa50449d9a6e3e09)
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 
75 int	man_is_on_domain = TRUE;
76 
77 /*
78  * Domain side function prototypes.
79  */
80 int	man_get_iosram(manc_t *);
81 int	man_domain_configure(void);
82 int	man_domain_deconfigure(void);
83 int	man_path_discovery(void);
84 int	man_dossc_switch(uint32_t);
85 int	man_dr_attach(dev_info_t *);
86 int	man_dr_detach(dev_info_t *);
87 static int	man_dr_submit_work_wait(dev_info_t *, int);
88 static int	man_find_devs(mi_path_t *, uchar_t);
89 static int 	man_dip_is_schizoxmits0_pcib(dev_info_t *, int *, int *);
90 static int	man_dip_is_eri(dev_info_t *, man_dev_t *);
91 static int	man_dip_is_attached(dev_info_t *);
92 static int 	man_get_eri_dev_info(dev_info_t *, man_dev_t *);
93 static int	man_mbox_initialized = FALSE;
94 
95 /*
96  * Externs
97  */
98 extern int	man_pg_cmd(mi_path_t *, man_work_t *);
99 extern kmutex_t		man_lock;
100 extern void		*man_softstate;
101 extern man_work_t	*man_work_alloc(int, int);
102 extern void		man_work_free(man_work_t *);
103 extern void		man_work_add(man_workq_t *, man_work_t *);
104 extern man_workq_t	*man_bwork_q;
105 extern man_workq_t	*man_iwork_q;
106 extern queue_t		*man_ctl_wq;
107 
108 #if defined(DEBUG)
109 static void man_print_manc(manc_t *);
110 extern uint32_t	man_debug;
111 #endif  /* DEBUG */
112 
113 int
114 man_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 
149 exit:
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  */
161 int
162 man_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 
226 exit:
227 	MAN_DBG(MAN_CONFIG, ("man_path_discovery: returns %d\n", status));
228 
229 	return (status);
230 }
231 
232 int
233 man_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 */
251 int
252 man_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 
288 exit:
289 	mutex_exit(&man_lock);
290 
291 	return (status);
292 }
293 
294 int
295 man_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 	 */
314 again:
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 
344 exit:
345 	MAN_DBG(MAN_DR, ("man_dr_detach: returns %d", status));
346 	return (status);
347 }
348 
349 static int
350 man_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 
402 exit:
403 	return (status);
404 }
405 
406 /*
407  * Notify SSC of switch request and wait for response.
408  */
409 int
410 man_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 	}
484 exit:
485 	return (status);
486 }
487 
488 
489 /*
490  *  Read IOSRAM info.
491  */
492 int
493 man_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 
526 static 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  */
549 int
550 man_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  */
581 static int
582 man_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  */
661 static int
662 man_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  */
720 static int
721 man_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 
789 notfound:
790 	return (FALSE);
791 }
792 
793 static int
794 man_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 
832 static int
833 man_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)
854 static void
855 man_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