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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Page retirement can be an extended process due to the fact that a retirement 31 * may not be possible when the original request is made. The kernel will 32 * repeatedly attempt to retire a given page, but will not let us know when the 33 * page has been retired. We therefore have to poll to see if the retirement 34 * has been completed. This poll is implemented with a bounded exponential 35 * backoff to reduce the burden which we impose upon the system. 36 * 37 * To reduce the burden on fmd in the face of retirement storms, we schedule 38 * all retries as a group. In the simplest case, we attempt to retire a single 39 * page. When forced to retry, we initially schedule a retry at a configurable 40 * interval t. If the retry fails, we schedule another at 2 * t, and so on, 41 * until t reaches the maximum interval (also configurable). Future retries 42 * for that page will occur with t equal to the maximum interval value. We 43 * will never give up on a retirement. 44 * 45 * With multiple retirements, the situation gets slightly more complicated. As 46 * indicated above, we schedule retries as a group. We don't want to deny new 47 * pages their short retry intervals, so we'll (re)set the retry interval to the 48 * value appropriate for the newest page. 49 */ 50 51 #include <cma.h> 52 53 #include <fcntl.h> 54 #include <errno.h> 55 #include <unistd.h> 56 #include <strings.h> 57 #include <fm/fmd_api.h> 58 #include <fm/libtopo.h> 59 #include <sys/fm/protocol.h> 60 #include <sys/mem.h> 61 62 int 63 cma_page_cmd(fmd_hdl_t *hdl, int cmd, nvlist_t *nvl) 64 { 65 mem_page_t mpage; 66 char *fmribuf; 67 size_t fmrisz; 68 int fd, rc, err; 69 70 if ((fd = open("/dev/mem", O_RDONLY)) < 0) 71 return (-1); /* errno is set for us */ 72 73 if ((errno = nvlist_size(nvl, &fmrisz, NV_ENCODE_NATIVE)) != 0 || 74 fmrisz > MEM_FMRI_MAX_BUFSIZE || 75 (fmribuf = fmd_hdl_alloc(hdl, fmrisz, FMD_SLEEP)) == NULL) { 76 (void) close(fd); 77 return (-1); /* errno is set for us */ 78 } 79 80 if ((errno = nvlist_pack(nvl, &fmribuf, &fmrisz, 81 NV_ENCODE_NATIVE, 0)) != 0) { 82 fmd_hdl_free(hdl, fmribuf, fmrisz); 83 (void) close(fd); 84 return (-1); /* errno is set for us */ 85 } 86 87 mpage.m_fmri = fmribuf; 88 mpage.m_fmrisz = fmrisz; 89 90 if ((rc = ioctl(fd, cmd, &mpage)) < 0) 91 err = errno; 92 93 fmd_hdl_free(hdl, fmribuf, fmrisz); 94 95 (void) close(fd); 96 97 if (rc < 0) { 98 errno = err; 99 return (-1); 100 } 101 102 return (0); 103 } 104