xref: /illumos-gate/usr/src/uts/common/io/rsm/rsmops.c (revision 48bbca81)
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
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2239b361b2SRichard Bean  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*48bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <sys/types.h>
287c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
297c478bd9Sstevel@tonic-gate #include <sys/stat.h>
307c478bd9Sstevel@tonic-gate #include <sys/proc.h>
317c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
327c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
337c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
347c478bd9Sstevel@tonic-gate #include <sys/file.h>
357c478bd9Sstevel@tonic-gate #include <sys/rsm/rsm_common.h>
367c478bd9Sstevel@tonic-gate #include <sys/rsm/rsmpi.h>
377c478bd9Sstevel@tonic-gate #include <sys/rsm/rsmpi_driver.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /* lint -w2 */
407c478bd9Sstevel@tonic-gate static struct modlmisc modlmisc = {
4139b361b2SRichard Bean 	&mod_miscops, "RSMOPS module",
427c478bd9Sstevel@tonic-gate };
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
457c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modlmisc, NULL
467c478bd9Sstevel@tonic-gate };
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate static kmutex_t rsmops_lock;
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate static rsmops_drv_t *rsmops_drv_head = NULL;
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate static int rsmops_threads_started = 0;
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate int
_init(void)557c478bd9Sstevel@tonic-gate _init(void)
567c478bd9Sstevel@tonic-gate {
577c478bd9Sstevel@tonic-gate 	int	err;
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate 	mutex_init(&rsmops_lock, NULL, MUTEX_DEFAULT, NULL);
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate 	if ((err = mod_install(&modlinkage)) != 0)
627c478bd9Sstevel@tonic-gate 		mutex_destroy(&rsmops_lock);
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 	return (err);
657c478bd9Sstevel@tonic-gate }
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate int
_fini(void)687c478bd9Sstevel@tonic-gate _fini(void)
697c478bd9Sstevel@tonic-gate {
707c478bd9Sstevel@tonic-gate 	int	err;
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	mutex_enter(&rsmops_lock);
737c478bd9Sstevel@tonic-gate 	if (rsmops_drv_head) {
747c478bd9Sstevel@tonic-gate 		/* Somebody is still registered with us - we cannot unload */
757c478bd9Sstevel@tonic-gate 		mutex_exit(&rsmops_lock);
767c478bd9Sstevel@tonic-gate 		return (EBUSY);
777c478bd9Sstevel@tonic-gate 	}
787c478bd9Sstevel@tonic-gate 	if (rsmops_threads_started) {
797c478bd9Sstevel@tonic-gate 		/*
807c478bd9Sstevel@tonic-gate 		 * Some threads have been started.  We do not have any
817c478bd9Sstevel@tonic-gate 		 * well-supported way of checking whether they have all
827c478bd9Sstevel@tonic-gate 		 * exited.  For now, fail attempt to unload if we have
837c478bd9Sstevel@tonic-gate 		 * ever started any threads.  This is overkill, but ...
847c478bd9Sstevel@tonic-gate 		 */
857c478bd9Sstevel@tonic-gate 		mutex_exit(&rsmops_lock);
867c478bd9Sstevel@tonic-gate 		return (EBUSY);
877c478bd9Sstevel@tonic-gate 	}
887c478bd9Sstevel@tonic-gate 	mutex_exit(&rsmops_lock);
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	if ((err = mod_remove(&modlinkage)) == 0)
917c478bd9Sstevel@tonic-gate 		mutex_destroy(&rsmops_lock);
927c478bd9Sstevel@tonic-gate 	return (err);
937c478bd9Sstevel@tonic-gate }
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)967c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
997c478bd9Sstevel@tonic-gate }
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate static void
rsmops_thread_entry(rsmops_drv_t * p_drv)1027c478bd9Sstevel@tonic-gate rsmops_thread_entry(rsmops_drv_t *p_drv)
1037c478bd9Sstevel@tonic-gate {
1047c478bd9Sstevel@tonic-gate 	/* p_drv->ctrl_cnt has already been increased by the time we get here */
1057c478bd9Sstevel@tonic-gate 	ASSERT(p_drv->drv.rsm_thread_entry_pt);
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	/* call the driver with the thread */
1087c478bd9Sstevel@tonic-gate 	(*(p_drv->drv.rsm_thread_entry_pt))(p_drv->drv.drv_name);
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	/* thread has returned */
1117c478bd9Sstevel@tonic-gate 	mutex_enter(&rsmops_lock);
1127c478bd9Sstevel@tonic-gate 	p_drv->ctrl_cnt--;
1137c478bd9Sstevel@tonic-gate 	mutex_exit(&rsmops_lock);
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate /* This is expected to be called from the driver's init function */
1177c478bd9Sstevel@tonic-gate int
rsm_register_driver(rsmops_registry_t * p_registry)1187c478bd9Sstevel@tonic-gate rsm_register_driver(rsmops_registry_t *p_registry)
1197c478bd9Sstevel@tonic-gate {
1207c478bd9Sstevel@tonic-gate 	rsmops_drv_t **pp_tail;
1217c478bd9Sstevel@tonic-gate 	rsmops_drv_t *p;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	if (p_registry->rsm_version > RSM_VERSION) {
1247c478bd9Sstevel@tonic-gate 		/* The driver is up-rev than me.  Fail attempt to register */
1257c478bd9Sstevel@tonic-gate 		return (RSMERR_BAD_DRIVER_VERSION);
1267c478bd9Sstevel@tonic-gate 	}
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	/*
1297c478bd9Sstevel@tonic-gate 	 * RSM_VERSION: Since this is the first version, there cannot be any
1307c478bd9Sstevel@tonic-gate 	 * down-rev drivers - this will be an issue in the future
1317c478bd9Sstevel@tonic-gate 	 */
1327c478bd9Sstevel@tonic-gate 	if (p_registry->rsm_version != RSM_VERSION)
1337c478bd9Sstevel@tonic-gate 		return (RSMERR_BAD_DRIVER_VERSION);
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	mutex_enter(&rsmops_lock);
1367c478bd9Sstevel@tonic-gate 	/* First, search that this driver is not already registered */
1377c478bd9Sstevel@tonic-gate 	pp_tail = &rsmops_drv_head;
1387c478bd9Sstevel@tonic-gate 	while (*pp_tail) {
1397c478bd9Sstevel@tonic-gate 		if (strcmp((*pp_tail)->drv.drv_name, p_registry->drv_name)
1407c478bd9Sstevel@tonic-gate 		    == 0) {
1417c478bd9Sstevel@tonic-gate 			mutex_exit(&rsmops_lock);
1427c478bd9Sstevel@tonic-gate 			return (RSMERR_DRIVER_NAME_IN_USE);
1437c478bd9Sstevel@tonic-gate 		}
1447c478bd9Sstevel@tonic-gate 		pp_tail = &((*pp_tail)->next);
1457c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	p = kmem_alloc(sizeof (rsmops_drv_t), KM_SLEEP);
1487c478bd9Sstevel@tonic-gate 	p->drv = *p_registry;	/* copy entire rsmops_registry_t structure */
1497c478bd9Sstevel@tonic-gate 	p->next = NULL;
1507c478bd9Sstevel@tonic-gate 	p->ctrl_cnt = 0;
1517c478bd9Sstevel@tonic-gate 	p->ctrl_head = NULL;
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	if (p->drv.rsm_thread_entry_pt) {
1547c478bd9Sstevel@tonic-gate 		/* thread entry point is defined - we need to create a thread */
1557c478bd9Sstevel@tonic-gate 		extern  pri_t   minclsyspri;
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 		p->ctrl_cnt++;	/* bump up the count right now */
1587c478bd9Sstevel@tonic-gate 		p->thread_id = thread_create(NULL, 0, rsmops_thread_entry,
1597c478bd9Sstevel@tonic-gate 		    p, 0, &p0, TS_RUN, minclsyspri);
1607c478bd9Sstevel@tonic-gate 		rsmops_threads_started++;
1617c478bd9Sstevel@tonic-gate 	} else
1627c478bd9Sstevel@tonic-gate 		p->thread_id = NULL;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	*pp_tail = p;
1657c478bd9Sstevel@tonic-gate 	mutex_exit(&rsmops_lock);
1667c478bd9Sstevel@tonic-gate 	return (RSM_SUCCESS);
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate /*
1707c478bd9Sstevel@tonic-gate  * This is expected to be called from the driver's fini function
1717c478bd9Sstevel@tonic-gate  * if this function returns EBUSY, the driver is supposed to fail
1727c478bd9Sstevel@tonic-gate  * its own fini operation
1737c478bd9Sstevel@tonic-gate  */
1747c478bd9Sstevel@tonic-gate int
rsm_unregister_driver(rsmops_registry_t * p_registry)1757c478bd9Sstevel@tonic-gate rsm_unregister_driver(rsmops_registry_t *p_registry)
1767c478bd9Sstevel@tonic-gate {
1777c478bd9Sstevel@tonic-gate 	rsmops_drv_t **pp_tail;
1787c478bd9Sstevel@tonic-gate 	rsmops_drv_t *p;
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	mutex_enter(&rsmops_lock);
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	/* Search for the driver */
1837c478bd9Sstevel@tonic-gate 	pp_tail = &rsmops_drv_head;
1847c478bd9Sstevel@tonic-gate 	while (*pp_tail) {
1857c478bd9Sstevel@tonic-gate 		if (strcmp((*pp_tail)->drv.drv_name, p_registry->drv_name)) {
1867c478bd9Sstevel@tonic-gate 			pp_tail = &((*pp_tail)->next);
1877c478bd9Sstevel@tonic-gate 			continue;
1887c478bd9Sstevel@tonic-gate 		}
1897c478bd9Sstevel@tonic-gate 		/* check ref count - if somebody is using it, return EBUSY */
1907c478bd9Sstevel@tonic-gate 		if ((*pp_tail)->ctrl_cnt) {
1917c478bd9Sstevel@tonic-gate 			mutex_exit(&rsmops_lock);
1927c478bd9Sstevel@tonic-gate 			return (RSMERR_CTLRS_REGISTERED);
1937c478bd9Sstevel@tonic-gate 		}
1947c478bd9Sstevel@tonic-gate 		/* Nobody is using it - we can allow the unregister to happen */
1957c478bd9Sstevel@tonic-gate 		p = *pp_tail;
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 		/* Stomp the guy out of our linked list */
1987c478bd9Sstevel@tonic-gate 		*pp_tail = (*pp_tail)->next;
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 		/* release the memory */
2017c478bd9Sstevel@tonic-gate 		kmem_free(p, sizeof (rsmops_drv_t));
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 		mutex_exit(&rsmops_lock);
2047c478bd9Sstevel@tonic-gate 		return (RSM_SUCCESS);
2057c478bd9Sstevel@tonic-gate 	}
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	/* Could not find the guy */
2087c478bd9Sstevel@tonic-gate 	mutex_exit(&rsmops_lock);
2097c478bd9Sstevel@tonic-gate 	return (RSMERR_DRIVER_NOT_REGISTERED);
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate /* Should be called holding the rsmops_lock mutex */
2137c478bd9Sstevel@tonic-gate static rsmops_drv_t *
find_rsmpi_driver(const char * name)2147c478bd9Sstevel@tonic-gate find_rsmpi_driver(const char *name)
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate 	rsmops_drv_t *p_rsmops_list;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&rsmops_lock));
2197c478bd9Sstevel@tonic-gate 	/* the name is of the form "sci", "wci" etc */
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	for (p_rsmops_list = rsmops_drv_head; p_rsmops_list != NULL;
2227c478bd9Sstevel@tonic-gate 	    p_rsmops_list = p_rsmops_list->next) {
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 		if (strcmp(name, p_rsmops_list->drv.drv_name) == 0) {
2257c478bd9Sstevel@tonic-gate 			return (p_rsmops_list);
2267c478bd9Sstevel@tonic-gate 		}
2277c478bd9Sstevel@tonic-gate 	}
2287c478bd9Sstevel@tonic-gate 	return (NULL);
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate /* Should be called holding the rsmops_lock mutex */
2337c478bd9Sstevel@tonic-gate static rsmops_ctrl_t *
find_rsmpi_controller(const char * name,uint_t number)2347c478bd9Sstevel@tonic-gate find_rsmpi_controller(const char *name, uint_t number)
2357c478bd9Sstevel@tonic-gate {
2367c478bd9Sstevel@tonic-gate 	rsmops_drv_t *p_drv;
2377c478bd9Sstevel@tonic-gate 	rsmops_ctrl_t *p;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&rsmops_lock));
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	if ((p_drv = find_rsmpi_driver(name)) == NULL)
2427c478bd9Sstevel@tonic-gate 		return (NULL);
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	for (p = p_drv->ctrl_head; p != NULL; p = p->next) {
2457c478bd9Sstevel@tonic-gate 		ASSERT(p->p_drv == p_drv);
2467c478bd9Sstevel@tonic-gate 		if (p->number == number)
2477c478bd9Sstevel@tonic-gate 			return (p);
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate 	return (NULL);
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate /* Should be called holding the rsmops_lock mutex */
2537c478bd9Sstevel@tonic-gate static rsmops_ctrl_t *
find_rsmpi_controller_handle(rsm_controller_handle_t cntlr_handle)2547c478bd9Sstevel@tonic-gate find_rsmpi_controller_handle(rsm_controller_handle_t cntlr_handle)
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate 	rsmops_drv_t *p_drv;
2577c478bd9Sstevel@tonic-gate 	rsmops_ctrl_t *p;
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&rsmops_lock));
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	for (p_drv = rsmops_drv_head; p_drv != NULL; p_drv = p_drv->next) {
2627c478bd9Sstevel@tonic-gate 		for (p = p_drv->ctrl_head; p != NULL; p = p->next) {
2637c478bd9Sstevel@tonic-gate 			if (p->handle == cntlr_handle)
2647c478bd9Sstevel@tonic-gate 				return (p);
2657c478bd9Sstevel@tonic-gate 		}
2667c478bd9Sstevel@tonic-gate 	}
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	return (NULL);
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate static vnode_t *
2727c478bd9Sstevel@tonic-gate rsmops_device_open(const char *major_name, const minor_t minor_num);
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate int
rsm_get_controller(const char * name,uint_t number,rsm_controller_object_t * controller,uint_t version)2757c478bd9Sstevel@tonic-gate rsm_get_controller(const char *name, uint_t number,
2767c478bd9Sstevel@tonic-gate     rsm_controller_object_t *controller, uint_t version)
2777c478bd9Sstevel@tonic-gate {
2787c478bd9Sstevel@tonic-gate 	rsmops_ctrl_t *p_ctrl;
2797c478bd9Sstevel@tonic-gate 	rsmops_drv_t *p_drv;
2807c478bd9Sstevel@tonic-gate 	vnode_t *vp;
2817c478bd9Sstevel@tonic-gate 	int error;
2827c478bd9Sstevel@tonic-gate 	int (*rsm_get_controller_handler)
2837c478bd9Sstevel@tonic-gate 	    (const char *name, uint_t number,
2847c478bd9Sstevel@tonic-gate 	    rsm_controller_object_t *pcontroller, uint_t version);
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	mutex_enter(&rsmops_lock);
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	/* check if the controller is already registered */
2897c478bd9Sstevel@tonic-gate 	if ((p_ctrl = find_rsmpi_controller(name, number)) == NULL) {
2907c478bd9Sstevel@tonic-gate 		/*
2917c478bd9Sstevel@tonic-gate 		 * controller is not registered.  We should try to load it
2927c478bd9Sstevel@tonic-gate 		 * First check if the driver is registered
2937c478bd9Sstevel@tonic-gate 		 */
2947c478bd9Sstevel@tonic-gate 		if ((p_drv = find_rsmpi_driver(name)) == NULL) {
295*48bbca81SDaniel Hoffman 			/* Cannot find the driver.  Try to load it */
2967c478bd9Sstevel@tonic-gate 			mutex_exit(&rsmops_lock);
2977c478bd9Sstevel@tonic-gate 			if ((error = modload("drv", (char *)name)) == -1) {
2987c478bd9Sstevel@tonic-gate 				return (RSMERR_CTLR_NOT_PRESENT);
2997c478bd9Sstevel@tonic-gate 			}
3007c478bd9Sstevel@tonic-gate 			mutex_enter(&rsmops_lock);
3017c478bd9Sstevel@tonic-gate 			if ((p_drv = find_rsmpi_driver(name)) == NULL) {
3027c478bd9Sstevel@tonic-gate 				mutex_exit(&rsmops_lock);
3037c478bd9Sstevel@tonic-gate 				/*
3047c478bd9Sstevel@tonic-gate 				 * Cannot find yet - maybe the driver we loaded
3057c478bd9Sstevel@tonic-gate 				 * was not a RSMPI driver at all.  We'll just
3067c478bd9Sstevel@tonic-gate 				 * fail this call.
3077c478bd9Sstevel@tonic-gate 				 */
3087c478bd9Sstevel@tonic-gate 				return (RSMERR_CTLR_NOT_PRESENT);
3097c478bd9Sstevel@tonic-gate 			}
3107c478bd9Sstevel@tonic-gate 		}
3117c478bd9Sstevel@tonic-gate 		ASSERT(p_drv);
3127c478bd9Sstevel@tonic-gate 		p_ctrl = find_rsmpi_controller(name, number);
3137c478bd9Sstevel@tonic-gate 		if (p_ctrl == NULL) {
3147c478bd9Sstevel@tonic-gate 			/*
3157c478bd9Sstevel@tonic-gate 			 * controller is not registered.
3167c478bd9Sstevel@tonic-gate 			 * try to do a VOP_OPEN to force it to get registered
3177c478bd9Sstevel@tonic-gate 			 */
3187c478bd9Sstevel@tonic-gate 			mutex_exit(&rsmops_lock);
3197c478bd9Sstevel@tonic-gate 			vp = rsmops_device_open(name, number);
3207c478bd9Sstevel@tonic-gate 			mutex_enter(&rsmops_lock);
3217c478bd9Sstevel@tonic-gate 			if (vp != NULL) {
3227c478bd9Sstevel@tonic-gate 				(void) VOP_CLOSE(vp, FREAD|FWRITE, 0, 0,
323da6c28aaSamw 				    CRED(), NULL);
3247c478bd9Sstevel@tonic-gate 				VN_RELE(vp);
3257c478bd9Sstevel@tonic-gate 			}
3267c478bd9Sstevel@tonic-gate 			p_ctrl = find_rsmpi_controller(name, number);
3277c478bd9Sstevel@tonic-gate 			if (p_ctrl == NULL) {
3287c478bd9Sstevel@tonic-gate 				mutex_exit(&rsmops_lock);
3297c478bd9Sstevel@tonic-gate 				return (RSMERR_CTLR_NOT_PRESENT);
3307c478bd9Sstevel@tonic-gate 			}
3317c478bd9Sstevel@tonic-gate 		}
3327c478bd9Sstevel@tonic-gate 		ASSERT(p_ctrl);
3337c478bd9Sstevel@tonic-gate 	} else {
3347c478bd9Sstevel@tonic-gate 		p_drv = p_ctrl->p_drv;
3357c478bd9Sstevel@tonic-gate 	}
3367c478bd9Sstevel@tonic-gate 	ASSERT(p_drv);
3377c478bd9Sstevel@tonic-gate 	ASSERT(p_drv == p_ctrl->p_drv);
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	rsm_get_controller_handler = p_drv->drv.rsm_get_controller_handler;
3407c478bd9Sstevel@tonic-gate 	/*
3417c478bd9Sstevel@tonic-gate 	 * Increase the refcnt right now, so that attempts to deregister
3427c478bd9Sstevel@tonic-gate 	 * while we are using this entry will fail
3437c478bd9Sstevel@tonic-gate 	 */
3447c478bd9Sstevel@tonic-gate 	p_ctrl->refcnt++;
3457c478bd9Sstevel@tonic-gate 	mutex_exit(&rsmops_lock);
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	error = (*rsm_get_controller_handler)(name, number, controller,
3487c478bd9Sstevel@tonic-gate 	    version);
3497c478bd9Sstevel@tonic-gate 	if (error != RSM_SUCCESS) {
3507c478bd9Sstevel@tonic-gate 		/* We failed - drop the refcnt back */
3517c478bd9Sstevel@tonic-gate 		mutex_enter(&rsmops_lock);
3527c478bd9Sstevel@tonic-gate 		/*
3537c478bd9Sstevel@tonic-gate 		 * Even though we had released the global lock, we can
3547c478bd9Sstevel@tonic-gate 		 * guarantee that p_ctrl is still meaningful (and has not
3557c478bd9Sstevel@tonic-gate 		 * been deregistered, freed whatever) because we were holding
3567c478bd9Sstevel@tonic-gate 		 * refcnt on it.  So, it is okay to just use p_ctrl here
3577c478bd9Sstevel@tonic-gate 		 * after re-acquiring the global lock
3587c478bd9Sstevel@tonic-gate 		 */
3597c478bd9Sstevel@tonic-gate 		p_ctrl->refcnt--;
3607c478bd9Sstevel@tonic-gate 		mutex_exit(&rsmops_lock);
3617c478bd9Sstevel@tonic-gate 	} else {
3627c478bd9Sstevel@tonic-gate 		/*
3637c478bd9Sstevel@tonic-gate 		 * Initialize the controller handle field
3647c478bd9Sstevel@tonic-gate 		 */
3657c478bd9Sstevel@tonic-gate 		mutex_enter(&rsmops_lock);
3667c478bd9Sstevel@tonic-gate 		if ((p_ctrl = find_rsmpi_controller(name, number)) == NULL) {
3677c478bd9Sstevel@tonic-gate 			mutex_exit(&rsmops_lock);
3687c478bd9Sstevel@tonic-gate 			return (RSMERR_CTLR_NOT_PRESENT);
3697c478bd9Sstevel@tonic-gate 		}
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 		p_ctrl->handle = controller->handle;
3727c478bd9Sstevel@tonic-gate 		mutex_exit(&rsmops_lock);
3737c478bd9Sstevel@tonic-gate 	}
3747c478bd9Sstevel@tonic-gate 	return (error);
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate int
rsm_release_controller(const char * name,uint_t number,rsm_controller_object_t * controller)3787c478bd9Sstevel@tonic-gate rsm_release_controller(const char *name, uint_t number,
3797c478bd9Sstevel@tonic-gate     rsm_controller_object_t *controller)
3807c478bd9Sstevel@tonic-gate {
3817c478bd9Sstevel@tonic-gate 	rsmops_ctrl_t *p_ctrl;
3827c478bd9Sstevel@tonic-gate 	rsmops_drv_t *p_drv;
3837c478bd9Sstevel@tonic-gate 	int error;
3847c478bd9Sstevel@tonic-gate 	int (*releaser)(const char *name, uint_t number,
3857c478bd9Sstevel@tonic-gate 	    rsm_controller_object_t *controller);
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	mutex_enter(&rsmops_lock);
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	if ((p_ctrl = find_rsmpi_controller(name, number)) == NULL) {
3907c478bd9Sstevel@tonic-gate 		mutex_exit(&rsmops_lock);
3917c478bd9Sstevel@tonic-gate 		return (RSMERR_CTLR_NOT_PRESENT);
3927c478bd9Sstevel@tonic-gate 	}
3937c478bd9Sstevel@tonic-gate 	p_drv = find_rsmpi_driver(name);
3947c478bd9Sstevel@tonic-gate 	ASSERT(p_drv);	/* If we found controller, there MUST be a driver */
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	/* Found the appropriate driver.  Forward the call to it */
3977c478bd9Sstevel@tonic-gate 	releaser = p_drv->drv.rsm_release_controller_handler;
3987c478bd9Sstevel@tonic-gate 	mutex_exit(&rsmops_lock);
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	error = (*releaser)(name, number, controller);
4017c478bd9Sstevel@tonic-gate 	if (error == RSM_SUCCESS) {
4027c478bd9Sstevel@tonic-gate 		mutex_enter(&rsmops_lock);
4037c478bd9Sstevel@tonic-gate 		p_ctrl->refcnt--;
4047c478bd9Sstevel@tonic-gate 		mutex_exit(&rsmops_lock);
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 	return (error);
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate /* This is expected to be called from the driver's attach function */
4107c478bd9Sstevel@tonic-gate int
rsm_register_controller(const char * name,uint_t number,rsm_controller_attr_t * attrp)4117c478bd9Sstevel@tonic-gate rsm_register_controller(const char *name, uint_t number,
4127c478bd9Sstevel@tonic-gate     rsm_controller_attr_t *attrp)
4137c478bd9Sstevel@tonic-gate {
4147c478bd9Sstevel@tonic-gate 	rsmops_drv_t *p_drv;
4157c478bd9Sstevel@tonic-gate 	rsmops_ctrl_t *p_ctrl;
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	if (strlen(name) > MAX_DRVNAME)
4187c478bd9Sstevel@tonic-gate 		return (RSMERR_NAME_TOO_LONG);
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	mutex_enter(&rsmops_lock);
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	/* Check if the driver is registered with us */
4237c478bd9Sstevel@tonic-gate 	p_drv = find_rsmpi_driver(name);
4247c478bd9Sstevel@tonic-gate 	if (p_drv == NULL) {
4257c478bd9Sstevel@tonic-gate 		/*
4267c478bd9Sstevel@tonic-gate 		 * Hey! Driver is not registered, but we are getting a
4277c478bd9Sstevel@tonic-gate 		 * controller ??
4287c478bd9Sstevel@tonic-gate 		 */
4297c478bd9Sstevel@tonic-gate 		mutex_exit(&rsmops_lock);
4307c478bd9Sstevel@tonic-gate 		return (RSMERR_DRIVER_NOT_REGISTERED);
4317c478bd9Sstevel@tonic-gate 	}
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	/* Check if the controller is already registered with us */
4347c478bd9Sstevel@tonic-gate 	p_ctrl = find_rsmpi_controller(name, number);
4357c478bd9Sstevel@tonic-gate 	if (p_ctrl) {
4367c478bd9Sstevel@tonic-gate 		/* already registered */
4377c478bd9Sstevel@tonic-gate 		mutex_exit(&rsmops_lock);
4387c478bd9Sstevel@tonic-gate 		return (RSMERR_CTLR_ALREADY_REGISTERED);
4397c478bd9Sstevel@tonic-gate 	}
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	/* WAIT: sanity check - verify that the dip matches up to name,number */
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	p_ctrl = kmem_alloc(sizeof (rsmops_ctrl_t), KM_SLEEP);
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	/* bump up controller count on the driver */
4467c478bd9Sstevel@tonic-gate 	p_drv->ctrl_cnt++;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	p_ctrl->p_drv = p_drv;	/* setup the back pointer */
4497c478bd9Sstevel@tonic-gate 	p_ctrl->number = number;
4507c478bd9Sstevel@tonic-gate 	p_ctrl->refcnt = 0;
4517c478bd9Sstevel@tonic-gate 	p_ctrl->attrp = attrp;
4527c478bd9Sstevel@tonic-gate 	p_ctrl->handle = NULL;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	/* Now link to head of list */
4557c478bd9Sstevel@tonic-gate 	p_ctrl->next = p_drv->ctrl_head;
4567c478bd9Sstevel@tonic-gate 	p_drv->ctrl_head = p_ctrl;
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	mutex_exit(&rsmops_lock);
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	return (RSM_SUCCESS);
4617c478bd9Sstevel@tonic-gate }
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate /*
4647c478bd9Sstevel@tonic-gate  * This is expected to be called from the driver's detach function
4657c478bd9Sstevel@tonic-gate  * if this function returns EBUSY, the driver is supposed to fail
466*48bbca81SDaniel Hoffman  * its own detach operation
4677c478bd9Sstevel@tonic-gate  */
4687c478bd9Sstevel@tonic-gate int
rsm_unregister_controller(const char * name,uint_t number)4697c478bd9Sstevel@tonic-gate rsm_unregister_controller(const char *name, uint_t number)
4707c478bd9Sstevel@tonic-gate {
4717c478bd9Sstevel@tonic-gate 	rsmops_drv_t *p_drv;
4727c478bd9Sstevel@tonic-gate 	rsmops_ctrl_t **p_prev;
4737c478bd9Sstevel@tonic-gate 	rsmops_ctrl_t *found;
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	mutex_enter(&rsmops_lock);
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	/* Check if the driver is registered with us */
4787c478bd9Sstevel@tonic-gate 	p_drv = find_rsmpi_driver(name);
4797c478bd9Sstevel@tonic-gate 	if (p_drv == NULL) {
4807c478bd9Sstevel@tonic-gate 		/* Hey!  Driver is not registered */
4817c478bd9Sstevel@tonic-gate 		mutex_exit(&rsmops_lock);
4827c478bd9Sstevel@tonic-gate 		return (RSMERR_DRIVER_NOT_REGISTERED);
4837c478bd9Sstevel@tonic-gate 	}
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	/* Search for the controller in the list */
4867c478bd9Sstevel@tonic-gate 	for (p_prev = &p_drv->ctrl_head; *p_prev; p_prev = &((*p_prev)->next)) {
4877c478bd9Sstevel@tonic-gate 		if ((*p_prev)->number == number) {
4887c478bd9Sstevel@tonic-gate 			/* Found the controller.  Check if it is busy */
4897c478bd9Sstevel@tonic-gate 			found = *p_prev;
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 			if (found->refcnt) {
4927c478bd9Sstevel@tonic-gate 				/* Controller is busy -  handles outstanding */
4937c478bd9Sstevel@tonic-gate 				mutex_exit(&rsmops_lock);
4947c478bd9Sstevel@tonic-gate 				return (RSMERR_CTLR_IN_USE);
4957c478bd9Sstevel@tonic-gate 			}
4967c478bd9Sstevel@tonic-gate 			/* unlink it out */
4977c478bd9Sstevel@tonic-gate 			*p_prev = found->next;
4987c478bd9Sstevel@tonic-gate 			/* bump down controller count on the driver */
4997c478bd9Sstevel@tonic-gate 			p_drv->ctrl_cnt--;
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 			mutex_exit(&rsmops_lock);
5027c478bd9Sstevel@tonic-gate 			kmem_free(found, sizeof (rsmops_ctrl_t));
5037c478bd9Sstevel@tonic-gate 			return (RSM_SUCCESS);
5047c478bd9Sstevel@tonic-gate 		}
5057c478bd9Sstevel@tonic-gate 	}
5067c478bd9Sstevel@tonic-gate 	mutex_exit(&rsmops_lock);
5077c478bd9Sstevel@tonic-gate 	/* Could not find the right controller */
5087c478bd9Sstevel@tonic-gate 	return (RSMERR_CTLR_NOT_REGISTERED);
5097c478bd9Sstevel@tonic-gate }
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate /*
5137c478bd9Sstevel@tonic-gate  * This opens and closes the appropriate device with minor number -
5147c478bd9Sstevel@tonic-gate  * hopefully, it will cause the driver to attach and register a controller
5157c478bd9Sstevel@tonic-gate  * with us
5167c478bd9Sstevel@tonic-gate  */
5177c478bd9Sstevel@tonic-gate static vnode_t *
rsmops_device_open(const char * major_name,const minor_t minor_num)5187c478bd9Sstevel@tonic-gate rsmops_device_open(const char *major_name, const minor_t minor_num)
5197c478bd9Sstevel@tonic-gate {
5207c478bd9Sstevel@tonic-gate 	major_t maj;
5217c478bd9Sstevel@tonic-gate 	vnode_t *vp;
5227c478bd9Sstevel@tonic-gate 	int ret;
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	if (minor_num == (minor_t)-1) {
5257c478bd9Sstevel@tonic-gate 		return (NULL);
5267c478bd9Sstevel@tonic-gate 	}
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	maj = ddi_name_to_major((char *)major_name);
5297c478bd9Sstevel@tonic-gate 	if (maj == (major_t)-1) {
5307c478bd9Sstevel@tonic-gate 		return (NULL);
5317c478bd9Sstevel@tonic-gate 	}
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	vp = makespecvp(makedevice(maj, minor_num), VCHR);
5347c478bd9Sstevel@tonic-gate 
535da6c28aaSamw 	ret = VOP_OPEN(&vp, FREAD|FWRITE, CRED(), NULL);
5367c478bd9Sstevel@tonic-gate 	if (ret == 0) {
5377c478bd9Sstevel@tonic-gate 		return (vp);
5387c478bd9Sstevel@tonic-gate 	} else {
5397c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
5407c478bd9Sstevel@tonic-gate 		return (NULL);
5417c478bd9Sstevel@tonic-gate 	}
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate /*
5457c478bd9Sstevel@tonic-gate  * Attributes for controller identified by the handle are returned
5467c478bd9Sstevel@tonic-gate  * via *attrp. Modifications of attributes is prohibited by client!
5477c478bd9Sstevel@tonic-gate  */
5487c478bd9Sstevel@tonic-gate int
rsm_get_controller_attr(rsm_controller_handle_t handle,rsm_controller_attr_t ** attrp)5497c478bd9Sstevel@tonic-gate rsm_get_controller_attr(rsm_controller_handle_t handle,
5507c478bd9Sstevel@tonic-gate     rsm_controller_attr_t **attrp)
5517c478bd9Sstevel@tonic-gate {
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	rsmops_ctrl_t *p_ctrl;
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	if (handle == NULL)
5567c478bd9Sstevel@tonic-gate 		return (RSMERR_BAD_CTLR_HNDL);
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	mutex_enter(&rsmops_lock);
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	/* find controller */
5617c478bd9Sstevel@tonic-gate 	if ((p_ctrl = find_rsmpi_controller_handle(handle)) == NULL) {
5627c478bd9Sstevel@tonic-gate 		/* can't supply attributes for invalid controller */
5637c478bd9Sstevel@tonic-gate 		mutex_exit(&rsmops_lock);
5647c478bd9Sstevel@tonic-gate 		return (RSMERR_BAD_CTLR_HNDL);
5657c478bd9Sstevel@tonic-gate 	}
5667c478bd9Sstevel@tonic-gate 	*attrp =  p_ctrl->attrp;
5677c478bd9Sstevel@tonic-gate 	mutex_exit(&rsmops_lock);
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	return (RSM_SUCCESS);
5707c478bd9Sstevel@tonic-gate }
571