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 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 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 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 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 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 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 * 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 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 * 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 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 * 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 * 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 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 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 * 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