13530Srb144127 /* 23530Srb144127 * CDDL HEADER START 33530Srb144127 * 43530Srb144127 * The contents of this file are subject to the terms of the 53530Srb144127 * Common Development and Distribution License (the "License"). 63530Srb144127 * You may not use this file except in compliance with the License. 73530Srb144127 * 83530Srb144127 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93530Srb144127 * or http://www.opensolaris.org/os/licensing. 103530Srb144127 * See the License for the specific language governing permissions 113530Srb144127 * and limitations under the License. 123530Srb144127 * 133530Srb144127 * When distributing Covered Code, include this CDDL HEADER in each 143530Srb144127 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153530Srb144127 * If applicable, add the following below this CDDL HEADER, with the 163530Srb144127 * fields enclosed by brackets "[]" replaced with your own identifying 173530Srb144127 * information: Portions Copyright [yyyy] [name of copyright owner] 183530Srb144127 * 193530Srb144127 * CDDL HEADER END 203530Srb144127 */ 213530Srb144127 /* 223530Srb144127 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 233530Srb144127 * Use is subject to license terms. 243530Srb144127 */ 253530Srb144127 263530Srb144127 #pragma ident "%Z%%M% %I% %E% SMI" 273530Srb144127 283530Srb144127 /* 293530Srb144127 * sun4v domain services PRI driver 303530Srb144127 */ 313530Srb144127 323530Srb144127 #include <sys/types.h> 333530Srb144127 #include <sys/file.h> 343530Srb144127 #include <sys/errno.h> 353530Srb144127 #include <sys/open.h> 363530Srb144127 #include <sys/cred.h> 373530Srb144127 #include <sys/uio.h> 383530Srb144127 #include <sys/stat.h> 393530Srb144127 #include <sys/ksynch.h> 403530Srb144127 #include <sys/modctl.h> 413530Srb144127 #include <sys/conf.h> 423530Srb144127 #include <sys/devops.h> 433530Srb144127 #include <sys/debug.h> 443530Srb144127 #include <sys/cmn_err.h> 453530Srb144127 #include <sys/ddi.h> 463530Srb144127 #include <sys/sunddi.h> 473530Srb144127 #include <sys/ds.h> 483530Srb144127 493530Srb144127 #include <sys/ds_pri.h> 503530Srb144127 513530Srb144127 static uint_t ds_pri_debug = 0; 523530Srb144127 #define DS_PRI_DBG if (ds_pri_debug) printf 533530Srb144127 543530Srb144127 #define DS_PRI_NAME "ds_pri" 553530Srb144127 563530Srb144127 #define TEST_HARNESS 573530Srb144127 #ifdef TEST_HARNESS 583530Srb144127 #define DS_PRI_MAX_PRI_SIZE (64 * 1024) 593530Srb144127 603530Srb144127 #define DSIOC_TEST_REG 97 613530Srb144127 #define DSIOC_TEST_UNREG 98 623530Srb144127 #define DSIOC_TEST_DATA 99 633530Srb144127 643530Srb144127 struct ds_pri_test_data { 653530Srb144127 size_t size; 663530Srb144127 void *data; 673530Srb144127 }; 683530Srb144127 693530Srb144127 struct ds_pri_test_data32 { 703530Srb144127 size32_t size; 713530Srb144127 caddr32_t data; 723530Srb144127 }; 733530Srb144127 #endif /* TEST_HARNESS */ 743530Srb144127 753530Srb144127 typedef enum { 763530Srb144127 DS_PRI_REQUEST = 0, 773530Srb144127 DS_PRI_DATA = 1, 783530Srb144127 DS_PRI_UPDATE = 2 793530Srb144127 } ds_pri_msg_type_t; 803530Srb144127 813530Srb144127 typedef struct { 823530Srb144127 struct { 833530Srb144127 uint64_t seq_num; 843530Srb144127 uint64_t type; 853530Srb144127 } hdr; 863530Srb144127 uint8_t data[1]; 873530Srb144127 } ds_pri_msg_t; 883530Srb144127 893530Srb144127 /* The following are bit field flags */ 903530Srb144127 /* No service implies no PRI and no outstanding request */ 913530Srb144127 typedef enum { 923530Srb144127 DS_PRI_NO_SERVICE = 0x0, 933530Srb144127 DS_PRI_HAS_SERVICE = 0x1, 943530Srb144127 DS_PRI_REQUESTED = 0x2, 953530Srb144127 DS_PRI_HAS_PRI = 0x4 963530Srb144127 } ds_pri_flags_t; 973530Srb144127 983530Srb144127 struct ds_pri_state { 993530Srb144127 dev_info_t *dip; 1003530Srb144127 int instance; 1013530Srb144127 1023530Srb144127 kmutex_t lock; 1033530Srb144127 kcondvar_t cv; 1043530Srb144127 1053530Srb144127 /* PRI/DS */ 1063530Srb144127 ds_pri_flags_t state; 1073530Srb144127 uint64_t gencount; 1083530Srb144127 ds_svc_hdl_t ds_pri_handle; 1093530Srb144127 void *ds_pri; 1103530Srb144127 size_t ds_pri_len; 1113530Srb144127 uint64_t req_id; 1123530Srb144127 uint64_t last_req_id; 1133941Svenki int num_opens; 1143530Srb144127 }; 1153530Srb144127 1163530Srb144127 typedef struct ds_pri_state ds_pri_state_t; 1173530Srb144127 1183530Srb144127 static void *ds_pri_statep; 1193530Srb144127 1203530Srb144127 static void request_pri(ds_pri_state_t *sp); 1213530Srb144127 1223530Srb144127 static int ds_pri_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 1233530Srb144127 static int ds_pri_attach(dev_info_t *, ddi_attach_cmd_t); 1243530Srb144127 static int ds_pri_detach(dev_info_t *, ddi_detach_cmd_t); 1253530Srb144127 static int ds_pri_open(dev_t *, int, int, cred_t *); 1263530Srb144127 static int ds_pri_close(dev_t, int, int, cred_t *); 1273530Srb144127 static int ds_pri_read(dev_t, struct uio *, cred_t *); 1283530Srb144127 static int ds_pri_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 1293530Srb144127 1303530Srb144127 /* 1313530Srb144127 * DS Callbacks 1323530Srb144127 */ 1333530Srb144127 static void ds_pri_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t); 1343530Srb144127 static void ds_pri_unreg_handler(ds_cb_arg_t arg); 1353530Srb144127 static void ds_pri_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen); 1363530Srb144127 1373530Srb144127 /* 1383530Srb144127 * PRI DS capability registration 1393530Srb144127 */ 1403530Srb144127 1413530Srb144127 static ds_ver_t ds_pri_ver_1_0 = { 1, 0 }; 1423530Srb144127 1433530Srb144127 static ds_capability_t ds_pri_cap = { 1443530Srb144127 "pri", 1453530Srb144127 &ds_pri_ver_1_0, 1463530Srb144127 1 1473530Srb144127 }; 1483530Srb144127 1493530Srb144127 /* 1503530Srb144127 * PRI DS Client callback vector 1513530Srb144127 */ 1523530Srb144127 static ds_clnt_ops_t ds_pri_ops = { 1533530Srb144127 ds_pri_reg_handler, /* ds_reg_cb */ 1543530Srb144127 ds_pri_unreg_handler, /* ds_unreg_cb */ 1553530Srb144127 ds_pri_data_handler, /* ds_data_cb */ 1563530Srb144127 NULL /* cb_arg */ 1573530Srb144127 }; 1583530Srb144127 1593530Srb144127 /* 1603530Srb144127 * DS PRI driver Ops Vector 1613530Srb144127 */ 1623530Srb144127 static struct cb_ops ds_pri_cb_ops = { 1633530Srb144127 ds_pri_open, /* cb_open */ 1643530Srb144127 ds_pri_close, /* cb_close */ 1653530Srb144127 nodev, /* cb_strategy */ 1663530Srb144127 nodev, /* cb_print */ 1673530Srb144127 nodev, /* cb_dump */ 1683530Srb144127 ds_pri_read, /* cb_read */ 1693530Srb144127 nodev, /* cb_write */ 1703530Srb144127 ds_pri_ioctl, /* cb_ioctl */ 1713530Srb144127 nodev, /* cb_devmap */ 1723530Srb144127 nodev, /* cb_mmap */ 1733530Srb144127 nodev, /* cb_segmap */ 1743530Srb144127 nochpoll, /* cb_chpoll */ 1753530Srb144127 ddi_prop_op, /* cb_prop_op */ 1763530Srb144127 (struct streamtab *)NULL, /* cb_str */ 1773530Srb144127 D_MP | D_64BIT, /* cb_flag */ 1783530Srb144127 CB_REV, /* cb_rev */ 1793530Srb144127 nodev, /* cb_aread */ 1803530Srb144127 nodev /* cb_awrite */ 1813530Srb144127 }; 1823530Srb144127 1833530Srb144127 static struct dev_ops ds_pri_dev_ops = { 1843530Srb144127 DEVO_REV, /* devo_rev */ 1853530Srb144127 0, /* devo_refcnt */ 1863530Srb144127 ds_pri_getinfo, /* devo_getinfo */ 1873530Srb144127 nulldev, /* devo_identify */ 1883530Srb144127 nulldev, /* devo_probe */ 1893530Srb144127 ds_pri_attach, /* devo_attach */ 1903530Srb144127 ds_pri_detach, /* devo_detach */ 1913530Srb144127 nodev, /* devo_reset */ 1923530Srb144127 &ds_pri_cb_ops, /* devo_cb_ops */ 1933530Srb144127 (struct bus_ops *)NULL, /* devo_bus_ops */ 1943530Srb144127 nulldev /* devo_power */ 1953530Srb144127 }; 1963530Srb144127 1973530Srb144127 static struct modldrv modldrv = { 1983530Srb144127 &mod_driverops, 1993530Srb144127 "Domain Services PRI Driver 1.0", 2003530Srb144127 &ds_pri_dev_ops 2013530Srb144127 }; 2023530Srb144127 2033530Srb144127 static struct modlinkage modlinkage = { 2043530Srb144127 MODREV_1, 2053530Srb144127 (void *)&modldrv, 2063530Srb144127 NULL 2073530Srb144127 }; 2083530Srb144127 2093530Srb144127 2103530Srb144127 int 2113530Srb144127 _init(void) 2123530Srb144127 { 2133530Srb144127 int retval; 2143530Srb144127 2153530Srb144127 retval = ddi_soft_state_init(&ds_pri_statep, 2163530Srb144127 sizeof (ds_pri_state_t), 0); 2173530Srb144127 if (retval != 0) 2183530Srb144127 return (retval); 2193530Srb144127 2203530Srb144127 retval = mod_install(&modlinkage); 2213530Srb144127 if (retval != 0) { 2223530Srb144127 ddi_soft_state_fini(&ds_pri_statep); 2233530Srb144127 return (retval); 2243530Srb144127 } 2253530Srb144127 2263530Srb144127 return (retval); 2273530Srb144127 } 2283530Srb144127 2293530Srb144127 2303530Srb144127 int 2313530Srb144127 _info(struct modinfo *modinfop) 2323530Srb144127 { 2333530Srb144127 return (mod_info(&modlinkage, modinfop)); 2343530Srb144127 } 2353530Srb144127 2363530Srb144127 2373530Srb144127 int 2383530Srb144127 _fini(void) 2393530Srb144127 { 2403530Srb144127 int retval; 2413530Srb144127 2423530Srb144127 if ((retval = mod_remove(&modlinkage)) != 0) 2433530Srb144127 return (retval); 2443530Srb144127 2453530Srb144127 ddi_soft_state_fini(&ds_pri_statep); 2463530Srb144127 2473530Srb144127 return (retval); 2483530Srb144127 } 2493530Srb144127 2503530Srb144127 2513530Srb144127 /*ARGSUSED*/ 2523530Srb144127 static int 2533530Srb144127 ds_pri_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 2543530Srb144127 { 2553530Srb144127 ds_pri_state_t *sp; 2563530Srb144127 int retval = DDI_FAILURE; 2573530Srb144127 2583530Srb144127 ASSERT(resultp != NULL); 2593530Srb144127 2603530Srb144127 switch (cmd) { 2613530Srb144127 case DDI_INFO_DEVT2DEVINFO: 2623530Srb144127 sp = ddi_get_soft_state(ds_pri_statep, getminor((dev_t)arg)); 2633530Srb144127 if (sp != NULL) { 2643530Srb144127 *resultp = sp->dip; 2653530Srb144127 retval = DDI_SUCCESS; 2663530Srb144127 } else 2673530Srb144127 *resultp = NULL; 2683530Srb144127 break; 2693530Srb144127 2703530Srb144127 case DDI_INFO_DEVT2INSTANCE: 2713530Srb144127 *resultp = (void *)(uintptr_t)getminor((dev_t)arg); 2723530Srb144127 retval = DDI_SUCCESS; 2733530Srb144127 break; 2743530Srb144127 2753530Srb144127 default: 2763530Srb144127 break; 2773530Srb144127 } 2783530Srb144127 2793530Srb144127 return (retval); 2803530Srb144127 } 2813530Srb144127 2823530Srb144127 2833530Srb144127 static int 2843530Srb144127 ds_pri_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2853530Srb144127 { 2863530Srb144127 int instance; 2873530Srb144127 ds_pri_state_t *sp; 2883530Srb144127 int rv; 2893530Srb144127 2903530Srb144127 switch (cmd) { 2913530Srb144127 case DDI_ATTACH: 2923530Srb144127 break; 2933530Srb144127 2943530Srb144127 case DDI_RESUME: 2953530Srb144127 return (DDI_SUCCESS); 2963530Srb144127 2973530Srb144127 default: 2983530Srb144127 return (DDI_FAILURE); 2993530Srb144127 } 3003530Srb144127 3013530Srb144127 instance = ddi_get_instance(dip); 3023530Srb144127 3033530Srb144127 if (ddi_soft_state_zalloc(ds_pri_statep, instance) != 3043530Srb144127 DDI_SUCCESS) { 3053530Srb144127 cmn_err(CE_WARN, "%s@%d: Unable to allocate state", 3063530Srb144127 DS_PRI_NAME, instance); 3073530Srb144127 return (DDI_FAILURE); 3083530Srb144127 } 3093530Srb144127 sp = ddi_get_soft_state(ds_pri_statep, instance); 3103530Srb144127 3113530Srb144127 mutex_init(&sp->lock, NULL, MUTEX_DEFAULT, NULL); 3123530Srb144127 cv_init(&sp->cv, NULL, CV_DEFAULT, NULL); 3133530Srb144127 3143530Srb144127 if (ddi_create_minor_node(dip, DS_PRI_NAME, S_IFCHR, instance, 3153530Srb144127 DDI_PSEUDO, 0) != DDI_SUCCESS) { 3163530Srb144127 cmn_err(CE_WARN, "%s@%d: Unable to create minor node", 3173530Srb144127 DS_PRI_NAME, instance); 3183530Srb144127 goto fail; 3193530Srb144127 } 3203530Srb144127 3213530Srb144127 if (ds_pri_ops.cb_arg != NULL) 3223530Srb144127 goto fail; 3233530Srb144127 ds_pri_ops.cb_arg = dip; 3243530Srb144127 3253530Srb144127 sp->state = DS_PRI_NO_SERVICE; 3263530Srb144127 3273530Srb144127 /* Until the service registers the handle is invalid */ 3283530Srb144127 sp->ds_pri_handle = DS_INVALID_HDL; 3293530Srb144127 3303530Srb144127 sp->ds_pri = NULL; 3313530Srb144127 sp->ds_pri_len = 0; 3323530Srb144127 sp->req_id = 0; 3333941Svenki sp->num_opens = 0; 3343530Srb144127 3353530Srb144127 if ((rv = ds_cap_init(&ds_pri_cap, &ds_pri_ops)) != 0) { 3363530Srb144127 cmn_err(CE_NOTE, "ds_cap_init failed: %d", rv); 3373530Srb144127 goto fail; 3383530Srb144127 } 3393530Srb144127 3403530Srb144127 ddi_report_dev(dip); 3413530Srb144127 3423530Srb144127 return (DDI_SUCCESS); 3433530Srb144127 3443530Srb144127 fail: 3453530Srb144127 ddi_remove_minor_node(dip, NULL); 3463530Srb144127 cv_destroy(&sp->cv); 3473530Srb144127 mutex_destroy(&sp->lock); 3483530Srb144127 ddi_soft_state_free(ds_pri_statep, instance); 3493530Srb144127 return (DDI_FAILURE); 3503530Srb144127 3513530Srb144127 } 3523530Srb144127 3533530Srb144127 3543530Srb144127 /*ARGSUSED*/ 3553530Srb144127 static int 3563530Srb144127 ds_pri_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3573530Srb144127 { 3583530Srb144127 ds_pri_state_t *sp; 3593530Srb144127 int instance; 3603530Srb144127 int rv; 3613530Srb144127 3623530Srb144127 instance = ddi_get_instance(dip); 3633530Srb144127 sp = ddi_get_soft_state(ds_pri_statep, instance); 3643530Srb144127 3653530Srb144127 switch (cmd) { 3663530Srb144127 case DDI_DETACH: 3673530Srb144127 break; 3683530Srb144127 3693530Srb144127 case DDI_SUSPEND: 3703530Srb144127 return (DDI_SUCCESS); 3713530Srb144127 3723530Srb144127 default: 3733530Srb144127 return (DDI_FAILURE); 3743530Srb144127 } 3753530Srb144127 3763530Srb144127 /* This really shouldn't fail - but check anyway */ 3773530Srb144127 if ((rv = ds_cap_fini(&ds_pri_cap)) != 0) { 3783530Srb144127 cmn_err(CE_WARN, "ds_cap_fini failed: %d", rv); 3793530Srb144127 } 3803530Srb144127 3813530Srb144127 if (sp != NULL && sp->ds_pri_len != 0) 3823530Srb144127 kmem_free(sp->ds_pri, sp->ds_pri_len); 3833530Srb144127 3843530Srb144127 ddi_remove_minor_node(dip, NULL); 3853530Srb144127 cv_destroy(&sp->cv); 3863530Srb144127 mutex_destroy(&sp->lock); 3873530Srb144127 ddi_soft_state_free(ds_pri_statep, instance); 3883530Srb144127 3893530Srb144127 return (DDI_SUCCESS); 3903530Srb144127 } 3913530Srb144127 3923530Srb144127 3933530Srb144127 /*ARGSUSED*/ 3943530Srb144127 static int 3953530Srb144127 ds_pri_open(dev_t *devp, int flag, int otyp, cred_t *credp) 3963530Srb144127 { 3973530Srb144127 ds_pri_state_t *sp; 3983530Srb144127 int instance; 3993530Srb144127 4003530Srb144127 if (otyp != OTYP_CHR) 4013530Srb144127 return (EINVAL); 4023530Srb144127 4033530Srb144127 instance = getminor(*devp); 4043530Srb144127 sp = ddi_get_soft_state(ds_pri_statep, instance); 4053530Srb144127 if (sp == NULL) 4063530Srb144127 return (ENXIO); 4073530Srb144127 4083941Svenki mutex_enter(&sp->lock); 4093941Svenki 4103941Svenki /* 4113941Svenki * If we're here and the state is DS_PRI_NO_SERVICE then this 4123941Svenki * means that ds hasn't yet called the registration callback. 413*4109Skellena * A while loop is necessary as we might have been woken up 414*4109Skellena * prematurely, e.g., due to a debugger or "pstack" etc. 4153941Svenki * Wait here and the callback will signal us when it has completed 4163941Svenki * its work. 4173941Svenki */ 418*4109Skellena while (sp->state == DS_PRI_NO_SERVICE) { 4193941Svenki if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 4203941Svenki mutex_exit(&sp->lock); 4213941Svenki return (EINTR); 4223941Svenki } 4233941Svenki } 4243941Svenki 4253941Svenki sp->num_opens++; 4263941Svenki mutex_exit(&sp->lock); 4273941Svenki 4283530Srb144127 /* 4293530Srb144127 * On open we dont fetch the PRI even if we have a valid service 4303530Srb144127 * handle. PRI fetch is essentially lazy and on-demand. 4313530Srb144127 */ 4323530Srb144127 4333530Srb144127 DS_PRI_DBG("ds_pri_open: state = 0x%x\n", sp->state); 4343530Srb144127 4353530Srb144127 return (0); 4363530Srb144127 } 4373530Srb144127 4383530Srb144127 4393530Srb144127 /*ARGSUSED*/ 4403530Srb144127 static int 4413530Srb144127 ds_pri_close(dev_t dev, int flag, int otyp, cred_t *credp) 4423530Srb144127 { 4433530Srb144127 int instance; 4443941Svenki ds_pri_state_t *sp; 4453530Srb144127 4463530Srb144127 if (otyp != OTYP_CHR) 4473530Srb144127 return (EINVAL); 4483530Srb144127 4493530Srb144127 DS_PRI_DBG("ds_pri_close\n"); 4503530Srb144127 4513530Srb144127 instance = getminor(dev); 4523941Svenki if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 4533530Srb144127 return (ENXIO); 4543530Srb144127 4553941Svenki mutex_enter(&sp->lock); 4563941Svenki if (!(sp->state & DS_PRI_HAS_SERVICE)) { 4573941Svenki mutex_exit(&sp->lock); 4583941Svenki return (0); 4593941Svenki } 4603941Svenki 4613941Svenki if (--sp->num_opens > 0) { 4623941Svenki mutex_exit(&sp->lock); 4633941Svenki return (0); 4643941Svenki } 4653941Svenki 4663941Svenki /* If we have an old PRI - remove it */ 4673941Svenki if (sp->state & DS_PRI_HAS_PRI) { 4683941Svenki if (sp->ds_pri != NULL && sp->ds_pri_len > 0) { 4693941Svenki /* 4703941Svenki * remove the old data if we have an 4713941Svenki * outstanding request 4723941Svenki */ 4733941Svenki kmem_free(sp->ds_pri, sp->ds_pri_len); 4743941Svenki sp->ds_pri_len = 0; 4753941Svenki sp->ds_pri = NULL; 4763941Svenki } 4773941Svenki sp->state &= ~DS_PRI_HAS_PRI; 4783941Svenki } 4793941Svenki sp->state &= ~DS_PRI_REQUESTED; 4803941Svenki mutex_exit(&sp->lock); 4813530Srb144127 return (0); 4823530Srb144127 } 4833530Srb144127 4843530Srb144127 4853530Srb144127 /*ARGSUSED*/ 4863530Srb144127 static int 4873530Srb144127 ds_pri_read(dev_t dev, struct uio *uiop, cred_t *credp) 4883530Srb144127 { 4893530Srb144127 ds_pri_state_t *sp; 4903530Srb144127 int instance; 4913530Srb144127 size_t len; 4923530Srb144127 int retval; 4933530Srb144127 caddr_t tmpbufp; 4943530Srb144127 4953530Srb144127 instance = getminor(dev); 4963530Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 4973530Srb144127 return (ENXIO); 4983530Srb144127 4993530Srb144127 len = uiop->uio_resid; 5003530Srb144127 5013530Srb144127 if (len == 0) 5023530Srb144127 return (0); 5033530Srb144127 5043530Srb144127 mutex_enter(&sp->lock); 5053530Srb144127 5063530Srb144127 DS_PRI_DBG("ds_pri_read: state = 0x%x\n", sp->state); 5073530Srb144127 5083530Srb144127 /* block or bail if there is no current PRI */ 5093530Srb144127 if (!(sp->state & DS_PRI_HAS_PRI)) { 5103530Srb144127 DS_PRI_DBG("ds_pri_read: no PRI held\n"); 5113530Srb144127 5123530Srb144127 if (uiop->uio_fmode & (FNDELAY | FNONBLOCK)) { 5133530Srb144127 mutex_exit(&sp->lock); 5143530Srb144127 return (EAGAIN); 5153530Srb144127 } 5163530Srb144127 5173530Srb144127 while (!(sp->state & DS_PRI_HAS_PRI)) { 5183530Srb144127 DS_PRI_DBG("ds_pri_read: state = 0x%x\n", sp->state); 5193530Srb144127 request_pri(sp); 5203530Srb144127 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 5213530Srb144127 mutex_exit(&sp->lock); 5223530Srb144127 return (EINTR); 5233530Srb144127 } 5243530Srb144127 } 5253530Srb144127 } 5263530Srb144127 5273530Srb144127 if (uiop->uio_offset < 0 || uiop->uio_offset > sp->ds_pri_len) { 5283530Srb144127 mutex_exit(&sp->lock); 5293530Srb144127 return (EINVAL); 5303530Srb144127 } 5313530Srb144127 5323530Srb144127 if (len > (sp->ds_pri_len - uiop->uio_offset)) 5333530Srb144127 len = sp->ds_pri_len - uiop->uio_offset; 5343530Srb144127 5353530Srb144127 /* already checked that offset < ds_pri_len above */ 5363530Srb144127 if (len == 0) { 5373530Srb144127 mutex_exit(&sp->lock); 5383530Srb144127 return (0); 5393530Srb144127 } 5403530Srb144127 5413530Srb144127 /* 5423530Srb144127 * We're supposed to move the data out to userland, but 5433530Srb144127 * that can suspend because of page faults etc., and meanwhile 5443530Srb144127 * other parts of this driver want to update the PRI buffer ... 5453530Srb144127 * we could hold the data buffer locked with a flag etc., 5463530Srb144127 * but that's still a lock ... a simpler mechanism - if not quite 5473530Srb144127 * as performance efficient is to simply clone here the part of 5483530Srb144127 * the buffer we care about and then the original can be released 5493530Srb144127 * for further updates while the uiomove continues. 5503530Srb144127 */ 5513530Srb144127 5523530Srb144127 tmpbufp = kmem_alloc(len, KM_SLEEP); 5533530Srb144127 bcopy(((caddr_t)sp->ds_pri) + uiop->uio_offset, tmpbufp, len); 5543530Srb144127 mutex_exit(&sp->lock); 5553530Srb144127 5563530Srb144127 retval = uiomove(tmpbufp, len, UIO_READ, uiop); 5573530Srb144127 5583530Srb144127 kmem_free(tmpbufp, len); 5593530Srb144127 5603530Srb144127 return (retval); 5613530Srb144127 } 5623530Srb144127 5633530Srb144127 5643530Srb144127 /*ARGSUSED*/ 5653530Srb144127 static int 5663530Srb144127 ds_pri_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 5673530Srb144127 int *rvalp) 5683530Srb144127 { 5693530Srb144127 ds_pri_state_t *sp; 5703530Srb144127 int instance; 5713530Srb144127 5723530Srb144127 instance = getminor(dev); 5733530Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 5743530Srb144127 return (ENXIO); 5753530Srb144127 5763530Srb144127 switch (cmd) { 5773530Srb144127 case DSPRI_GETINFO: { 5783530Srb144127 struct dspri_info info; 5793530Srb144127 5803530Srb144127 if (!(mode & FREAD)) 5813530Srb144127 return (EACCES); 5823530Srb144127 5833530Srb144127 /* 5843530Srb144127 * We are not guaranteed that ddi_copyout(9F) will read 5853530Srb144127 * atomically anything larger than a byte. Therefore we 5863530Srb144127 * must duplicate the size before copying it out to the user. 5873530Srb144127 */ 5883530Srb144127 mutex_enter(&sp->lock); 5893530Srb144127 5903530Srb144127 loop:; 5913530Srb144127 if (sp->state & DS_PRI_HAS_PRI) { 5923530Srb144127 /* If we have a PRI simply return the info */ 5933530Srb144127 info.size = sp->ds_pri_len; 5943530Srb144127 info.token = sp->gencount; 5953530Srb144127 } else 5963530Srb144127 if (!(sp->state & DS_PRI_HAS_SERVICE)) { 5973530Srb144127 /* If we have no service return a nil response */ 5983530Srb144127 info.size = 0; 5993530Srb144127 info.token = 0; 6003530Srb144127 } else { 6013530Srb144127 request_pri(sp); 6023530Srb144127 /* wait for something & check again */ 6033530Srb144127 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 6043530Srb144127 mutex_exit(&sp->lock); 6053530Srb144127 return (EINTR); 6063530Srb144127 } 6073530Srb144127 goto loop; 6083530Srb144127 } 6093530Srb144127 DS_PRI_DBG("ds_pri_ioctl: DSPRI_GETINFO sz=0x%lx tok=0x%lx\n", 6103530Srb144127 info.size, info.token); 6113530Srb144127 mutex_exit(&sp->lock); 6123530Srb144127 6133530Srb144127 if (ddi_copyout(&info, (void *)arg, sizeof (info), mode) != 0) 6143530Srb144127 return (EFAULT); 6153530Srb144127 break; 6163530Srb144127 } 6173530Srb144127 6183530Srb144127 case DSPRI_WAIT: { 6193530Srb144127 uint64_t gencount; 6203530Srb144127 6213530Srb144127 if (ddi_copyin((void *)arg, &gencount, sizeof (gencount), 6223530Srb144127 mode) != 0) 6233530Srb144127 return (EFAULT); 6243530Srb144127 6253530Srb144127 mutex_enter(&sp->lock); 6263530Srb144127 6273530Srb144127 DS_PRI_DBG("ds_pri_ioctl: DSPRI_WAIT gen=0x%lx sp->gen=0x%lx\n", 6283530Srb144127 gencount, sp->gencount); 6293530Srb144127 6303530Srb144127 while ((sp->state & DS_PRI_HAS_PRI) == 0 || 6313530Srb144127 gencount == sp->gencount) { 632*4109Skellena if ((sp->state & DS_PRI_HAS_PRI) == 0) 633*4109Skellena request_pri(sp); 6343530Srb144127 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 6353530Srb144127 mutex_exit(&sp->lock); 6363530Srb144127 return (EINTR); 6373530Srb144127 } 6383530Srb144127 } 6393530Srb144127 mutex_exit(&sp->lock); 6403530Srb144127 break; 6413530Srb144127 } 6423530Srb144127 6433530Srb144127 default: 6443530Srb144127 return (ENOTTY); 6453530Srb144127 } 6463530Srb144127 return (0); 6473530Srb144127 } 6483530Srb144127 6493530Srb144127 6503530Srb144127 /* assumes sp->lock is held when called */ 6513530Srb144127 static void 6523530Srb144127 request_pri(ds_pri_state_t *sp) 6533530Srb144127 { 6543530Srb144127 ds_pri_msg_t reqmsg; 6553530Srb144127 6563530Srb144127 ASSERT(MUTEX_HELD(&sp->lock)); 6573530Srb144127 6583530Srb144127 /* If a request is already pending we're done */ 6593530Srb144127 if (!(sp->state & DS_PRI_HAS_SERVICE)) 6603530Srb144127 return; 6613530Srb144127 if (sp->state & DS_PRI_REQUESTED) 6623530Srb144127 return; 6633530Srb144127 6643530Srb144127 /* If we have an old PRI - remove it */ 6653530Srb144127 if (sp->state & DS_PRI_HAS_PRI) { 6663530Srb144127 ASSERT(sp->ds_pri_len != 0); 6673530Srb144127 ASSERT(sp->ds_pri != NULL); 6683530Srb144127 6693530Srb144127 /* remove the old data if we have an outstanding request */ 6703530Srb144127 kmem_free(sp->ds_pri, sp->ds_pri_len); 6713530Srb144127 sp->ds_pri_len = 0; 6723530Srb144127 sp->ds_pri = NULL; 6733530Srb144127 sp->state &= ~DS_PRI_HAS_PRI; 6743530Srb144127 } else { 6753530Srb144127 ASSERT(sp->ds_pri == NULL); 6763530Srb144127 ASSERT(sp->ds_pri_len == 0); 6773530Srb144127 } 6783530Srb144127 6793530Srb144127 reqmsg.hdr.seq_num = ++(sp->req_id); 6803530Srb144127 reqmsg.hdr.type = DS_PRI_REQUEST; 6813530Srb144127 6823530Srb144127 DS_PRI_DBG("request_pri: request id 0x%lx\n", sp->req_id); 6833530Srb144127 6843530Srb144127 /* 6853530Srb144127 * Request consists of header only. 6863530Srb144127 * We don't care about fail status for ds_send; 6873530Srb144127 * if it does fail we will get an unregister callback 6883530Srb144127 * from the DS framework and we handle the state change 6893530Srb144127 * there. 6903530Srb144127 */ 6913530Srb144127 (void) ds_cap_send(sp->ds_pri_handle, &reqmsg, sizeof (reqmsg.hdr)); 6923530Srb144127 6933530Srb144127 sp->state |= DS_PRI_REQUESTED; 6943530Srb144127 sp->last_req_id = sp->req_id; 6953530Srb144127 } 6963530Srb144127 6973530Srb144127 /* 6983530Srb144127 * DS Callbacks 6993530Srb144127 */ 7003530Srb144127 /*ARGSUSED*/ 7013530Srb144127 static void 7023530Srb144127 ds_pri_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl) 7033530Srb144127 { 7043530Srb144127 dev_info_t *dip = arg; 7053530Srb144127 ds_pri_state_t *sp; 7063530Srb144127 int instance; 7073530Srb144127 7083530Srb144127 instance = ddi_get_instance(dip); 7093530Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 7103530Srb144127 return; 7113530Srb144127 7123530Srb144127 DS_PRI_DBG("ds_pri_reg_handler: registering handle 0x%lx for version " 7133530Srb144127 "0x%x:0x%x\n", (uint64_t)hdl, ver->major, ver->minor); 7143530Srb144127 7153530Srb144127 /* When the domain service comes up automatically req the pri */ 7163530Srb144127 mutex_enter(&sp->lock); 7173530Srb144127 7183530Srb144127 ASSERT(sp->ds_pri_handle == DS_INVALID_HDL); 7193530Srb144127 sp->ds_pri_handle = hdl; 7203530Srb144127 7213530Srb144127 ASSERT(sp->state == DS_PRI_NO_SERVICE); 7223530Srb144127 ASSERT(sp->ds_pri == NULL); 7233530Srb144127 ASSERT(sp->ds_pri_len == 0); 7243530Srb144127 7253530Srb144127 /* have service, but no PRI */ 7263530Srb144127 sp->state |= DS_PRI_HAS_SERVICE; 7273530Srb144127 7283941Svenki /* 7293941Svenki * Cannot request a PRI here, because the reg handler cannot 7303941Svenki * do a DS send operation - we take care of this later. 7313941Svenki */ 7323941Svenki 7333941Svenki /* Wake up anyone waiting in open() */ 7343941Svenki cv_broadcast(&sp->cv); 7353941Svenki 7363530Srb144127 mutex_exit(&sp->lock); 7373530Srb144127 } 7383530Srb144127 7393530Srb144127 7403530Srb144127 static void 7413530Srb144127 ds_pri_unreg_handler(ds_cb_arg_t arg) 7423530Srb144127 { 7433530Srb144127 dev_info_t *dip = arg; 7443530Srb144127 ds_pri_state_t *sp; 7453530Srb144127 int instance; 7463530Srb144127 7473530Srb144127 instance = ddi_get_instance(dip); 7483530Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 7493530Srb144127 return; 7503530Srb144127 7513530Srb144127 DS_PRI_DBG("ds_pri_unreg_handler: un-registering ds_pri service\n"); 7523530Srb144127 7533530Srb144127 mutex_enter(&sp->lock); 7543530Srb144127 7553530Srb144127 /* Once the service goes - if we have a PRI at hand free it up */ 7563530Srb144127 if (sp->ds_pri_len != 0) { 7573530Srb144127 kmem_free(sp->ds_pri, sp->ds_pri_len); 7583530Srb144127 sp->ds_pri_len = 0; 7593530Srb144127 sp->ds_pri = NULL; 7603530Srb144127 } 7613530Srb144127 sp->ds_pri_handle = DS_INVALID_HDL; 7623530Srb144127 sp->state = DS_PRI_NO_SERVICE; 7633530Srb144127 7643530Srb144127 mutex_exit(&sp->lock); 7653530Srb144127 } 7663530Srb144127 7673530Srb144127 7683530Srb144127 static void 7693530Srb144127 ds_pri_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) 7703530Srb144127 { 7713530Srb144127 dev_info_t *dip = arg; 7723530Srb144127 ds_pri_state_t *sp; 7733530Srb144127 int instance; 7743530Srb144127 void *data; 7753530Srb144127 ds_pri_msg_t *msgp; 7763530Srb144127 size_t pri_size; 7773530Srb144127 7783530Srb144127 msgp = (ds_pri_msg_t *)buf; 7793530Srb144127 7803530Srb144127 /* make sure the header is at least valid */ 7813530Srb144127 if (buflen < sizeof (msgp->hdr)) 7823530Srb144127 return; 7833530Srb144127 7843530Srb144127 DS_PRI_DBG("ds_pri_data_handler: msg buf len 0x%lx : type 0x%lx, " 7853530Srb144127 "seqn 0x%lx\n", buflen, msgp->hdr.type, msgp->hdr.seq_num); 7863530Srb144127 7873530Srb144127 instance = ddi_get_instance(dip); 7883530Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 7893530Srb144127 return; 7903530Srb144127 7913530Srb144127 mutex_enter(&sp->lock); 7923530Srb144127 7933530Srb144127 ASSERT(sp->state & DS_PRI_HAS_SERVICE); 7943530Srb144127 7953530Srb144127 switch (msgp->hdr.type) { 7963530Srb144127 case DS_PRI_DATA: /* in response to a request from us */ 7973530Srb144127 break; 7983530Srb144127 case DS_PRI_UPDATE: /* aynch notification */ 7993530Srb144127 /* our default response to this is to request the PRI */ 8003530Srb144127 /* simply issue a request for the new PRI */ 8013530Srb144127 request_pri(sp); 8023530Srb144127 goto done; 8033530Srb144127 default: /* ignore garbage or unknown message types */ 8043530Srb144127 goto done; 8053530Srb144127 } 8063530Srb144127 8073530Srb144127 /* 8083530Srb144127 * If there is no pending PRI request, then we've received a 8093530Srb144127 * bogus data message ... so ignore it. 8103530Srb144127 */ 8113530Srb144127 8123530Srb144127 if (!(sp->state & DS_PRI_REQUESTED)) { 8133530Srb144127 cmn_err(CE_WARN, "Received DS pri data without request"); 8143530Srb144127 goto done; 8153530Srb144127 } 8163530Srb144127 8173530Srb144127 /* response to a request therefore old PRI must be gone */ 8183530Srb144127 ASSERT(!(sp->state & DS_PRI_HAS_PRI)); 8193530Srb144127 ASSERT(sp->ds_pri_len == 0); 8203530Srb144127 ASSERT(sp->ds_pri == NULL); 8213530Srb144127 8223530Srb144127 /* response seq_num should match our request seq_num */ 8233530Srb144127 if (msgp->hdr.seq_num != sp->last_req_id) { 8243530Srb144127 cmn_err(CE_WARN, "Received DS pri data out of sequence with " 8253530Srb144127 "request"); 8263530Srb144127 goto done; 8273530Srb144127 } 8283530Srb144127 8293530Srb144127 pri_size = buflen - sizeof (msgp->hdr); 8303530Srb144127 data = kmem_alloc(pri_size, KM_SLEEP); 8313530Srb144127 sp->ds_pri = data; 8323530Srb144127 sp->ds_pri_len = pri_size; 8333530Srb144127 bcopy(msgp->data, data, sp->ds_pri_len); 8343530Srb144127 sp->state &= ~DS_PRI_REQUESTED; 8353530Srb144127 sp->state |= DS_PRI_HAS_PRI; 8363530Srb144127 8373530Srb144127 sp->gencount++; 8383530Srb144127 cv_broadcast(&sp->cv); 8393530Srb144127 8403530Srb144127 done:; 8413530Srb144127 mutex_exit(&sp->lock); 8423530Srb144127 } 843