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