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*12209Ssree.lakshmi.vemuri@oracle.com * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
233530Srb144127 */
243530Srb144127
253530Srb144127 /*
263530Srb144127 * sun4v domain services PRI driver
273530Srb144127 */
283530Srb144127
293530Srb144127 #include <sys/types.h>
303530Srb144127 #include <sys/file.h>
313530Srb144127 #include <sys/errno.h>
323530Srb144127 #include <sys/open.h>
333530Srb144127 #include <sys/cred.h>
343530Srb144127 #include <sys/uio.h>
353530Srb144127 #include <sys/stat.h>
363530Srb144127 #include <sys/ksynch.h>
373530Srb144127 #include <sys/modctl.h>
383530Srb144127 #include <sys/conf.h>
393530Srb144127 #include <sys/devops.h>
403530Srb144127 #include <sys/debug.h>
413530Srb144127 #include <sys/cmn_err.h>
423530Srb144127 #include <sys/ddi.h>
433530Srb144127 #include <sys/sunddi.h>
443530Srb144127 #include <sys/ds.h>
4511304SJanie.Lu@Sun.COM #include <sys/hypervisor_api.h>
4611304SJanie.Lu@Sun.COM #include <sys/machsystm.h>
4711304SJanie.Lu@Sun.COM #include <sys/sysmacros.h>
4811304SJanie.Lu@Sun.COM #include <sys/hsvc.h>
4911304SJanie.Lu@Sun.COM #include <sys/bitmap.h>
503530Srb144127 #include <sys/ds_pri.h>
513530Srb144127
523530Srb144127 static uint_t ds_pri_debug = 0;
533530Srb144127 #define DS_PRI_DBG if (ds_pri_debug) printf
543530Srb144127
553530Srb144127 #define DS_PRI_NAME "ds_pri"
563530Srb144127
573530Srb144127 #define TEST_HARNESS
583530Srb144127 #ifdef TEST_HARNESS
593530Srb144127 #define DS_PRI_MAX_PRI_SIZE (64 * 1024)
603530Srb144127
613530Srb144127 #define DSIOC_TEST_REG 97
623530Srb144127 #define DSIOC_TEST_UNREG 98
633530Srb144127 #define DSIOC_TEST_DATA 99
643530Srb144127
653530Srb144127 struct ds_pri_test_data {
663530Srb144127 size_t size;
673530Srb144127 void *data;
683530Srb144127 };
693530Srb144127
703530Srb144127 struct ds_pri_test_data32 {
713530Srb144127 size32_t size;
723530Srb144127 caddr32_t data;
733530Srb144127 };
743530Srb144127 #endif /* TEST_HARNESS */
753530Srb144127
763530Srb144127 typedef enum {
773530Srb144127 DS_PRI_REQUEST = 0,
783530Srb144127 DS_PRI_DATA = 1,
793530Srb144127 DS_PRI_UPDATE = 2
803530Srb144127 } ds_pri_msg_type_t;
813530Srb144127
823530Srb144127 typedef struct {
833530Srb144127 struct {
843530Srb144127 uint64_t seq_num;
853530Srb144127 uint64_t type;
863530Srb144127 } hdr;
873530Srb144127 uint8_t data[1];
883530Srb144127 } ds_pri_msg_t;
893530Srb144127
9011304SJanie.Lu@Sun.COM /*
9111304SJanie.Lu@Sun.COM * The following are bit field flags. No service implies no DS PRI and
9211304SJanie.Lu@Sun.COM * no outstanding request.
9311304SJanie.Lu@Sun.COM */
943530Srb144127 typedef enum {
953530Srb144127 DS_PRI_NO_SERVICE = 0x0,
963530Srb144127 DS_PRI_HAS_SERVICE = 0x1,
973530Srb144127 DS_PRI_REQUESTED = 0x2,
983530Srb144127 DS_PRI_HAS_PRI = 0x4
993530Srb144127 } ds_pri_flags_t;
1003530Srb144127
1013530Srb144127 struct ds_pri_state {
1023530Srb144127 dev_info_t *dip;
1033530Srb144127 int instance;
1043530Srb144127
1053530Srb144127 kmutex_t lock;
1063530Srb144127 kcondvar_t cv;
1073530Srb144127
1083530Srb144127 /* PRI/DS */
1093530Srb144127 ds_pri_flags_t state;
1103530Srb144127 uint64_t gencount;
1113530Srb144127 ds_svc_hdl_t ds_pri_handle;
1123530Srb144127 void *ds_pri;
1133530Srb144127 size_t ds_pri_len;
1143530Srb144127 uint64_t req_id;
1153530Srb144127 uint64_t last_req_id;
1163941Svenki int num_opens;
1173530Srb144127 };
1183530Srb144127
1193530Srb144127 typedef struct ds_pri_state ds_pri_state_t;
1203530Srb144127
1213530Srb144127 static void *ds_pri_statep;
1223530Srb144127
1233530Srb144127 static void request_pri(ds_pri_state_t *sp);
12411304SJanie.Lu@Sun.COM static uint64_t ds_get_hv_pri(ds_pri_state_t *sp);
1253530Srb144127
1263530Srb144127 static int ds_pri_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
1273530Srb144127 static int ds_pri_attach(dev_info_t *, ddi_attach_cmd_t);
1283530Srb144127 static int ds_pri_detach(dev_info_t *, ddi_detach_cmd_t);
1293530Srb144127 static int ds_pri_open(dev_t *, int, int, cred_t *);
1303530Srb144127 static int ds_pri_close(dev_t, int, int, cred_t *);
1313530Srb144127 static int ds_pri_read(dev_t, struct uio *, cred_t *);
1323530Srb144127 static int ds_pri_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
1333530Srb144127
1343530Srb144127 /*
1353530Srb144127 * DS Callbacks
1363530Srb144127 */
1373530Srb144127 static void ds_pri_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
1383530Srb144127 static void ds_pri_unreg_handler(ds_cb_arg_t arg);
1393530Srb144127 static void ds_pri_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
1403530Srb144127
1413530Srb144127 /*
1423530Srb144127 * PRI DS capability registration
1433530Srb144127 */
1443530Srb144127
1453530Srb144127 static ds_ver_t ds_pri_ver_1_0 = { 1, 0 };
1463530Srb144127
1473530Srb144127 static ds_capability_t ds_pri_cap = {
1483530Srb144127 "pri",
1493530Srb144127 &ds_pri_ver_1_0,
1503530Srb144127 1
1513530Srb144127 };
1523530Srb144127
1533530Srb144127 /*
1543530Srb144127 * PRI DS Client callback vector
1553530Srb144127 */
1563530Srb144127 static ds_clnt_ops_t ds_pri_ops = {
1573530Srb144127 ds_pri_reg_handler, /* ds_reg_cb */
1583530Srb144127 ds_pri_unreg_handler, /* ds_unreg_cb */
1593530Srb144127 ds_pri_data_handler, /* ds_data_cb */
1603530Srb144127 NULL /* cb_arg */
1613530Srb144127 };
1623530Srb144127
1633530Srb144127 /*
1643530Srb144127 * DS PRI driver Ops Vector
1653530Srb144127 */
1663530Srb144127 static struct cb_ops ds_pri_cb_ops = {
1673530Srb144127 ds_pri_open, /* cb_open */
1683530Srb144127 ds_pri_close, /* cb_close */
1693530Srb144127 nodev, /* cb_strategy */
1703530Srb144127 nodev, /* cb_print */
1713530Srb144127 nodev, /* cb_dump */
1723530Srb144127 ds_pri_read, /* cb_read */
1733530Srb144127 nodev, /* cb_write */
1743530Srb144127 ds_pri_ioctl, /* cb_ioctl */
1753530Srb144127 nodev, /* cb_devmap */
1763530Srb144127 nodev, /* cb_mmap */
1773530Srb144127 nodev, /* cb_segmap */
1783530Srb144127 nochpoll, /* cb_chpoll */
1793530Srb144127 ddi_prop_op, /* cb_prop_op */
1803530Srb144127 (struct streamtab *)NULL, /* cb_str */
1813530Srb144127 D_MP | D_64BIT, /* cb_flag */
1823530Srb144127 CB_REV, /* cb_rev */
1833530Srb144127 nodev, /* cb_aread */
1843530Srb144127 nodev /* cb_awrite */
1853530Srb144127 };
1863530Srb144127
1873530Srb144127 static struct dev_ops ds_pri_dev_ops = {
1883530Srb144127 DEVO_REV, /* devo_rev */
1893530Srb144127 0, /* devo_refcnt */
1903530Srb144127 ds_pri_getinfo, /* devo_getinfo */
1913530Srb144127 nulldev, /* devo_identify */
1923530Srb144127 nulldev, /* devo_probe */
1933530Srb144127 ds_pri_attach, /* devo_attach */
1943530Srb144127 ds_pri_detach, /* devo_detach */
1953530Srb144127 nodev, /* devo_reset */
1963530Srb144127 &ds_pri_cb_ops, /* devo_cb_ops */
1973530Srb144127 (struct bus_ops *)NULL, /* devo_bus_ops */
1987656SSherry.Moore@Sun.COM nulldev, /* devo_power */
1997656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* devo_quiesce */
2003530Srb144127 };
2013530Srb144127
2023530Srb144127 static struct modldrv modldrv = {
2033530Srb144127 &mod_driverops,
2047656SSherry.Moore@Sun.COM "Domain Services PRI Driver",
2053530Srb144127 &ds_pri_dev_ops
2063530Srb144127 };
2073530Srb144127
2083530Srb144127 static struct modlinkage modlinkage = {
2093530Srb144127 MODREV_1,
2103530Srb144127 (void *)&modldrv,
2113530Srb144127 NULL
2123530Srb144127 };
2133530Srb144127
21411304SJanie.Lu@Sun.COM static boolean_t hsvc_pboot_available = B_FALSE;
21511304SJanie.Lu@Sun.COM static hsvc_info_t pboot_hsvc = {
21611304SJanie.Lu@Sun.COM HSVC_REV_1, NULL, HSVC_GROUP_PBOOT, 1, 0, NULL
21711304SJanie.Lu@Sun.COM };
2183530Srb144127
2193530Srb144127 int
_init(void)2203530Srb144127 _init(void)
2213530Srb144127 {
2223530Srb144127 int retval;
22311304SJanie.Lu@Sun.COM uint64_t hsvc_pboot_minor;
22411304SJanie.Lu@Sun.COM uint64_t status;
22511304SJanie.Lu@Sun.COM
22611304SJanie.Lu@Sun.COM status = hsvc_register(&pboot_hsvc, &hsvc_pboot_minor);
22711304SJanie.Lu@Sun.COM if (status == H_EOK) {
22811304SJanie.Lu@Sun.COM hsvc_pboot_available = B_TRUE;
22911304SJanie.Lu@Sun.COM } else {
23011304SJanie.Lu@Sun.COM DS_PRI_DBG("hypervisor services not negotiated "
23111304SJanie.Lu@Sun.COM "for group number: 0x%lx errorno: 0x%lx\n",
23211304SJanie.Lu@Sun.COM pboot_hsvc.hsvc_group, status);
23311304SJanie.Lu@Sun.COM }
2343530Srb144127
2353530Srb144127 retval = ddi_soft_state_init(&ds_pri_statep,
2363530Srb144127 sizeof (ds_pri_state_t), 0);
2373530Srb144127 if (retval != 0)
2383530Srb144127 return (retval);
2393530Srb144127
2403530Srb144127 retval = mod_install(&modlinkage);
2413530Srb144127 if (retval != 0) {
2423530Srb144127 ddi_soft_state_fini(&ds_pri_statep);
2433530Srb144127 return (retval);
2443530Srb144127 }
2453530Srb144127
2463530Srb144127 return (retval);
2473530Srb144127 }
2483530Srb144127
2493530Srb144127
2503530Srb144127 int
_info(struct modinfo * modinfop)2513530Srb144127 _info(struct modinfo *modinfop)
2523530Srb144127 {
2533530Srb144127 return (mod_info(&modlinkage, modinfop));
2543530Srb144127 }
2553530Srb144127
2563530Srb144127
2573530Srb144127 int
_fini(void)2583530Srb144127 _fini(void)
2593530Srb144127 {
2603530Srb144127 int retval;
2613530Srb144127
2623530Srb144127 if ((retval = mod_remove(&modlinkage)) != 0)
2633530Srb144127 return (retval);
2643530Srb144127
2653530Srb144127 ddi_soft_state_fini(&ds_pri_statep);
2663530Srb144127
267*12209Ssree.lakshmi.vemuri@oracle.com if (hsvc_pboot_available)
268*12209Ssree.lakshmi.vemuri@oracle.com (void) hsvc_unregister(&pboot_hsvc);
26911304SJanie.Lu@Sun.COM
2703530Srb144127 return (retval);
2713530Srb144127 }
2723530Srb144127
2733530Srb144127
2743530Srb144127 /*ARGSUSED*/
2753530Srb144127 static int
ds_pri_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)2763530Srb144127 ds_pri_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
2773530Srb144127 {
2783530Srb144127 ds_pri_state_t *sp;
2793530Srb144127 int retval = DDI_FAILURE;
2803530Srb144127
2813530Srb144127 ASSERT(resultp != NULL);
2823530Srb144127
2833530Srb144127 switch (cmd) {
2843530Srb144127 case DDI_INFO_DEVT2DEVINFO:
2853530Srb144127 sp = ddi_get_soft_state(ds_pri_statep, getminor((dev_t)arg));
2863530Srb144127 if (sp != NULL) {
2873530Srb144127 *resultp = sp->dip;
2883530Srb144127 retval = DDI_SUCCESS;
2893530Srb144127 } else
2903530Srb144127 *resultp = NULL;
2913530Srb144127 break;
2923530Srb144127
2933530Srb144127 case DDI_INFO_DEVT2INSTANCE:
2943530Srb144127 *resultp = (void *)(uintptr_t)getminor((dev_t)arg);
2953530Srb144127 retval = DDI_SUCCESS;
2963530Srb144127 break;
2973530Srb144127
2983530Srb144127 default:
2993530Srb144127 break;
3003530Srb144127 }
3013530Srb144127
3023530Srb144127 return (retval);
3033530Srb144127 }
3043530Srb144127
3053530Srb144127
3063530Srb144127 static int
ds_pri_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)3073530Srb144127 ds_pri_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3083530Srb144127 {
3093530Srb144127 int instance;
3103530Srb144127 ds_pri_state_t *sp;
3113530Srb144127 int rv;
31211304SJanie.Lu@Sun.COM uint64_t status;
3133530Srb144127
3143530Srb144127 switch (cmd) {
3153530Srb144127 case DDI_ATTACH:
3163530Srb144127 break;
3173530Srb144127
3183530Srb144127 case DDI_RESUME:
3193530Srb144127 return (DDI_SUCCESS);
3203530Srb144127
3213530Srb144127 default:
3223530Srb144127 return (DDI_FAILURE);
3233530Srb144127 }
3243530Srb144127
3253530Srb144127 instance = ddi_get_instance(dip);
3263530Srb144127
3273530Srb144127 if (ddi_soft_state_zalloc(ds_pri_statep, instance) !=
3283530Srb144127 DDI_SUCCESS) {
3293530Srb144127 cmn_err(CE_WARN, "%s@%d: Unable to allocate state",
3303530Srb144127 DS_PRI_NAME, instance);
3313530Srb144127 return (DDI_FAILURE);
3323530Srb144127 }
3333530Srb144127 sp = ddi_get_soft_state(ds_pri_statep, instance);
3343530Srb144127
3353530Srb144127 mutex_init(&sp->lock, NULL, MUTEX_DEFAULT, NULL);
3363530Srb144127 cv_init(&sp->cv, NULL, CV_DEFAULT, NULL);
3373530Srb144127
3383530Srb144127 if (ddi_create_minor_node(dip, DS_PRI_NAME, S_IFCHR, instance,
3394407Snarayan DDI_PSEUDO, 0) != DDI_SUCCESS) {
3403530Srb144127 cmn_err(CE_WARN, "%s@%d: Unable to create minor node",
3413530Srb144127 DS_PRI_NAME, instance);
3423530Srb144127 goto fail;
3433530Srb144127 }
3443530Srb144127
3453530Srb144127 if (ds_pri_ops.cb_arg != NULL)
3463530Srb144127 goto fail;
3473530Srb144127 ds_pri_ops.cb_arg = dip;
3483530Srb144127
3493530Srb144127 sp->state = DS_PRI_NO_SERVICE;
3503530Srb144127
3513530Srb144127 /* Until the service registers the handle is invalid */
3523530Srb144127 sp->ds_pri_handle = DS_INVALID_HDL;
3533530Srb144127
3543530Srb144127 sp->ds_pri = NULL;
3553530Srb144127 sp->ds_pri_len = 0;
3563530Srb144127 sp->req_id = 0;
3573941Svenki sp->num_opens = 0;
3583530Srb144127
35911304SJanie.Lu@Sun.COM /*
36011304SJanie.Lu@Sun.COM * See if we can get the static hv pri data. Static pri data
36111304SJanie.Lu@Sun.COM * is only available for privileged domains.
36211304SJanie.Lu@Sun.COM */
363*12209Ssree.lakshmi.vemuri@oracle.com if (hsvc_pboot_available) {
36411304SJanie.Lu@Sun.COM if ((status = ds_get_hv_pri(sp)) != 0) {
36511304SJanie.Lu@Sun.COM cmn_err(CE_NOTE, "ds_get_hv_pri failed: 0x%lx", status);
36611304SJanie.Lu@Sun.COM }
36711304SJanie.Lu@Sun.COM }
36811304SJanie.Lu@Sun.COM
3693530Srb144127 if ((rv = ds_cap_init(&ds_pri_cap, &ds_pri_ops)) != 0) {
3703530Srb144127 cmn_err(CE_NOTE, "ds_cap_init failed: %d", rv);
3713530Srb144127 goto fail;
3723530Srb144127 }
3733530Srb144127
3743530Srb144127 ddi_report_dev(dip);
3753530Srb144127
3763530Srb144127 return (DDI_SUCCESS);
3773530Srb144127
3783530Srb144127 fail:
37911304SJanie.Lu@Sun.COM if (sp->ds_pri)
38011304SJanie.Lu@Sun.COM kmem_free(sp->ds_pri, sp->ds_pri_len);
3813530Srb144127 ddi_remove_minor_node(dip, NULL);
3823530Srb144127 cv_destroy(&sp->cv);
3833530Srb144127 mutex_destroy(&sp->lock);
3843530Srb144127 ddi_soft_state_free(ds_pri_statep, instance);
3853530Srb144127 return (DDI_FAILURE);
3863530Srb144127
3873530Srb144127 }
3883530Srb144127
3893530Srb144127
3903530Srb144127 /*ARGSUSED*/
3913530Srb144127 static int
ds_pri_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)3923530Srb144127 ds_pri_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3933530Srb144127 {
3943530Srb144127 ds_pri_state_t *sp;
3953530Srb144127 int instance;
3963530Srb144127 int rv;
3973530Srb144127
3983530Srb144127 instance = ddi_get_instance(dip);
3993530Srb144127 sp = ddi_get_soft_state(ds_pri_statep, instance);
4003530Srb144127
4013530Srb144127 switch (cmd) {
4023530Srb144127 case DDI_DETACH:
4033530Srb144127 break;
4043530Srb144127
4053530Srb144127 case DDI_SUSPEND:
4063530Srb144127 return (DDI_SUCCESS);
4073530Srb144127
4083530Srb144127 default:
4093530Srb144127 return (DDI_FAILURE);
4103530Srb144127 }
4113530Srb144127
4123530Srb144127 /* This really shouldn't fail - but check anyway */
4133530Srb144127 if ((rv = ds_cap_fini(&ds_pri_cap)) != 0) {
4143530Srb144127 cmn_err(CE_WARN, "ds_cap_fini failed: %d", rv);
4153530Srb144127 }
4163530Srb144127
4173530Srb144127 if (sp != NULL && sp->ds_pri_len != 0)
4183530Srb144127 kmem_free(sp->ds_pri, sp->ds_pri_len);
4193530Srb144127
4204407Snarayan ds_pri_ops.cb_arg = NULL;
4214407Snarayan
4223530Srb144127 ddi_remove_minor_node(dip, NULL);
4233530Srb144127 cv_destroy(&sp->cv);
4243530Srb144127 mutex_destroy(&sp->lock);
4253530Srb144127 ddi_soft_state_free(ds_pri_statep, instance);
4263530Srb144127
4273530Srb144127 return (DDI_SUCCESS);
4283530Srb144127 }
4293530Srb144127
4303530Srb144127
4313530Srb144127 /*ARGSUSED*/
4323530Srb144127 static int
ds_pri_open(dev_t * devp,int flag,int otyp,cred_t * credp)4333530Srb144127 ds_pri_open(dev_t *devp, int flag, int otyp, cred_t *credp)
4343530Srb144127 {
4353530Srb144127 ds_pri_state_t *sp;
4363530Srb144127 int instance;
4373530Srb144127
4383530Srb144127 if (otyp != OTYP_CHR)
4393530Srb144127 return (EINVAL);
4403530Srb144127
4413530Srb144127 instance = getminor(*devp);
4423530Srb144127 sp = ddi_get_soft_state(ds_pri_statep, instance);
4433530Srb144127 if (sp == NULL)
4443530Srb144127 return (ENXIO);
4453530Srb144127
4463941Svenki mutex_enter(&sp->lock);
4473941Svenki
4483941Svenki /*
44911304SJanie.Lu@Sun.COM * Proceed if we have PRI data (possibly obtained from
45011304SJanie.Lu@Sun.COM * static HV PRI or last pushed DS PRI data update).
45111304SJanie.Lu@Sun.COM * If no PRI data and we have no DS PRI service then this
45211304SJanie.Lu@Sun.COM * means that PRI DS has never called the registration callback.
4534109Skellena * A while loop is necessary as we might have been woken up
4544109Skellena * prematurely, e.g., due to a debugger or "pstack" etc.
4553941Svenki * Wait here and the callback will signal us when it has completed
4563941Svenki * its work.
4573941Svenki */
45811304SJanie.Lu@Sun.COM if (!(sp->state & DS_PRI_HAS_PRI)) {
45911304SJanie.Lu@Sun.COM while (!(sp->state & DS_PRI_HAS_SERVICE)) {
46011304SJanie.Lu@Sun.COM if (cv_wait_sig(&sp->cv, &sp->lock) == 0) {
46111304SJanie.Lu@Sun.COM mutex_exit(&sp->lock);
46211304SJanie.Lu@Sun.COM return (EINTR);
46311304SJanie.Lu@Sun.COM }
4643941Svenki }
4653941Svenki }
4663941Svenki
4673941Svenki sp->num_opens++;
4683941Svenki mutex_exit(&sp->lock);
4693941Svenki
4703530Srb144127 DS_PRI_DBG("ds_pri_open: state = 0x%x\n", sp->state);
4713530Srb144127
4723530Srb144127 return (0);
4733530Srb144127 }
4743530Srb144127
4753530Srb144127
4763530Srb144127 /*ARGSUSED*/
4773530Srb144127 static int
ds_pri_close(dev_t dev,int flag,int otyp,cred_t * credp)4783530Srb144127 ds_pri_close(dev_t dev, int flag, int otyp, cred_t *credp)
4793530Srb144127 {
4803530Srb144127 int instance;
4813941Svenki ds_pri_state_t *sp;
4823530Srb144127
4833530Srb144127 if (otyp != OTYP_CHR)
4843530Srb144127 return (EINVAL);
4853530Srb144127
4863530Srb144127 DS_PRI_DBG("ds_pri_close\n");
4873530Srb144127
4883530Srb144127 instance = getminor(dev);
4893941Svenki if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
4903530Srb144127 return (ENXIO);
4913530Srb144127
4923941Svenki mutex_enter(&sp->lock);
4933941Svenki if (!(sp->state & DS_PRI_HAS_SERVICE)) {
4943941Svenki mutex_exit(&sp->lock);
4953941Svenki return (0);
4963941Svenki }
4973941Svenki
4983941Svenki if (--sp->num_opens > 0) {
4993941Svenki mutex_exit(&sp->lock);
5003941Svenki return (0);
5013941Svenki }
5023941Svenki
5033941Svenki sp->state &= ~DS_PRI_REQUESTED;
5043941Svenki mutex_exit(&sp->lock);
5053530Srb144127 return (0);
5063530Srb144127 }
5073530Srb144127
5083530Srb144127
5093530Srb144127 /*ARGSUSED*/
5103530Srb144127 static int
ds_pri_read(dev_t dev,struct uio * uiop,cred_t * credp)5113530Srb144127 ds_pri_read(dev_t dev, struct uio *uiop, cred_t *credp)
5123530Srb144127 {
5133530Srb144127 ds_pri_state_t *sp;
5143530Srb144127 int instance;
5153530Srb144127 size_t len;
5163530Srb144127 int retval;
5173530Srb144127 caddr_t tmpbufp;
5189387SSree.Vemuri@Sun.COM offset_t off = uiop->uio_offset;
5193530Srb144127
5203530Srb144127 instance = getminor(dev);
5213530Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
5223530Srb144127 return (ENXIO);
5233530Srb144127
5243530Srb144127 len = uiop->uio_resid;
5253530Srb144127
5263530Srb144127 if (len == 0)
5273530Srb144127 return (0);
5283530Srb144127
5293530Srb144127 mutex_enter(&sp->lock);
5303530Srb144127
5313530Srb144127 DS_PRI_DBG("ds_pri_read: state = 0x%x\n", sp->state);
5323530Srb144127
5333530Srb144127 /* block or bail if there is no current PRI */
5343530Srb144127 if (!(sp->state & DS_PRI_HAS_PRI)) {
5353530Srb144127 DS_PRI_DBG("ds_pri_read: no PRI held\n");
5363530Srb144127
5373530Srb144127 if (uiop->uio_fmode & (FNDELAY | FNONBLOCK)) {
5383530Srb144127 mutex_exit(&sp->lock);
5393530Srb144127 return (EAGAIN);
5403530Srb144127 }
5413530Srb144127
5423530Srb144127 while (!(sp->state & DS_PRI_HAS_PRI)) {
5433530Srb144127 DS_PRI_DBG("ds_pri_read: state = 0x%x\n", sp->state);
5443530Srb144127 request_pri(sp);
5453530Srb144127 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) {
5463530Srb144127 mutex_exit(&sp->lock);
5473530Srb144127 return (EINTR);
5483530Srb144127 }
5493530Srb144127 }
5503530Srb144127 }
5513530Srb144127
5529387SSree.Vemuri@Sun.COM if (len > sp->ds_pri_len)
5539387SSree.Vemuri@Sun.COM len = sp->ds_pri_len;
5543530Srb144127
5553530Srb144127 if (len == 0) {
5563530Srb144127 mutex_exit(&sp->lock);
5573530Srb144127 return (0);
5583530Srb144127 }
5593530Srb144127
5603530Srb144127 /*
5613530Srb144127 * We're supposed to move the data out to userland, but
5623530Srb144127 * that can suspend because of page faults etc., and meanwhile
5633530Srb144127 * other parts of this driver want to update the PRI buffer ...
5643530Srb144127 * we could hold the data buffer locked with a flag etc.,
5653530Srb144127 * but that's still a lock ... a simpler mechanism - if not quite
5663530Srb144127 * as performance efficient is to simply clone here the part of
5673530Srb144127 * the buffer we care about and then the original can be released
5683530Srb144127 * for further updates while the uiomove continues.
5693530Srb144127 */
5703530Srb144127
5713530Srb144127 tmpbufp = kmem_alloc(len, KM_SLEEP);
5729387SSree.Vemuri@Sun.COM bcopy(((caddr_t)sp->ds_pri), tmpbufp, len);
5733530Srb144127 mutex_exit(&sp->lock);
5743530Srb144127
5753530Srb144127 retval = uiomove(tmpbufp, len, UIO_READ, uiop);
5763530Srb144127
5773530Srb144127 kmem_free(tmpbufp, len);
5783530Srb144127
5799387SSree.Vemuri@Sun.COM /*
5809387SSree.Vemuri@Sun.COM * restore uio_offset after uiomove since the driver
5819387SSree.Vemuri@Sun.COM * does not support the concept of position.
5829387SSree.Vemuri@Sun.COM */
5839387SSree.Vemuri@Sun.COM uiop->uio_offset = off;
5849387SSree.Vemuri@Sun.COM
5853530Srb144127 return (retval);
5863530Srb144127 }
5873530Srb144127
5883530Srb144127
5893530Srb144127 /*ARGSUSED*/
5903530Srb144127 static int
ds_pri_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)5913530Srb144127 ds_pri_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
5923530Srb144127 int *rvalp)
5933530Srb144127 {
5943530Srb144127 ds_pri_state_t *sp;
5953530Srb144127 int instance;
5963530Srb144127
5973530Srb144127 instance = getminor(dev);
5983530Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
5993530Srb144127 return (ENXIO);
6003530Srb144127
6013530Srb144127 switch (cmd) {
6023530Srb144127 case DSPRI_GETINFO: {
6033530Srb144127 struct dspri_info info;
6043530Srb144127
6053530Srb144127 if (!(mode & FREAD))
6063530Srb144127 return (EACCES);
6073530Srb144127
6083530Srb144127 /*
6093530Srb144127 * We are not guaranteed that ddi_copyout(9F) will read
6103530Srb144127 * atomically anything larger than a byte. Therefore we
6113530Srb144127 * must duplicate the size before copying it out to the user.
6123530Srb144127 */
6133530Srb144127 mutex_enter(&sp->lock);
6143530Srb144127
6153530Srb144127 loop:;
6163530Srb144127 if (sp->state & DS_PRI_HAS_PRI) {
6173530Srb144127 /* If we have a PRI simply return the info */
6183530Srb144127 info.size = sp->ds_pri_len;
6193530Srb144127 info.token = sp->gencount;
6203530Srb144127 } else
6213530Srb144127 if (!(sp->state & DS_PRI_HAS_SERVICE)) {
6223530Srb144127 /* If we have no service return a nil response */
6233530Srb144127 info.size = 0;
6243530Srb144127 info.token = 0;
6253530Srb144127 } else {
6263530Srb144127 request_pri(sp);
6273530Srb144127 /* wait for something & check again */
6283530Srb144127 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) {
6293530Srb144127 mutex_exit(&sp->lock);
6303530Srb144127 return (EINTR);
6313530Srb144127 }
6323530Srb144127 goto loop;
6333530Srb144127 }
6343530Srb144127 DS_PRI_DBG("ds_pri_ioctl: DSPRI_GETINFO sz=0x%lx tok=0x%lx\n",
6354407Snarayan info.size, info.token);
6363530Srb144127 mutex_exit(&sp->lock);
6373530Srb144127
6383530Srb144127 if (ddi_copyout(&info, (void *)arg, sizeof (info), mode) != 0)
6393530Srb144127 return (EFAULT);
6403530Srb144127 break;
6413530Srb144127 }
6423530Srb144127
6433530Srb144127 case DSPRI_WAIT: {
6443530Srb144127 uint64_t gencount;
6453530Srb144127
6463530Srb144127 if (ddi_copyin((void *)arg, &gencount, sizeof (gencount),
6473530Srb144127 mode) != 0)
6483530Srb144127 return (EFAULT);
6493530Srb144127
6503530Srb144127 mutex_enter(&sp->lock);
6513530Srb144127
6523530Srb144127 DS_PRI_DBG("ds_pri_ioctl: DSPRI_WAIT gen=0x%lx sp->gen=0x%lx\n",
6534407Snarayan gencount, sp->gencount);
6543530Srb144127
6553530Srb144127 while ((sp->state & DS_PRI_HAS_PRI) == 0 ||
6564407Snarayan gencount == sp->gencount) {
6574109Skellena if ((sp->state & DS_PRI_HAS_PRI) == 0)
6584109Skellena request_pri(sp);
6593530Srb144127 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) {
6603530Srb144127 mutex_exit(&sp->lock);
6613530Srb144127 return (EINTR);
6623530Srb144127 }
6633530Srb144127 }
6643530Srb144127 mutex_exit(&sp->lock);
6653530Srb144127 break;
6663530Srb144127 }
6673530Srb144127
6683530Srb144127 default:
6693530Srb144127 return (ENOTTY);
6703530Srb144127 }
6713530Srb144127 return (0);
6723530Srb144127 }
6733530Srb144127
6743530Srb144127
6753530Srb144127 /* assumes sp->lock is held when called */
6763530Srb144127 static void
request_pri(ds_pri_state_t * sp)6773530Srb144127 request_pri(ds_pri_state_t *sp)
6783530Srb144127 {
6793530Srb144127 ds_pri_msg_t reqmsg;
6803530Srb144127
6813530Srb144127 ASSERT(MUTEX_HELD(&sp->lock));
6823530Srb144127
6833530Srb144127 /* If a request is already pending we're done */
6843530Srb144127 if (!(sp->state & DS_PRI_HAS_SERVICE))
6853530Srb144127 return;
6863530Srb144127 if (sp->state & DS_PRI_REQUESTED)
6873530Srb144127 return;
6883530Srb144127
6893530Srb144127 /* If we have an old PRI - remove it */
6903530Srb144127 if (sp->state & DS_PRI_HAS_PRI) {
6913530Srb144127 ASSERT(sp->ds_pri_len != 0);
6923530Srb144127 ASSERT(sp->ds_pri != NULL);
6933530Srb144127
6943530Srb144127 /* remove the old data if we have an outstanding request */
6953530Srb144127 kmem_free(sp->ds_pri, sp->ds_pri_len);
6963530Srb144127 sp->ds_pri_len = 0;
6973530Srb144127 sp->ds_pri = NULL;
6983530Srb144127 sp->state &= ~DS_PRI_HAS_PRI;
6993530Srb144127 } else {
7003530Srb144127 ASSERT(sp->ds_pri == NULL);
7013530Srb144127 ASSERT(sp->ds_pri_len == 0);
7023530Srb144127 }
7033530Srb144127
7043530Srb144127 reqmsg.hdr.seq_num = ++(sp->req_id);
7053530Srb144127 reqmsg.hdr.type = DS_PRI_REQUEST;
7063530Srb144127
7073530Srb144127 DS_PRI_DBG("request_pri: request id 0x%lx\n", sp->req_id);
7083530Srb144127
7093530Srb144127 /*
7103530Srb144127 * Request consists of header only.
7113530Srb144127 * We don't care about fail status for ds_send;
7123530Srb144127 * if it does fail we will get an unregister callback
7133530Srb144127 * from the DS framework and we handle the state change
7143530Srb144127 * there.
7153530Srb144127 */
7163530Srb144127 (void) ds_cap_send(sp->ds_pri_handle, &reqmsg, sizeof (reqmsg.hdr));
7173530Srb144127
7183530Srb144127 sp->state |= DS_PRI_REQUESTED;
7193530Srb144127 sp->last_req_id = sp->req_id;
7203530Srb144127 }
7213530Srb144127
7223530Srb144127 /*
7233530Srb144127 * DS Callbacks
7243530Srb144127 */
7253530Srb144127 /*ARGSUSED*/
7263530Srb144127 static void
ds_pri_reg_handler(ds_cb_arg_t arg,ds_ver_t * ver,ds_svc_hdl_t hdl)7273530Srb144127 ds_pri_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
7283530Srb144127 {
7293530Srb144127 dev_info_t *dip = arg;
7303530Srb144127 ds_pri_state_t *sp;
7313530Srb144127 int instance;
7323530Srb144127
7333530Srb144127 instance = ddi_get_instance(dip);
7343530Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
7353530Srb144127 return;
7363530Srb144127
7373530Srb144127 DS_PRI_DBG("ds_pri_reg_handler: registering handle 0x%lx for version "
7384407Snarayan "0x%x:0x%x\n", (uint64_t)hdl, ver->major, ver->minor);
7393530Srb144127
74011304SJanie.Lu@Sun.COM /* When the domain service comes up automatically update the state */
7413530Srb144127 mutex_enter(&sp->lock);
7423530Srb144127
7433530Srb144127 ASSERT(sp->ds_pri_handle == DS_INVALID_HDL);
7443530Srb144127 sp->ds_pri_handle = hdl;
7453530Srb144127
74611304SJanie.Lu@Sun.COM ASSERT(!(sp->state & DS_PRI_HAS_SERVICE));
7473530Srb144127 sp->state |= DS_PRI_HAS_SERVICE;
7483530Srb144127
7493941Svenki /*
7503941Svenki * Cannot request a PRI here, because the reg handler cannot
7513941Svenki * do a DS send operation - we take care of this later.
75211304SJanie.Lu@Sun.COM * Static hv pri data might be available.
7533941Svenki */
7543941Svenki
7553941Svenki /* Wake up anyone waiting in open() */
7563941Svenki cv_broadcast(&sp->cv);
7573941Svenki
7583530Srb144127 mutex_exit(&sp->lock);
7593530Srb144127 }
7603530Srb144127
7613530Srb144127
7623530Srb144127 static void
ds_pri_unreg_handler(ds_cb_arg_t arg)7633530Srb144127 ds_pri_unreg_handler(ds_cb_arg_t arg)
7643530Srb144127 {
7653530Srb144127 dev_info_t *dip = arg;
7663530Srb144127 ds_pri_state_t *sp;
7673530Srb144127 int instance;
7683530Srb144127
7693530Srb144127 instance = ddi_get_instance(dip);
7703530Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
7713530Srb144127 return;
7723530Srb144127
7733530Srb144127 DS_PRI_DBG("ds_pri_unreg_handler: un-registering ds_pri service\n");
7743530Srb144127
7753530Srb144127 mutex_enter(&sp->lock);
7763530Srb144127
77711304SJanie.Lu@Sun.COM /*
77811304SJanie.Lu@Sun.COM * Note that if the service goes offline, we don't
77911304SJanie.Lu@Sun.COM * free up the current PRI data at hand. It is assumed
78011304SJanie.Lu@Sun.COM * that PRI DS service will only push new update when
78111304SJanie.Lu@Sun.COM * it comes online. We mark the state to indicate no
78211304SJanie.Lu@Sun.COM * DS PRI service is available. The current PRI data if
78311304SJanie.Lu@Sun.COM * available is provided to the consumers.
78411304SJanie.Lu@Sun.COM */
7853530Srb144127 sp->ds_pri_handle = DS_INVALID_HDL;
78611304SJanie.Lu@Sun.COM sp->state &= ~DS_PRI_HAS_SERVICE;
7873530Srb144127
7883530Srb144127 mutex_exit(&sp->lock);
7893530Srb144127 }
7903530Srb144127
7913530Srb144127
7923530Srb144127 static void
ds_pri_data_handler(ds_cb_arg_t arg,void * buf,size_t buflen)7933530Srb144127 ds_pri_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
7943530Srb144127 {
7953530Srb144127 dev_info_t *dip = arg;
7963530Srb144127 ds_pri_state_t *sp;
7973530Srb144127 int instance;
7983530Srb144127 void *data;
7993530Srb144127 ds_pri_msg_t *msgp;
8003530Srb144127 size_t pri_size;
8013530Srb144127
8023530Srb144127 msgp = (ds_pri_msg_t *)buf;
8033530Srb144127
8043530Srb144127 /* make sure the header is at least valid */
8053530Srb144127 if (buflen < sizeof (msgp->hdr))
8063530Srb144127 return;
8073530Srb144127
8083530Srb144127 DS_PRI_DBG("ds_pri_data_handler: msg buf len 0x%lx : type 0x%lx, "
8094407Snarayan "seqn 0x%lx\n", buflen, msgp->hdr.type, msgp->hdr.seq_num);
8103530Srb144127
8113530Srb144127 instance = ddi_get_instance(dip);
8123530Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
8133530Srb144127 return;
8143530Srb144127
8153530Srb144127 mutex_enter(&sp->lock);
8163530Srb144127
8173530Srb144127 ASSERT(sp->state & DS_PRI_HAS_SERVICE);
8183530Srb144127
8193530Srb144127 switch (msgp->hdr.type) {
8203530Srb144127 case DS_PRI_DATA: /* in response to a request from us */
8213530Srb144127 break;
8223530Srb144127 case DS_PRI_UPDATE: /* aynch notification */
8233530Srb144127 /* our default response to this is to request the PRI */
8243530Srb144127 /* simply issue a request for the new PRI */
8253530Srb144127 request_pri(sp);
8263530Srb144127 goto done;
8273530Srb144127 default: /* ignore garbage or unknown message types */
8283530Srb144127 goto done;
8293530Srb144127 }
8303530Srb144127
8313530Srb144127 /*
8323530Srb144127 * If there is no pending PRI request, then we've received a
8333530Srb144127 * bogus data message ... so ignore it.
8343530Srb144127 */
8353530Srb144127
8363530Srb144127 if (!(sp->state & DS_PRI_REQUESTED)) {
8373530Srb144127 cmn_err(CE_WARN, "Received DS pri data without request");
8383530Srb144127 goto done;
8393530Srb144127 }
8403530Srb144127
8413530Srb144127 /* response to a request therefore old PRI must be gone */
8423530Srb144127 ASSERT(!(sp->state & DS_PRI_HAS_PRI));
8433530Srb144127 ASSERT(sp->ds_pri_len == 0);
8443530Srb144127 ASSERT(sp->ds_pri == NULL);
8453530Srb144127
8463530Srb144127 /* response seq_num should match our request seq_num */
8473530Srb144127 if (msgp->hdr.seq_num != sp->last_req_id) {
8483530Srb144127 cmn_err(CE_WARN, "Received DS pri data out of sequence with "
8494407Snarayan "request");
8503530Srb144127 goto done;
8513530Srb144127 }
8523530Srb144127
8533530Srb144127 pri_size = buflen - sizeof (msgp->hdr);
85411304SJanie.Lu@Sun.COM if (pri_size == 0) {
85511304SJanie.Lu@Sun.COM cmn_err(CE_WARN, "Received DS pri data of size 0");
85611304SJanie.Lu@Sun.COM goto done;
85711304SJanie.Lu@Sun.COM }
8583530Srb144127 data = kmem_alloc(pri_size, KM_SLEEP);
8593530Srb144127 sp->ds_pri = data;
8603530Srb144127 sp->ds_pri_len = pri_size;
8613530Srb144127 bcopy(msgp->data, data, sp->ds_pri_len);
8623530Srb144127 sp->state &= ~DS_PRI_REQUESTED;
8633530Srb144127 sp->state |= DS_PRI_HAS_PRI;
8643530Srb144127
8653530Srb144127 sp->gencount++;
8663530Srb144127 cv_broadcast(&sp->cv);
8673530Srb144127
8683530Srb144127 done:;
8693530Srb144127 mutex_exit(&sp->lock);
8703530Srb144127 }
87111304SJanie.Lu@Sun.COM
87211304SJanie.Lu@Sun.COM /*
87311304SJanie.Lu@Sun.COM * Routine to get static PRI data from the Hypervisor.
87411304SJanie.Lu@Sun.COM * If successful, this PRI data is the last known PRI
87511304SJanie.Lu@Sun.COM * data generated since the last poweron reset.
87611304SJanie.Lu@Sun.COM */
87711304SJanie.Lu@Sun.COM static uint64_t
ds_get_hv_pri(ds_pri_state_t * sp)87811304SJanie.Lu@Sun.COM ds_get_hv_pri(ds_pri_state_t *sp)
87911304SJanie.Lu@Sun.COM {
88011304SJanie.Lu@Sun.COM uint64_t status;
88111304SJanie.Lu@Sun.COM uint64_t pri_size;
88211304SJanie.Lu@Sun.COM uint64_t buf_size;
88311304SJanie.Lu@Sun.COM uint64_t buf_pa;
88411304SJanie.Lu@Sun.COM caddr_t buf_va = NULL;
88511304SJanie.Lu@Sun.COM caddr_t pri_data;
88611304SJanie.Lu@Sun.COM
88711304SJanie.Lu@Sun.COM /*
88811304SJanie.Lu@Sun.COM * Get pri buffer size by calling hcall with buffer size 0.
88911304SJanie.Lu@Sun.COM */
89011304SJanie.Lu@Sun.COM pri_size = 0LL;
89111304SJanie.Lu@Sun.COM status = hv_mach_pri((uint64_t)0, &pri_size);
89211304SJanie.Lu@Sun.COM if (status == H_ENOTSUPPORTED || status == H_ENOACCESS) {
893*12209Ssree.lakshmi.vemuri@oracle.com /*
894*12209Ssree.lakshmi.vemuri@oracle.com * hv_mach_pri() is not supported on a guest domain.
895*12209Ssree.lakshmi.vemuri@oracle.com * Unregister pboot API group to prevent failures.
896*12209Ssree.lakshmi.vemuri@oracle.com */
897*12209Ssree.lakshmi.vemuri@oracle.com (void) hsvc_unregister(&pboot_hsvc);
898*12209Ssree.lakshmi.vemuri@oracle.com hsvc_pboot_available = B_FALSE;
89911304SJanie.Lu@Sun.COM DS_PRI_DBG("ds_get_hv_pri: hv_mach_pri service is not "
90011304SJanie.Lu@Sun.COM "available. errorno: 0x%lx\n", status);
901*12209Ssree.lakshmi.vemuri@oracle.com return (0);
902*12209Ssree.lakshmi.vemuri@oracle.com } else if (pri_size == 0) {
903*12209Ssree.lakshmi.vemuri@oracle.com return (1);
904*12209Ssree.lakshmi.vemuri@oracle.com } else {
905*12209Ssree.lakshmi.vemuri@oracle.com DS_PRI_DBG("ds_get_hv_pri: hv_mach_pri pri size: 0x%lx\n",
906*12209Ssree.lakshmi.vemuri@oracle.com pri_size);
90711304SJanie.Lu@Sun.COM }
90811304SJanie.Lu@Sun.COM
90911304SJanie.Lu@Sun.COM /*
91011304SJanie.Lu@Sun.COM * contig_mem_alloc requires size to be a power of 2.
91111304SJanie.Lu@Sun.COM * Increase size to next power of 2 if necessary.
91211304SJanie.Lu@Sun.COM */
91311304SJanie.Lu@Sun.COM if ((pri_size & (pri_size - 1)) != 0)
91411304SJanie.Lu@Sun.COM buf_size = 1 << highbit(pri_size);
91511304SJanie.Lu@Sun.COM DS_PRI_DBG("ds_get_hv_pri: buf_size = 0x%lx\n", buf_size);
91611304SJanie.Lu@Sun.COM
91711304SJanie.Lu@Sun.COM buf_va = contig_mem_alloc(buf_size);
91811304SJanie.Lu@Sun.COM if (buf_va == NULL)
91911304SJanie.Lu@Sun.COM return (1);
92011304SJanie.Lu@Sun.COM
92111304SJanie.Lu@Sun.COM buf_pa = va_to_pa(buf_va);
92211304SJanie.Lu@Sun.COM DS_PRI_DBG("ds_get_hv_pri: buf_pa 0x%lx\n", buf_pa);
92311304SJanie.Lu@Sun.COM status = hv_mach_pri(buf_pa, &pri_size);
92411304SJanie.Lu@Sun.COM DS_PRI_DBG("ds_get_hv_pri: hv_mach_pri status = 0x%lx\n", status);
92511304SJanie.Lu@Sun.COM
92611304SJanie.Lu@Sun.COM if (status == H_EOK) {
92711304SJanie.Lu@Sun.COM pri_data = kmem_alloc(pri_size, KM_SLEEP);
92811304SJanie.Lu@Sun.COM sp->ds_pri = pri_data;
92911304SJanie.Lu@Sun.COM sp->ds_pri_len = pri_size;
93011304SJanie.Lu@Sun.COM bcopy(buf_va, pri_data, sp->ds_pri_len);
93111304SJanie.Lu@Sun.COM sp->state |= DS_PRI_HAS_PRI;
93211304SJanie.Lu@Sun.COM sp->gencount++;
93311304SJanie.Lu@Sun.COM }
93411304SJanie.Lu@Sun.COM
93511304SJanie.Lu@Sun.COM contig_mem_free(buf_va, buf_size);
93611304SJanie.Lu@Sun.COM
93711304SJanie.Lu@Sun.COM return (status);
93811304SJanie.Lu@Sun.COM }
939