xref: /illumos-gate/usr/src/uts/sun4/io/efcode/fc_subr.c (revision 6d22b733)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23*6d22b733Sdhain  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*6d22b733Sdhain  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * Kernel framework functions for the fcode interpreter
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/conf.h>
357c478bd9Sstevel@tonic-gate #include <sys/debug.h>
367c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
377c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
387c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
397c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
407c478bd9Sstevel@tonic-gate #include <sys/esunddi.h>
417c478bd9Sstevel@tonic-gate #include <sys/ksynch.h>
427c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
437c478bd9Sstevel@tonic-gate #include <sys/errno.h>
447c478bd9Sstevel@tonic-gate #include <sys/fcode.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #ifdef	DEBUG
477c478bd9Sstevel@tonic-gate int fcode_debug = 0;
487c478bd9Sstevel@tonic-gate #else
497c478bd9Sstevel@tonic-gate int fcode_debug = 0;
507c478bd9Sstevel@tonic-gate #endif
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate static kmutex_t fc_request_lock;
537c478bd9Sstevel@tonic-gate static kmutex_t fc_resource_lock;
547c478bd9Sstevel@tonic-gate static kmutex_t fc_hash_lock;
557c478bd9Sstevel@tonic-gate static kmutex_t fc_device_tree_lock;
567c478bd9Sstevel@tonic-gate static kmutex_t fc_phandle_lock;
577c478bd9Sstevel@tonic-gate static kcondvar_t fc_request_cv;
587c478bd9Sstevel@tonic-gate static struct fc_request *fc_request_head;
597c478bd9Sstevel@tonic-gate static int fc_initialized;
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate static void fcode_timer(void *);
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate int fcode_timeout = 300;	/* seconds */
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate int fcodem_unloadable;
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate extern int hz;
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate  * Initialize the fcode interpreter framework ... must be called
717c478bd9Sstevel@tonic-gate  * prior to activating any of the fcode interpreter framework including
727c478bd9Sstevel@tonic-gate  * the driver.
737c478bd9Sstevel@tonic-gate  */
747c478bd9Sstevel@tonic-gate static void
fcode_init(void)757c478bd9Sstevel@tonic-gate fcode_init(void)
767c478bd9Sstevel@tonic-gate {
777c478bd9Sstevel@tonic-gate 	if (fc_initialized)
787c478bd9Sstevel@tonic-gate 		return;
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	mutex_init(&fc_request_lock, NULL, MUTEX_DRIVER, NULL);
817c478bd9Sstevel@tonic-gate 	mutex_init(&fc_resource_lock, NULL, MUTEX_DRIVER, NULL);
827c478bd9Sstevel@tonic-gate 	mutex_init(&fc_hash_lock, NULL, MUTEX_DRIVER, NULL);
837c478bd9Sstevel@tonic-gate 	mutex_init(&fc_device_tree_lock, NULL, MUTEX_DRIVER, NULL);
847c478bd9Sstevel@tonic-gate 	mutex_init(&fc_phandle_lock, NULL, MUTEX_DRIVER, NULL);
857c478bd9Sstevel@tonic-gate 	cv_init(&fc_request_cv, NULL, CV_DRIVER, NULL);
867c478bd9Sstevel@tonic-gate 	++fc_initialized;
877c478bd9Sstevel@tonic-gate }
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate static void
fcode_fini(void)907c478bd9Sstevel@tonic-gate fcode_fini(void)
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate 	mutex_destroy(&fc_request_lock);
937c478bd9Sstevel@tonic-gate 	mutex_destroy(&fc_resource_lock);
947c478bd9Sstevel@tonic-gate 	mutex_destroy(&fc_hash_lock);
957c478bd9Sstevel@tonic-gate 	cv_destroy(&fc_request_cv);
967c478bd9Sstevel@tonic-gate 	fc_initialized = 0;
977c478bd9Sstevel@tonic-gate }
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate /*
1007c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
1017c478bd9Sstevel@tonic-gate  */
1027c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = {
1037c478bd9Sstevel@tonic-gate 	&mod_miscops, "FCode framework 1.13"
1047c478bd9Sstevel@tonic-gate };
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1077c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modlmisc, NULL
1087c478bd9Sstevel@tonic-gate };
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate int
_init(void)1117c478bd9Sstevel@tonic-gate _init(void)
1127c478bd9Sstevel@tonic-gate {
1137c478bd9Sstevel@tonic-gate 	int error;
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	fcode_init();
1167c478bd9Sstevel@tonic-gate 	if ((error = mod_install(&modlinkage)) != 0)
1177c478bd9Sstevel@tonic-gate 		fcode_fini();
1187c478bd9Sstevel@tonic-gate 	return (error);
1197c478bd9Sstevel@tonic-gate }
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate int
_fini(void)1227c478bd9Sstevel@tonic-gate _fini(void)
1237c478bd9Sstevel@tonic-gate {
1247c478bd9Sstevel@tonic-gate 	int error = EBUSY;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	if (fcodem_unloadable)
1277c478bd9Sstevel@tonic-gate 		if ((error = mod_remove(&modlinkage)) == 0)
1287c478bd9Sstevel@tonic-gate 			fcode_fini();
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	return (error);
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1347c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1377c478bd9Sstevel@tonic-gate }
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate /*
1407c478bd9Sstevel@tonic-gate  * Framework function to invoke the interpreter. Wait and return when the
1417c478bd9Sstevel@tonic-gate  * interpreter is done. See fcode.h for details.
1427c478bd9Sstevel@tonic-gate  */
1437c478bd9Sstevel@tonic-gate int
fcode_interpreter(dev_info_t * ap,fc_ops_t * ops,fco_handle_t handle)1447c478bd9Sstevel@tonic-gate fcode_interpreter(dev_info_t *ap, fc_ops_t *ops, fco_handle_t handle)
1457c478bd9Sstevel@tonic-gate {
1467c478bd9Sstevel@tonic-gate 	struct fc_request *fp, *qp;
1477c478bd9Sstevel@tonic-gate 	int error;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	ASSERT(fc_initialized);
1507c478bd9Sstevel@tonic-gate 	ASSERT(ap);
1517c478bd9Sstevel@tonic-gate 	ASSERT(ops);
1527c478bd9Sstevel@tonic-gate 	ASSERT(handle);
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	/*
1557c478bd9Sstevel@tonic-gate 	 * Create a request structure
1567c478bd9Sstevel@tonic-gate 	 */
1577c478bd9Sstevel@tonic-gate 	fp = kmem_zalloc(sizeof (struct fc_request), KM_SLEEP);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	fp->next = NULL;
1607c478bd9Sstevel@tonic-gate 	fp->busy = FC_R_INIT;
1617c478bd9Sstevel@tonic-gate 	fp->error = FC_SUCCESS;
1627c478bd9Sstevel@tonic-gate 	fp->ap_dip = ap;
1637c478bd9Sstevel@tonic-gate 	fp->ap_ops = ops;
1647c478bd9Sstevel@tonic-gate 	fp->handle = handle;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	/*
1677c478bd9Sstevel@tonic-gate 	 * Add the request to the end of the request list.
1687c478bd9Sstevel@tonic-gate 	 */
1697c478bd9Sstevel@tonic-gate 	mutex_enter(&fc_request_lock);
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	if (fc_request_head == NULL)
1727c478bd9Sstevel@tonic-gate 		fc_request_head = fp;
1737c478bd9Sstevel@tonic-gate 	else {
1747c478bd9Sstevel@tonic-gate 		for (qp = fc_request_head; qp->next != NULL; qp = qp->next)
1757c478bd9Sstevel@tonic-gate 			/* empty */;
1767c478bd9Sstevel@tonic-gate 		qp->next = fp;
1777c478bd9Sstevel@tonic-gate 	}
1787c478bd9Sstevel@tonic-gate 	mutex_exit(&fc_request_lock);
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	/*
1817c478bd9Sstevel@tonic-gate 	 * log a message (ie: i_ddi_log_event) indicating that a request
1827c478bd9Sstevel@tonic-gate 	 * has been queued to start the userland fcode interpreter.
1837c478bd9Sstevel@tonic-gate 	 * This call is the glue to the eventd and automates the process.
1847c478bd9Sstevel@tonic-gate 	 */
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	/*
1877c478bd9Sstevel@tonic-gate 	 * Signal the driver if it's waiting for a request to be queued.
1887c478bd9Sstevel@tonic-gate 	 */
1897c478bd9Sstevel@tonic-gate 	cv_broadcast(&fc_request_cv);
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	/*
1927c478bd9Sstevel@tonic-gate 	 * Wait for the request to be serviced
1937c478bd9Sstevel@tonic-gate 	 */
1947c478bd9Sstevel@tonic-gate 	mutex_enter(&fc_request_lock);
1957c478bd9Sstevel@tonic-gate 	fp->timeout = timeout(fcode_timer, fp, hz * fcode_timeout);
1967c478bd9Sstevel@tonic-gate 	while (fp->busy != FC_R_DONE)
1977c478bd9Sstevel@tonic-gate 		cv_wait(&fc_request_cv, &fc_request_lock);
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	if (fp->timeout) {
2007c478bd9Sstevel@tonic-gate 		(void) untimeout(fp->timeout);
2017c478bd9Sstevel@tonic-gate 		fp->timeout = NULL;
2027c478bd9Sstevel@tonic-gate 	}
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	/*
2057c478bd9Sstevel@tonic-gate 	 * Remove the request from the queue (while still holding the lock)
2067c478bd9Sstevel@tonic-gate 	 */
2077c478bd9Sstevel@tonic-gate 	if (fc_request_head == fp)
2087c478bd9Sstevel@tonic-gate 		fc_request_head = fp->next;
2097c478bd9Sstevel@tonic-gate 	else {
2107c478bd9Sstevel@tonic-gate 		for (qp = fc_request_head; qp->next != fp; qp = qp->next)
2117c478bd9Sstevel@tonic-gate 			/* empty */;
2127c478bd9Sstevel@tonic-gate 		qp->next = fp->next;
2137c478bd9Sstevel@tonic-gate 	}
2147c478bd9Sstevel@tonic-gate 	mutex_exit(&fc_request_lock);
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	FC_DEBUG1(2, CE_CONT, "fcode_interpreter: request finished, fp %p\n",
2177c478bd9Sstevel@tonic-gate 	    fp);
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	/*
2207c478bd9Sstevel@tonic-gate 	 * Free the request structure and return any errors.
2217c478bd9Sstevel@tonic-gate 	 */
2227c478bd9Sstevel@tonic-gate 	error = fp->error;
2237c478bd9Sstevel@tonic-gate 	kmem_free(fp, sizeof (struct fc_request));
2247c478bd9Sstevel@tonic-gate 	return (error);
2257c478bd9Sstevel@tonic-gate }
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate /*
2287c478bd9Sstevel@tonic-gate  * Timeout requests thet don't get picked up by the interpreter.  This
2297c478bd9Sstevel@tonic-gate  * would happen if the daemon is not running.  If the timer goes off
2307c478bd9Sstevel@tonic-gate  * and it's state is not FC_R_INIT, then the interpreter has picked up the
2317c478bd9Sstevel@tonic-gate  * request.
2327c478bd9Sstevel@tonic-gate  */
2337c478bd9Sstevel@tonic-gate static void
fcode_timer(void * arg)2347c478bd9Sstevel@tonic-gate fcode_timer(void *arg)
2357c478bd9Sstevel@tonic-gate {
2367c478bd9Sstevel@tonic-gate 	struct fc_request *fp = arg;
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	mutex_enter(&fc_request_lock);
2397c478bd9Sstevel@tonic-gate 	fp->timeout = 0;
2407c478bd9Sstevel@tonic-gate 	if (fp->busy == FC_R_INIT) {
2417c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "fcode_timer: Timeout waiting for "
2427c478bd9Sstevel@tonic-gate 		    "interpreter - Interpreter did not pick up request\n");
2437c478bd9Sstevel@tonic-gate 		fp->busy = FC_R_DONE;
2447c478bd9Sstevel@tonic-gate 		fp->error = FC_TIMEOUT;
2457c478bd9Sstevel@tonic-gate 		mutex_exit(&fc_request_lock);
2467c478bd9Sstevel@tonic-gate 		cv_broadcast(&fc_request_cv);
2477c478bd9Sstevel@tonic-gate 		return;
248*6d22b733Sdhain 	} else if (fp->error != FC_SUCCESS) {
249*6d22b733Sdhain 		/*
250*6d22b733Sdhain 		 * An error was detected, but didn't close the driver.
251*6d22b733Sdhain 		 * This will allow the process to error out, returning
252*6d22b733Sdhain 		 * the interpreter error code instead of FC_TIMEOUT.
253*6d22b733Sdhain 		 */
254*6d22b733Sdhain 		fp->busy = FC_R_DONE;
255*6d22b733Sdhain 		cv_broadcast(&fc_request_cv);
256*6d22b733Sdhain 		mutex_exit(&fc_request_lock);
257*6d22b733Sdhain 		return;
2587c478bd9Sstevel@tonic-gate 	} else {
2597c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "fcode_timer: Timeout waiting for "
2607c478bd9Sstevel@tonic-gate 		    "interpreter - Interpreter is executing request\n");
2617c478bd9Sstevel@tonic-gate 	}
2627c478bd9Sstevel@tonic-gate 	mutex_exit(&fc_request_lock);
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate /*
2667c478bd9Sstevel@tonic-gate  * This is the function the driver calls to wait for and get
2677c478bd9Sstevel@tonic-gate  * a request.  The call should be interruptable since it's done
2687c478bd9Sstevel@tonic-gate  * at read(2) time, so allow for signals to interrupt us.
2697c478bd9Sstevel@tonic-gate  *
2707c478bd9Sstevel@tonic-gate  * Return NULL if the wait was interrupted, else return a pointer
2717c478bd9Sstevel@tonic-gate  * to the fc_request structure (marked as busy).
2727c478bd9Sstevel@tonic-gate  *
2737c478bd9Sstevel@tonic-gate  * Note that we have to check for a request first, before waiting,
2747c478bd9Sstevel@tonic-gate  * in case the request is already queued. In this case, the signal
2757c478bd9Sstevel@tonic-gate  * may have already been delivered.
2767c478bd9Sstevel@tonic-gate  */
2777c478bd9Sstevel@tonic-gate struct fc_request *
fc_get_request(void)2787c478bd9Sstevel@tonic-gate fc_get_request(void)
2797c478bd9Sstevel@tonic-gate {
2807c478bd9Sstevel@tonic-gate 	struct fc_request *fp;
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	ASSERT(fc_initialized);
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	mutex_enter(&fc_request_lock);
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	/*CONSTANTCONDITION*/
2877c478bd9Sstevel@tonic-gate 	while (1) {
2887c478bd9Sstevel@tonic-gate 		for (fp = fc_request_head; fp != NULL; fp = fp->next) {
2897c478bd9Sstevel@tonic-gate 			if (fp->busy == FC_R_INIT) {
2907c478bd9Sstevel@tonic-gate 				fp->busy = FC_R_BUSY;
2917c478bd9Sstevel@tonic-gate 				mutex_exit(&fc_request_lock);
2927c478bd9Sstevel@tonic-gate 				return (fp);
2937c478bd9Sstevel@tonic-gate 			}
2947c478bd9Sstevel@tonic-gate 		}
2957c478bd9Sstevel@tonic-gate 		if (cv_wait_sig(&fc_request_cv, &fc_request_lock) == 0) {
2967c478bd9Sstevel@tonic-gate 			mutex_exit(&fc_request_lock);
2977c478bd9Sstevel@tonic-gate 			return (NULL);
2987c478bd9Sstevel@tonic-gate 		}
2997c478bd9Sstevel@tonic-gate 	}
3007c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
3017c478bd9Sstevel@tonic-gate }
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate /*
3047c478bd9Sstevel@tonic-gate  * This is the function the driver calls when it's finished with
3057c478bd9Sstevel@tonic-gate  * a request.  Mark the request as done and signal the thread that
3067c478bd9Sstevel@tonic-gate  * enqueued the request.
3077c478bd9Sstevel@tonic-gate  */
3087c478bd9Sstevel@tonic-gate void
fc_finish_request(struct fc_request * fp)3097c478bd9Sstevel@tonic-gate fc_finish_request(struct fc_request *fp)
3107c478bd9Sstevel@tonic-gate {
3117c478bd9Sstevel@tonic-gate 	ASSERT(fc_initialized);
3127c478bd9Sstevel@tonic-gate 	ASSERT(fp);
3137c478bd9Sstevel@tonic-gate 	ASSERT(fp->busy == FC_R_BUSY);
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	mutex_enter(&fc_request_lock);
3167c478bd9Sstevel@tonic-gate 	fp->busy = FC_R_DONE;
3177c478bd9Sstevel@tonic-gate 	mutex_exit(&fc_request_lock);
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	cv_broadcast(&fc_request_cv);
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate /*
3237c478bd9Sstevel@tonic-gate  * Generic resource list management subroutines
3247c478bd9Sstevel@tonic-gate  */
3257c478bd9Sstevel@tonic-gate void
fc_add_resource(fco_handle_t rp,struct fc_resource * ip)3267c478bd9Sstevel@tonic-gate fc_add_resource(fco_handle_t rp, struct fc_resource *ip)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate 	ASSERT(rp);
3297c478bd9Sstevel@tonic-gate 	ASSERT(ip);
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	mutex_enter(&fc_resource_lock);
3327c478bd9Sstevel@tonic-gate 	ip->next = NULL;
3337c478bd9Sstevel@tonic-gate 	if (rp->head != NULL)
3347c478bd9Sstevel@tonic-gate 		ip->next = rp->head;
3357c478bd9Sstevel@tonic-gate 	rp->head = ip;
3367c478bd9Sstevel@tonic-gate 	mutex_exit(&fc_resource_lock);
3377c478bd9Sstevel@tonic-gate }
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate void
fc_rem_resource(fco_handle_t rp,struct fc_resource * ip)3407c478bd9Sstevel@tonic-gate fc_rem_resource(fco_handle_t rp, struct fc_resource *ip)
3417c478bd9Sstevel@tonic-gate {
3427c478bd9Sstevel@tonic-gate 	struct fc_resource *fp;
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	ASSERT(rp);
3457c478bd9Sstevel@tonic-gate 	ASSERT(ip);
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	if (rp->head == NULL)  {
3487c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "fc_rem_resource: NULL list head!\n");
3497c478bd9Sstevel@tonic-gate 		return;
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	mutex_enter(&fc_resource_lock);
3537c478bd9Sstevel@tonic-gate 	if (rp->head == ip) {
3547c478bd9Sstevel@tonic-gate 		rp->head = ip->next;
3557c478bd9Sstevel@tonic-gate 		mutex_exit(&fc_resource_lock);
3567c478bd9Sstevel@tonic-gate 		return;
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	for (fp = rp->head; fp && (fp->next != ip); fp = fp->next)
3607c478bd9Sstevel@tonic-gate 		/* empty */;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	if (fp == NULL)  {
3637c478bd9Sstevel@tonic-gate 		mutex_exit(&fc_resource_lock);
3647c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "fc_rem_resource: Item not on list!\n");
3657c478bd9Sstevel@tonic-gate 		return;
3667c478bd9Sstevel@tonic-gate 	}
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	fp->next = ip->next;
3697c478bd9Sstevel@tonic-gate 	mutex_exit(&fc_resource_lock);
3707c478bd9Sstevel@tonic-gate }
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3737c478bd9Sstevel@tonic-gate void
fc_lock_resource_list(fco_handle_t rp)3747c478bd9Sstevel@tonic-gate fc_lock_resource_list(fco_handle_t rp)
3757c478bd9Sstevel@tonic-gate {
3767c478bd9Sstevel@tonic-gate 	mutex_enter(&fc_resource_lock);
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3807c478bd9Sstevel@tonic-gate void
fc_unlock_resource_list(fco_handle_t rp)3817c478bd9Sstevel@tonic-gate fc_unlock_resource_list(fco_handle_t rp)
3827c478bd9Sstevel@tonic-gate {
3837c478bd9Sstevel@tonic-gate 	mutex_exit(&fc_resource_lock);
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate /*
3877c478bd9Sstevel@tonic-gate  * Common helper ops and subroutines
3887c478bd9Sstevel@tonic-gate  */
3897c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3907c478bd9Sstevel@tonic-gate int
fc_syntax_error(fc_ci_t * cp,char * msg)3917c478bd9Sstevel@tonic-gate fc_syntax_error(fc_ci_t *cp, char *msg)
3927c478bd9Sstevel@tonic-gate {
3937c478bd9Sstevel@tonic-gate 	cp->error = fc_int2cell(-1);
3947c478bd9Sstevel@tonic-gate 	cp->nresults = fc_int2cell(0);
3957c478bd9Sstevel@tonic-gate 	return (0);
3967c478bd9Sstevel@tonic-gate }
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3997c478bd9Sstevel@tonic-gate int
fc_priv_error(fc_ci_t * cp,char * msg)4007c478bd9Sstevel@tonic-gate fc_priv_error(fc_ci_t *cp, char *msg)
4017c478bd9Sstevel@tonic-gate {
4027c478bd9Sstevel@tonic-gate 	cp->priv_error = fc_int2cell(-1);
4037c478bd9Sstevel@tonic-gate 	cp->error = fc_int2cell(0);
4047c478bd9Sstevel@tonic-gate 	cp->nresults = fc_int2cell(0);
4057c478bd9Sstevel@tonic-gate 	return (0);
4067c478bd9Sstevel@tonic-gate }
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4097c478bd9Sstevel@tonic-gate int
fc_success_op(dev_info_t * ap,fco_handle_t handle,fc_ci_t * cp)4107c478bd9Sstevel@tonic-gate fc_success_op(dev_info_t *ap, fco_handle_t handle, fc_ci_t *cp)
4117c478bd9Sstevel@tonic-gate {
4127c478bd9Sstevel@tonic-gate 	cp->priv_error = cp->error = fc_int2cell(0);
4137c478bd9Sstevel@tonic-gate 	return (0);
4147c478bd9Sstevel@tonic-gate }
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate /*
4177c478bd9Sstevel@tonic-gate  * fc_fail_op: This 'handles' a request by specifically failing it,
4187c478bd9Sstevel@tonic-gate  * as opposed to not handling it and returning '-1' to indicate
4197c478bd9Sstevel@tonic-gate  * 'service unknown' and allowing somebody else in the chain to
4207c478bd9Sstevel@tonic-gate  * handle it.
4217c478bd9Sstevel@tonic-gate  */
4227c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4237c478bd9Sstevel@tonic-gate int
fc_fail_op(dev_info_t * ap,fco_handle_t handle,fc_ci_t * cp)4247c478bd9Sstevel@tonic-gate fc_fail_op(dev_info_t *ap, fco_handle_t handle, fc_ci_t *cp)
4257c478bd9Sstevel@tonic-gate {
4267c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "fcode ops: fail service name <%s>\n",
4277c478bd9Sstevel@tonic-gate 	    (char *)fc_cell2ptr(cp->svc_name));
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	cp->nresults = fc_int2cell(0);
4307c478bd9Sstevel@tonic-gate 	cp->error = fc_int2cell(-1);
4317c478bd9Sstevel@tonic-gate 	return (0);
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate /*
4357c478bd9Sstevel@tonic-gate  * Functions to manage the set of handles we give to the interpreter.
4367c478bd9Sstevel@tonic-gate  * The handles are opaque and internally represent dev_info_t pointers.
4377c478bd9Sstevel@tonic-gate  */
4387c478bd9Sstevel@tonic-gate struct fc_phandle_entry **
fc_handle_to_phandle_head(fco_handle_t rp)4397c478bd9Sstevel@tonic-gate fc_handle_to_phandle_head(fco_handle_t rp)
4407c478bd9Sstevel@tonic-gate {
4417c478bd9Sstevel@tonic-gate 	while (rp->next_handle)
4427c478bd9Sstevel@tonic-gate 		rp = rp->next_handle;
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	return (&rp->ptable);
4457c478bd9Sstevel@tonic-gate }
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4487c478bd9Sstevel@tonic-gate void
fc_phandle_table_alloc(struct fc_phandle_entry ** head)4497c478bd9Sstevel@tonic-gate fc_phandle_table_alloc(struct fc_phandle_entry **head)
4507c478bd9Sstevel@tonic-gate {
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate void
fc_phandle_table_free(struct fc_phandle_entry ** head)4547c478bd9Sstevel@tonic-gate fc_phandle_table_free(struct fc_phandle_entry **head)
4557c478bd9Sstevel@tonic-gate {
4567c478bd9Sstevel@tonic-gate 	struct fc_phandle_entry *ip, *np;
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	/*
4597c478bd9Sstevel@tonic-gate 	 * Free each entry in the table.
4607c478bd9Sstevel@tonic-gate 	 */
4617c478bd9Sstevel@tonic-gate 	for (ip = *head; ip; ip = np) {
4627c478bd9Sstevel@tonic-gate 		np = ip->next;
4637c478bd9Sstevel@tonic-gate 		kmem_free(ip, sizeof (struct fc_phandle_entry));
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate 	*head = NULL;
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate dev_info_t *
fc_phandle_to_dip(struct fc_phandle_entry ** head,fc_phandle_t handle)4697c478bd9Sstevel@tonic-gate fc_phandle_to_dip(struct fc_phandle_entry **head, fc_phandle_t handle)
4707c478bd9Sstevel@tonic-gate {
4717c478bd9Sstevel@tonic-gate 	struct fc_phandle_entry *ip;
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	mutex_enter(&fc_hash_lock);
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	for (ip = *head; ip; ip = ip->next)
4767c478bd9Sstevel@tonic-gate 		if (ip->h == handle)
4777c478bd9Sstevel@tonic-gate 			break;
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	mutex_exit(&fc_hash_lock);
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	return (ip ? ip->dip : NULL);
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate fc_phandle_t
fc_dip_to_phandle(struct fc_phandle_entry ** head,dev_info_t * dip)4857c478bd9Sstevel@tonic-gate fc_dip_to_phandle(struct fc_phandle_entry **head, dev_info_t *dip)
4867c478bd9Sstevel@tonic-gate {
4877c478bd9Sstevel@tonic-gate 	struct fc_phandle_entry *hp, *np;
4887c478bd9Sstevel@tonic-gate 	fc_phandle_t h;
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	ASSERT(dip);
4917c478bd9Sstevel@tonic-gate 	h = (fc_phandle_t)ddi_get_nodeid(dip);
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	/*
4947c478bd9Sstevel@tonic-gate 	 * Just in case, allocate a new entry ...
4957c478bd9Sstevel@tonic-gate 	 */
4967c478bd9Sstevel@tonic-gate 	np = kmem_zalloc(sizeof (struct fc_phandle_entry), KM_SLEEP);
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	mutex_enter(&fc_hash_lock);
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	/*
5017c478bd9Sstevel@tonic-gate 	 * If we already have this dip in the table, just return the handle
5027c478bd9Sstevel@tonic-gate 	 */
5037c478bd9Sstevel@tonic-gate 	for (hp = *head; hp; hp = hp->next) {
5047c478bd9Sstevel@tonic-gate 		if (hp->dip == dip) {
5057c478bd9Sstevel@tonic-gate 			mutex_exit(&fc_hash_lock);
5067c478bd9Sstevel@tonic-gate 			kmem_free(np, sizeof (struct fc_phandle_entry));
5077c478bd9Sstevel@tonic-gate 			return (h);
5087c478bd9Sstevel@tonic-gate 		}
5097c478bd9Sstevel@tonic-gate 	}
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	/*
5127c478bd9Sstevel@tonic-gate 	 * Insert this entry to the list of known entries
5137c478bd9Sstevel@tonic-gate 	 */
5147c478bd9Sstevel@tonic-gate 	np->next = *head;
5157c478bd9Sstevel@tonic-gate 	np->dip = dip;
5167c478bd9Sstevel@tonic-gate 	np->h = h;
5177c478bd9Sstevel@tonic-gate 	*head = np;
5187c478bd9Sstevel@tonic-gate 	mutex_exit(&fc_hash_lock);
5197c478bd9Sstevel@tonic-gate 	return (h);
5207c478bd9Sstevel@tonic-gate }
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate /*
5237c478bd9Sstevel@tonic-gate  * We won't need this function once the ddi is modified to handle
5247c478bd9Sstevel@tonic-gate  * unique non-prom nodeids.  For now, this allows us to add a given
5257c478bd9Sstevel@tonic-gate  * nodeid to the device tree without dereferencing the value in the
5267c478bd9Sstevel@tonic-gate  * devinfo node, so we have a parallel mechanism.
5277c478bd9Sstevel@tonic-gate  */
5287c478bd9Sstevel@tonic-gate void
fc_add_dip_to_phandle(struct fc_phandle_entry ** head,dev_info_t * dip,fc_phandle_t h)5297c478bd9Sstevel@tonic-gate fc_add_dip_to_phandle(struct fc_phandle_entry **head, dev_info_t *dip,
5307c478bd9Sstevel@tonic-gate     fc_phandle_t h)
5317c478bd9Sstevel@tonic-gate {
5327c478bd9Sstevel@tonic-gate 	struct fc_phandle_entry *hp, *np;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	ASSERT(dip);
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	/*
5377c478bd9Sstevel@tonic-gate 	 * Just in case, allocate a new entry ...
5387c478bd9Sstevel@tonic-gate 	 */
5397c478bd9Sstevel@tonic-gate 	np = kmem_zalloc(sizeof (struct fc_phandle_entry), KM_SLEEP);
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	mutex_enter(&fc_hash_lock);
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	/*
5447c478bd9Sstevel@tonic-gate 	 * If we already have this dip in the table, just return the handle
5457c478bd9Sstevel@tonic-gate 	 */
5467c478bd9Sstevel@tonic-gate 	for (hp = *head; hp; hp = hp->next) {
5477c478bd9Sstevel@tonic-gate 		if (hp->dip == dip) {
5487c478bd9Sstevel@tonic-gate 			mutex_exit(&fc_hash_lock);
5497c478bd9Sstevel@tonic-gate 			kmem_free(np, sizeof (struct fc_phandle_entry));
5507c478bd9Sstevel@tonic-gate 			return;
5517c478bd9Sstevel@tonic-gate 		}
5527c478bd9Sstevel@tonic-gate 	}
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	/*
5557c478bd9Sstevel@tonic-gate 	 * Insert this entry to the list of known entries
5567c478bd9Sstevel@tonic-gate 	 */
5577c478bd9Sstevel@tonic-gate 	np->next = *head;
5587c478bd9Sstevel@tonic-gate 	np->dip = dip;
5597c478bd9Sstevel@tonic-gate 	np->h = h;
5607c478bd9Sstevel@tonic-gate 	*head = np;
5617c478bd9Sstevel@tonic-gate 	mutex_exit(&fc_hash_lock);
5627c478bd9Sstevel@tonic-gate }
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate /*
5657c478bd9Sstevel@tonic-gate  * Functions to manage our copy of our subtree.
5667c478bd9Sstevel@tonic-gate  *
5677c478bd9Sstevel@tonic-gate  * The head of the device tree is always stored in the last 'handle'
5687c478bd9Sstevel@tonic-gate  * in the handle chain.
5697c478bd9Sstevel@tonic-gate  */
5707c478bd9Sstevel@tonic-gate struct fc_device_tree **
fc_handle_to_dtree_head(fco_handle_t rp)5717c478bd9Sstevel@tonic-gate fc_handle_to_dtree_head(fco_handle_t rp)
5727c478bd9Sstevel@tonic-gate {
5737c478bd9Sstevel@tonic-gate 	while (rp->next_handle)
5747c478bd9Sstevel@tonic-gate 		rp = rp->next_handle;
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	return (&rp->dtree);
5777c478bd9Sstevel@tonic-gate }
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate struct fc_device_tree *
fc_handle_to_dtree(fco_handle_t rp)5807c478bd9Sstevel@tonic-gate fc_handle_to_dtree(fco_handle_t rp)
5817c478bd9Sstevel@tonic-gate {
5827c478bd9Sstevel@tonic-gate 	struct fc_device_tree **head = fc_handle_to_dtree_head(rp);
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	return (*head);
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate /*
5887c478bd9Sstevel@tonic-gate  * The root of the subtree is the attachment point ...
5897c478bd9Sstevel@tonic-gate  * Thus, there is never an empty device tree.
5907c478bd9Sstevel@tonic-gate  */
5917c478bd9Sstevel@tonic-gate void
fc_create_device_tree(dev_info_t * ap,struct fc_device_tree ** head)5927c478bd9Sstevel@tonic-gate fc_create_device_tree(dev_info_t *ap, struct fc_device_tree **head)
5937c478bd9Sstevel@tonic-gate {
5947c478bd9Sstevel@tonic-gate 	struct fc_device_tree *dp;
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 	dp = kmem_zalloc(sizeof (struct fc_device_tree), KM_SLEEP);
5977c478bd9Sstevel@tonic-gate 	dp->dip = ap;
5987c478bd9Sstevel@tonic-gate 	*head = dp;
5997c478bd9Sstevel@tonic-gate }
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate #ifdef	notdef
6027c478bd9Sstevel@tonic-gate static void
fc_remove_subtree(struct fc_device_tree * dp)6037c478bd9Sstevel@tonic-gate fc_remove_subtree(struct fc_device_tree *dp)
6047c478bd9Sstevel@tonic-gate {
6057c478bd9Sstevel@tonic-gate 	struct fc_device_tree *np;
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	if (dp->child) {
6087c478bd9Sstevel@tonic-gate 		fc_remove_subtree(dp->child);
6097c478bd9Sstevel@tonic-gate 		dp->child = NULL;
6107c478bd9Sstevel@tonic-gate 	}
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	/*
6137c478bd9Sstevel@tonic-gate 	 * Remove each peer node, working our way backwards from the
6147c478bd9Sstevel@tonic-gate 	 * last peer node to the first peer node.
6157c478bd9Sstevel@tonic-gate 	 */
6167c478bd9Sstevel@tonic-gate 	if (dp->peer != NULL) {
6177c478bd9Sstevel@tonic-gate 		for (np = dp->peer; np->peer; np = dp->peer) {
6187c478bd9Sstevel@tonic-gate 			for (/* empty */; np->peer; np = np->peer)
6197c478bd9Sstevel@tonic-gate 				/* empty */;
6207c478bd9Sstevel@tonic-gate 			fc_remove_subtree(np->peer);
6217c478bd9Sstevel@tonic-gate 			np->peer = NULL;
6227c478bd9Sstevel@tonic-gate 		}
6237c478bd9Sstevel@tonic-gate 		fc_remove_subtree(dp->peer)
6247c478bd9Sstevel@tonic-gate 		dp->peer = NULL;
6257c478bd9Sstevel@tonic-gate 	}
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	ASSERT((dp->child == NULL) && (dp->peer == NULL));
6287c478bd9Sstevel@tonic-gate 	kmem_free(dp, sizeof (struct fc_device_tree));
6297c478bd9Sstevel@tonic-gate }
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate void
fc_remove_device_tree(struct fc_device_tree ** head)6327c478bd9Sstevel@tonic-gate fc_remove_device_tree(struct fc_device_tree **head)
6337c478bd9Sstevel@tonic-gate {
6347c478bd9Sstevel@tonic-gate 	ASSERT(head && (*head != NULL));
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	fc_remove_subtree(*head);
6377c478bd9Sstevel@tonic-gate 	*head = NULL;
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate #endif	/* notdef */
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate void
fc_remove_device_tree(struct fc_device_tree ** head)6427c478bd9Sstevel@tonic-gate fc_remove_device_tree(struct fc_device_tree **head)
6437c478bd9Sstevel@tonic-gate {
6447c478bd9Sstevel@tonic-gate 	struct fc_device_tree *dp;
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	ASSERT(head && (*head != NULL));
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	dp = *head;
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	if (dp->child)
6517c478bd9Sstevel@tonic-gate 		fc_remove_device_tree(&dp->child);
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	if (dp->peer)
6547c478bd9Sstevel@tonic-gate 		fc_remove_device_tree(&dp->peer);
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	ASSERT((dp->child == NULL) && (dp->peer == NULL));
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	kmem_free(dp, sizeof (struct fc_device_tree));
6597c478bd9Sstevel@tonic-gate 	*head = NULL;
6607c478bd9Sstevel@tonic-gate }
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate struct fc_device_tree *
fc_find_node(dev_info_t * dip,struct fc_device_tree * hp)6637c478bd9Sstevel@tonic-gate fc_find_node(dev_info_t *dip, struct fc_device_tree *hp)
6647c478bd9Sstevel@tonic-gate {
6657c478bd9Sstevel@tonic-gate 	struct fc_device_tree *p;
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	while (hp) {
6687c478bd9Sstevel@tonic-gate 		if (hp->dip == dip)
6697c478bd9Sstevel@tonic-gate 			return (hp);
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 		if (hp->child)
6727c478bd9Sstevel@tonic-gate 			if ((p = fc_find_node(dip, hp->child)) != NULL)
6737c478bd9Sstevel@tonic-gate 				return (p);
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 		hp = hp->peer;
6767c478bd9Sstevel@tonic-gate 	}
6777c478bd9Sstevel@tonic-gate 	return (NULL);
6787c478bd9Sstevel@tonic-gate }
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate void
fc_add_child(dev_info_t * child,dev_info_t * parent,struct fc_device_tree * hp)6817c478bd9Sstevel@tonic-gate fc_add_child(dev_info_t *child, dev_info_t *parent, struct fc_device_tree *hp)
6827c478bd9Sstevel@tonic-gate {
6837c478bd9Sstevel@tonic-gate 	struct fc_device_tree *p, *q;
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	q = kmem_zalloc(sizeof (struct fc_device_tree), KM_SLEEP);
6867c478bd9Sstevel@tonic-gate 	q->dip = child;
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	mutex_enter(&fc_device_tree_lock);
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate #ifdef	DEBUG
6917c478bd9Sstevel@tonic-gate 	/* XXX: Revisit ASSERT vs PANIC */
6927c478bd9Sstevel@tonic-gate 	p = fc_find_node(child, hp);
6937c478bd9Sstevel@tonic-gate 	ASSERT(p == NULL);
6947c478bd9Sstevel@tonic-gate #endif
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	p = fc_find_node(parent, hp);
6977c478bd9Sstevel@tonic-gate 	ASSERT(p != NULL);
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 	q->peer = p->child;
7007c478bd9Sstevel@tonic-gate 	p->child = q;
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	mutex_exit(&fc_device_tree_lock);
7037c478bd9Sstevel@tonic-gate }
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate void
fc_remove_child(dev_info_t * child,struct fc_device_tree * head)7067c478bd9Sstevel@tonic-gate fc_remove_child(dev_info_t *child, struct fc_device_tree *head)
7077c478bd9Sstevel@tonic-gate {
7087c478bd9Sstevel@tonic-gate 	struct fc_device_tree *p, *c, *n;
7097c478bd9Sstevel@tonic-gate 	dev_info_t *parent = ddi_get_parent(child);
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	mutex_enter(&fc_device_tree_lock);
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	p = fc_find_node(parent, head);
7147c478bd9Sstevel@tonic-gate 	ASSERT(p != NULL);
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	/*
7177c478bd9Sstevel@tonic-gate 	 * Find the child within the parent's subtree ...
7187c478bd9Sstevel@tonic-gate 	 */
7197c478bd9Sstevel@tonic-gate 	c = fc_find_node(child, p);
7207c478bd9Sstevel@tonic-gate 	ASSERT(c != NULL);
7217c478bd9Sstevel@tonic-gate 	ASSERT(c->child == NULL);
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 	/*
7247c478bd9Sstevel@tonic-gate 	 * If it's the first child, remove it, otherwise
7257c478bd9Sstevel@tonic-gate 	 * remove it from the child's peer list.
7267c478bd9Sstevel@tonic-gate 	 */
7277c478bd9Sstevel@tonic-gate 	if (p->child == c) {
7287c478bd9Sstevel@tonic-gate 		p->child = c->peer;
7297c478bd9Sstevel@tonic-gate 	} else {
7307c478bd9Sstevel@tonic-gate 		int found = 0;
7317c478bd9Sstevel@tonic-gate 		for (n = p->child; n->peer; n = n->peer) {
7327c478bd9Sstevel@tonic-gate 			if (n->peer == c) {
7337c478bd9Sstevel@tonic-gate 				n->peer = c->peer;
7347c478bd9Sstevel@tonic-gate 				found = 1;
7357c478bd9Sstevel@tonic-gate 				break;
7367c478bd9Sstevel@tonic-gate 			}
7377c478bd9Sstevel@tonic-gate 		}
7387c478bd9Sstevel@tonic-gate 		if (!found)
7397c478bd9Sstevel@tonic-gate 			cmn_err(CE_PANIC, "fc_remove_child: not found\n");
7407c478bd9Sstevel@tonic-gate 	}
7417c478bd9Sstevel@tonic-gate 	mutex_exit(&fc_device_tree_lock);
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 	kmem_free(c, sizeof (struct fc_device_tree));
7447c478bd9Sstevel@tonic-gate }
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate dev_info_t *
fc_child_node(dev_info_t * parent,struct fc_device_tree * hp)7477c478bd9Sstevel@tonic-gate fc_child_node(dev_info_t *parent, struct fc_device_tree *hp)
7487c478bd9Sstevel@tonic-gate {
7497c478bd9Sstevel@tonic-gate 	struct fc_device_tree *p;
7507c478bd9Sstevel@tonic-gate 	dev_info_t *dip = NULL;
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	mutex_enter(&fc_device_tree_lock);
7537c478bd9Sstevel@tonic-gate 	p = fc_find_node(parent, hp);
7547c478bd9Sstevel@tonic-gate 	if (p && p->child)
7557c478bd9Sstevel@tonic-gate 		dip = p->child->dip;
7567c478bd9Sstevel@tonic-gate 	mutex_exit(&fc_device_tree_lock);
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	return (dip);
7597c478bd9Sstevel@tonic-gate }
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate dev_info_t *
fc_peer_node(dev_info_t * devi,struct fc_device_tree * hp)7627c478bd9Sstevel@tonic-gate fc_peer_node(dev_info_t *devi, struct fc_device_tree *hp)
7637c478bd9Sstevel@tonic-gate {
7647c478bd9Sstevel@tonic-gate 	struct fc_device_tree *p;
7657c478bd9Sstevel@tonic-gate 	dev_info_t *dip = NULL;
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 	mutex_enter(&fc_device_tree_lock);
7687c478bd9Sstevel@tonic-gate 	p = fc_find_node(devi, hp);
7697c478bd9Sstevel@tonic-gate 	if (p && p->peer)
7707c478bd9Sstevel@tonic-gate 		dip = p->peer->dip;
7717c478bd9Sstevel@tonic-gate 	mutex_exit(&fc_device_tree_lock);
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	return (dip);
7747c478bd9Sstevel@tonic-gate }
775