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 #include <stdlib.h>
28 #include <errno.h>
29 #include <sys/types.h>
30 #include <libnvpair.h>
31 #include <sys/fcntl.h>
32 #include <sys/devfm.h>
33 #include <fmd_agent_impl.h>
34 
35 static int
cleanup_set_errno(fmd_agent_hdl_t * hdl,nvlist_t * innvl,nvlist_t * outnvl,int err)36 cleanup_set_errno(fmd_agent_hdl_t *hdl, nvlist_t *innvl, nvlist_t *outnvl,
37     int err)
38 {
39 	nvlist_free(innvl);
40 	nvlist_free(outnvl);
41 	return (fmd_agent_seterrno(hdl, err));
42 }
43 
44 static int
fmd_agent_physcpu_info_v1(fmd_agent_hdl_t * hdl,nvlist_t *** cpusp,uint_t * ncpup)45 fmd_agent_physcpu_info_v1(fmd_agent_hdl_t *hdl, nvlist_t ***cpusp,
46     uint_t *ncpup)
47 {
48 	int err;
49 	nvlist_t *nvl, **nvl_array, **cpus;
50 	uint_t i, n;
51 
52 	if ((err = fmd_agent_nvl_ioctl(hdl, FM_IOC_PHYSCPU_INFO, 1,
53 	    NULL, &nvl)) != 0)
54 		return (cleanup_set_errno(hdl, NULL, NULL, err));
55 	if ((err = nvlist_lookup_nvlist_array(nvl, FM_PHYSCPU_INFO_CPUS,
56 	    &cpus, &n)) != 0)
57 		return (cleanup_set_errno(hdl, NULL, nvl, err));
58 
59 	if ((nvl_array = umem_alloc(sizeof (nvlist_t *) * n, UMEM_DEFAULT))
60 	    == NULL)
61 		return (cleanup_set_errno(hdl, NULL, nvl, errno));
62 	for (i = 0; i < n; i++) {
63 		if ((err = nvlist_dup(cpus[i], nvl_array + i, 0)) != 0) {
64 			while (i > 0)
65 				nvlist_free(nvl_array[--i]);
66 			umem_free(nvl_array, sizeof (nvlist_t *) * n);
67 			return (cleanup_set_errno(hdl, NULL, nvl, err));
68 		}
69 	}
70 
71 	nvlist_free(nvl);
72 	*cpusp = nvl_array;
73 	*ncpup = n;
74 	return (0);
75 }
76 
77 int
fmd_agent_physcpu_info(fmd_agent_hdl_t * hdl,nvlist_t *** cpusp,uint_t * ncpu)78 fmd_agent_physcpu_info(fmd_agent_hdl_t *hdl, nvlist_t ***cpusp, uint_t *ncpu)
79 {
80 	uint32_t ver;
81 
82 	if (fmd_agent_version(hdl, FM_CPU_INFO_VERSION, &ver) == -1)
83 		return (fmd_agent_seterrno(hdl, errno));
84 
85 	switch (ver) {
86 	case 1:
87 		return (fmd_agent_physcpu_info_v1(hdl, cpusp, ncpu));
88 
89 	default:
90 		return (fmd_agent_seterrno(hdl, ENOTSUP));
91 	}
92 }
93 
94 static int
fmd_agent_cpuop_v1(fmd_agent_hdl_t * hdl,int cmd,int chipid,int coreid,int strandid,int * old_status)95 fmd_agent_cpuop_v1(fmd_agent_hdl_t *hdl, int cmd, int chipid, int coreid,
96     int strandid, int *old_status)
97 {
98 	int err;
99 	nvlist_t *nvl = NULL, *outnvl = NULL;
100 	int32_t status;
101 
102 	if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) != 0 ||
103 	    (err = nvlist_add_int32(nvl, FM_CPU_RETIRE_CHIP_ID, chipid)) != 0 ||
104 	    (err = nvlist_add_int32(nvl, FM_CPU_RETIRE_CORE_ID, coreid)) != 0 ||
105 	    (err = nvlist_add_int32(nvl, FM_CPU_RETIRE_STRAND_ID, strandid))
106 	    != 0 || (err = fmd_agent_nvl_ioctl(hdl, cmd, 1, nvl, &outnvl)) != 0)
107 		return (cleanup_set_errno(hdl, nvl, NULL, err));
108 
109 	nvlist_free(nvl);
110 	if (outnvl != NULL) {
111 		if (old_status != NULL) {
112 			(void) nvlist_lookup_int32(outnvl,
113 			    FM_CPU_RETIRE_OLDSTATUS, &status);
114 			*old_status = status;
115 		}
116 		nvlist_free(outnvl);
117 	}
118 
119 	return (0);
120 }
121 
122 static int
fmd_agent_cpuop(fmd_agent_hdl_t * hdl,int cmd,int chipid,int coreid,int strandid,int * old_status)123 fmd_agent_cpuop(fmd_agent_hdl_t *hdl, int cmd, int chipid, int coreid,
124     int strandid, int *old_status)
125 {
126 	uint32_t ver;
127 
128 	if (fmd_agent_version(hdl, FM_CPU_OP_VERSION, &ver) == -1)
129 		return (cleanup_set_errno(hdl, NULL, NULL, errno));
130 
131 	switch (ver) {
132 	case 1:
133 		return (fmd_agent_cpuop_v1(hdl, cmd, chipid, coreid, strandid,
134 		    old_status));
135 
136 	default:
137 		return (fmd_agent_seterrno(hdl, ENOTSUP));
138 	}
139 }
140 
141 int
fmd_agent_cpu_retire(fmd_agent_hdl_t * hdl,int chipid,int coreid,int strandid)142 fmd_agent_cpu_retire(fmd_agent_hdl_t *hdl, int chipid, int coreid, int strandid)
143 {
144 	int ret;
145 
146 	ret = fmd_agent_cpuop(hdl, FM_IOC_CPU_RETIRE, chipid, coreid, strandid,
147 	    NULL);
148 
149 	return (ret == 0 ? FMD_AGENT_RETIRE_DONE : FMD_AGENT_RETIRE_FAIL);
150 }
151 
152 int
fmd_agent_cpu_isretired(fmd_agent_hdl_t * hdl,int chipid,int coreid,int strandid)153 fmd_agent_cpu_isretired(fmd_agent_hdl_t *hdl, int chipid, int coreid,
154     int strandid)
155 {
156 	int ret, status;
157 
158 	ret = fmd_agent_cpuop(hdl, FM_IOC_CPU_STATUS, chipid, coreid, strandid,
159 	    &status);
160 
161 	return (ret == 0 && status != P_ONLINE ?
162 	    FMD_AGENT_RETIRE_DONE : FMD_AGENT_RETIRE_FAIL);
163 }
164 
165 int
fmd_agent_cpu_unretire(fmd_agent_hdl_t * hdl,int chipid,int coreid,int strandid)166 fmd_agent_cpu_unretire(fmd_agent_hdl_t *hdl, int chipid, int coreid,
167     int strandid)
168 {
169 	int ret;
170 
171 	ret = fmd_agent_cpuop(hdl, FM_IOC_CPU_UNRETIRE, chipid, coreid,
172 	    strandid, NULL);
173 
174 	return (ret == 0 ? FMD_AGENT_RETIRE_DONE : FMD_AGENT_RETIRE_FAIL);
175 }
176