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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 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  * E-cache flushing
31  *
32  * Prior to clearing the UE cache, the CPU state code needs to ensure that the
33  * CPU's E-cache has been flushed.  The flushing is handled by the routines in
34  * in this file, which use the memory controller (mc) driver to perform the
35  * flush.
36  *
37  * Matters are complicated by the fact that there isn't a well-known device name
38  * for driver access - we have to hunt around for one.  Furthermore, the minor
39  * nodes that are created correspond to individual memory controllers, and as
40  * such can change during a DR.  We'll search for a memory controller device
41  * during initialization just to make sure that we can do E$ flushing on this
42  * platform, but we're also able to rescan if the device we found suddenly
43  * disappears.
44  */
45 
46 #include <cmd_ecache.h>
47 #include <cmd.h>
48 
49 #include <string.h>
50 #include <fcntl.h>
51 #include <unistd.h>
52 #include <errno.h>
53 #include <dirent.h>
54 #include <fm/fmd_api.h>
55 #include <sys/mc.h>
56 #include <sys/param.h>
57 
58 static int
ecache_scan_dir(const char * dir,const char * pref,char * buf,size_t bufsz)59 ecache_scan_dir(const char *dir, const char *pref, char *buf, size_t bufsz)
60 {
61 	struct dirent *dp;
62 	char path[MAXPATHLEN];
63 	DIR *mcdir;
64 
65 	if ((mcdir = opendir(dir)) == NULL)
66 		return (-1); /* errno is set for us */
67 
68 	while ((dp = readdir(mcdir)) != NULL) {
69 		struct mc_ctrlconf mcc;
70 		int fd;
71 
72 		if (strncmp(dp->d_name, pref, strlen(pref)) != 0)
73 			continue;
74 
75 		(void) snprintf(path, sizeof (path), "%s/%s", dir, dp->d_name);
76 
77 		if ((fd = open(path, O_RDONLY)) < 0)
78 			continue;
79 
80 		mcc.nmcs = 0;
81 		if (ioctl(fd, MCIOC_CTRLCONF, &mcc) >= 0 || errno != EINVAL ||
82 		    mcc.nmcs == 0) {
83 			(void) close(fd);
84 			continue;
85 		}
86 
87 		(void) close(fd);
88 		(void) closedir(mcdir);
89 
90 		if (strlen(path) >= bufsz)
91 			return (cmd_set_errno(ENOSPC));
92 		(void) strcpy(buf, path);
93 		return (0);
94 	}
95 
96 	(void) closedir(mcdir);
97 	return (cmd_set_errno(ENOENT));
98 }
99 
100 static int
ecache_find_device(char * buf,size_t bufsz)101 ecache_find_device(char *buf, size_t bufsz)
102 {
103 	if (ecache_scan_dir("/dev/mc", "mc", buf, bufsz) != 0) {
104 		/*
105 		 * Yet more platform-specific hackery.  It's possible that the
106 		 * /dev/mc links could be out of date, and thus we may not be
107 		 * able to use any of them.  As a fallback, therefore, we're
108 		 * going to search a couple of well-known locations in /devices.
109 		 */
110 		const char *dir = "/devices/ssm@0,0";
111 
112 		if (access(dir, R_OK) != 0)
113 			dir = "/devices";
114 
115 		return (ecache_scan_dir(dir, "memory-controller", buf, bufsz));
116 	}
117 
118 	return (0);
119 }
120 
121 int
cmd_ecache_init(void)122 cmd_ecache_init(void)
123 {
124 	return (ecache_find_device(cmd.cmd_ecache_dev,
125 	    sizeof (cmd.cmd_ecache_dev)));
126 }
127 
128 int
cmd_ecache_flush(int cpuid)129 cmd_ecache_flush(int cpuid)
130 {
131 	int fd;
132 
133 	if ((fd = open(cmd.cmd_ecache_dev, O_RDONLY)) < 0) {
134 		if (errno != ENOENT)
135 			return (-1); /* errno is set for us */
136 
137 		/*
138 		 * A DR may have occurred, thus rendering our path invalid.
139 		 * Try once to find another one.
140 		 */
141 		if (cmd_ecache_init() < 0 ||
142 		    (fd = open(cmd.cmd_ecache_dev, O_RDONLY)) < 0)
143 			return (-1); /* errno is set for us */
144 	}
145 
146 	if (ioctl(fd, MCIOC_ECFLUSH, cpuid) < 0) {
147 		int oserr = errno;
148 		(void) close(fd);
149 		return (cmd_set_errno(oserr));
150 	}
151 
152 	(void) close(fd);
153 	return (0);
154 }
155