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