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