xref: /onnv-gate/usr/src/lib/libpri/common/pri.c (revision 4109:20d5b06dbce1)
13530Srb144127 /*
23530Srb144127  * CDDL HEADER START
33530Srb144127  *
43530Srb144127  * The contents of this file are subject to the terms of the
53530Srb144127  * Common Development and Distribution License (the "License").
63530Srb144127  * You may not use this file except in compliance with the License.
73530Srb144127  *
83530Srb144127  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93530Srb144127  * or http://www.opensolaris.org/os/licensing.
103530Srb144127  * See the License for the specific language governing permissions
113530Srb144127  * and limitations under the License.
123530Srb144127  *
133530Srb144127  * When distributing Covered Code, include this CDDL HEADER in each
143530Srb144127  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153530Srb144127  * If applicable, add the following below this CDDL HEADER, with the
163530Srb144127  * fields enclosed by brackets "[]" replaced with your own identifying
173530Srb144127  * information: Portions Copyright [yyyy] [name of copyright owner]
183530Srb144127  *
193530Srb144127  * CDDL HEADER END
203530Srb144127  */
213530Srb144127 /*
223530Srb144127  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
233530Srb144127  * Use is subject to license terms.
243530Srb144127  */
253530Srb144127 
263530Srb144127 #pragma ident	"%Z%%M%	%I%	%E% SMI"
273530Srb144127 
283530Srb144127 #include <stdio.h>
293530Srb144127 #include <sys/param.h>
303530Srb144127 #include <fcntl.h>
313530Srb144127 #include <poll.h>
323530Srb144127 #include <string.h>
333530Srb144127 #include <unistd.h>
343530Srb144127 #include <errno.h>
353530Srb144127 
363530Srb144127 #include "sys/ds_pri.h"
373530Srb144127 #include "pri.h"
383530Srb144127 
39*4109Skellena static int pri_fd = -1;
40*4109Skellena 
41*4109Skellena 
42*4109Skellena 
433530Srb144127 /*
44*4109Skellena  * Library init function
453530Srb144127  * Returns: Success (0), Failure (-1)
463530Srb144127  */
473530Srb144127 int
pri_init(void)483530Srb144127 pri_init(void)
493530Srb144127 {
50*4109Skellena 	int fd;
51*4109Skellena 
52*4109Skellena 	if (pri_fd != -1)
53*4109Skellena 		return (-1);
54*4109Skellena 
55*4109Skellena 	fd = open(DS_PRI_DRIVER, O_RDONLY);
56*4109Skellena 	if (fd < 0)
57*4109Skellena 		return (-1);
58*4109Skellena 
59*4109Skellena 	pri_fd = fd;
60*4109Skellena 
613530Srb144127 	return (0);
623530Srb144127 }
633530Srb144127 
643530Srb144127 /*
65*4109Skellena  * Library fini function
663530Srb144127  * Returns: N/A
673530Srb144127  */
683530Srb144127 void
pri_fini(void)693530Srb144127 pri_fini(void)
703530Srb144127 {
71*4109Skellena 	if (pri_fd < 0)
72*4109Skellena 		return;
73*4109Skellena 
74*4109Skellena 	(void) close(pri_fd);
75*4109Skellena 	pri_fd = -1;
763530Srb144127 }
773530Srb144127 
783530Srb144127 /*
793530Srb144127  * PRI retrieval function.
803530Srb144127  * Description:
813530Srb144127  *	- Library routine to retrieve the Physical Resource Inventory (PRI)
823530Srb144127  *	- Utilized by sun4v platforms which support Logical Domains
833530Srb144127  *	- Interacts with the ds_pri pseudo driver to retrieve the
843530Srb144127  *	  PRI. ds_pri driver in turn gets the PRI from the
853530Srb144127  *	  Domain Services kernel module. Domain Services gets the
863530Srb144127  *	  PRI from the Service Processor via LDC (Logical Domain
873530Srb144127  *	  Channel).
883530Srb144127  *	- Consumers of this api include FMA, Zeus, and picld
893530Srb144127  *	- MT-Safe, Stateless
903530Srb144127  *
913530Srb144127  * Imports:
923530Srb144127  *	- ds_pri driver interfaces
933530Srb144127  *
943530Srb144127  * Arguments:
953530Srb144127  *	- wait: specifies whether caller wants to wait for a new PRI,
963530Srb144127  *		PRI_GET is no-wait, PRI_WAITGET is wait-forever
973530Srb144127  *	- token: opaque PRI token, accepted from and/or returned to caller,
983530Srb144127  *		see write-only or read-write semantics below
993530Srb144127  *	- buf: PRI buffer received from ds_pri driver, returned to caller
1003530Srb144127  *	- allocp: caller provided pointer to memory allocator function
1013530Srb144127  *	- freep: caller provided pointer to memory free function
1023530Srb144127  *
1033530Srb144127  * Calling Semantics:
1043530Srb144127  *	- PRI_GET call ignores the token passed in, and returns
1053530Srb144127  *	  immediately with current PRI and its token (if any)
1063530Srb144127  *	- PRI_WAITGET call returns only upon the receipt of a new PRI
1073530Srb144127  *	  whose token differs from the token passed in by the caller;
1083530Srb144127  *	  the passed in token should come from a previous pri_get()
1093530Srb144127  *	  call with return value >= 0; the new PRI buffer and its token
1103530Srb144127  *	  are returned to the caller
1113530Srb144127  *	- If wait time must be bounded, the caller can spawn a thread
1123530Srb144127  *	  which makes a PRI_WAITGET call; caller can choose to kill the
1133530Srb144127  *	  spawned thread after a finite time
1143530Srb144127  *
1153530Srb144127  * Usage Semantics:
1163530Srb144127  *	- Caller can use the returned PRI buffer as an argument to
1173530Srb144127  *	  to md_init_intern() to process it into a machine
1183530Srb144127  *	  descriptor (md_t) format
1193530Srb144127  *	- Caller can choose to supply the same allocator and free
1203530Srb144127  *	  functions to the md_init_intern() call
1213530Srb144127  *	- Once the caller is done using these data structures,
1223530Srb144127  *	  the following actions need to be performed by the caller:
1233530Srb144127  *		- md_fini(mdp) if called md_init_intern()
1243530Srb144127  *		- freep(bufp, size)
1253530Srb144127  *
1263530Srb144127  * Returns:
1273530Srb144127  *	>0 if PRI is returned successfully (size of PRI buffer)
1283530Srb144127  *	0 if no PRI is available
129*4109Skellena  *	-1 if there is an error (errno contains the error code
130*4109Skellena  *	provided)
1313530Srb144127  *
1323530Srb144127  */
1333530Srb144127 ssize_t
pri_get(uint8_t wait,uint64_t * token,uint64_t ** buf,void * (* allocp)(size_t),void (* freep)(void *,size_t))1343530Srb144127 pri_get(uint8_t wait, uint64_t *token, uint64_t **buf,
1353530Srb144127 		void *(*allocp)(size_t), void (*freep)(void *, size_t))
1363530Srb144127 {
1373530Srb144127 	uint64_t		*bufp;		/* buf holding PRI */
1383530Srb144127 	size_t			size;		/* sizeof PRI */
1393530Srb144127 	struct dspri_info	pri_info;	/* info about PRI */
1403530Srb144127 	struct dspri_info	pri_info2;	/* for PRI delta check */
1413530Srb144127 
142*4109Skellena 	if (pri_fd < 0) {
143*4109Skellena 		errno = EBADF;
1443530Srb144127 		return (-1);
145*4109Skellena 	}
1463530Srb144127 
1473530Srb144127 	if (wait == PRI_WAITGET) {
1483530Srb144127 		/* wait until have new PRI with different token */
149*4109Skellena 		if (ioctl(pri_fd, DSPRI_WAIT, token) < 0) {
1503530Srb144127 			return (-1);
1513530Srb144127 		}
1523530Srb144127 	}
1533530Srb144127 
1543530Srb144127 	do {
1553530Srb144127 		/* get info on current PRI */
156*4109Skellena 		if (ioctl(pri_fd, DSPRI_GETINFO, &pri_info) < 0) {
1573530Srb144127 			return (-1);
1583530Srb144127 		}
1593530Srb144127 
1603530Srb144127 		size = (size_t)pri_info.size;
1613530Srb144127 
1623530Srb144127 		/* check to see if no PRI available yet */
1633530Srb144127 		if (size == 0) {
1643530Srb144127 			*token = pri_info.token;
1653530Srb144127 			return (0);
1663530Srb144127 		}
1673530Srb144127 
1683530Srb144127 		/* allocate a buffer and read the PRI into it */
1693530Srb144127 		if ((bufp = (uint64_t *)allocp(size)) == NULL) {
170*4109Skellena 			if (errno == 0)
171*4109Skellena 				errno = ENOMEM;
1723530Srb144127 			return (-1);
1733530Srb144127 		}
174*4109Skellena 		if (read(pri_fd, bufp, size) < 0) {
1753530Srb144127 			freep(bufp, size);
1763530Srb144127 			return (-1);
1773530Srb144127 		}
1783530Srb144127 
1793530Srb144127 		/*
1803530Srb144127 		 * Check whether PRI token changed between the time
1813530Srb144127 		 * we did the DSPRI_GETINFO ioctl() and the actual
1823530Srb144127 		 * read() from the ds_pri driver. The token delta check
1833530Srb144127 		 * tries to catch the above race condition; be sure
1843530Srb144127 		 * to not leak memory on retries.
1853530Srb144127 		 */
186*4109Skellena 		if (ioctl(pri_fd, DSPRI_GETINFO, &pri_info2) < 0) {
1873530Srb144127 			freep(bufp, size);
1883530Srb144127 			return (-1);
1893530Srb144127 		}
1903530Srb144127 		if (pri_info2.token != pri_info.token)
1913530Srb144127 			freep(bufp, size);
1923530Srb144127 
1933530Srb144127 	} while (pri_info2.token != pri_info.token);
1943530Srb144127 
1953530Srb144127 	/* return the PRI, its token, and its size to the caller */
1963530Srb144127 	*buf = bufp;
1973530Srb144127 	*token = pri_info.token;
1983530Srb144127 	return ((ssize_t)size);
1993530Srb144127 }
200