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 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 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 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