xref: /illumos-gate/usr/src/lib/libpri/common/pri.c (revision 1da57d55)
1ef884685Srb /*
2ef884685Srb  * CDDL HEADER START
3ef884685Srb  *
4ef884685Srb  * The contents of this file are subject to the terms of the
5ef884685Srb  * Common Development and Distribution License (the "License").
6ef884685Srb  * You may not use this file except in compliance with the License.
7ef884685Srb  *
8ef884685Srb  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9ef884685Srb  * or http://www.opensolaris.org/os/licensing.
10ef884685Srb  * See the License for the specific language governing permissions
11ef884685Srb  * and limitations under the License.
12ef884685Srb  *
13ef884685Srb  * When distributing Covered Code, include this CDDL HEADER in each
14ef884685Srb  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15ef884685Srb  * If applicable, add the following below this CDDL HEADER, with the
16ef884685Srb  * fields enclosed by brackets "[]" replaced with your own identifying
17ef884685Srb  * information: Portions Copyright [yyyy] [name of copyright owner]
18ef884685Srb  *
19ef884685Srb  * CDDL HEADER END
20ef884685Srb  */
21ef884685Srb /*
22ef884685Srb  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23ef884685Srb  * Use is subject to license terms.
24ef884685Srb  */
25ef884685Srb 
26ef884685Srb #include <stdio.h>
27ef884685Srb #include <sys/param.h>
28ef884685Srb #include <fcntl.h>
29ef884685Srb #include <poll.h>
30ef884685Srb #include <string.h>
31ef884685Srb #include <unistd.h>
32ef884685Srb #include <errno.h>
33ef884685Srb 
34ef884685Srb #include "sys/ds_pri.h"
35ef884685Srb #include "pri.h"
36ef884685Srb 
37*e82e447aSkellena static int pri_fd = -1;
38*e82e447aSkellena 
39*e82e447aSkellena 
40*e82e447aSkellena 
41ef884685Srb /*
42*e82e447aSkellena  * Library init function
43ef884685Srb  * Returns: Success (0), Failure (-1)
44ef884685Srb  */
45ef884685Srb int
pri_init(void)46ef884685Srb pri_init(void)
47ef884685Srb {
48*e82e447aSkellena 	int fd;
49*e82e447aSkellena 
50*e82e447aSkellena 	if (pri_fd != -1)
51*e82e447aSkellena 		return (-1);
52*e82e447aSkellena 
53*e82e447aSkellena 	fd = open(DS_PRI_DRIVER, O_RDONLY);
54*e82e447aSkellena 	if (fd < 0)
55*e82e447aSkellena 		return (-1);
56*e82e447aSkellena 
57*e82e447aSkellena 	pri_fd = fd;
58*e82e447aSkellena 
59ef884685Srb 	return (0);
60ef884685Srb }
61ef884685Srb 
62ef884685Srb /*
63*e82e447aSkellena  * Library fini function
64ef884685Srb  * Returns: N/A
65ef884685Srb  */
66ef884685Srb void
pri_fini(void)67ef884685Srb pri_fini(void)
68ef884685Srb {
69*e82e447aSkellena 	if (pri_fd < 0)
70*e82e447aSkellena 		return;
71*e82e447aSkellena 
72*e82e447aSkellena 	(void) close(pri_fd);
73*e82e447aSkellena 	pri_fd = -1;
74ef884685Srb }
75ef884685Srb 
76ef884685Srb /*
77ef884685Srb  * PRI retrieval function.
78ef884685Srb  * Description:
79ef884685Srb  *	- Library routine to retrieve the Physical Resource Inventory (PRI)
80ef884685Srb  *	- Utilized by sun4v platforms which support Logical Domains
81ef884685Srb  *	- Interacts with the ds_pri pseudo driver to retrieve the
82ef884685Srb  *	  PRI. ds_pri driver in turn gets the PRI from the
83ef884685Srb  *	  Domain Services kernel module. Domain Services gets the
84ef884685Srb  *	  PRI from the Service Processor via LDC (Logical Domain
85ef884685Srb  *	  Channel).
86ef884685Srb  *	- Consumers of this api include FMA, Zeus, and picld
87ef884685Srb  *	- MT-Safe, Stateless
88ef884685Srb  *
89ef884685Srb  * Imports:
90ef884685Srb  *	- ds_pri driver interfaces
91ef884685Srb  *
92ef884685Srb  * Arguments:
93ef884685Srb  *	- wait: specifies whether caller wants to wait for a new PRI,
94ef884685Srb  *		PRI_GET is no-wait, PRI_WAITGET is wait-forever
95ef884685Srb  *	- token: opaque PRI token, accepted from and/or returned to caller,
96ef884685Srb  *		see write-only or read-write semantics below
97ef884685Srb  *	- buf: PRI buffer received from ds_pri driver, returned to caller
98ef884685Srb  *	- allocp: caller provided pointer to memory allocator function
99ef884685Srb  *	- freep: caller provided pointer to memory free function
100ef884685Srb  *
101ef884685Srb  * Calling Semantics:
102ef884685Srb  *	- PRI_GET call ignores the token passed in, and returns
103ef884685Srb  *	  immediately with current PRI and its token (if any)
104ef884685Srb  *	- PRI_WAITGET call returns only upon the receipt of a new PRI
105ef884685Srb  *	  whose token differs from the token passed in by the caller;
106ef884685Srb  *	  the passed in token should come from a previous pri_get()
107ef884685Srb  *	  call with return value >= 0; the new PRI buffer and its token
108ef884685Srb  *	  are returned to the caller
109ef884685Srb  *	- If wait time must be bounded, the caller can spawn a thread
110ef884685Srb  *	  which makes a PRI_WAITGET call; caller can choose to kill the
111ef884685Srb  *	  spawned thread after a finite time
112ef884685Srb  *
113ef884685Srb  * Usage Semantics:
114ef884685Srb  *	- Caller can use the returned PRI buffer as an argument to
115ef884685Srb  *	  to md_init_intern() to process it into a machine
116ef884685Srb  *	  descriptor (md_t) format
117ef884685Srb  *	- Caller can choose to supply the same allocator and free
118ef884685Srb  *	  functions to the md_init_intern() call
119ef884685Srb  *	- Once the caller is done using these data structures,
120ef884685Srb  *	  the following actions need to be performed by the caller:
121ef884685Srb  *		- md_fini(mdp) if called md_init_intern()
122ef884685Srb  *		- freep(bufp, size)
123ef884685Srb  *
124ef884685Srb  * Returns:
125ef884685Srb  *	>0 if PRI is returned successfully (size of PRI buffer)
126ef884685Srb  *	0 if no PRI is available
127*e82e447aSkellena  *	-1 if there is an error (errno contains the error code
128*e82e447aSkellena  *	provided)
129ef884685Srb  *
130ef884685Srb  */
131ef884685Srb ssize_t
pri_get(uint8_t wait,uint64_t * token,uint64_t ** buf,void * (* allocp)(size_t),void (* freep)(void *,size_t))132ef884685Srb pri_get(uint8_t wait, uint64_t *token, uint64_t **buf,
133ef884685Srb 		void *(*allocp)(size_t), void (*freep)(void *, size_t))
134ef884685Srb {
135ef884685Srb 	uint64_t		*bufp;		/* buf holding PRI */
136ef884685Srb 	size_t			size;		/* sizeof PRI */
137ef884685Srb 	struct dspri_info	pri_info;	/* info about PRI */
138ef884685Srb 	struct dspri_info	pri_info2;	/* for PRI delta check */
139ef884685Srb 
140*e82e447aSkellena 	if (pri_fd < 0) {
141*e82e447aSkellena 		errno = EBADF;
142ef884685Srb 		return (-1);
143*e82e447aSkellena 	}
144ef884685Srb 
145ef884685Srb 	if (wait == PRI_WAITGET) {
146ef884685Srb 		/* wait until have new PRI with different token */
147*e82e447aSkellena 		if (ioctl(pri_fd, DSPRI_WAIT, token) < 0) {
148ef884685Srb 			return (-1);
149ef884685Srb 		}
150ef884685Srb 	}
151ef884685Srb 
152ef884685Srb 	do {
153ef884685Srb 		/* get info on current PRI */
154*e82e447aSkellena 		if (ioctl(pri_fd, DSPRI_GETINFO, &pri_info) < 0) {
155ef884685Srb 			return (-1);
156ef884685Srb 		}
157ef884685Srb 
158ef884685Srb 		size = (size_t)pri_info.size;
159ef884685Srb 
160ef884685Srb 		/* check to see if no PRI available yet */
161ef884685Srb 		if (size == 0) {
162ef884685Srb 			*token = pri_info.token;
163ef884685Srb 			return (0);
164ef884685Srb 		}
165ef884685Srb 
166ef884685Srb 		/* allocate a buffer and read the PRI into it */
167ef884685Srb 		if ((bufp = (uint64_t *)allocp(size)) == NULL) {
168*e82e447aSkellena 			if (errno == 0)
169*e82e447aSkellena 				errno = ENOMEM;
170ef884685Srb 			return (-1);
171ef884685Srb 		}
172*e82e447aSkellena 		if (read(pri_fd, bufp, size) < 0) {
173ef884685Srb 			freep(bufp, size);
174ef884685Srb 			return (-1);
175ef884685Srb 		}
176ef884685Srb 
177ef884685Srb 		/*
178ef884685Srb 		 * Check whether PRI token changed between the time
179ef884685Srb 		 * we did the DSPRI_GETINFO ioctl() and the actual
180ef884685Srb 		 * read() from the ds_pri driver. The token delta check
181ef884685Srb 		 * tries to catch the above race condition; be sure
182ef884685Srb 		 * to not leak memory on retries.
183ef884685Srb 		 */
184*e82e447aSkellena 		if (ioctl(pri_fd, DSPRI_GETINFO, &pri_info2) < 0) {
185ef884685Srb 			freep(bufp, size);
186ef884685Srb 			return (-1);
187ef884685Srb 		}
188ef884685Srb 		if (pri_info2.token != pri_info.token)
189ef884685Srb 			freep(bufp, size);
190ef884685Srb 
191ef884685Srb 	} while (pri_info2.token != pri_info.token);
192ef884685Srb 
193ef884685Srb 	/* return the PRI, its token, and its size to the caller */
194ef884685Srb 	*buf = bufp;
195ef884685Srb 	*token = pri_info.token;
196ef884685Srb 	return ((ssize_t)size);
197ef884685Srb }
198