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