xref: /onnv-gate/usr/src/uts/i86pc/os/pci_cfgacc_x86.c (revision 12520:7be44e5d23d7)
111245SZhijun.Fu@Sun.COM /*
211245SZhijun.Fu@Sun.COM  * CDDL HEADER START
311245SZhijun.Fu@Sun.COM  *
411245SZhijun.Fu@Sun.COM  * The contents of this file are subject to the terms of the
511245SZhijun.Fu@Sun.COM  * Common Development and Distribution License (the "License").
611245SZhijun.Fu@Sun.COM  * You may not use this file except in compliance with the License.
711245SZhijun.Fu@Sun.COM  *
811245SZhijun.Fu@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911245SZhijun.Fu@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1011245SZhijun.Fu@Sun.COM  * See the License for the specific language governing permissions
1111245SZhijun.Fu@Sun.COM  * and limitations under the License.
1211245SZhijun.Fu@Sun.COM  *
1311245SZhijun.Fu@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1411245SZhijun.Fu@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511245SZhijun.Fu@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1611245SZhijun.Fu@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1711245SZhijun.Fu@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1811245SZhijun.Fu@Sun.COM  *
1911245SZhijun.Fu@Sun.COM  * CDDL HEADER END
2011245SZhijun.Fu@Sun.COM  */
2111245SZhijun.Fu@Sun.COM 
2211245SZhijun.Fu@Sun.COM /*
2312212SZhijun.Fu@Sun.COM  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2411245SZhijun.Fu@Sun.COM  */
2511245SZhijun.Fu@Sun.COM 
2611245SZhijun.Fu@Sun.COM #include <sys/systm.h>
2711245SZhijun.Fu@Sun.COM #include <sys/pci_cfgacc.h>
2811245SZhijun.Fu@Sun.COM #include <sys/pci_cfgspace.h>
2911245SZhijun.Fu@Sun.COM #include <sys/pci_cfgspace_impl.h>
3011245SZhijun.Fu@Sun.COM #include <sys/sunddi.h>
3111245SZhijun.Fu@Sun.COM #include <sys/sysmacros.h>
3211245SZhijun.Fu@Sun.COM #include <sys/x86_archext.h>
3311245SZhijun.Fu@Sun.COM #include <sys/pci.h>
3412212SZhijun.Fu@Sun.COM #include <sys/cmn_err.h>
3511245SZhijun.Fu@Sun.COM #include <vm/hat_i86.h>
3611245SZhijun.Fu@Sun.COM #include <vm/seg_kmem.h>
3711245SZhijun.Fu@Sun.COM #include <vm/kboot_mmu.h>
3811245SZhijun.Fu@Sun.COM 
3911245SZhijun.Fu@Sun.COM #define	PCIE_CFG_SPACE_SIZE	(PCI_CONF_HDR_SIZE << 4)
4011245SZhijun.Fu@Sun.COM #define	PCI_BDF_BUS(bdf)	((((uint16_t)bdf) & 0xff00) >> 8)
4111245SZhijun.Fu@Sun.COM #define	PCI_BDF_DEV(bdf)	((((uint16_t)bdf) & 0xf8) >> 3)
4211245SZhijun.Fu@Sun.COM #define	PCI_BDF_FUNC(bdf)	(((uint16_t)bdf) & 0x7)
4311245SZhijun.Fu@Sun.COM 
4411245SZhijun.Fu@Sun.COM /* patchable variables */
4511245SZhijun.Fu@Sun.COM volatile boolean_t pci_cfgacc_force_io = B_FALSE;
4611245SZhijun.Fu@Sun.COM 
4711245SZhijun.Fu@Sun.COM extern uintptr_t alloc_vaddr(size_t, paddr_t);
4811245SZhijun.Fu@Sun.COM 
4911245SZhijun.Fu@Sun.COM void pci_cfgacc_acc(pci_cfgacc_req_t *);
5011245SZhijun.Fu@Sun.COM 
5111245SZhijun.Fu@Sun.COM boolean_t pci_cfgacc_find_workaround(uint16_t);
5211245SZhijun.Fu@Sun.COM /*
5311245SZhijun.Fu@Sun.COM  * IS_P2ALIGNED() is used to make sure offset is 'size'-aligned, so
5411245SZhijun.Fu@Sun.COM  * it's guaranteed that the access will not cross 4k page boundary.
5511245SZhijun.Fu@Sun.COM  * Thus only 1 page is allocated for all config space access, and the
5611245SZhijun.Fu@Sun.COM  * virtual address of that page is cached in pci_cfgacc_virt_base.
5711245SZhijun.Fu@Sun.COM  */
5811245SZhijun.Fu@Sun.COM static caddr_t pci_cfgacc_virt_base = NULL;
5911245SZhijun.Fu@Sun.COM 
6011245SZhijun.Fu@Sun.COM static caddr_t
pci_cfgacc_map(paddr_t phys_addr)6111245SZhijun.Fu@Sun.COM pci_cfgacc_map(paddr_t phys_addr)
6211245SZhijun.Fu@Sun.COM {
6311245SZhijun.Fu@Sun.COM #ifdef __xpv
6411245SZhijun.Fu@Sun.COM 	phys_addr = pfn_to_pa(xen_assign_pfn(mmu_btop(phys_addr))) |
6511245SZhijun.Fu@Sun.COM 	    (phys_addr & MMU_PAGEOFFSET);
6611245SZhijun.Fu@Sun.COM #endif
6711245SZhijun.Fu@Sun.COM 	if (khat_running) {
6811245SZhijun.Fu@Sun.COM 		pfn_t pfn = mmu_btop(phys_addr);
6911245SZhijun.Fu@Sun.COM 		/*
7011245SZhijun.Fu@Sun.COM 		 * pci_cfgacc_virt_base may hold address left from early
7111245SZhijun.Fu@Sun.COM 		 * boot, which points to low mem. Realloc virtual address
7211245SZhijun.Fu@Sun.COM 		 * in kernel space since it's already late in boot now.
7311245SZhijun.Fu@Sun.COM 		 * Note: no need to unmap first, clear_boot_mappings() will
7411245SZhijun.Fu@Sun.COM 		 * do that for us.
7511245SZhijun.Fu@Sun.COM 		 */
7612212SZhijun.Fu@Sun.COM 		if (pci_cfgacc_virt_base < (caddr_t)kernelbase)
7712212SZhijun.Fu@Sun.COM 			pci_cfgacc_virt_base = vmem_alloc(heap_arena,
7812212SZhijun.Fu@Sun.COM 			    MMU_PAGESIZE, VM_SLEEP);
7912212SZhijun.Fu@Sun.COM 
8011245SZhijun.Fu@Sun.COM 		hat_devload(kas.a_hat, pci_cfgacc_virt_base,
8111245SZhijun.Fu@Sun.COM 		    MMU_PAGESIZE, pfn, PROT_READ | PROT_WRITE |
8211245SZhijun.Fu@Sun.COM 		    HAT_STRICTORDER, HAT_LOAD_LOCK);
8311245SZhijun.Fu@Sun.COM 	} else {
8411245SZhijun.Fu@Sun.COM 		paddr_t	pa_base = P2ALIGN(phys_addr, MMU_PAGESIZE);
8511245SZhijun.Fu@Sun.COM 
8612212SZhijun.Fu@Sun.COM 		if (pci_cfgacc_virt_base == NULL)
8712212SZhijun.Fu@Sun.COM 			pci_cfgacc_virt_base =
8812212SZhijun.Fu@Sun.COM 			    (caddr_t)alloc_vaddr(MMU_PAGESIZE, MMU_PAGESIZE);
8912212SZhijun.Fu@Sun.COM 
9011245SZhijun.Fu@Sun.COM 		kbm_map((uintptr_t)pci_cfgacc_virt_base, pa_base, 0, 0);
9111245SZhijun.Fu@Sun.COM 	}
9211245SZhijun.Fu@Sun.COM 
9311245SZhijun.Fu@Sun.COM 	return (pci_cfgacc_virt_base + (phys_addr & MMU_PAGEOFFSET));
9411245SZhijun.Fu@Sun.COM }
9511245SZhijun.Fu@Sun.COM 
9611245SZhijun.Fu@Sun.COM static void
pci_cfgacc_unmap()9711245SZhijun.Fu@Sun.COM pci_cfgacc_unmap()
9811245SZhijun.Fu@Sun.COM {
9911245SZhijun.Fu@Sun.COM 	if (khat_running)
10011245SZhijun.Fu@Sun.COM 		hat_unload(kas.a_hat, pci_cfgacc_virt_base, MMU_PAGESIZE,
10111245SZhijun.Fu@Sun.COM 		    HAT_UNLOAD_UNLOCK);
10211245SZhijun.Fu@Sun.COM }
10311245SZhijun.Fu@Sun.COM 
10411245SZhijun.Fu@Sun.COM static void
pci_cfgacc_io(pci_cfgacc_req_t * req)10511245SZhijun.Fu@Sun.COM pci_cfgacc_io(pci_cfgacc_req_t *req)
10611245SZhijun.Fu@Sun.COM {
10712212SZhijun.Fu@Sun.COM 	uint8_t bus, dev, func;
10812212SZhijun.Fu@Sun.COM 	uint16_t ioacc_offset;	/* 4K config access with IO ECS */
10911245SZhijun.Fu@Sun.COM 
11011245SZhijun.Fu@Sun.COM 	bus = PCI_BDF_BUS(req->bdf);
11111245SZhijun.Fu@Sun.COM 	dev = PCI_BDF_DEV(req->bdf);
11211245SZhijun.Fu@Sun.COM 	func = PCI_BDF_FUNC(req->bdf);
11311245SZhijun.Fu@Sun.COM 	ioacc_offset = req->offset;
11412212SZhijun.Fu@Sun.COM 
11511245SZhijun.Fu@Sun.COM 	switch (req->size) {
11611245SZhijun.Fu@Sun.COM 	case 1:
11711245SZhijun.Fu@Sun.COM 		if (req->write)
11811245SZhijun.Fu@Sun.COM 			(*pci_putb_func)(bus, dev, func,
11911245SZhijun.Fu@Sun.COM 			    ioacc_offset, VAL8(req));
12011245SZhijun.Fu@Sun.COM 		else
12111245SZhijun.Fu@Sun.COM 			VAL8(req) = (*pci_getb_func)(bus, dev, func,
12211245SZhijun.Fu@Sun.COM 			    ioacc_offset);
12311245SZhijun.Fu@Sun.COM 		break;
12411245SZhijun.Fu@Sun.COM 	case 2:
12511245SZhijun.Fu@Sun.COM 		if (req->write)
12611245SZhijun.Fu@Sun.COM 			(*pci_putw_func)(bus, dev, func,
12711245SZhijun.Fu@Sun.COM 			    ioacc_offset, VAL16(req));
12811245SZhijun.Fu@Sun.COM 		else
12911245SZhijun.Fu@Sun.COM 			VAL16(req) = (*pci_getw_func)(bus, dev, func,
13011245SZhijun.Fu@Sun.COM 			    ioacc_offset);
13111245SZhijun.Fu@Sun.COM 		break;
13211245SZhijun.Fu@Sun.COM 	case 4:
13311245SZhijun.Fu@Sun.COM 		if (req->write)
13411245SZhijun.Fu@Sun.COM 			(*pci_putl_func)(bus, dev, func,
13511245SZhijun.Fu@Sun.COM 			    ioacc_offset, VAL32(req));
13611245SZhijun.Fu@Sun.COM 		else
13711245SZhijun.Fu@Sun.COM 			VAL32(req) = (*pci_getl_func)(bus, dev, func,
13811245SZhijun.Fu@Sun.COM 			    ioacc_offset);
13911245SZhijun.Fu@Sun.COM 		break;
14012212SZhijun.Fu@Sun.COM 	case 8:
14112212SZhijun.Fu@Sun.COM 		if (req->write) {
14212212SZhijun.Fu@Sun.COM 			(*pci_putl_func)(bus, dev, func,
14312212SZhijun.Fu@Sun.COM 			    ioacc_offset, VAL64(req) & 0xffffffff);
14412212SZhijun.Fu@Sun.COM 			(*pci_putl_func)(bus, dev, func,
14512212SZhijun.Fu@Sun.COM 			    ioacc_offset + 4, VAL64(req) >> 32);
14612212SZhijun.Fu@Sun.COM 		} else {
14712212SZhijun.Fu@Sun.COM 			VAL64(req) = (*pci_getl_func)(bus, dev, func,
14812212SZhijun.Fu@Sun.COM 			    ioacc_offset);
14912212SZhijun.Fu@Sun.COM 			VAL64(req) |= (uint64_t)(*pci_getl_func)(bus, dev, func,
15012212SZhijun.Fu@Sun.COM 			    ioacc_offset + 4) << 32;
15112212SZhijun.Fu@Sun.COM 		}
15212212SZhijun.Fu@Sun.COM 		break;
15311245SZhijun.Fu@Sun.COM 	}
15411245SZhijun.Fu@Sun.COM }
15511245SZhijun.Fu@Sun.COM 
15612212SZhijun.Fu@Sun.COM static void
pci_cfgacc_mmio(pci_cfgacc_req_t * req)15711245SZhijun.Fu@Sun.COM pci_cfgacc_mmio(pci_cfgacc_req_t *req)
15811245SZhijun.Fu@Sun.COM {
15911245SZhijun.Fu@Sun.COM 	caddr_t vaddr;
16011245SZhijun.Fu@Sun.COM 	paddr_t paddr;
16111245SZhijun.Fu@Sun.COM 
16211245SZhijun.Fu@Sun.COM 	paddr = (paddr_t)req->bdf << 12;
16311245SZhijun.Fu@Sun.COM 	paddr += mcfg_mem_base + req->offset;
16411245SZhijun.Fu@Sun.COM 
16511787SKerry.Shu@Sun.COM 	mutex_enter(&pcicfg_mmio_mutex);
16612212SZhijun.Fu@Sun.COM 	vaddr = pci_cfgacc_map(paddr);
16711245SZhijun.Fu@Sun.COM 
16811245SZhijun.Fu@Sun.COM 	switch (req->size) {
16911245SZhijun.Fu@Sun.COM 	case 1:
17011245SZhijun.Fu@Sun.COM 		if (req->write)
17111245SZhijun.Fu@Sun.COM 			*((uint8_t *)vaddr) = VAL8(req);
17211245SZhijun.Fu@Sun.COM 		else
17311245SZhijun.Fu@Sun.COM 			VAL8(req) = *((uint8_t *)vaddr);
17411245SZhijun.Fu@Sun.COM 		break;
17511245SZhijun.Fu@Sun.COM 	case 2:
17611245SZhijun.Fu@Sun.COM 		if (req->write)
17711245SZhijun.Fu@Sun.COM 			*((uint16_t *)vaddr) = VAL16(req);
17811245SZhijun.Fu@Sun.COM 		else
17911245SZhijun.Fu@Sun.COM 			VAL16(req) = *((uint16_t *)vaddr);
18011245SZhijun.Fu@Sun.COM 		break;
18111245SZhijun.Fu@Sun.COM 	case 4:
18211245SZhijun.Fu@Sun.COM 		if (req->write)
18311245SZhijun.Fu@Sun.COM 			*((uint32_t *)vaddr) = VAL32(req);
18411245SZhijun.Fu@Sun.COM 		else
18511245SZhijun.Fu@Sun.COM 			VAL32(req) = *((uint32_t *)vaddr);
18611245SZhijun.Fu@Sun.COM 		break;
18711245SZhijun.Fu@Sun.COM 	case 8:
18811245SZhijun.Fu@Sun.COM 		if (req->write)
18911245SZhijun.Fu@Sun.COM 			*((uint64_t *)vaddr) = VAL64(req);
19011245SZhijun.Fu@Sun.COM 		else
19111245SZhijun.Fu@Sun.COM 			VAL64(req) = *((uint64_t *)vaddr);
19211245SZhijun.Fu@Sun.COM 		break;
19311245SZhijun.Fu@Sun.COM 	}
19411245SZhijun.Fu@Sun.COM 	pci_cfgacc_unmap();
19511787SKerry.Shu@Sun.COM 	mutex_exit(&pcicfg_mmio_mutex);
19611245SZhijun.Fu@Sun.COM }
19711245SZhijun.Fu@Sun.COM 
19811245SZhijun.Fu@Sun.COM static boolean_t
pci_cfgacc_valid(pci_cfgacc_req_t * req,uint16_t cfgspc_size)199*12520SZhijun.Fu@Sun.COM pci_cfgacc_valid(pci_cfgacc_req_t *req, uint16_t cfgspc_size)
20011245SZhijun.Fu@Sun.COM {
20112212SZhijun.Fu@Sun.COM 	int sz = req->size;
20212212SZhijun.Fu@Sun.COM 
20312212SZhijun.Fu@Sun.COM 	if (IS_P2ALIGNED(req->offset, sz) &&
204*12520SZhijun.Fu@Sun.COM 	    (req->offset + sz - 1 < cfgspc_size) &&
20512212SZhijun.Fu@Sun.COM 	    ((sz & 0xf) && ISP2(sz)))
20612212SZhijun.Fu@Sun.COM 		return (B_TRUE);
20712212SZhijun.Fu@Sun.COM 
20812212SZhijun.Fu@Sun.COM 	cmn_err(CE_WARN, "illegal PCI request: offset = %x, size = %d",
20912212SZhijun.Fu@Sun.COM 	    req->offset, sz);
21012212SZhijun.Fu@Sun.COM 	return (B_FALSE);
21112212SZhijun.Fu@Sun.COM }
21212212SZhijun.Fu@Sun.COM 
21312212SZhijun.Fu@Sun.COM void
pci_cfgacc_check_io(pci_cfgacc_req_t * req)21412212SZhijun.Fu@Sun.COM pci_cfgacc_check_io(pci_cfgacc_req_t *req)
21512212SZhijun.Fu@Sun.COM {
21612212SZhijun.Fu@Sun.COM 	uint8_t bus;
21712212SZhijun.Fu@Sun.COM 
21812212SZhijun.Fu@Sun.COM 	bus = PCI_BDF_BUS(req->bdf);
21912212SZhijun.Fu@Sun.COM 
22012212SZhijun.Fu@Sun.COM 	if (pci_cfgacc_force_io || (mcfg_mem_base == NULL) ||
22112212SZhijun.Fu@Sun.COM 	    (bus < mcfg_bus_start) || (bus > mcfg_bus_end) ||
22212212SZhijun.Fu@Sun.COM 	    pci_cfgacc_find_workaround(req->bdf))
22312212SZhijun.Fu@Sun.COM 		req->ioacc = B_TRUE;
22411245SZhijun.Fu@Sun.COM }
22511245SZhijun.Fu@Sun.COM 
22611245SZhijun.Fu@Sun.COM void
pci_cfgacc_acc(pci_cfgacc_req_t * req)22711245SZhijun.Fu@Sun.COM pci_cfgacc_acc(pci_cfgacc_req_t *req)
22811245SZhijun.Fu@Sun.COM {
22912212SZhijun.Fu@Sun.COM 	extern uint_t pci_iocfg_max_offset;
23011245SZhijun.Fu@Sun.COM 
23111245SZhijun.Fu@Sun.COM 	if (!req->write)
23212212SZhijun.Fu@Sun.COM 		VAL64(req) = (uint64_t)-1;
23311245SZhijun.Fu@Sun.COM 
23412212SZhijun.Fu@Sun.COM 	pci_cfgacc_check_io(req);
23511245SZhijun.Fu@Sun.COM 
23612212SZhijun.Fu@Sun.COM 	if (req->ioacc) {
237*12520SZhijun.Fu@Sun.COM 		if (pci_cfgacc_valid(req, pci_iocfg_max_offset + 1))
23812212SZhijun.Fu@Sun.COM 			pci_cfgacc_io(req);
23912212SZhijun.Fu@Sun.COM 	} else {
24012212SZhijun.Fu@Sun.COM 		if (pci_cfgacc_valid(req, PCIE_CFG_SPACE_SIZE))
24112212SZhijun.Fu@Sun.COM 			pci_cfgacc_mmio(req);
24212212SZhijun.Fu@Sun.COM 	}
24311245SZhijun.Fu@Sun.COM }
24411245SZhijun.Fu@Sun.COM 
24511245SZhijun.Fu@Sun.COM typedef	struct cfgacc_bus_range {
24611245SZhijun.Fu@Sun.COM 	struct cfgacc_bus_range *next;
24711245SZhijun.Fu@Sun.COM 	uint16_t bdf;
24811245SZhijun.Fu@Sun.COM 	uchar_t	secbus;
24911245SZhijun.Fu@Sun.COM 	uchar_t	subbus;
25011245SZhijun.Fu@Sun.COM } cfgacc_bus_range_t;
25111245SZhijun.Fu@Sun.COM 
25211245SZhijun.Fu@Sun.COM cfgacc_bus_range_t *pci_cfgacc_bus_head = NULL;
25311245SZhijun.Fu@Sun.COM 
25411245SZhijun.Fu@Sun.COM #define	BUS_INSERT(prev, el) \
25511245SZhijun.Fu@Sun.COM 	el->next = *prev; \
25611245SZhijun.Fu@Sun.COM 	*prev = el;
25711245SZhijun.Fu@Sun.COM 
25811245SZhijun.Fu@Sun.COM #define	BUS_REMOVE(prev, el) \
25911245SZhijun.Fu@Sun.COM 	*prev = el->next;
26011245SZhijun.Fu@Sun.COM 
26111245SZhijun.Fu@Sun.COM /*
26211245SZhijun.Fu@Sun.COM  * This function is only supposed to be called in device tree setup time,
26311245SZhijun.Fu@Sun.COM  * thus no lock is needed.
26411245SZhijun.Fu@Sun.COM  */
26511245SZhijun.Fu@Sun.COM void
pci_cfgacc_add_workaround(uint16_t bdf,uchar_t secbus,uchar_t subbus)26611245SZhijun.Fu@Sun.COM pci_cfgacc_add_workaround(uint16_t bdf, uchar_t secbus, uchar_t subbus)
26711245SZhijun.Fu@Sun.COM {
26811245SZhijun.Fu@Sun.COM 	cfgacc_bus_range_t	*entry;
26911245SZhijun.Fu@Sun.COM 
27011245SZhijun.Fu@Sun.COM 	entry = kmem_zalloc(sizeof (cfgacc_bus_range_t), KM_SLEEP);
27111245SZhijun.Fu@Sun.COM 	entry->bdf = bdf;
27211245SZhijun.Fu@Sun.COM 	entry->secbus = secbus;
27311245SZhijun.Fu@Sun.COM 	entry->subbus = subbus;
27411245SZhijun.Fu@Sun.COM 	BUS_INSERT(&pci_cfgacc_bus_head, entry);
27511245SZhijun.Fu@Sun.COM }
27611245SZhijun.Fu@Sun.COM 
27711245SZhijun.Fu@Sun.COM boolean_t
pci_cfgacc_find_workaround(uint16_t bdf)27811245SZhijun.Fu@Sun.COM pci_cfgacc_find_workaround(uint16_t bdf)
27911245SZhijun.Fu@Sun.COM {
28011245SZhijun.Fu@Sun.COM 	cfgacc_bus_range_t	*entry;
28111245SZhijun.Fu@Sun.COM 	uchar_t			bus;
28211245SZhijun.Fu@Sun.COM 
28311245SZhijun.Fu@Sun.COM 	for (entry = pci_cfgacc_bus_head; entry != NULL;
28411245SZhijun.Fu@Sun.COM 	    entry = entry->next) {
28511245SZhijun.Fu@Sun.COM 		if (bdf == entry->bdf) {
28611245SZhijun.Fu@Sun.COM 			/* found a device which is known to be broken */
28711245SZhijun.Fu@Sun.COM 			return (B_TRUE);
28811245SZhijun.Fu@Sun.COM 		}
28911245SZhijun.Fu@Sun.COM 
29011245SZhijun.Fu@Sun.COM 		bus = PCI_BDF_BUS(bdf);
29111245SZhijun.Fu@Sun.COM 		if ((bus != 0) && (bus >= entry->secbus) &&
29211245SZhijun.Fu@Sun.COM 		    (bus <= entry->subbus)) {
29311245SZhijun.Fu@Sun.COM 			/*
29411245SZhijun.Fu@Sun.COM 			 * found a device whose parent/grandparent is
29511245SZhijun.Fu@Sun.COM 			 * known to be broken.
29611245SZhijun.Fu@Sun.COM 			 */
29711245SZhijun.Fu@Sun.COM 			return (B_TRUE);
29811245SZhijun.Fu@Sun.COM 		}
29911245SZhijun.Fu@Sun.COM 	}
30011245SZhijun.Fu@Sun.COM 
30111245SZhijun.Fu@Sun.COM 	return (B_FALSE);
30211245SZhijun.Fu@Sun.COM }
303