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