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