xref: /illumos-gate/usr/src/uts/sun4u/io/ppm_xgsubr.c (revision 07d06da50d310a325b457d6330165aebab1e0064)
15cff7825Smh27603 /*
25cff7825Smh27603  * CDDL HEADER START
35cff7825Smh27603  *
45cff7825Smh27603  * The contents of this file are subject to the terms of the
55cff7825Smh27603  * Common Development and Distribution License (the "License").
65cff7825Smh27603  * You may not use this file except in compliance with the License.
75cff7825Smh27603  *
85cff7825Smh27603  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95cff7825Smh27603  * or http://www.opensolaris.org/os/licensing.
105cff7825Smh27603  * See the License for the specific language governing permissions
115cff7825Smh27603  * and limitations under the License.
125cff7825Smh27603  *
135cff7825Smh27603  * When distributing Covered Code, include this CDDL HEADER in each
145cff7825Smh27603  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155cff7825Smh27603  * If applicable, add the following below this CDDL HEADER, with the
165cff7825Smh27603  * fields enclosed by brackets "[]" replaced with your own identifying
175cff7825Smh27603  * information: Portions Copyright [yyyy] [name of copyright owner]
185cff7825Smh27603  *
195cff7825Smh27603  * CDDL HEADER END
205cff7825Smh27603  */
21*07d06da5SSurya Prakki 
225cff7825Smh27603 /*
23*07d06da5SSurya Prakki  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
245cff7825Smh27603  * Use is subject to license terms.
255cff7825Smh27603  */
265cff7825Smh27603 
275cff7825Smh27603 /*
285cff7825Smh27603  * common code for ppm drivers
295cff7825Smh27603  */
305cff7825Smh27603 #include <sys/modctl.h>
315cff7825Smh27603 #include <sys/ddi.h>
325cff7825Smh27603 #include <sys/sunddi.h>
335cff7825Smh27603 #include <sys/ddi_impldefs.h>
345cff7825Smh27603 #include <sys/ppmvar.h>
355cff7825Smh27603 #include <sys/ppmio.h>
365cff7825Smh27603 #include <sys/epm.h>
375cff7825Smh27603 #include <sys/open.h>
385cff7825Smh27603 #include <sys/file.h>
395cff7825Smh27603 #include <sys/policy.h>
405cff7825Smh27603 
415cff7825Smh27603 
425cff7825Smh27603 #ifdef DEBUG
435cff7825Smh27603 uint_t	ppm_debug = 0;
445cff7825Smh27603 #endif
455cff7825Smh27603 
465cff7825Smh27603 int	ppm_inst = -1;
475cff7825Smh27603 char	*ppm_prefix;
485cff7825Smh27603 void	*ppm_statep;
495cff7825Smh27603 
505cff7825Smh27603 
515cff7825Smh27603 /*
525cff7825Smh27603  * common module _init
535cff7825Smh27603  */
545cff7825Smh27603 int
ppm_init(struct modlinkage * mlp,size_t size,char * prefix)555cff7825Smh27603 ppm_init(struct modlinkage *mlp, size_t size, char *prefix)
565cff7825Smh27603 {
575cff7825Smh27603 #ifdef DEBUG
585cff7825Smh27603 	char *str = "ppm_init";
595cff7825Smh27603 #endif
605cff7825Smh27603 	int error;
615cff7825Smh27603 
625cff7825Smh27603 	ppm_prefix = prefix;
635cff7825Smh27603 
645cff7825Smh27603 	error = ddi_soft_state_init(&ppm_statep, size, 1);
655cff7825Smh27603 	DPRINTF(D_INIT, ("%s: ss init %d\n", str, error));
665cff7825Smh27603 	if (error != DDI_SUCCESS)
675cff7825Smh27603 		return (error);
685cff7825Smh27603 
695cff7825Smh27603 	if (error = mod_install(mlp))
705cff7825Smh27603 		ddi_soft_state_fini(&ppm_statep);
715cff7825Smh27603 	DPRINTF(D_INIT, ("%s: mod_install %d\n", str, error));
725cff7825Smh27603 
735cff7825Smh27603 	return (error);
745cff7825Smh27603 }
755cff7825Smh27603 
765cff7825Smh27603 
775cff7825Smh27603 /* ARGSUSED */
785cff7825Smh27603 int
ppm_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)795cff7825Smh27603 ppm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
805cff7825Smh27603 {
815cff7825Smh27603 	struct ppm_unit *overlay;
825cff7825Smh27603 	int rval;
835cff7825Smh27603 
845cff7825Smh27603 	if (ppm_inst == -1)
855cff7825Smh27603 		return (DDI_FAILURE);
865cff7825Smh27603 
875cff7825Smh27603 	switch (cmd) {
885cff7825Smh27603 	case DDI_INFO_DEVT2DEVINFO:
895cff7825Smh27603 		if (overlay = ddi_get_soft_state(ppm_statep, ppm_inst)) {
905cff7825Smh27603 			*resultp = overlay->dip;
915cff7825Smh27603 			rval = DDI_SUCCESS;
925cff7825Smh27603 		} else
935cff7825Smh27603 			rval = DDI_FAILURE;
945cff7825Smh27603 		return (rval);
955cff7825Smh27603 
965cff7825Smh27603 	case DDI_INFO_DEVT2INSTANCE:
975cff7825Smh27603 		*resultp = (void *)(uintptr_t)ppm_inst;
985cff7825Smh27603 		return (DDI_SUCCESS);
995cff7825Smh27603 
1005cff7825Smh27603 	default:
1015cff7825Smh27603 		return (DDI_FAILURE);
1025cff7825Smh27603 	}
1035cff7825Smh27603 }
1045cff7825Smh27603 
1055cff7825Smh27603 
1065cff7825Smh27603 /* ARGSUSED */
1075cff7825Smh27603 int
ppm_open(dev_t * devp,int flag,int otyp,cred_t * cred_p)1085cff7825Smh27603 ppm_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
1095cff7825Smh27603 {
1105cff7825Smh27603 	if (otyp != OTYP_CHR)
1115cff7825Smh27603 		return (EINVAL);
1125cff7825Smh27603 	DPRINTF(D_OPEN, ("ppm_open: \"%s\", devp 0x%p, flag 0x%x, otyp %d\n",
113*07d06da5SSurya Prakki 	    ppm_prefix, (void *)devp, flag, otyp));
1145cff7825Smh27603 	return (0);
1155cff7825Smh27603 }
1165cff7825Smh27603 
1175cff7825Smh27603 
1185cff7825Smh27603 /* ARGSUSED */
1195cff7825Smh27603 int
ppm_close(dev_t dev,int flag,int otyp,cred_t * credp)1205cff7825Smh27603 ppm_close(dev_t dev, int flag, int otyp, cred_t *credp)
1215cff7825Smh27603 {
1225cff7825Smh27603 	DPRINTF(D_CLOSE, ("ppm_close: \"%s\", dev 0x%lx, flag 0x%x, otyp %d\n",
1235cff7825Smh27603 	    ppm_prefix, dev, flag, otyp));
1245cff7825Smh27603 	return (DDI_SUCCESS);
1255cff7825Smh27603 }
1265cff7825Smh27603 
1275cff7825Smh27603 
1285cff7825Smh27603 /*
1295cff7825Smh27603  * lookup arrays of strings from configuration data (XXppm.conf)
1305cff7825Smh27603  */
1315cff7825Smh27603 static int
ppm_get_confdata(struct ppm_cdata ** cdp,dev_info_t * dip)1325cff7825Smh27603 ppm_get_confdata(struct ppm_cdata **cdp, dev_info_t *dip)
1335cff7825Smh27603 {
1345cff7825Smh27603 	struct ppm_cdata *cinfo;
1355cff7825Smh27603 	int err;
1365cff7825Smh27603 
1375cff7825Smh27603 	for (; (cinfo = *cdp) != NULL; cdp++) {
1385cff7825Smh27603 		err = ddi_prop_lookup_string_array(
1395cff7825Smh27603 		    DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1405cff7825Smh27603 		    cinfo->name, &cinfo->strings, &cinfo->cnt);
1415cff7825Smh27603 		if (err != DDI_PROP_SUCCESS) {
1425cff7825Smh27603 			DPRINTF(D_ERROR,
1435cff7825Smh27603 			    ("ppm_get_confdata: no %s found\n", cinfo->name));
1445cff7825Smh27603 			break;
1455cff7825Smh27603 		}
1465cff7825Smh27603 	}
1475cff7825Smh27603 	return (err);
1485cff7825Smh27603 }
1495cff7825Smh27603 
1505cff7825Smh27603 
1515cff7825Smh27603 /*
1525cff7825Smh27603  * free allocated ddi prop strings, and free
1535cff7825Smh27603  * ppm_db_t lists where there's an error.
1545cff7825Smh27603  */
1555cff7825Smh27603 static int
ppm_attach_err(struct ppm_cdata ** cdp,int err)1565cff7825Smh27603 ppm_attach_err(struct ppm_cdata **cdp, int err)
1575cff7825Smh27603 {
1585cff7825Smh27603 	ppm_domain_t **dompp;
1595cff7825Smh27603 	ppm_db_t *db, *tmp;
1605cff7825Smh27603 
1615cff7825Smh27603 	if (cdp) {
1625cff7825Smh27603 		for (; *cdp; cdp++) {
1635cff7825Smh27603 			if ((*cdp)->strings) {
1645cff7825Smh27603 				ddi_prop_free((*cdp)->strings);
1655cff7825Smh27603 				(*cdp)->strings = NULL;
1665cff7825Smh27603 			}
1675cff7825Smh27603 		}
1685cff7825Smh27603 	}
1695cff7825Smh27603 
1705cff7825Smh27603 	if (err != DDI_SUCCESS) {
1715cff7825Smh27603 		for (dompp = ppm_domains; *dompp; dompp++) {
1725cff7825Smh27603 			for (db = (*dompp)->conflist; (tmp = db) != NULL; ) {
1735cff7825Smh27603 				db = db->next;
1745cff7825Smh27603 				kmem_free(tmp->name, strlen(tmp->name) + 1);
1755cff7825Smh27603 				kmem_free(tmp, sizeof (*tmp));
1765cff7825Smh27603 			}
1775cff7825Smh27603 			(*dompp)->conflist = NULL;
1785cff7825Smh27603 		}
1795cff7825Smh27603 		err = DDI_FAILURE;
1805cff7825Smh27603 	}
1815cff7825Smh27603 
1825cff7825Smh27603 	return (err);
1835cff7825Smh27603 }
1845cff7825Smh27603 
1855cff7825Smh27603 
1865cff7825Smh27603 ppm_domain_t *
ppm_lookup_domain(char * dname)1875cff7825Smh27603 ppm_lookup_domain(char *dname)
1885cff7825Smh27603 {
1895cff7825Smh27603 	ppm_domain_t **dompp;
1905cff7825Smh27603 
1915cff7825Smh27603 	for (dompp = ppm_domains; *dompp; dompp++)
1925cff7825Smh27603 		if (strcmp(dname, (*dompp)->name) == 0)
1935cff7825Smh27603 			break;
1945cff7825Smh27603 	return (*dompp);
1955cff7825Smh27603 }
1965cff7825Smh27603 
1975cff7825Smh27603 
1985cff7825Smh27603 /*
1995cff7825Smh27603  * create a ppm-private database from parsed .conf data; we start with
2005cff7825Smh27603  * two string arrays (device pathnames and domain names) and treat them
2015cff7825Smh27603  * as matched pairs where device[N] is part of domain[N]
2025cff7825Smh27603  */
2035cff7825Smh27603 int
ppm_create_db(dev_info_t * dip)2045cff7825Smh27603 ppm_create_db(dev_info_t *dip)
2055cff7825Smh27603 {
2065cff7825Smh27603 #ifdef DEBUG
2075cff7825Smh27603 	char *str = "ppm_create_db";
2085cff7825Smh27603 #endif
2095cff7825Smh27603 	struct ppm_cdata devdata, domdata, *cdata[3];
2105cff7825Smh27603 	ppm_domain_t *domp;
2115cff7825Smh27603 	ppm_db_t *new;
2125cff7825Smh27603 	char **dev_namep, **dom_namep;
2135cff7825Smh27603 	char *wild;
2145cff7825Smh27603 	int err;
2155cff7825Smh27603 
2165cff7825Smh27603 	bzero(&devdata, sizeof (devdata));
2175cff7825Smh27603 	bzero(&domdata, sizeof (domdata));
2185cff7825Smh27603 	devdata.name = "ppm-devices";
2195cff7825Smh27603 	domdata.name = "ppm-domains";
2205cff7825Smh27603 	cdata[0] = &devdata;
2215cff7825Smh27603 	cdata[1] = &domdata;
2225cff7825Smh27603 	cdata[2] = NULL;
2235cff7825Smh27603 	if (err = ppm_get_confdata(cdata, dip))
2245cff7825Smh27603 		return (ppm_attach_err(cdata, err));
2255cff7825Smh27603 	else if (devdata.cnt != domdata.cnt) {
2265cff7825Smh27603 		DPRINTF(D_ERROR,
2275cff7825Smh27603 		    ("%s: %sppm.conf has a mismatched number of %s and %s\n",
2285cff7825Smh27603 		    str, ppm_prefix, devdata.name, domdata.name));
2295cff7825Smh27603 		return (ppm_attach_err(cdata, DDI_FAILURE));
2305cff7825Smh27603 	}
2315cff7825Smh27603 
2325cff7825Smh27603 	/*
2335cff7825Smh27603 	 * loop through device/domain pairs and build
2345cff7825Smh27603 	 * a linked list of devices within known domains
2355cff7825Smh27603 	 */
2365cff7825Smh27603 	for (dev_namep = devdata.strings, dom_namep = domdata.strings;
2375cff7825Smh27603 	    *dev_namep; dev_namep++, dom_namep++) {
2385cff7825Smh27603 		domp = ppm_lookup_domain(*dom_namep);
2395cff7825Smh27603 		if (domp == NULL) {
2405cff7825Smh27603 			DPRINTF(D_ERROR, ("%s: invalid domain \"%s\" for "
2415cff7825Smh27603 			    "device \"%s\"\n", str, *dom_namep, *dev_namep));
2425cff7825Smh27603 			return (ppm_attach_err(cdata, DDI_FAILURE));
2435cff7825Smh27603 		}
2445cff7825Smh27603 
2455cff7825Smh27603 		/*
2465cff7825Smh27603 		 * allocate a new ppm db entry and link it to
2475cff7825Smh27603 		 * the front of conflist within this domain
2485cff7825Smh27603 		 */
2495cff7825Smh27603 		new = kmem_zalloc(sizeof (*new), KM_SLEEP);
2505cff7825Smh27603 		new->name = kmem_zalloc(strlen(*dev_namep) + 1, KM_SLEEP);
2515cff7825Smh27603 		(void) strcpy(new->name, *dev_namep);
2525cff7825Smh27603 		new->next = domp->conflist;
2535cff7825Smh27603 		domp->conflist = new;
2545cff7825Smh27603 
2555cff7825Smh27603 		/*
2565cff7825Smh27603 		 * when the device name contains a wildcard,
2575cff7825Smh27603 		 * save the length of the preceding string
2585cff7825Smh27603 		 */
2595cff7825Smh27603 		if (wild = strchr(new->name, '*'))
2605cff7825Smh27603 			new->plen = (wild - new->name);
2615cff7825Smh27603 		DPRINTF(D_CREATEDB, ("%s: \"%s\", added \"%s\"\n",
2625cff7825Smh27603 		    str, domp->name, new->name));
2635cff7825Smh27603 	}
2645cff7825Smh27603 
2655cff7825Smh27603 	return (ppm_attach_err(cdata, DDI_SUCCESS));
2665cff7825Smh27603 }
2675cff7825Smh27603 
2685cff7825Smh27603 
2695cff7825Smh27603 /*
2705cff7825Smh27603  * scan conf devices within each domain for a matching device name
2715cff7825Smh27603  */
2725cff7825Smh27603 ppm_domain_t *
ppm_lookup_dev(dev_info_t * dip)2735cff7825Smh27603 ppm_lookup_dev(dev_info_t *dip)
2745cff7825Smh27603 {
2755cff7825Smh27603 	char path[MAXNAMELEN];
2765cff7825Smh27603 	ppm_domain_t **dompp;
2775cff7825Smh27603 	ppm_db_t *dbp;
2785cff7825Smh27603 
2795cff7825Smh27603 	(void) ddi_pathname(dip, path);
2805cff7825Smh27603 	for (dompp = ppm_domains; *dompp; dompp++) {
2815cff7825Smh27603 		for (dbp = (*dompp)->conflist; dbp; dbp = dbp->next) {
2825cff7825Smh27603 			if (dbp->plen == 0) {
2835cff7825Smh27603 				if (strcmp(path, dbp->name) == 0)
2845cff7825Smh27603 					return (*dompp);
2855cff7825Smh27603 			} else if (strncmp(path, dbp->name, dbp->plen) == 0)
2865cff7825Smh27603 				return (*dompp);
2875cff7825Smh27603 		}
2885cff7825Smh27603 	}
2895cff7825Smh27603 
2905cff7825Smh27603 	return (NULL);
2915cff7825Smh27603 }
2925cff7825Smh27603 
2935cff7825Smh27603 
2945cff7825Smh27603 /*
2955cff7825Smh27603  * returns 1 (claimed), 0 (not claimed)
2965cff7825Smh27603  */
2975cff7825Smh27603 int
ppm_claim_dev(dev_info_t * dip)2985cff7825Smh27603 ppm_claim_dev(dev_info_t *dip)
2995cff7825Smh27603 {
3005cff7825Smh27603 	ppm_domain_t *domp;
3015cff7825Smh27603 
3025cff7825Smh27603 	domp = ppm_lookup_dev(dip);
3035cff7825Smh27603 
3045cff7825Smh27603 #ifdef DEBUG
3055cff7825Smh27603 	if (domp) {
3065cff7825Smh27603 		char path[MAXNAMELEN];
3075cff7825Smh27603 		DPRINTF(D_CLAIMDEV,
3085cff7825Smh27603 		    ("ppm_claim_dev: \"%s\", matched \"%s\"\n",
3095cff7825Smh27603 		    domp->name, ddi_pathname(dip, path)));
3105cff7825Smh27603 	}
3115cff7825Smh27603 
3125cff7825Smh27603 #endif
3135cff7825Smh27603 
3145cff7825Smh27603 	return (domp != NULL);
3155cff7825Smh27603 }
3165cff7825Smh27603 
3175cff7825Smh27603 
3185cff7825Smh27603 /*
3195cff7825Smh27603  * create/init a new ppm device and link into the domain
3205cff7825Smh27603  */
3215cff7825Smh27603 ppm_dev_t *
ppm_add_dev(dev_info_t * dip,ppm_domain_t * domp)3225cff7825Smh27603 ppm_add_dev(dev_info_t *dip, ppm_domain_t *domp)
3235cff7825Smh27603 {
3245cff7825Smh27603 	char path[MAXNAMELEN];
3255cff7825Smh27603 	ppm_dev_t *new = NULL;
3265cff7825Smh27603 	int cmpt;
3275cff7825Smh27603 
3285cff7825Smh27603 	ASSERT(MUTEX_HELD(&domp->lock));
3295cff7825Smh27603 	(void) ddi_pathname(dip, path);
3305cff7825Smh27603 	/*
3315cff7825Smh27603 	 * For devs which have exported "pm-components" we want to create
3325cff7825Smh27603 	 * a data structure for each component.  When a driver chooses not
3335cff7825Smh27603 	 * to export the prop we treat its device as having a single
3345cff7825Smh27603 	 * component and build a structure for it anyway.  All other ppm
3355cff7825Smh27603 	 * logic will act as if this device were always up and can thus
3365cff7825Smh27603 	 * make correct decisions about it in relation to other devices
3375cff7825Smh27603 	 * in its domain.
3385cff7825Smh27603 	 */
3395cff7825Smh27603 	for (cmpt = PM_GET_PM_INFO(dip) ? PM_NUMCMPTS(dip) : 1; cmpt--; ) {
3405cff7825Smh27603 		new = kmem_zalloc(sizeof (*new), KM_SLEEP);
3415cff7825Smh27603 		new->path = kmem_zalloc(strlen(path) + 1, KM_SLEEP);
3425cff7825Smh27603 		(void) strcpy(new->path, path);
3435cff7825Smh27603 		new->domp = domp;
3445cff7825Smh27603 		new->dip = dip;
3455cff7825Smh27603 		new->cmpt = cmpt;
3465cff7825Smh27603 		if (ppmf.dev_init)
3475cff7825Smh27603 			(*ppmf.dev_init)(new);
3485cff7825Smh27603 		new->next = domp->devlist;
3495cff7825Smh27603 		domp->devlist = new;
3505cff7825Smh27603 		DPRINTF(D_ADDDEV,
3515cff7825Smh27603 		    ("ppm_add_dev: \"%s\", \"%s\", ppm_dev 0x%p\n",
352*07d06da5SSurya Prakki 		    new->path, domp->name, (void *)new));
3535cff7825Smh27603 	}
3545cff7825Smh27603 
3555cff7825Smh27603 	ASSERT(new != NULL);
3565cff7825Smh27603 	/*
3575cff7825Smh27603 	 * devi_pm_ppm_private should be set only after all
3585cff7825Smh27603 	 * ppm_dev s related to all components have been
3595cff7825Smh27603 	 * initialized and domain's pwr_cnt is incremented
3605cff7825Smh27603 	 * for each of them.
3615cff7825Smh27603 	 */
3625cff7825Smh27603 	PPM_SET_PRIVATE(dip, new);
3635cff7825Smh27603 
3645cff7825Smh27603 	return (new);
3655cff7825Smh27603 }
3665cff7825Smh27603 
3675cff7825Smh27603 
3685cff7825Smh27603 /*
3695cff7825Smh27603  * returns an existing or newly created ppm device reference
3705cff7825Smh27603  */
3715cff7825Smh27603 ppm_dev_t *
ppm_get_dev(dev_info_t * dip,ppm_domain_t * domp)3725cff7825Smh27603 ppm_get_dev(dev_info_t *dip, ppm_domain_t *domp)
3735cff7825Smh27603 {
3745cff7825Smh27603 	ppm_dev_t *pdp;
3755cff7825Smh27603 
3765cff7825Smh27603 	mutex_enter(&domp->lock);
3775cff7825Smh27603 	pdp = PPM_GET_PRIVATE(dip);
3785cff7825Smh27603 	if (pdp == NULL)
3795cff7825Smh27603 		pdp = ppm_add_dev(dip, domp);
3805cff7825Smh27603 	mutex_exit(&domp->lock);
3815cff7825Smh27603 
3825cff7825Smh27603 	return (pdp);
3835cff7825Smh27603 }
3845cff7825Smh27603 
3855cff7825Smh27603 
3865cff7825Smh27603 /*
3875cff7825Smh27603  * scan a domain's device list and remove those with .dip
3885cff7825Smh27603  * matching the arg *dip; we need to scan the entire list
3895cff7825Smh27603  * for the case of devices with multiple components
3905cff7825Smh27603  */
3915cff7825Smh27603 void
ppm_rem_dev(dev_info_t * dip)3925cff7825Smh27603 ppm_rem_dev(dev_info_t *dip)
3935cff7825Smh27603 {
3945cff7825Smh27603 	ppm_dev_t *pdp, **devpp;
3955cff7825Smh27603 	ppm_domain_t *domp;
3965cff7825Smh27603 
3975cff7825Smh27603 	pdp = PPM_GET_PRIVATE(dip);
3985cff7825Smh27603 	ASSERT(pdp);
3995cff7825Smh27603 	domp = pdp->domp;
4005cff7825Smh27603 	ASSERT(domp);
4015cff7825Smh27603 
4025cff7825Smh27603 	mutex_enter(&domp->lock);
4035cff7825Smh27603 	for (devpp = &domp->devlist; (pdp = *devpp) != NULL; ) {
4045cff7825Smh27603 		if (pdp->dip != dip) {
4055cff7825Smh27603 			devpp = &pdp->next;
4065cff7825Smh27603 			continue;
4075cff7825Smh27603 		}
4085cff7825Smh27603 
4095cff7825Smh27603 		DPRINTF(D_REMDEV, ("ppm_rem_dev: path \"%s\", ppm_dev 0x%p\n",
410*07d06da5SSurya Prakki 		    pdp->path, (void *)pdp));
4115cff7825Smh27603 
4125cff7825Smh27603 		PPM_SET_PRIVATE(dip, NULL);
4135cff7825Smh27603 		*devpp = pdp->next;
4145cff7825Smh27603 		if (ppmf.dev_fini)
4155cff7825Smh27603 			(*ppmf.dev_fini)(pdp);
4165cff7825Smh27603 		kmem_free(pdp->path, strlen(pdp->path) + 1);
4175cff7825Smh27603 		kmem_free(pdp, sizeof (*pdp));
4185cff7825Smh27603 	}
4195cff7825Smh27603 	mutex_exit(&domp->lock);
4205cff7825Smh27603 }
4215cff7825Smh27603 
4225cff7825Smh27603 
4235cff7825Smh27603 /* ARGSUSED */
4245cff7825Smh27603 int
ppm_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)4255cff7825Smh27603 ppm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
4265cff7825Smh27603     cred_t *cred_p, int *rval_p)
4275cff7825Smh27603 {
4285cff7825Smh27603 #ifdef DEBUG
4295cff7825Smh27603 	char *str = "ppm_ioctl";
4305cff7825Smh27603 	char *rwfmt = "%s: mode error: 0x%x is missing %s perm, cmd 0x%x\n";
4315cff7825Smh27603 	char *iofmt = "%s: copy%s error, arg 0x%p\n";
4325cff7825Smh27603 #endif
4335cff7825Smh27603 	ppmreq_t req;
4345cff7825Smh27603 	uint8_t level;
4355cff7825Smh27603 
4365cff7825Smh27603 	DPRINTF(D_IOCTL, ("%s: dev 0x%lx, cmd 0x%x, arg 0x%lx, mode 0x%x\n",
4375cff7825Smh27603 	    str, dev, cmd, arg, mode));
4385cff7825Smh27603 
4395cff7825Smh27603 	if (ddi_copyin((caddr_t)arg, &req, sizeof (req), mode)) {
4405cff7825Smh27603 		DPRINTF(D_IOCTL, (iofmt, str, "in", arg));
4415cff7825Smh27603 		return (EFAULT);
4425cff7825Smh27603 	}
4435cff7825Smh27603 
4445cff7825Smh27603 	/*
4455cff7825Smh27603 	 * Currently, only PPM_INTERNAL_DEVICE_POWER device type is supported
4465cff7825Smh27603 	 */
4475cff7825Smh27603 	if (req.ppmdev != PPM_INTERNAL_DEVICE_POWER) {
4485cff7825Smh27603 		DPRINTF(D_IOCTL, ("%s: unrecognized device type %d\n",
4495cff7825Smh27603 		    str, req.ppmdev));
4505cff7825Smh27603 		return (EINVAL);
4515cff7825Smh27603 	}
4525cff7825Smh27603 
4535cff7825Smh27603 	switch (cmd) {
4545cff7825Smh27603 	case PPMIOCSET:
4555cff7825Smh27603 		if (secpolicy_power_mgmt(cred_p) != 0) {
4565cff7825Smh27603 			DPRINTF(D_IOCTL, ("%s: bad cred for cmd 0x%x\n",
4575cff7825Smh27603 			    str, cmd));
4585cff7825Smh27603 			return (EPERM);
4595cff7825Smh27603 		} else if (!(mode & FWRITE)) {
4605cff7825Smh27603 			DPRINTF(D_IOCTL, (rwfmt, str, mode, "write"));
4615cff7825Smh27603 			return (EPERM);
4625cff7825Smh27603 		}
4635cff7825Smh27603 
4645cff7825Smh27603 		level = req.ppmop.idev_power.level;
4655cff7825Smh27603 		if ((level != PPM_IDEV_POWER_ON) &&
4665cff7825Smh27603 		    (level != PPM_IDEV_POWER_OFF)) {
4675cff7825Smh27603 			DPRINTF(D_IOCTL,
4685cff7825Smh27603 			    ("%s: invalid power level %d, cmd 0x%x\n",
4695cff7825Smh27603 			    str, level, cmd));
4705cff7825Smh27603 			return (EINVAL);
4715cff7825Smh27603 		}
4725cff7825Smh27603 		if (ppmf.iocset == NULL)
4735cff7825Smh27603 			return (ENOTSUP);
4745cff7825Smh27603 		(*ppmf.iocset)(level);
4755cff7825Smh27603 		break;
4765cff7825Smh27603 
4775cff7825Smh27603 	case PPMIOCGET:
4785cff7825Smh27603 		if (!(mode & FREAD)) {
4795cff7825Smh27603 			DPRINTF(D_IOCTL, (rwfmt, str, mode, "read"));
4805cff7825Smh27603 			return (EPERM);
4815cff7825Smh27603 		}
4825cff7825Smh27603 
4835cff7825Smh27603 		if (ppmf.iocget == NULL)
4845cff7825Smh27603 			return (ENOTSUP);
4855cff7825Smh27603 		req.ppmop.idev_power.level = (*ppmf.iocget)();
4865cff7825Smh27603 		if (ddi_copyout((const void *)&req, (void *)arg,
4875cff7825Smh27603 		    sizeof (req), mode)) {
4885cff7825Smh27603 			DPRINTF(D_ERROR, (iofmt, str, "out", arg));
4895cff7825Smh27603 			return (EFAULT);
4905cff7825Smh27603 		}
4915cff7825Smh27603 		break;
4925cff7825Smh27603 
4935cff7825Smh27603 	default:
4945cff7825Smh27603 		DPRINTF(D_IOCTL, ("%s: unrecognized cmd 0x%x\n", str, cmd));
4955cff7825Smh27603 		return (EINVAL);
4965cff7825Smh27603 	}
4975cff7825Smh27603 
4985cff7825Smh27603 	return (0);
4995cff7825Smh27603 }
5005cff7825Smh27603 
5015cff7825Smh27603 
5025cff7825Smh27603 #ifdef DEBUG
5035cff7825Smh27603 #define	FLINTSTR(flags, sym) { flags, sym, #sym }
5045cff7825Smh27603 #define	PMR_UNKNOWN -1
5055cff7825Smh27603 /*
5065cff7825Smh27603  * convert a ctlop integer to a char string.  this helps printing
5075cff7825Smh27603  * meaningful info when cltops are received from the pm framework.
5085cff7825Smh27603  * since some ctlops are so frequent, we use mask to limit output:
5095cff7825Smh27603  * a valid string is returned when ctlop is found and when
5105cff7825Smh27603  * (cmd.flags & mask) is true; otherwise NULL is returned.
5115cff7825Smh27603  */
5125cff7825Smh27603 char *
ppm_get_ctlstr(int ctlop,uint_t mask)5135cff7825Smh27603 ppm_get_ctlstr(int ctlop, uint_t mask)
5145cff7825Smh27603 {
5155cff7825Smh27603 	struct ctlop_cmd {
5165cff7825Smh27603 		uint_t flags;
5175cff7825Smh27603 		int ctlop;
5185cff7825Smh27603 		char *str;
5195cff7825Smh27603 	};
5205cff7825Smh27603 
5215cff7825Smh27603 	struct ctlop_cmd *ccp;
5225cff7825Smh27603 	static struct ctlop_cmd cmds[] = {
5235cff7825Smh27603 		FLINTSTR(D_SETPWR, PMR_SET_POWER),
5245cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_SUSPEND),
5255cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_RESUME),
5265cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PRE_SET_POWER),
5275cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_POST_SET_POWER),
5285cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PPM_SET_POWER),
5295cff7825Smh27603 		FLINTSTR(0, PMR_PPM_ATTACH),
5305cff7825Smh27603 		FLINTSTR(0, PMR_PPM_DETACH),
5315cff7825Smh27603 		FLINTSTR(D_CTLOPS1, PMR_PPM_POWER_CHANGE_NOTIFY),
5325cff7825Smh27603 		FLINTSTR(D_CTLOPS1, PMR_REPORT_PMCAP),
5335cff7825Smh27603 		FLINTSTR(D_CTLOPS1, PMR_CHANGED_POWER),
5345cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_PROBE),
5355cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PPM_POST_PROBE),
5365cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_ATTACH),
5375cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PPM_POST_ATTACH),
5385cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_DETACH),
5395cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PPM_POST_DETACH),
5405cff7825Smh27603 		FLINTSTR(D_CTLOPS1, PMR_PPM_UNMANAGE),
5415cff7825Smh27603 		FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_RESUME),
5425cff7825Smh27603 		FLINTSTR(D_CTLOPS1, PMR_PPM_ALL_LOWEST),
5435cff7825Smh27603 		FLINTSTR(D_LOCKS, PMR_PPM_LOCK_POWER),
5445cff7825Smh27603 		FLINTSTR(D_LOCKS, PMR_PPM_UNLOCK_POWER),
5455cff7825Smh27603 		FLINTSTR(D_LOCKS, PMR_PPM_TRY_LOCK_POWER),
5465cff7825Smh27603 		FLINTSTR(D_CTLOPS1 | D_CTLOPS2, PMR_UNKNOWN),
5475cff7825Smh27603 	};
5485cff7825Smh27603 
5495cff7825Smh27603 	for (ccp = cmds; ccp->ctlop != PMR_UNKNOWN; ccp++)
5505cff7825Smh27603 		if (ctlop == ccp->ctlop)
5515cff7825Smh27603 			break;
5525cff7825Smh27603 
5535cff7825Smh27603 	if (ccp->flags & mask)
5545cff7825Smh27603 		return (ccp->str);
5555cff7825Smh27603 	return (NULL);
5565cff7825Smh27603 }
5575cff7825Smh27603 #endif
558