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