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 /* 22*9387SSree.Vemuri@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 233530Srb144127 * Use is subject to license terms. 243530Srb144127 */ 253530Srb144127 263530Srb144127 273530Srb144127 /* 283530Srb144127 * sun4v domain services PRI driver 293530Srb144127 */ 303530Srb144127 313530Srb144127 #include <sys/types.h> 323530Srb144127 #include <sys/file.h> 333530Srb144127 #include <sys/errno.h> 343530Srb144127 #include <sys/open.h> 353530Srb144127 #include <sys/cred.h> 363530Srb144127 #include <sys/uio.h> 373530Srb144127 #include <sys/stat.h> 383530Srb144127 #include <sys/ksynch.h> 393530Srb144127 #include <sys/modctl.h> 403530Srb144127 #include <sys/conf.h> 413530Srb144127 #include <sys/devops.h> 423530Srb144127 #include <sys/debug.h> 433530Srb144127 #include <sys/cmn_err.h> 443530Srb144127 #include <sys/ddi.h> 453530Srb144127 #include <sys/sunddi.h> 463530Srb144127 #include <sys/ds.h> 473530Srb144127 483530Srb144127 #include <sys/ds_pri.h> 493530Srb144127 503530Srb144127 static uint_t ds_pri_debug = 0; 513530Srb144127 #define DS_PRI_DBG if (ds_pri_debug) printf 523530Srb144127 533530Srb144127 #define DS_PRI_NAME "ds_pri" 543530Srb144127 553530Srb144127 #define TEST_HARNESS 563530Srb144127 #ifdef TEST_HARNESS 573530Srb144127 #define DS_PRI_MAX_PRI_SIZE (64 * 1024) 583530Srb144127 593530Srb144127 #define DSIOC_TEST_REG 97 603530Srb144127 #define DSIOC_TEST_UNREG 98 613530Srb144127 #define DSIOC_TEST_DATA 99 623530Srb144127 633530Srb144127 struct ds_pri_test_data { 643530Srb144127 size_t size; 653530Srb144127 void *data; 663530Srb144127 }; 673530Srb144127 683530Srb144127 struct ds_pri_test_data32 { 693530Srb144127 size32_t size; 703530Srb144127 caddr32_t data; 713530Srb144127 }; 723530Srb144127 #endif /* TEST_HARNESS */ 733530Srb144127 743530Srb144127 typedef enum { 753530Srb144127 DS_PRI_REQUEST = 0, 763530Srb144127 DS_PRI_DATA = 1, 773530Srb144127 DS_PRI_UPDATE = 2 783530Srb144127 } ds_pri_msg_type_t; 793530Srb144127 803530Srb144127 typedef struct { 813530Srb144127 struct { 823530Srb144127 uint64_t seq_num; 833530Srb144127 uint64_t type; 843530Srb144127 } hdr; 853530Srb144127 uint8_t data[1]; 863530Srb144127 } ds_pri_msg_t; 873530Srb144127 883530Srb144127 /* The following are bit field flags */ 893530Srb144127 /* No service implies no PRI and no outstanding request */ 903530Srb144127 typedef enum { 913530Srb144127 DS_PRI_NO_SERVICE = 0x0, 923530Srb144127 DS_PRI_HAS_SERVICE = 0x1, 933530Srb144127 DS_PRI_REQUESTED = 0x2, 943530Srb144127 DS_PRI_HAS_PRI = 0x4 953530Srb144127 } ds_pri_flags_t; 963530Srb144127 973530Srb144127 struct ds_pri_state { 983530Srb144127 dev_info_t *dip; 993530Srb144127 int instance; 1003530Srb144127 1013530Srb144127 kmutex_t lock; 1023530Srb144127 kcondvar_t cv; 1033530Srb144127 1043530Srb144127 /* PRI/DS */ 1053530Srb144127 ds_pri_flags_t state; 1063530Srb144127 uint64_t gencount; 1073530Srb144127 ds_svc_hdl_t ds_pri_handle; 1083530Srb144127 void *ds_pri; 1093530Srb144127 size_t ds_pri_len; 1103530Srb144127 uint64_t req_id; 1113530Srb144127 uint64_t last_req_id; 1123941Svenki int num_opens; 1133530Srb144127 }; 1143530Srb144127 1153530Srb144127 typedef struct ds_pri_state ds_pri_state_t; 1163530Srb144127 1173530Srb144127 static void *ds_pri_statep; 1183530Srb144127 1193530Srb144127 static void request_pri(ds_pri_state_t *sp); 1203530Srb144127 1213530Srb144127 static int ds_pri_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 1223530Srb144127 static int ds_pri_attach(dev_info_t *, ddi_attach_cmd_t); 1233530Srb144127 static int ds_pri_detach(dev_info_t *, ddi_detach_cmd_t); 1243530Srb144127 static int ds_pri_open(dev_t *, int, int, cred_t *); 1253530Srb144127 static int ds_pri_close(dev_t, int, int, cred_t *); 1263530Srb144127 static int ds_pri_read(dev_t, struct uio *, cred_t *); 1273530Srb144127 static int ds_pri_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 1283530Srb144127 1293530Srb144127 /* 1303530Srb144127 * DS Callbacks 1313530Srb144127 */ 1323530Srb144127 static void ds_pri_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t); 1333530Srb144127 static void ds_pri_unreg_handler(ds_cb_arg_t arg); 1343530Srb144127 static void ds_pri_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen); 1353530Srb144127 1363530Srb144127 /* 1373530Srb144127 * PRI DS capability registration 1383530Srb144127 */ 1393530Srb144127 1403530Srb144127 static ds_ver_t ds_pri_ver_1_0 = { 1, 0 }; 1413530Srb144127 1423530Srb144127 static ds_capability_t ds_pri_cap = { 1433530Srb144127 "pri", 1443530Srb144127 &ds_pri_ver_1_0, 1453530Srb144127 1 1463530Srb144127 }; 1473530Srb144127 1483530Srb144127 /* 1493530Srb144127 * PRI DS Client callback vector 1503530Srb144127 */ 1513530Srb144127 static ds_clnt_ops_t ds_pri_ops = { 1523530Srb144127 ds_pri_reg_handler, /* ds_reg_cb */ 1533530Srb144127 ds_pri_unreg_handler, /* ds_unreg_cb */ 1543530Srb144127 ds_pri_data_handler, /* ds_data_cb */ 1553530Srb144127 NULL /* cb_arg */ 1563530Srb144127 }; 1573530Srb144127 1583530Srb144127 /* 1593530Srb144127 * DS PRI driver Ops Vector 1603530Srb144127 */ 1613530Srb144127 static struct cb_ops ds_pri_cb_ops = { 1623530Srb144127 ds_pri_open, /* cb_open */ 1633530Srb144127 ds_pri_close, /* cb_close */ 1643530Srb144127 nodev, /* cb_strategy */ 1653530Srb144127 nodev, /* cb_print */ 1663530Srb144127 nodev, /* cb_dump */ 1673530Srb144127 ds_pri_read, /* cb_read */ 1683530Srb144127 nodev, /* cb_write */ 1693530Srb144127 ds_pri_ioctl, /* cb_ioctl */ 1703530Srb144127 nodev, /* cb_devmap */ 1713530Srb144127 nodev, /* cb_mmap */ 1723530Srb144127 nodev, /* cb_segmap */ 1733530Srb144127 nochpoll, /* cb_chpoll */ 1743530Srb144127 ddi_prop_op, /* cb_prop_op */ 1753530Srb144127 (struct streamtab *)NULL, /* cb_str */ 1763530Srb144127 D_MP | D_64BIT, /* cb_flag */ 1773530Srb144127 CB_REV, /* cb_rev */ 1783530Srb144127 nodev, /* cb_aread */ 1793530Srb144127 nodev /* cb_awrite */ 1803530Srb144127 }; 1813530Srb144127 1823530Srb144127 static struct dev_ops ds_pri_dev_ops = { 1833530Srb144127 DEVO_REV, /* devo_rev */ 1843530Srb144127 0, /* devo_refcnt */ 1853530Srb144127 ds_pri_getinfo, /* devo_getinfo */ 1863530Srb144127 nulldev, /* devo_identify */ 1873530Srb144127 nulldev, /* devo_probe */ 1883530Srb144127 ds_pri_attach, /* devo_attach */ 1893530Srb144127 ds_pri_detach, /* devo_detach */ 1903530Srb144127 nodev, /* devo_reset */ 1913530Srb144127 &ds_pri_cb_ops, /* devo_cb_ops */ 1923530Srb144127 (struct bus_ops *)NULL, /* devo_bus_ops */ 1937656SSherry.Moore@Sun.COM nulldev, /* devo_power */ 1947656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* devo_quiesce */ 1953530Srb144127 }; 1963530Srb144127 1973530Srb144127 static struct modldrv modldrv = { 1983530Srb144127 &mod_driverops, 1997656SSherry.Moore@Sun.COM "Domain Services PRI Driver", 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, 3154407Snarayan 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 3844407Snarayan ds_pri_ops.cb_arg = NULL; 3854407Snarayan 3863530Srb144127 ddi_remove_minor_node(dip, NULL); 3873530Srb144127 cv_destroy(&sp->cv); 3883530Srb144127 mutex_destroy(&sp->lock); 3893530Srb144127 ddi_soft_state_free(ds_pri_statep, instance); 3903530Srb144127 3913530Srb144127 return (DDI_SUCCESS); 3923530Srb144127 } 3933530Srb144127 3943530Srb144127 3953530Srb144127 /*ARGSUSED*/ 3963530Srb144127 static int 3973530Srb144127 ds_pri_open(dev_t *devp, int flag, int otyp, cred_t *credp) 3983530Srb144127 { 3993530Srb144127 ds_pri_state_t *sp; 4003530Srb144127 int instance; 4013530Srb144127 4023530Srb144127 if (otyp != OTYP_CHR) 4033530Srb144127 return (EINVAL); 4043530Srb144127 4053530Srb144127 instance = getminor(*devp); 4063530Srb144127 sp = ddi_get_soft_state(ds_pri_statep, instance); 4073530Srb144127 if (sp == NULL) 4083530Srb144127 return (ENXIO); 4093530Srb144127 4103941Svenki mutex_enter(&sp->lock); 4113941Svenki 4123941Svenki /* 4133941Svenki * If we're here and the state is DS_PRI_NO_SERVICE then this 4143941Svenki * means that ds hasn't yet called the registration callback. 4154109Skellena * A while loop is necessary as we might have been woken up 4164109Skellena * prematurely, e.g., due to a debugger or "pstack" etc. 4173941Svenki * Wait here and the callback will signal us when it has completed 4183941Svenki * its work. 4193941Svenki */ 4204109Skellena while (sp->state == DS_PRI_NO_SERVICE) { 4213941Svenki if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 4223941Svenki mutex_exit(&sp->lock); 4233941Svenki return (EINTR); 4243941Svenki } 4253941Svenki } 4263941Svenki 4273941Svenki sp->num_opens++; 4283941Svenki mutex_exit(&sp->lock); 4293941Svenki 4303530Srb144127 /* 4313530Srb144127 * On open we dont fetch the PRI even if we have a valid service 4323530Srb144127 * handle. PRI fetch is essentially lazy and on-demand. 4333530Srb144127 */ 4343530Srb144127 4353530Srb144127 DS_PRI_DBG("ds_pri_open: state = 0x%x\n", sp->state); 4363530Srb144127 4373530Srb144127 return (0); 4383530Srb144127 } 4393530Srb144127 4403530Srb144127 4413530Srb144127 /*ARGSUSED*/ 4423530Srb144127 static int 4433530Srb144127 ds_pri_close(dev_t dev, int flag, int otyp, cred_t *credp) 4443530Srb144127 { 4453530Srb144127 int instance; 4463941Svenki ds_pri_state_t *sp; 4473530Srb144127 4483530Srb144127 if (otyp != OTYP_CHR) 4493530Srb144127 return (EINVAL); 4503530Srb144127 4513530Srb144127 DS_PRI_DBG("ds_pri_close\n"); 4523530Srb144127 4533530Srb144127 instance = getminor(dev); 4543941Svenki if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 4553530Srb144127 return (ENXIO); 4563530Srb144127 4573941Svenki mutex_enter(&sp->lock); 4583941Svenki if (!(sp->state & DS_PRI_HAS_SERVICE)) { 4593941Svenki mutex_exit(&sp->lock); 4603941Svenki return (0); 4613941Svenki } 4623941Svenki 4633941Svenki if (--sp->num_opens > 0) { 4643941Svenki mutex_exit(&sp->lock); 4653941Svenki return (0); 4663941Svenki } 4673941Svenki 4683941Svenki /* If we have an old PRI - remove it */ 4693941Svenki if (sp->state & DS_PRI_HAS_PRI) { 4703941Svenki if (sp->ds_pri != NULL && sp->ds_pri_len > 0) { 4713941Svenki /* 4723941Svenki * remove the old data if we have an 4733941Svenki * outstanding request 4743941Svenki */ 4753941Svenki kmem_free(sp->ds_pri, sp->ds_pri_len); 4763941Svenki sp->ds_pri_len = 0; 4773941Svenki sp->ds_pri = NULL; 4783941Svenki } 4793941Svenki sp->state &= ~DS_PRI_HAS_PRI; 4803941Svenki } 4813941Svenki sp->state &= ~DS_PRI_REQUESTED; 4823941Svenki mutex_exit(&sp->lock); 4833530Srb144127 return (0); 4843530Srb144127 } 4853530Srb144127 4863530Srb144127 4873530Srb144127 /*ARGSUSED*/ 4883530Srb144127 static int 4893530Srb144127 ds_pri_read(dev_t dev, struct uio *uiop, cred_t *credp) 4903530Srb144127 { 4913530Srb144127 ds_pri_state_t *sp; 4923530Srb144127 int instance; 4933530Srb144127 size_t len; 4943530Srb144127 int retval; 4953530Srb144127 caddr_t tmpbufp; 496*9387SSree.Vemuri@Sun.COM offset_t off = uiop->uio_offset; 4973530Srb144127 4983530Srb144127 instance = getminor(dev); 4993530Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 5003530Srb144127 return (ENXIO); 5013530Srb144127 5023530Srb144127 len = uiop->uio_resid; 5033530Srb144127 5043530Srb144127 if (len == 0) 5053530Srb144127 return (0); 5063530Srb144127 5073530Srb144127 mutex_enter(&sp->lock); 5083530Srb144127 5093530Srb144127 DS_PRI_DBG("ds_pri_read: state = 0x%x\n", sp->state); 5103530Srb144127 5113530Srb144127 /* block or bail if there is no current PRI */ 5123530Srb144127 if (!(sp->state & DS_PRI_HAS_PRI)) { 5133530Srb144127 DS_PRI_DBG("ds_pri_read: no PRI held\n"); 5143530Srb144127 5153530Srb144127 if (uiop->uio_fmode & (FNDELAY | FNONBLOCK)) { 5163530Srb144127 mutex_exit(&sp->lock); 5173530Srb144127 return (EAGAIN); 5183530Srb144127 } 5193530Srb144127 5203530Srb144127 while (!(sp->state & DS_PRI_HAS_PRI)) { 5213530Srb144127 DS_PRI_DBG("ds_pri_read: state = 0x%x\n", sp->state); 5223530Srb144127 request_pri(sp); 5233530Srb144127 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 5243530Srb144127 mutex_exit(&sp->lock); 5253530Srb144127 return (EINTR); 5263530Srb144127 } 5273530Srb144127 } 5283530Srb144127 } 5293530Srb144127 530*9387SSree.Vemuri@Sun.COM if (len > sp->ds_pri_len) 531*9387SSree.Vemuri@Sun.COM len = sp->ds_pri_len; 5323530Srb144127 5333530Srb144127 if (len == 0) { 5343530Srb144127 mutex_exit(&sp->lock); 5353530Srb144127 return (0); 5363530Srb144127 } 5373530Srb144127 5383530Srb144127 /* 5393530Srb144127 * We're supposed to move the data out to userland, but 5403530Srb144127 * that can suspend because of page faults etc., and meanwhile 5413530Srb144127 * other parts of this driver want to update the PRI buffer ... 5423530Srb144127 * we could hold the data buffer locked with a flag etc., 5433530Srb144127 * but that's still a lock ... a simpler mechanism - if not quite 5443530Srb144127 * as performance efficient is to simply clone here the part of 5453530Srb144127 * the buffer we care about and then the original can be released 5463530Srb144127 * for further updates while the uiomove continues. 5473530Srb144127 */ 5483530Srb144127 5493530Srb144127 tmpbufp = kmem_alloc(len, KM_SLEEP); 550*9387SSree.Vemuri@Sun.COM bcopy(((caddr_t)sp->ds_pri), tmpbufp, len); 5513530Srb144127 mutex_exit(&sp->lock); 5523530Srb144127 5533530Srb144127 retval = uiomove(tmpbufp, len, UIO_READ, uiop); 5543530Srb144127 5553530Srb144127 kmem_free(tmpbufp, len); 5563530Srb144127 557*9387SSree.Vemuri@Sun.COM /* 558*9387SSree.Vemuri@Sun.COM * restore uio_offset after uiomove since the driver 559*9387SSree.Vemuri@Sun.COM * does not support the concept of position. 560*9387SSree.Vemuri@Sun.COM */ 561*9387SSree.Vemuri@Sun.COM uiop->uio_offset = off; 562*9387SSree.Vemuri@Sun.COM 5633530Srb144127 return (retval); 5643530Srb144127 } 5653530Srb144127 5663530Srb144127 5673530Srb144127 /*ARGSUSED*/ 5683530Srb144127 static int 5693530Srb144127 ds_pri_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 5703530Srb144127 int *rvalp) 5713530Srb144127 { 5723530Srb144127 ds_pri_state_t *sp; 5733530Srb144127 int instance; 5743530Srb144127 5753530Srb144127 instance = getminor(dev); 5763530Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 5773530Srb144127 return (ENXIO); 5783530Srb144127 5793530Srb144127 switch (cmd) { 5803530Srb144127 case DSPRI_GETINFO: { 5813530Srb144127 struct dspri_info info; 5823530Srb144127 5833530Srb144127 if (!(mode & FREAD)) 5843530Srb144127 return (EACCES); 5853530Srb144127 5863530Srb144127 /* 5873530Srb144127 * We are not guaranteed that ddi_copyout(9F) will read 5883530Srb144127 * atomically anything larger than a byte. Therefore we 5893530Srb144127 * must duplicate the size before copying it out to the user. 5903530Srb144127 */ 5913530Srb144127 mutex_enter(&sp->lock); 5923530Srb144127 5933530Srb144127 loop:; 5943530Srb144127 if (sp->state & DS_PRI_HAS_PRI) { 5953530Srb144127 /* If we have a PRI simply return the info */ 5963530Srb144127 info.size = sp->ds_pri_len; 5973530Srb144127 info.token = sp->gencount; 5983530Srb144127 } else 5993530Srb144127 if (!(sp->state & DS_PRI_HAS_SERVICE)) { 6003530Srb144127 /* If we have no service return a nil response */ 6013530Srb144127 info.size = 0; 6023530Srb144127 info.token = 0; 6033530Srb144127 } else { 6043530Srb144127 request_pri(sp); 6053530Srb144127 /* wait for something & check again */ 6063530Srb144127 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 6073530Srb144127 mutex_exit(&sp->lock); 6083530Srb144127 return (EINTR); 6093530Srb144127 } 6103530Srb144127 goto loop; 6113530Srb144127 } 6123530Srb144127 DS_PRI_DBG("ds_pri_ioctl: DSPRI_GETINFO sz=0x%lx tok=0x%lx\n", 6134407Snarayan info.size, info.token); 6143530Srb144127 mutex_exit(&sp->lock); 6153530Srb144127 6163530Srb144127 if (ddi_copyout(&info, (void *)arg, sizeof (info), mode) != 0) 6173530Srb144127 return (EFAULT); 6183530Srb144127 break; 6193530Srb144127 } 6203530Srb144127 6213530Srb144127 case DSPRI_WAIT: { 6223530Srb144127 uint64_t gencount; 6233530Srb144127 6243530Srb144127 if (ddi_copyin((void *)arg, &gencount, sizeof (gencount), 6253530Srb144127 mode) != 0) 6263530Srb144127 return (EFAULT); 6273530Srb144127 6283530Srb144127 mutex_enter(&sp->lock); 6293530Srb144127 6303530Srb144127 DS_PRI_DBG("ds_pri_ioctl: DSPRI_WAIT gen=0x%lx sp->gen=0x%lx\n", 6314407Snarayan gencount, sp->gencount); 6323530Srb144127 6333530Srb144127 while ((sp->state & DS_PRI_HAS_PRI) == 0 || 6344407Snarayan gencount == sp->gencount) { 6354109Skellena if ((sp->state & DS_PRI_HAS_PRI) == 0) 6364109Skellena request_pri(sp); 6373530Srb144127 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 6383530Srb144127 mutex_exit(&sp->lock); 6393530Srb144127 return (EINTR); 6403530Srb144127 } 6413530Srb144127 } 6423530Srb144127 mutex_exit(&sp->lock); 6433530Srb144127 break; 6443530Srb144127 } 6453530Srb144127 6463530Srb144127 default: 6473530Srb144127 return (ENOTTY); 6483530Srb144127 } 6493530Srb144127 return (0); 6503530Srb144127 } 6513530Srb144127 6523530Srb144127 6533530Srb144127 /* assumes sp->lock is held when called */ 6543530Srb144127 static void 6553530Srb144127 request_pri(ds_pri_state_t *sp) 6563530Srb144127 { 6573530Srb144127 ds_pri_msg_t reqmsg; 6583530Srb144127 6593530Srb144127 ASSERT(MUTEX_HELD(&sp->lock)); 6603530Srb144127 6613530Srb144127 /* If a request is already pending we're done */ 6623530Srb144127 if (!(sp->state & DS_PRI_HAS_SERVICE)) 6633530Srb144127 return; 6643530Srb144127 if (sp->state & DS_PRI_REQUESTED) 6653530Srb144127 return; 6663530Srb144127 6673530Srb144127 /* If we have an old PRI - remove it */ 6683530Srb144127 if (sp->state & DS_PRI_HAS_PRI) { 6693530Srb144127 ASSERT(sp->ds_pri_len != 0); 6703530Srb144127 ASSERT(sp->ds_pri != NULL); 6713530Srb144127 6723530Srb144127 /* remove the old data if we have an outstanding request */ 6733530Srb144127 kmem_free(sp->ds_pri, sp->ds_pri_len); 6743530Srb144127 sp->ds_pri_len = 0; 6753530Srb144127 sp->ds_pri = NULL; 6763530Srb144127 sp->state &= ~DS_PRI_HAS_PRI; 6773530Srb144127 } else { 6783530Srb144127 ASSERT(sp->ds_pri == NULL); 6793530Srb144127 ASSERT(sp->ds_pri_len == 0); 6803530Srb144127 } 6813530Srb144127 6823530Srb144127 reqmsg.hdr.seq_num = ++(sp->req_id); 6833530Srb144127 reqmsg.hdr.type = DS_PRI_REQUEST; 6843530Srb144127 6853530Srb144127 DS_PRI_DBG("request_pri: request id 0x%lx\n", sp->req_id); 6863530Srb144127 6873530Srb144127 /* 6883530Srb144127 * Request consists of header only. 6893530Srb144127 * We don't care about fail status for ds_send; 6903530Srb144127 * if it does fail we will get an unregister callback 6913530Srb144127 * from the DS framework and we handle the state change 6923530Srb144127 * there. 6933530Srb144127 */ 6943530Srb144127 (void) ds_cap_send(sp->ds_pri_handle, &reqmsg, sizeof (reqmsg.hdr)); 6953530Srb144127 6963530Srb144127 sp->state |= DS_PRI_REQUESTED; 6973530Srb144127 sp->last_req_id = sp->req_id; 6983530Srb144127 } 6993530Srb144127 7003530Srb144127 /* 7013530Srb144127 * DS Callbacks 7023530Srb144127 */ 7033530Srb144127 /*ARGSUSED*/ 7043530Srb144127 static void 7053530Srb144127 ds_pri_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl) 7063530Srb144127 { 7073530Srb144127 dev_info_t *dip = arg; 7083530Srb144127 ds_pri_state_t *sp; 7093530Srb144127 int instance; 7103530Srb144127 7113530Srb144127 instance = ddi_get_instance(dip); 7123530Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 7133530Srb144127 return; 7143530Srb144127 7153530Srb144127 DS_PRI_DBG("ds_pri_reg_handler: registering handle 0x%lx for version " 7164407Snarayan "0x%x:0x%x\n", (uint64_t)hdl, ver->major, ver->minor); 7173530Srb144127 7183530Srb144127 /* When the domain service comes up automatically req the pri */ 7193530Srb144127 mutex_enter(&sp->lock); 7203530Srb144127 7213530Srb144127 ASSERT(sp->ds_pri_handle == DS_INVALID_HDL); 7223530Srb144127 sp->ds_pri_handle = hdl; 7233530Srb144127 7243530Srb144127 ASSERT(sp->state == DS_PRI_NO_SERVICE); 7253530Srb144127 ASSERT(sp->ds_pri == NULL); 7263530Srb144127 ASSERT(sp->ds_pri_len == 0); 7273530Srb144127 7283530Srb144127 /* have service, but no PRI */ 7293530Srb144127 sp->state |= DS_PRI_HAS_SERVICE; 7303530Srb144127 7313941Svenki /* 7323941Svenki * Cannot request a PRI here, because the reg handler cannot 7333941Svenki * do a DS send operation - we take care of this later. 7343941Svenki */ 7353941Svenki 7363941Svenki /* Wake up anyone waiting in open() */ 7373941Svenki cv_broadcast(&sp->cv); 7383941Svenki 7393530Srb144127 mutex_exit(&sp->lock); 7403530Srb144127 } 7413530Srb144127 7423530Srb144127 7433530Srb144127 static void 7443530Srb144127 ds_pri_unreg_handler(ds_cb_arg_t arg) 7453530Srb144127 { 7463530Srb144127 dev_info_t *dip = arg; 7473530Srb144127 ds_pri_state_t *sp; 7483530Srb144127 int instance; 7493530Srb144127 7503530Srb144127 instance = ddi_get_instance(dip); 7513530Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 7523530Srb144127 return; 7533530Srb144127 7543530Srb144127 DS_PRI_DBG("ds_pri_unreg_handler: un-registering ds_pri service\n"); 7553530Srb144127 7563530Srb144127 mutex_enter(&sp->lock); 7573530Srb144127 7583530Srb144127 /* Once the service goes - if we have a PRI at hand free it up */ 7593530Srb144127 if (sp->ds_pri_len != 0) { 7603530Srb144127 kmem_free(sp->ds_pri, sp->ds_pri_len); 7613530Srb144127 sp->ds_pri_len = 0; 7623530Srb144127 sp->ds_pri = NULL; 7633530Srb144127 } 7643530Srb144127 sp->ds_pri_handle = DS_INVALID_HDL; 7653530Srb144127 sp->state = DS_PRI_NO_SERVICE; 7663530Srb144127 7673530Srb144127 mutex_exit(&sp->lock); 7683530Srb144127 } 7693530Srb144127 7703530Srb144127 7713530Srb144127 static void 7723530Srb144127 ds_pri_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) 7733530Srb144127 { 7743530Srb144127 dev_info_t *dip = arg; 7753530Srb144127 ds_pri_state_t *sp; 7763530Srb144127 int instance; 7773530Srb144127 void *data; 7783530Srb144127 ds_pri_msg_t *msgp; 7793530Srb144127 size_t pri_size; 7803530Srb144127 7813530Srb144127 msgp = (ds_pri_msg_t *)buf; 7823530Srb144127 7833530Srb144127 /* make sure the header is at least valid */ 7843530Srb144127 if (buflen < sizeof (msgp->hdr)) 7853530Srb144127 return; 7863530Srb144127 7873530Srb144127 DS_PRI_DBG("ds_pri_data_handler: msg buf len 0x%lx : type 0x%lx, " 7884407Snarayan "seqn 0x%lx\n", buflen, msgp->hdr.type, msgp->hdr.seq_num); 7893530Srb144127 7903530Srb144127 instance = ddi_get_instance(dip); 7913530Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 7923530Srb144127 return; 7933530Srb144127 7943530Srb144127 mutex_enter(&sp->lock); 7953530Srb144127 7963530Srb144127 ASSERT(sp->state & DS_PRI_HAS_SERVICE); 7973530Srb144127 7983530Srb144127 switch (msgp->hdr.type) { 7993530Srb144127 case DS_PRI_DATA: /* in response to a request from us */ 8003530Srb144127 break; 8013530Srb144127 case DS_PRI_UPDATE: /* aynch notification */ 8023530Srb144127 /* our default response to this is to request the PRI */ 8033530Srb144127 /* simply issue a request for the new PRI */ 8043530Srb144127 request_pri(sp); 8053530Srb144127 goto done; 8063530Srb144127 default: /* ignore garbage or unknown message types */ 8073530Srb144127 goto done; 8083530Srb144127 } 8093530Srb144127 8103530Srb144127 /* 8113530Srb144127 * If there is no pending PRI request, then we've received a 8123530Srb144127 * bogus data message ... so ignore it. 8133530Srb144127 */ 8143530Srb144127 8153530Srb144127 if (!(sp->state & DS_PRI_REQUESTED)) { 8163530Srb144127 cmn_err(CE_WARN, "Received DS pri data without request"); 8173530Srb144127 goto done; 8183530Srb144127 } 8193530Srb144127 8203530Srb144127 /* response to a request therefore old PRI must be gone */ 8213530Srb144127 ASSERT(!(sp->state & DS_PRI_HAS_PRI)); 8223530Srb144127 ASSERT(sp->ds_pri_len == 0); 8233530Srb144127 ASSERT(sp->ds_pri == NULL); 8243530Srb144127 8253530Srb144127 /* response seq_num should match our request seq_num */ 8263530Srb144127 if (msgp->hdr.seq_num != sp->last_req_id) { 8273530Srb144127 cmn_err(CE_WARN, "Received DS pri data out of sequence with " 8284407Snarayan "request"); 8293530Srb144127 goto done; 8303530Srb144127 } 8313530Srb144127 8323530Srb144127 pri_size = buflen - sizeof (msgp->hdr); 8333530Srb144127 data = kmem_alloc(pri_size, KM_SLEEP); 8343530Srb144127 sp->ds_pri = data; 8353530Srb144127 sp->ds_pri_len = pri_size; 8363530Srb144127 bcopy(msgp->data, data, sp->ds_pri_len); 8373530Srb144127 sp->state &= ~DS_PRI_REQUESTED; 8383530Srb144127 sp->state |= DS_PRI_HAS_PRI; 8393530Srb144127 8403530Srb144127 sp->gencount++; 8413530Srb144127 cv_broadcast(&sp->cv); 8423530Srb144127 8433530Srb144127 done:; 8443530Srb144127 mutex_exit(&sp->lock); 8453530Srb144127 } 846