xref: /titanic_44/usr/src/uts/sun4v/io/ds_pri.c (revision de710d24d2fae4468e64da999e1d952a247f142c)
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
_init(void)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
_info(struct modinfo * modinfop)251ef884685Srb144127 _info(struct modinfo *modinfop)
252ef884685Srb144127 {
253ef884685Srb144127 	return (mod_info(&modlinkage, modinfop));
254ef884685Srb144127 }
255ef884685Srb144127 
256ef884685Srb144127 
257ef884685Srb144127 int
_fini(void)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
ds_pri_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)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
ds_pri_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
ds_pri_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
ds_pri_open(dev_t * devp,int flag,int otyp,cred_t * credp)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
ds_pri_close(dev_t dev,int flag,int otyp,cred_t * credp)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
ds_pri_read(dev_t dev,struct uio * uiop,cred_t * credp)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
ds_pri_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)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
request_pri(ds_pri_state_t * sp)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
ds_pri_reg_handler(ds_cb_arg_t arg,ds_ver_t * ver,ds_svc_hdl_t hdl)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
ds_pri_unreg_handler(ds_cb_arg_t arg)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
ds_pri_data_handler(ds_cb_arg_t arg,void * buf,size_t buflen)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
ds_get_hv_pri(ds_pri_state_t * sp)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