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