1ef884685Srb144127 /* 2ef884685Srb144127 * CDDL HEADER START 3ef884685Srb144127 * 4ef884685Srb144127 * The contents of this file are subject to the terms of the 5ef884685Srb144127 * Common Development and Distribution License (the "License"). 6ef884685Srb144127 * You may not use this file except in compliance with the License. 7ef884685Srb144127 * 8ef884685Srb144127 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9ef884685Srb144127 * or http://www.opensolaris.org/os/licensing. 10ef884685Srb144127 * See the License for the specific language governing permissions 11ef884685Srb144127 * and limitations under the License. 12ef884685Srb144127 * 13ef884685Srb144127 * When distributing Covered Code, include this CDDL HEADER in each 14ef884685Srb144127 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15ef884685Srb144127 * If applicable, add the following below this CDDL HEADER, with the 16ef884685Srb144127 * fields enclosed by brackets "[]" replaced with your own identifying 17ef884685Srb144127 * information: Portions Copyright [yyyy] [name of copyright owner] 18ef884685Srb144127 * 19ef884685Srb144127 * CDDL HEADER END 20ef884685Srb144127 */ 21ef884685Srb144127 /* 227c18cbb1SSree Vemuri * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 23ef884685Srb144127 */ 24ef884685Srb144127 25ef884685Srb144127 /* 26ef884685Srb144127 * sun4v domain services PRI driver 27ef884685Srb144127 */ 28ef884685Srb144127 29ef884685Srb144127 #include <sys/types.h> 30ef884685Srb144127 #include <sys/file.h> 31ef884685Srb144127 #include <sys/errno.h> 32ef884685Srb144127 #include <sys/open.h> 33ef884685Srb144127 #include <sys/cred.h> 34ef884685Srb144127 #include <sys/uio.h> 35ef884685Srb144127 #include <sys/stat.h> 36ef884685Srb144127 #include <sys/ksynch.h> 37ef884685Srb144127 #include <sys/modctl.h> 38ef884685Srb144127 #include <sys/conf.h> 39ef884685Srb144127 #include <sys/devops.h> 40ef884685Srb144127 #include <sys/debug.h> 41ef884685Srb144127 #include <sys/cmn_err.h> 42ef884685Srb144127 #include <sys/ddi.h> 43ef884685Srb144127 #include <sys/sunddi.h> 44ef884685Srb144127 #include <sys/ds.h> 454df55fdeSJanie Lu #include <sys/hypervisor_api.h> 464df55fdeSJanie Lu #include <sys/machsystm.h> 474df55fdeSJanie Lu #include <sys/sysmacros.h> 484df55fdeSJanie Lu #include <sys/hsvc.h> 494df55fdeSJanie Lu #include <sys/bitmap.h> 50ef884685Srb144127 #include <sys/ds_pri.h> 51ef884685Srb144127 52ef884685Srb144127 static uint_t ds_pri_debug = 0; 53ef884685Srb144127 #define DS_PRI_DBG if (ds_pri_debug) printf 54ef884685Srb144127 55ef884685Srb144127 #define DS_PRI_NAME "ds_pri" 56ef884685Srb144127 57ef884685Srb144127 #define TEST_HARNESS 58ef884685Srb144127 #ifdef TEST_HARNESS 59ef884685Srb144127 #define DS_PRI_MAX_PRI_SIZE (64 * 1024) 60ef884685Srb144127 61ef884685Srb144127 #define DSIOC_TEST_REG 97 62ef884685Srb144127 #define DSIOC_TEST_UNREG 98 63ef884685Srb144127 #define DSIOC_TEST_DATA 99 64ef884685Srb144127 65ef884685Srb144127 struct ds_pri_test_data { 66ef884685Srb144127 size_t size; 67ef884685Srb144127 void *data; 68ef884685Srb144127 }; 69ef884685Srb144127 70ef884685Srb144127 struct ds_pri_test_data32 { 71ef884685Srb144127 size32_t size; 72ef884685Srb144127 caddr32_t data; 73ef884685Srb144127 }; 74ef884685Srb144127 #endif /* TEST_HARNESS */ 75ef884685Srb144127 76ef884685Srb144127 typedef enum { 77ef884685Srb144127 DS_PRI_REQUEST = 0, 78ef884685Srb144127 DS_PRI_DATA = 1, 79ef884685Srb144127 DS_PRI_UPDATE = 2 80ef884685Srb144127 } ds_pri_msg_type_t; 81ef884685Srb144127 82ef884685Srb144127 typedef struct { 83ef884685Srb144127 struct { 84ef884685Srb144127 uint64_t seq_num; 85ef884685Srb144127 uint64_t type; 86ef884685Srb144127 } hdr; 87ef884685Srb144127 uint8_t data[1]; 88ef884685Srb144127 } ds_pri_msg_t; 89ef884685Srb144127 904df55fdeSJanie Lu /* 914df55fdeSJanie Lu * The following are bit field flags. No service implies no DS PRI and 924df55fdeSJanie Lu * no outstanding request. 934df55fdeSJanie Lu */ 94ef884685Srb144127 typedef enum { 95ef884685Srb144127 DS_PRI_NO_SERVICE = 0x0, 96ef884685Srb144127 DS_PRI_HAS_SERVICE = 0x1, 97ef884685Srb144127 DS_PRI_REQUESTED = 0x2, 98ef884685Srb144127 DS_PRI_HAS_PRI = 0x4 99ef884685Srb144127 } ds_pri_flags_t; 100ef884685Srb144127 101ef884685Srb144127 struct ds_pri_state { 102ef884685Srb144127 dev_info_t *dip; 103ef884685Srb144127 int instance; 104ef884685Srb144127 105ef884685Srb144127 kmutex_t lock; 106ef884685Srb144127 kcondvar_t cv; 107ef884685Srb144127 108ef884685Srb144127 /* PRI/DS */ 109ef884685Srb144127 ds_pri_flags_t state; 110ef884685Srb144127 uint64_t gencount; 111ef884685Srb144127 ds_svc_hdl_t ds_pri_handle; 112ef884685Srb144127 void *ds_pri; 113ef884685Srb144127 size_t ds_pri_len; 114ef884685Srb144127 uint64_t req_id; 115ef884685Srb144127 uint64_t last_req_id; 1160d63ce2bSvenki int num_opens; 117ef884685Srb144127 }; 118ef884685Srb144127 119ef884685Srb144127 typedef struct ds_pri_state ds_pri_state_t; 120ef884685Srb144127 121ef884685Srb144127 static void *ds_pri_statep; 122ef884685Srb144127 123ef884685Srb144127 static void request_pri(ds_pri_state_t *sp); 1244df55fdeSJanie Lu static uint64_t ds_get_hv_pri(ds_pri_state_t *sp); 125ef884685Srb144127 126ef884685Srb144127 static int ds_pri_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 127ef884685Srb144127 static int ds_pri_attach(dev_info_t *, ddi_attach_cmd_t); 128ef884685Srb144127 static int ds_pri_detach(dev_info_t *, ddi_detach_cmd_t); 129ef884685Srb144127 static int ds_pri_open(dev_t *, int, int, cred_t *); 130ef884685Srb144127 static int ds_pri_close(dev_t, int, int, cred_t *); 131ef884685Srb144127 static int ds_pri_read(dev_t, struct uio *, cred_t *); 132ef884685Srb144127 static int ds_pri_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 133ef884685Srb144127 134ef884685Srb144127 /* 135ef884685Srb144127 * DS Callbacks 136ef884685Srb144127 */ 137ef884685Srb144127 static void ds_pri_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t); 138ef884685Srb144127 static void ds_pri_unreg_handler(ds_cb_arg_t arg); 139ef884685Srb144127 static void ds_pri_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen); 140ef884685Srb144127 141ef884685Srb144127 /* 142ef884685Srb144127 * PRI DS capability registration 143ef884685Srb144127 */ 144ef884685Srb144127 145ef884685Srb144127 static ds_ver_t ds_pri_ver_1_0 = { 1, 0 }; 146ef884685Srb144127 147ef884685Srb144127 static ds_capability_t ds_pri_cap = { 148ef884685Srb144127 "pri", 149ef884685Srb144127 &ds_pri_ver_1_0, 150ef884685Srb144127 1 151ef884685Srb144127 }; 152ef884685Srb144127 153ef884685Srb144127 /* 154ef884685Srb144127 * PRI DS Client callback vector 155ef884685Srb144127 */ 156ef884685Srb144127 static ds_clnt_ops_t ds_pri_ops = { 157ef884685Srb144127 ds_pri_reg_handler, /* ds_reg_cb */ 158ef884685Srb144127 ds_pri_unreg_handler, /* ds_unreg_cb */ 159ef884685Srb144127 ds_pri_data_handler, /* ds_data_cb */ 160ef884685Srb144127 NULL /* cb_arg */ 161ef884685Srb144127 }; 162ef884685Srb144127 163ef884685Srb144127 /* 164ef884685Srb144127 * DS PRI driver Ops Vector 165ef884685Srb144127 */ 166ef884685Srb144127 static struct cb_ops ds_pri_cb_ops = { 167ef884685Srb144127 ds_pri_open, /* cb_open */ 168ef884685Srb144127 ds_pri_close, /* cb_close */ 169ef884685Srb144127 nodev, /* cb_strategy */ 170ef884685Srb144127 nodev, /* cb_print */ 171ef884685Srb144127 nodev, /* cb_dump */ 172ef884685Srb144127 ds_pri_read, /* cb_read */ 173ef884685Srb144127 nodev, /* cb_write */ 174ef884685Srb144127 ds_pri_ioctl, /* cb_ioctl */ 175ef884685Srb144127 nodev, /* cb_devmap */ 176ef884685Srb144127 nodev, /* cb_mmap */ 177ef884685Srb144127 nodev, /* cb_segmap */ 178ef884685Srb144127 nochpoll, /* cb_chpoll */ 179ef884685Srb144127 ddi_prop_op, /* cb_prop_op */ 180ef884685Srb144127 (struct streamtab *)NULL, /* cb_str */ 181ef884685Srb144127 D_MP | D_64BIT, /* cb_flag */ 182ef884685Srb144127 CB_REV, /* cb_rev */ 183ef884685Srb144127 nodev, /* cb_aread */ 184ef884685Srb144127 nodev /* cb_awrite */ 185ef884685Srb144127 }; 186ef884685Srb144127 187ef884685Srb144127 static struct dev_ops ds_pri_dev_ops = { 188ef884685Srb144127 DEVO_REV, /* devo_rev */ 189ef884685Srb144127 0, /* devo_refcnt */ 190ef884685Srb144127 ds_pri_getinfo, /* devo_getinfo */ 191ef884685Srb144127 nulldev, /* devo_identify */ 192ef884685Srb144127 nulldev, /* devo_probe */ 193ef884685Srb144127 ds_pri_attach, /* devo_attach */ 194ef884685Srb144127 ds_pri_detach, /* devo_detach */ 195ef884685Srb144127 nodev, /* devo_reset */ 196ef884685Srb144127 &ds_pri_cb_ops, /* devo_cb_ops */ 197ef884685Srb144127 (struct bus_ops *)NULL, /* devo_bus_ops */ 19819397407SSherry Moore nulldev, /* devo_power */ 19919397407SSherry Moore ddi_quiesce_not_needed, /* devo_quiesce */ 200ef884685Srb144127 }; 201ef884685Srb144127 202ef884685Srb144127 static struct modldrv modldrv = { 203ef884685Srb144127 &mod_driverops, 20419397407SSherry Moore "Domain Services PRI Driver", 205ef884685Srb144127 &ds_pri_dev_ops 206ef884685Srb144127 }; 207ef884685Srb144127 208ef884685Srb144127 static struct modlinkage modlinkage = { 209ef884685Srb144127 MODREV_1, 210ef884685Srb144127 (void *)&modldrv, 211ef884685Srb144127 NULL 212ef884685Srb144127 }; 213ef884685Srb144127 2144df55fdeSJanie Lu static boolean_t hsvc_pboot_available = B_FALSE; 2154df55fdeSJanie Lu static hsvc_info_t pboot_hsvc = { 2164df55fdeSJanie Lu HSVC_REV_1, NULL, HSVC_GROUP_PBOOT, 1, 0, NULL 2174df55fdeSJanie Lu }; 218ef884685Srb144127 219ef884685Srb144127 int 220ef884685Srb144127 _init(void) 221ef884685Srb144127 { 222ef884685Srb144127 int retval; 2234df55fdeSJanie Lu uint64_t hsvc_pboot_minor; 2244df55fdeSJanie Lu uint64_t status; 2254df55fdeSJanie Lu 2264df55fdeSJanie Lu status = hsvc_register(&pboot_hsvc, &hsvc_pboot_minor); 2274df55fdeSJanie Lu if (status == H_EOK) { 2284df55fdeSJanie Lu hsvc_pboot_available = B_TRUE; 2294df55fdeSJanie Lu } else { 2304df55fdeSJanie Lu DS_PRI_DBG("hypervisor services not negotiated " 2314df55fdeSJanie Lu "for group number: 0x%lx errorno: 0x%lx\n", 2324df55fdeSJanie Lu pboot_hsvc.hsvc_group, status); 2334df55fdeSJanie Lu } 234ef884685Srb144127 235ef884685Srb144127 retval = ddi_soft_state_init(&ds_pri_statep, 236ef884685Srb144127 sizeof (ds_pri_state_t), 0); 237ef884685Srb144127 if (retval != 0) 238ef884685Srb144127 return (retval); 239ef884685Srb144127 240ef884685Srb144127 retval = mod_install(&modlinkage); 241ef884685Srb144127 if (retval != 0) { 242ef884685Srb144127 ddi_soft_state_fini(&ds_pri_statep); 243ef884685Srb144127 return (retval); 244ef884685Srb144127 } 245ef884685Srb144127 246ef884685Srb144127 return (retval); 247ef884685Srb144127 } 248ef884685Srb144127 249ef884685Srb144127 250ef884685Srb144127 int 251ef884685Srb144127 _info(struct modinfo *modinfop) 252ef884685Srb144127 { 253ef884685Srb144127 return (mod_info(&modlinkage, modinfop)); 254ef884685Srb144127 } 255ef884685Srb144127 256ef884685Srb144127 257ef884685Srb144127 int 258ef884685Srb144127 _fini(void) 259ef884685Srb144127 { 260ef884685Srb144127 int retval; 261ef884685Srb144127 262ef884685Srb144127 if ((retval = mod_remove(&modlinkage)) != 0) 263ef884685Srb144127 return (retval); 264ef884685Srb144127 265ef884685Srb144127 ddi_soft_state_fini(&ds_pri_statep); 266ef884685Srb144127 2677c18cbb1SSree Vemuri if (hsvc_pboot_available) 2684df55fdeSJanie Lu (void) hsvc_unregister(&pboot_hsvc); 2694df55fdeSJanie Lu 270ef884685Srb144127 return (retval); 271ef884685Srb144127 } 272ef884685Srb144127 273ef884685Srb144127 274ef884685Srb144127 /*ARGSUSED*/ 275ef884685Srb144127 static int 276ef884685Srb144127 ds_pri_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 277ef884685Srb144127 { 278ef884685Srb144127 ds_pri_state_t *sp; 279ef884685Srb144127 int retval = DDI_FAILURE; 280ef884685Srb144127 281ef884685Srb144127 ASSERT(resultp != NULL); 282ef884685Srb144127 283ef884685Srb144127 switch (cmd) { 284ef884685Srb144127 case DDI_INFO_DEVT2DEVINFO: 285ef884685Srb144127 sp = ddi_get_soft_state(ds_pri_statep, getminor((dev_t)arg)); 286ef884685Srb144127 if (sp != NULL) { 287ef884685Srb144127 *resultp = sp->dip; 288ef884685Srb144127 retval = DDI_SUCCESS; 289ef884685Srb144127 } else 290ef884685Srb144127 *resultp = NULL; 291ef884685Srb144127 break; 292ef884685Srb144127 293ef884685Srb144127 case DDI_INFO_DEVT2INSTANCE: 294ef884685Srb144127 *resultp = (void *)(uintptr_t)getminor((dev_t)arg); 295ef884685Srb144127 retval = DDI_SUCCESS; 296ef884685Srb144127 break; 297ef884685Srb144127 298ef884685Srb144127 default: 299ef884685Srb144127 break; 300ef884685Srb144127 } 301ef884685Srb144127 302ef884685Srb144127 return (retval); 303ef884685Srb144127 } 304ef884685Srb144127 305ef884685Srb144127 306ef884685Srb144127 static int 307ef884685Srb144127 ds_pri_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 308ef884685Srb144127 { 309ef884685Srb144127 int instance; 310ef884685Srb144127 ds_pri_state_t *sp; 311ef884685Srb144127 int rv; 3124df55fdeSJanie Lu uint64_t status; 313ef884685Srb144127 314ef884685Srb144127 switch (cmd) { 315ef884685Srb144127 case DDI_ATTACH: 316ef884685Srb144127 break; 317ef884685Srb144127 318ef884685Srb144127 case DDI_RESUME: 319ef884685Srb144127 return (DDI_SUCCESS); 320ef884685Srb144127 321ef884685Srb144127 default: 322ef884685Srb144127 return (DDI_FAILURE); 323ef884685Srb144127 } 324ef884685Srb144127 325ef884685Srb144127 instance = ddi_get_instance(dip); 326ef884685Srb144127 327ef884685Srb144127 if (ddi_soft_state_zalloc(ds_pri_statep, instance) != 328ef884685Srb144127 DDI_SUCCESS) { 329ef884685Srb144127 cmn_err(CE_WARN, "%s@%d: Unable to allocate state", 330ef884685Srb144127 DS_PRI_NAME, instance); 331ef884685Srb144127 return (DDI_FAILURE); 332ef884685Srb144127 } 333ef884685Srb144127 sp = ddi_get_soft_state(ds_pri_statep, instance); 334ef884685Srb144127 335ef884685Srb144127 mutex_init(&sp->lock, NULL, MUTEX_DEFAULT, NULL); 336ef884685Srb144127 cv_init(&sp->cv, NULL, CV_DEFAULT, NULL); 337ef884685Srb144127 338ef884685Srb144127 if (ddi_create_minor_node(dip, DS_PRI_NAME, S_IFCHR, instance, 339ef884685Srb144127 DDI_PSEUDO, 0) != DDI_SUCCESS) { 340ef884685Srb144127 cmn_err(CE_WARN, "%s@%d: Unable to create minor node", 341ef884685Srb144127 DS_PRI_NAME, instance); 342ef884685Srb144127 goto fail; 343ef884685Srb144127 } 344ef884685Srb144127 345ef884685Srb144127 if (ds_pri_ops.cb_arg != NULL) 346ef884685Srb144127 goto fail; 347ef884685Srb144127 ds_pri_ops.cb_arg = dip; 348ef884685Srb144127 349ef884685Srb144127 sp->state = DS_PRI_NO_SERVICE; 350ef884685Srb144127 351ef884685Srb144127 /* Until the service registers the handle is invalid */ 352ef884685Srb144127 sp->ds_pri_handle = DS_INVALID_HDL; 353ef884685Srb144127 354ef884685Srb144127 sp->ds_pri = NULL; 355ef884685Srb144127 sp->ds_pri_len = 0; 356ef884685Srb144127 sp->req_id = 0; 3570d63ce2bSvenki sp->num_opens = 0; 358ef884685Srb144127 3594df55fdeSJanie Lu /* 3604df55fdeSJanie Lu * See if we can get the static hv pri data. Static pri data 3614df55fdeSJanie Lu * is only available for privileged domains. 3624df55fdeSJanie Lu */ 3637c18cbb1SSree Vemuri if (hsvc_pboot_available) { 3644df55fdeSJanie Lu if ((status = ds_get_hv_pri(sp)) != 0) { 3654df55fdeSJanie Lu cmn_err(CE_NOTE, "ds_get_hv_pri failed: 0x%lx", status); 3664df55fdeSJanie Lu } 3674df55fdeSJanie Lu } 3684df55fdeSJanie Lu 369ef884685Srb144127 if ((rv = ds_cap_init(&ds_pri_cap, &ds_pri_ops)) != 0) { 370ef884685Srb144127 cmn_err(CE_NOTE, "ds_cap_init failed: %d", rv); 371ef884685Srb144127 goto fail; 372ef884685Srb144127 } 373ef884685Srb144127 374ef884685Srb144127 ddi_report_dev(dip); 375ef884685Srb144127 376ef884685Srb144127 return (DDI_SUCCESS); 377ef884685Srb144127 378ef884685Srb144127 fail: 3794df55fdeSJanie Lu if (sp->ds_pri) 3804df55fdeSJanie Lu kmem_free(sp->ds_pri, sp->ds_pri_len); 381ef884685Srb144127 ddi_remove_minor_node(dip, NULL); 382ef884685Srb144127 cv_destroy(&sp->cv); 383ef884685Srb144127 mutex_destroy(&sp->lock); 384ef884685Srb144127 ddi_soft_state_free(ds_pri_statep, instance); 385ef884685Srb144127 return (DDI_FAILURE); 386ef884685Srb144127 387ef884685Srb144127 } 388ef884685Srb144127 389ef884685Srb144127 390ef884685Srb144127 /*ARGSUSED*/ 391ef884685Srb144127 static int 392ef884685Srb144127 ds_pri_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 393ef884685Srb144127 { 394ef884685Srb144127 ds_pri_state_t *sp; 395ef884685Srb144127 int instance; 396ef884685Srb144127 int rv; 397ef884685Srb144127 398ef884685Srb144127 instance = ddi_get_instance(dip); 399ef884685Srb144127 sp = ddi_get_soft_state(ds_pri_statep, instance); 400ef884685Srb144127 401ef884685Srb144127 switch (cmd) { 402ef884685Srb144127 case DDI_DETACH: 403ef884685Srb144127 break; 404ef884685Srb144127 405ef884685Srb144127 case DDI_SUSPEND: 406ef884685Srb144127 return (DDI_SUCCESS); 407ef884685Srb144127 408ef884685Srb144127 default: 409ef884685Srb144127 return (DDI_FAILURE); 410ef884685Srb144127 } 411ef884685Srb144127 412ef884685Srb144127 /* This really shouldn't fail - but check anyway */ 413ef884685Srb144127 if ((rv = ds_cap_fini(&ds_pri_cap)) != 0) { 414ef884685Srb144127 cmn_err(CE_WARN, "ds_cap_fini failed: %d", rv); 415ef884685Srb144127 } 416ef884685Srb144127 417ef884685Srb144127 if (sp != NULL && sp->ds_pri_len != 0) 418ef884685Srb144127 kmem_free(sp->ds_pri, sp->ds_pri_len); 419ef884685Srb144127 4203597045eSnarayan ds_pri_ops.cb_arg = NULL; 4213597045eSnarayan 422ef884685Srb144127 ddi_remove_minor_node(dip, NULL); 423ef884685Srb144127 cv_destroy(&sp->cv); 424ef884685Srb144127 mutex_destroy(&sp->lock); 425ef884685Srb144127 ddi_soft_state_free(ds_pri_statep, instance); 426ef884685Srb144127 427ef884685Srb144127 return (DDI_SUCCESS); 428ef884685Srb144127 } 429ef884685Srb144127 430ef884685Srb144127 431ef884685Srb144127 /*ARGSUSED*/ 432ef884685Srb144127 static int 433ef884685Srb144127 ds_pri_open(dev_t *devp, int flag, int otyp, cred_t *credp) 434ef884685Srb144127 { 435ef884685Srb144127 ds_pri_state_t *sp; 436ef884685Srb144127 int instance; 437ef884685Srb144127 438ef884685Srb144127 if (otyp != OTYP_CHR) 439ef884685Srb144127 return (EINVAL); 440ef884685Srb144127 441ef884685Srb144127 instance = getminor(*devp); 442ef884685Srb144127 sp = ddi_get_soft_state(ds_pri_statep, instance); 443ef884685Srb144127 if (sp == NULL) 444ef884685Srb144127 return (ENXIO); 445ef884685Srb144127 4460d63ce2bSvenki mutex_enter(&sp->lock); 4470d63ce2bSvenki 4480d63ce2bSvenki /* 4494df55fdeSJanie Lu * Proceed if we have PRI data (possibly obtained from 4504df55fdeSJanie Lu * static HV PRI or last pushed DS PRI data update). 4514df55fdeSJanie Lu * If no PRI data and we have no DS PRI service then this 4524df55fdeSJanie Lu * means that PRI DS has never called the registration callback. 453e82e447aSkellena * A while loop is necessary as we might have been woken up 454e82e447aSkellena * prematurely, e.g., due to a debugger or "pstack" etc. 4550d63ce2bSvenki * Wait here and the callback will signal us when it has completed 4560d63ce2bSvenki * its work. 4570d63ce2bSvenki */ 4584df55fdeSJanie Lu if (!(sp->state & DS_PRI_HAS_PRI)) { 4594df55fdeSJanie Lu while (!(sp->state & DS_PRI_HAS_SERVICE)) { 4600d63ce2bSvenki if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 4610d63ce2bSvenki mutex_exit(&sp->lock); 4620d63ce2bSvenki return (EINTR); 4630d63ce2bSvenki } 4640d63ce2bSvenki } 4654df55fdeSJanie Lu } 4660d63ce2bSvenki 4670d63ce2bSvenki sp->num_opens++; 4680d63ce2bSvenki mutex_exit(&sp->lock); 4690d63ce2bSvenki 470ef884685Srb144127 DS_PRI_DBG("ds_pri_open: state = 0x%x\n", sp->state); 471ef884685Srb144127 472ef884685Srb144127 return (0); 473ef884685Srb144127 } 474ef884685Srb144127 475ef884685Srb144127 476ef884685Srb144127 /*ARGSUSED*/ 477ef884685Srb144127 static int 478ef884685Srb144127 ds_pri_close(dev_t dev, int flag, int otyp, cred_t *credp) 479ef884685Srb144127 { 480ef884685Srb144127 int instance; 4810d63ce2bSvenki ds_pri_state_t *sp; 482ef884685Srb144127 483ef884685Srb144127 if (otyp != OTYP_CHR) 484ef884685Srb144127 return (EINVAL); 485ef884685Srb144127 486ef884685Srb144127 DS_PRI_DBG("ds_pri_close\n"); 487ef884685Srb144127 488ef884685Srb144127 instance = getminor(dev); 4890d63ce2bSvenki if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 490ef884685Srb144127 return (ENXIO); 491ef884685Srb144127 4920d63ce2bSvenki mutex_enter(&sp->lock); 4930d63ce2bSvenki if (!(sp->state & DS_PRI_HAS_SERVICE)) { 4940d63ce2bSvenki mutex_exit(&sp->lock); 4950d63ce2bSvenki return (0); 4960d63ce2bSvenki } 4970d63ce2bSvenki 4980d63ce2bSvenki if (--sp->num_opens > 0) { 4990d63ce2bSvenki mutex_exit(&sp->lock); 5000d63ce2bSvenki return (0); 5010d63ce2bSvenki } 5020d63ce2bSvenki 5030d63ce2bSvenki sp->state &= ~DS_PRI_REQUESTED; 5040d63ce2bSvenki mutex_exit(&sp->lock); 505ef884685Srb144127 return (0); 506ef884685Srb144127 } 507ef884685Srb144127 508ef884685Srb144127 509ef884685Srb144127 /*ARGSUSED*/ 510ef884685Srb144127 static int 511ef884685Srb144127 ds_pri_read(dev_t dev, struct uio *uiop, cred_t *credp) 512ef884685Srb144127 { 513ef884685Srb144127 ds_pri_state_t *sp; 514ef884685Srb144127 int instance; 515ef884685Srb144127 size_t len; 516ef884685Srb144127 int retval; 517ef884685Srb144127 caddr_t tmpbufp; 5189b69f4d8SSree Vemuri offset_t off = uiop->uio_offset; 519ef884685Srb144127 520ef884685Srb144127 instance = getminor(dev); 521ef884685Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 522ef884685Srb144127 return (ENXIO); 523ef884685Srb144127 524ef884685Srb144127 len = uiop->uio_resid; 525ef884685Srb144127 526ef884685Srb144127 if (len == 0) 527ef884685Srb144127 return (0); 528ef884685Srb144127 529ef884685Srb144127 mutex_enter(&sp->lock); 530ef884685Srb144127 531ef884685Srb144127 DS_PRI_DBG("ds_pri_read: state = 0x%x\n", sp->state); 532ef884685Srb144127 533ef884685Srb144127 /* block or bail if there is no current PRI */ 534ef884685Srb144127 if (!(sp->state & DS_PRI_HAS_PRI)) { 535ef884685Srb144127 DS_PRI_DBG("ds_pri_read: no PRI held\n"); 536ef884685Srb144127 537ef884685Srb144127 if (uiop->uio_fmode & (FNDELAY | FNONBLOCK)) { 538ef884685Srb144127 mutex_exit(&sp->lock); 539ef884685Srb144127 return (EAGAIN); 540ef884685Srb144127 } 541ef884685Srb144127 542ef884685Srb144127 while (!(sp->state & DS_PRI_HAS_PRI)) { 543ef884685Srb144127 DS_PRI_DBG("ds_pri_read: state = 0x%x\n", sp->state); 544ef884685Srb144127 request_pri(sp); 545ef884685Srb144127 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 546ef884685Srb144127 mutex_exit(&sp->lock); 547ef884685Srb144127 return (EINTR); 548ef884685Srb144127 } 549ef884685Srb144127 } 550ef884685Srb144127 } 551ef884685Srb144127 5529b69f4d8SSree Vemuri if (len > sp->ds_pri_len) 5539b69f4d8SSree Vemuri len = sp->ds_pri_len; 554ef884685Srb144127 555ef884685Srb144127 if (len == 0) { 556ef884685Srb144127 mutex_exit(&sp->lock); 557ef884685Srb144127 return (0); 558ef884685Srb144127 } 559ef884685Srb144127 560ef884685Srb144127 /* 561ef884685Srb144127 * We're supposed to move the data out to userland, but 562ef884685Srb144127 * that can suspend because of page faults etc., and meanwhile 563ef884685Srb144127 * other parts of this driver want to update the PRI buffer ... 564ef884685Srb144127 * we could hold the data buffer locked with a flag etc., 565ef884685Srb144127 * but that's still a lock ... a simpler mechanism - if not quite 566ef884685Srb144127 * as performance efficient is to simply clone here the part of 567ef884685Srb144127 * the buffer we care about and then the original can be released 568ef884685Srb144127 * for further updates while the uiomove continues. 569ef884685Srb144127 */ 570ef884685Srb144127 571ef884685Srb144127 tmpbufp = kmem_alloc(len, KM_SLEEP); 5729b69f4d8SSree Vemuri bcopy(((caddr_t)sp->ds_pri), tmpbufp, len); 573ef884685Srb144127 mutex_exit(&sp->lock); 574ef884685Srb144127 575ef884685Srb144127 retval = uiomove(tmpbufp, len, UIO_READ, uiop); 576ef884685Srb144127 577ef884685Srb144127 kmem_free(tmpbufp, len); 578ef884685Srb144127 5799b69f4d8SSree Vemuri /* 5809b69f4d8SSree Vemuri * restore uio_offset after uiomove since the driver 5819b69f4d8SSree Vemuri * does not support the concept of position. 5829b69f4d8SSree Vemuri */ 5839b69f4d8SSree Vemuri uiop->uio_offset = off; 5849b69f4d8SSree Vemuri 585ef884685Srb144127 return (retval); 586ef884685Srb144127 } 587ef884685Srb144127 588ef884685Srb144127 589ef884685Srb144127 /*ARGSUSED*/ 590ef884685Srb144127 static int 591ef884685Srb144127 ds_pri_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 592ef884685Srb144127 int *rvalp) 593ef884685Srb144127 { 594ef884685Srb144127 ds_pri_state_t *sp; 595ef884685Srb144127 int instance; 596ef884685Srb144127 597ef884685Srb144127 instance = getminor(dev); 598ef884685Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 599ef884685Srb144127 return (ENXIO); 600ef884685Srb144127 601ef884685Srb144127 switch (cmd) { 602ef884685Srb144127 case DSPRI_GETINFO: { 603ef884685Srb144127 struct dspri_info info; 604ef884685Srb144127 605ef884685Srb144127 if (!(mode & FREAD)) 606ef884685Srb144127 return (EACCES); 607ef884685Srb144127 608ef884685Srb144127 /* 609ef884685Srb144127 * We are not guaranteed that ddi_copyout(9F) will read 610ef884685Srb144127 * atomically anything larger than a byte. Therefore we 611ef884685Srb144127 * must duplicate the size before copying it out to the user. 612ef884685Srb144127 */ 613ef884685Srb144127 mutex_enter(&sp->lock); 614ef884685Srb144127 615ef884685Srb144127 loop:; 616ef884685Srb144127 if (sp->state & DS_PRI_HAS_PRI) { 617ef884685Srb144127 /* If we have a PRI simply return the info */ 618ef884685Srb144127 info.size = sp->ds_pri_len; 619ef884685Srb144127 info.token = sp->gencount; 620ef884685Srb144127 } else 621ef884685Srb144127 if (!(sp->state & DS_PRI_HAS_SERVICE)) { 622ef884685Srb144127 /* If we have no service return a nil response */ 623ef884685Srb144127 info.size = 0; 624ef884685Srb144127 info.token = 0; 625ef884685Srb144127 } else { 626ef884685Srb144127 request_pri(sp); 627ef884685Srb144127 /* wait for something & check again */ 628ef884685Srb144127 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 629ef884685Srb144127 mutex_exit(&sp->lock); 630ef884685Srb144127 return (EINTR); 631ef884685Srb144127 } 632ef884685Srb144127 goto loop; 633ef884685Srb144127 } 634ef884685Srb144127 DS_PRI_DBG("ds_pri_ioctl: DSPRI_GETINFO sz=0x%lx tok=0x%lx\n", 635ef884685Srb144127 info.size, info.token); 636ef884685Srb144127 mutex_exit(&sp->lock); 637ef884685Srb144127 638ef884685Srb144127 if (ddi_copyout(&info, (void *)arg, sizeof (info), mode) != 0) 639ef884685Srb144127 return (EFAULT); 640ef884685Srb144127 break; 641ef884685Srb144127 } 642ef884685Srb144127 643ef884685Srb144127 case DSPRI_WAIT: { 644ef884685Srb144127 uint64_t gencount; 645ef884685Srb144127 646ef884685Srb144127 if (ddi_copyin((void *)arg, &gencount, sizeof (gencount), 647ef884685Srb144127 mode) != 0) 648ef884685Srb144127 return (EFAULT); 649ef884685Srb144127 650ef884685Srb144127 mutex_enter(&sp->lock); 651ef884685Srb144127 652ef884685Srb144127 DS_PRI_DBG("ds_pri_ioctl: DSPRI_WAIT gen=0x%lx sp->gen=0x%lx\n", 653ef884685Srb144127 gencount, sp->gencount); 654ef884685Srb144127 655ef884685Srb144127 while ((sp->state & DS_PRI_HAS_PRI) == 0 || 656ef884685Srb144127 gencount == sp->gencount) { 657e82e447aSkellena if ((sp->state & DS_PRI_HAS_PRI) == 0) 658e82e447aSkellena request_pri(sp); 659ef884685Srb144127 if (cv_wait_sig(&sp->cv, &sp->lock) == 0) { 660ef884685Srb144127 mutex_exit(&sp->lock); 661ef884685Srb144127 return (EINTR); 662ef884685Srb144127 } 663ef884685Srb144127 } 664ef884685Srb144127 mutex_exit(&sp->lock); 665ef884685Srb144127 break; 666ef884685Srb144127 } 667ef884685Srb144127 668ef884685Srb144127 default: 669ef884685Srb144127 return (ENOTTY); 670ef884685Srb144127 } 671ef884685Srb144127 return (0); 672ef884685Srb144127 } 673ef884685Srb144127 674ef884685Srb144127 675ef884685Srb144127 /* assumes sp->lock is held when called */ 676ef884685Srb144127 static void 677ef884685Srb144127 request_pri(ds_pri_state_t *sp) 678ef884685Srb144127 { 679ef884685Srb144127 ds_pri_msg_t reqmsg; 680ef884685Srb144127 681ef884685Srb144127 ASSERT(MUTEX_HELD(&sp->lock)); 682ef884685Srb144127 683ef884685Srb144127 /* If a request is already pending we're done */ 684ef884685Srb144127 if (!(sp->state & DS_PRI_HAS_SERVICE)) 685ef884685Srb144127 return; 686ef884685Srb144127 if (sp->state & DS_PRI_REQUESTED) 687ef884685Srb144127 return; 688ef884685Srb144127 689ef884685Srb144127 /* If we have an old PRI - remove it */ 690ef884685Srb144127 if (sp->state & DS_PRI_HAS_PRI) { 691ef884685Srb144127 ASSERT(sp->ds_pri_len != 0); 692ef884685Srb144127 ASSERT(sp->ds_pri != NULL); 693ef884685Srb144127 694ef884685Srb144127 /* remove the old data if we have an outstanding request */ 695ef884685Srb144127 kmem_free(sp->ds_pri, sp->ds_pri_len); 696ef884685Srb144127 sp->ds_pri_len = 0; 697ef884685Srb144127 sp->ds_pri = NULL; 698ef884685Srb144127 sp->state &= ~DS_PRI_HAS_PRI; 699ef884685Srb144127 } else { 700ef884685Srb144127 ASSERT(sp->ds_pri == NULL); 701ef884685Srb144127 ASSERT(sp->ds_pri_len == 0); 702ef884685Srb144127 } 703ef884685Srb144127 704ef884685Srb144127 reqmsg.hdr.seq_num = ++(sp->req_id); 705ef884685Srb144127 reqmsg.hdr.type = DS_PRI_REQUEST; 706ef884685Srb144127 707ef884685Srb144127 DS_PRI_DBG("request_pri: request id 0x%lx\n", sp->req_id); 708ef884685Srb144127 709ef884685Srb144127 /* 710ef884685Srb144127 * Request consists of header only. 711ef884685Srb144127 * We don't care about fail status for ds_send; 712ef884685Srb144127 * if it does fail we will get an unregister callback 713ef884685Srb144127 * from the DS framework and we handle the state change 714ef884685Srb144127 * there. 715ef884685Srb144127 */ 716ef884685Srb144127 (void) ds_cap_send(sp->ds_pri_handle, &reqmsg, sizeof (reqmsg.hdr)); 717ef884685Srb144127 718ef884685Srb144127 sp->state |= DS_PRI_REQUESTED; 719ef884685Srb144127 sp->last_req_id = sp->req_id; 720ef884685Srb144127 } 721ef884685Srb144127 722ef884685Srb144127 /* 723ef884685Srb144127 * DS Callbacks 724ef884685Srb144127 */ 725ef884685Srb144127 /*ARGSUSED*/ 726ef884685Srb144127 static void 727ef884685Srb144127 ds_pri_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl) 728ef884685Srb144127 { 729ef884685Srb144127 dev_info_t *dip = arg; 730ef884685Srb144127 ds_pri_state_t *sp; 731ef884685Srb144127 int instance; 732ef884685Srb144127 733ef884685Srb144127 instance = ddi_get_instance(dip); 734ef884685Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 735ef884685Srb144127 return; 736ef884685Srb144127 737ef884685Srb144127 DS_PRI_DBG("ds_pri_reg_handler: registering handle 0x%lx for version " 738ef884685Srb144127 "0x%x:0x%x\n", (uint64_t)hdl, ver->major, ver->minor); 739ef884685Srb144127 7404df55fdeSJanie Lu /* When the domain service comes up automatically update the state */ 741ef884685Srb144127 mutex_enter(&sp->lock); 742ef884685Srb144127 743ef884685Srb144127 ASSERT(sp->ds_pri_handle == DS_INVALID_HDL); 744ef884685Srb144127 sp->ds_pri_handle = hdl; 745ef884685Srb144127 7464df55fdeSJanie Lu ASSERT(!(sp->state & DS_PRI_HAS_SERVICE)); 747ef884685Srb144127 sp->state |= DS_PRI_HAS_SERVICE; 748ef884685Srb144127 749ef884685Srb144127 /* 750ef884685Srb144127 * Cannot request a PRI here, because the reg handler cannot 751ef884685Srb144127 * do a DS send operation - we take care of this later. 7524df55fdeSJanie Lu * Static hv pri data might be available. 753ef884685Srb144127 */ 7540d63ce2bSvenki 7550d63ce2bSvenki /* Wake up anyone waiting in open() */ 7560d63ce2bSvenki cv_broadcast(&sp->cv); 7570d63ce2bSvenki 758ef884685Srb144127 mutex_exit(&sp->lock); 759ef884685Srb144127 } 760ef884685Srb144127 761ef884685Srb144127 762ef884685Srb144127 static void 763ef884685Srb144127 ds_pri_unreg_handler(ds_cb_arg_t arg) 764ef884685Srb144127 { 765ef884685Srb144127 dev_info_t *dip = arg; 766ef884685Srb144127 ds_pri_state_t *sp; 767ef884685Srb144127 int instance; 768ef884685Srb144127 769ef884685Srb144127 instance = ddi_get_instance(dip); 770ef884685Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 771ef884685Srb144127 return; 772ef884685Srb144127 773ef884685Srb144127 DS_PRI_DBG("ds_pri_unreg_handler: un-registering ds_pri service\n"); 774ef884685Srb144127 775ef884685Srb144127 mutex_enter(&sp->lock); 776ef884685Srb144127 7774df55fdeSJanie Lu /* 7784df55fdeSJanie Lu * Note that if the service goes offline, we don't 7794df55fdeSJanie Lu * free up the current PRI data at hand. It is assumed 7804df55fdeSJanie Lu * that PRI DS service will only push new update when 7814df55fdeSJanie Lu * it comes online. We mark the state to indicate no 7824df55fdeSJanie Lu * DS PRI service is available. The current PRI data if 7834df55fdeSJanie Lu * available is provided to the consumers. 7844df55fdeSJanie Lu */ 785ef884685Srb144127 sp->ds_pri_handle = DS_INVALID_HDL; 7864df55fdeSJanie Lu sp->state &= ~DS_PRI_HAS_SERVICE; 787ef884685Srb144127 788ef884685Srb144127 mutex_exit(&sp->lock); 789ef884685Srb144127 } 790ef884685Srb144127 791ef884685Srb144127 792ef884685Srb144127 static void 793ef884685Srb144127 ds_pri_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) 794ef884685Srb144127 { 795ef884685Srb144127 dev_info_t *dip = arg; 796ef884685Srb144127 ds_pri_state_t *sp; 797ef884685Srb144127 int instance; 798ef884685Srb144127 void *data; 799ef884685Srb144127 ds_pri_msg_t *msgp; 800ef884685Srb144127 size_t pri_size; 801ef884685Srb144127 802ef884685Srb144127 msgp = (ds_pri_msg_t *)buf; 803ef884685Srb144127 804ef884685Srb144127 /* make sure the header is at least valid */ 805ef884685Srb144127 if (buflen < sizeof (msgp->hdr)) 806ef884685Srb144127 return; 807ef884685Srb144127 808ef884685Srb144127 DS_PRI_DBG("ds_pri_data_handler: msg buf len 0x%lx : type 0x%lx, " 809ef884685Srb144127 "seqn 0x%lx\n", buflen, msgp->hdr.type, msgp->hdr.seq_num); 810ef884685Srb144127 811ef884685Srb144127 instance = ddi_get_instance(dip); 812ef884685Srb144127 if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL) 813ef884685Srb144127 return; 814ef884685Srb144127 815ef884685Srb144127 mutex_enter(&sp->lock); 816ef884685Srb144127 817ef884685Srb144127 ASSERT(sp->state & DS_PRI_HAS_SERVICE); 818ef884685Srb144127 819ef884685Srb144127 switch (msgp->hdr.type) { 820ef884685Srb144127 case DS_PRI_DATA: /* in response to a request from us */ 821ef884685Srb144127 break; 822ef884685Srb144127 case DS_PRI_UPDATE: /* aynch notification */ 823ef884685Srb144127 /* our default response to this is to request the PRI */ 824ef884685Srb144127 /* simply issue a request for the new PRI */ 825ef884685Srb144127 request_pri(sp); 826ef884685Srb144127 goto done; 827ef884685Srb144127 default: /* ignore garbage or unknown message types */ 828ef884685Srb144127 goto done; 829ef884685Srb144127 } 830ef884685Srb144127 831ef884685Srb144127 /* 832ef884685Srb144127 * If there is no pending PRI request, then we've received a 833ef884685Srb144127 * bogus data message ... so ignore it. 834ef884685Srb144127 */ 835ef884685Srb144127 836ef884685Srb144127 if (!(sp->state & DS_PRI_REQUESTED)) { 837ef884685Srb144127 cmn_err(CE_WARN, "Received DS pri data without request"); 838ef884685Srb144127 goto done; 839ef884685Srb144127 } 840ef884685Srb144127 841ef884685Srb144127 /* response to a request therefore old PRI must be gone */ 842ef884685Srb144127 ASSERT(!(sp->state & DS_PRI_HAS_PRI)); 843ef884685Srb144127 ASSERT(sp->ds_pri_len == 0); 844ef884685Srb144127 ASSERT(sp->ds_pri == NULL); 845ef884685Srb144127 846ef884685Srb144127 /* response seq_num should match our request seq_num */ 847ef884685Srb144127 if (msgp->hdr.seq_num != sp->last_req_id) { 848ef884685Srb144127 cmn_err(CE_WARN, "Received DS pri data out of sequence with " 849ef884685Srb144127 "request"); 850ef884685Srb144127 goto done; 851ef884685Srb144127 } 852ef884685Srb144127 853ef884685Srb144127 pri_size = buflen - sizeof (msgp->hdr); 8544df55fdeSJanie Lu if (pri_size == 0) { 8554df55fdeSJanie Lu cmn_err(CE_WARN, "Received DS pri data of size 0"); 8564df55fdeSJanie Lu goto done; 8574df55fdeSJanie Lu } 858ef884685Srb144127 data = kmem_alloc(pri_size, KM_SLEEP); 859ef884685Srb144127 sp->ds_pri = data; 860ef884685Srb144127 sp->ds_pri_len = pri_size; 861ef884685Srb144127 bcopy(msgp->data, data, sp->ds_pri_len); 862ef884685Srb144127 sp->state &= ~DS_PRI_REQUESTED; 863ef884685Srb144127 sp->state |= DS_PRI_HAS_PRI; 864ef884685Srb144127 865ef884685Srb144127 sp->gencount++; 866ef884685Srb144127 cv_broadcast(&sp->cv); 867ef884685Srb144127 868ef884685Srb144127 done:; 869ef884685Srb144127 mutex_exit(&sp->lock); 870ef884685Srb144127 } 8714df55fdeSJanie Lu 8724df55fdeSJanie Lu /* 8734df55fdeSJanie Lu * Routine to get static PRI data from the Hypervisor. 8744df55fdeSJanie Lu * If successful, this PRI data is the last known PRI 8754df55fdeSJanie Lu * data generated since the last poweron reset. 8764df55fdeSJanie Lu */ 8774df55fdeSJanie Lu static uint64_t 8784df55fdeSJanie Lu ds_get_hv_pri(ds_pri_state_t *sp) 8794df55fdeSJanie Lu { 8804df55fdeSJanie Lu uint64_t status; 8814df55fdeSJanie Lu uint64_t pri_size; 8824df55fdeSJanie Lu uint64_t buf_size; 8834df55fdeSJanie Lu uint64_t buf_pa; 8844df55fdeSJanie Lu caddr_t buf_va = NULL; 8854df55fdeSJanie Lu caddr_t pri_data; 8864df55fdeSJanie Lu 8874df55fdeSJanie Lu /* 8884df55fdeSJanie Lu * Get pri buffer size by calling hcall with buffer size 0. 8894df55fdeSJanie Lu */ 8904df55fdeSJanie Lu pri_size = 0LL; 8914df55fdeSJanie Lu status = hv_mach_pri((uint64_t)0, &pri_size); 8924df55fdeSJanie Lu if (status == H_ENOTSUPPORTED || status == H_ENOACCESS) { 8937c18cbb1SSree Vemuri /* 8947c18cbb1SSree Vemuri * hv_mach_pri() is not supported on a guest domain. 8957c18cbb1SSree Vemuri * Unregister pboot API group to prevent failures. 8967c18cbb1SSree Vemuri */ 8977c18cbb1SSree Vemuri (void) hsvc_unregister(&pboot_hsvc); 8987c18cbb1SSree Vemuri hsvc_pboot_available = B_FALSE; 8994df55fdeSJanie Lu DS_PRI_DBG("ds_get_hv_pri: hv_mach_pri service is not " 9004df55fdeSJanie Lu "available. errorno: 0x%lx\n", status); 9017c18cbb1SSree Vemuri return (0); 9027c18cbb1SSree Vemuri } else if (pri_size == 0) { 9037c18cbb1SSree Vemuri return (1); 9047c18cbb1SSree Vemuri } else { 9057c18cbb1SSree Vemuri DS_PRI_DBG("ds_get_hv_pri: hv_mach_pri pri size: 0x%lx\n", 9067c18cbb1SSree Vemuri pri_size); 9074df55fdeSJanie Lu } 9084df55fdeSJanie Lu 9094df55fdeSJanie Lu /* 9104df55fdeSJanie Lu * contig_mem_alloc requires size to be a power of 2. 9114df55fdeSJanie Lu * Increase size to next power of 2 if necessary. 9124df55fdeSJanie Lu */ 913*de710d24SJosef 'Jeff' Sipek if (!ISP2(pri_size)) 9144df55fdeSJanie Lu buf_size = 1 << highbit(pri_size); 9154df55fdeSJanie Lu DS_PRI_DBG("ds_get_hv_pri: buf_size = 0x%lx\n", buf_size); 9164df55fdeSJanie Lu 9174df55fdeSJanie Lu buf_va = contig_mem_alloc(buf_size); 9184df55fdeSJanie Lu if (buf_va == NULL) 9194df55fdeSJanie Lu return (1); 9204df55fdeSJanie Lu 9214df55fdeSJanie Lu buf_pa = va_to_pa(buf_va); 9224df55fdeSJanie Lu DS_PRI_DBG("ds_get_hv_pri: buf_pa 0x%lx\n", buf_pa); 9234df55fdeSJanie Lu status = hv_mach_pri(buf_pa, &pri_size); 9244df55fdeSJanie Lu DS_PRI_DBG("ds_get_hv_pri: hv_mach_pri status = 0x%lx\n", status); 9254df55fdeSJanie Lu 9264df55fdeSJanie Lu if (status == H_EOK) { 9274df55fdeSJanie Lu pri_data = kmem_alloc(pri_size, KM_SLEEP); 9284df55fdeSJanie Lu sp->ds_pri = pri_data; 9294df55fdeSJanie Lu sp->ds_pri_len = pri_size; 9304df55fdeSJanie Lu bcopy(buf_va, pri_data, sp->ds_pri_len); 9314df55fdeSJanie Lu sp->state |= DS_PRI_HAS_PRI; 9324df55fdeSJanie Lu sp->gencount++; 9334df55fdeSJanie Lu } 9344df55fdeSJanie Lu 9354df55fdeSJanie Lu contig_mem_free(buf_va, buf_size); 9364df55fdeSJanie Lu 9374df55fdeSJanie Lu return (status); 9384df55fdeSJanie Lu } 939