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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include "cfga_scsi.h"
27 
28 /*
29  * This file contains the entry points to the plug-in as defined in the
30  * config_admin(3X) man page.
31  */
32 
33 /*
34  * Set the version number
35  */
36 int cfga_version = CFGA_HSL_V2;
37 
38 /*
39  * For debugging - higher values increase verbosity
40  */
41 int _scfga_debug = 0;
42 
43 #pragma init(_cfgadm_scsi_init)
44 
45 static void
_cfgadm_scsi_init()46 _cfgadm_scsi_init()
47 {
48 	char *tstr;
49 
50 	if (tstr = getenv("SCFGA_DEBUG")) {
51 		_scfga_debug = atoi(tstr);
52 	}
53 }
54 
55 /*ARGSUSED*/
56 cfga_err_t
cfga_change_state(cfga_cmd_t state_change_cmd,const char * ap_id,const char * options,struct cfga_confirm * confp,struct cfga_msg * msgp,char ** errstring,cfga_flags_t flags)57 cfga_change_state(
58 	cfga_cmd_t state_change_cmd,
59 	const char *ap_id,
60 	const char *options,
61 	struct cfga_confirm *confp,
62 	struct cfga_msg *msgp,
63 	char **errstring,
64 	cfga_flags_t flags)
65 {
66 	apid_t apidt = {NULL};
67 	scfga_ret_t ret;
68 
69 	if (errstring != NULL) {
70 		*errstring = NULL;
71 	}
72 
73 	/*
74 	 * All sub-commands which can change state of device require
75 	 * root privileges.
76 	 */
77 	if (geteuid() != 0) {
78 		return (CFGA_PRIV);
79 	}
80 
81 	if (options != NULL && strcmp(options, OPT_DISABLE_RCM) != 0) {
82 		cfga_err(errstring, 0, ERRARG_OPT_INVAL, options, 0);
83 		return (CFGA_ERROR);
84 	}
85 
86 	if ((ret = apidt_create(ap_id, &apidt, errstring)) != SCFGA_OK) {
87 		return (err_cvt(ret));
88 	}
89 
90 	if (options != NULL)
91 		apidt.flags |= FLAG_DISABLE_RCM;
92 
93 	/* A dynamic component indicates a device, else it is the bus */
94 	if (apidt.dyncomp != NULL) {
95 		ret = dev_change_state(state_change_cmd, &apidt, flags,
96 		    errstring);
97 	} else {
98 		ret = bus_change_state(state_change_cmd, &apidt, confp, flags,
99 		    errstring);
100 	}
101 
102 	apidt_free(&apidt);
103 	return (err_cvt(ret));
104 }
105 
106 /*ARGSUSED*/
107 cfga_err_t
cfga_private_func(const char * func,const char * ap_id,const char * options,struct cfga_confirm * confp,struct cfga_msg * msgp,char ** errstring,cfga_flags_t flags)108 cfga_private_func(
109 	const char *func,
110 	const char *ap_id,
111 	const char *options,
112 	struct cfga_confirm *confp,
113 	struct cfga_msg *msgp,
114 	char **errstring,
115 	cfga_flags_t flags)
116 {
117 	apid_t apidt = {NULL};
118 	prompt_t args = {NULL};
119 	scfga_ret_t ret;
120 
121 	if (errstring != NULL)
122 		*errstring = NULL;
123 
124 	if (geteuid() != 0) {
125 		return (CFGA_PRIV);
126 	}
127 
128 	if (func == NULL) {
129 		return (CFGA_ERROR);
130 	}
131 
132 	if (options != NULL && strcmp(options, OPT_DISABLE_RCM) != 0) {
133 		cfga_err(errstring, 0, ERRARG_OPT_INVAL, options, 0);
134 		return (CFGA_ERROR);
135 	}
136 
137 	if ((ret = apidt_create(ap_id, &apidt, errstring)) != SCFGA_OK) {
138 		return (err_cvt(ret));
139 	}
140 
141 	if (apidt.dyntype == PATH_APID) {
142 		return (CFGA_OPNOTSUPP);
143 	}
144 
145 	if (options != NULL)
146 		apidt.flags |= FLAG_DISABLE_RCM;
147 
148 	args.confp = confp;
149 	args.msgp = msgp;
150 
151 	/*
152 	 * Process command
153 	 */
154 	ret = invoke_cmd(func, &apidt, &args, flags, errstring);
155 
156 	apidt_free(&apidt);
157 	return (err_cvt(ret));
158 }
159 
160 /*ARGSUSED*/
161 cfga_err_t
cfga_test(const char * ap_id,const char * options,struct cfga_msg * msgp,char ** errstring,cfga_flags_t flags)162 cfga_test(
163 	const char *ap_id,
164 	const char *options,
165 	struct cfga_msg *msgp,
166 	char **errstring,
167 	cfga_flags_t flags)
168 {
169 	if (errstring != NULL) {
170 		*errstring = NULL;
171 	}
172 
173 	if (geteuid() != 0) {
174 		return (CFGA_PRIV);
175 	}
176 
177 	return (CFGA_OPNOTSUPP);
178 }
179 
180 /*ARGSUSED*/
181 cfga_err_t
cfga_list_ext(const char * ap_id,cfga_list_data_t ** ap_id_list,int * nlistp,const char * options,const char * listopts,char ** errstring,cfga_flags_t flags)182 cfga_list_ext(
183 	const char *ap_id,
184 	cfga_list_data_t **ap_id_list,
185 	int *nlistp,
186 	const char *options,
187 	const char *listopts,
188 	char **errstring,
189 	cfga_flags_t flags)
190 {
191 	int hba, expand, nelem;
192 	ldata_list_t *llp = NULL;
193 	apid_t apidt = {NULL};
194 	scfga_cmd_t cmd;
195 	scfga_ret_t ret;
196 
197 	if (errstring != NULL) {
198 		*errstring = NULL;
199 	}
200 
201 	if (ap_id_list == NULL || nlistp == NULL) {
202 		return (CFGA_ERROR);
203 	}
204 
205 	*ap_id_list = NULL;
206 	*nlistp = 0;
207 
208 	/*
209 	 * There is no RCM involvement in "list" operations.
210 	 * The only supported option is OPT_USE_DIFORCE.
211 	 */
212 	if (options != NULL && strcmp(options, OPT_USE_DIFORCE) != 0) {
213 		cfga_err(errstring, 0, ERRARG_OPT_INVAL, options, 0);
214 		return (CFGA_ERROR);
215 	}
216 
217 	hba = 0;
218 	if (GET_DYN(ap_id) == NULL) {
219 		hba = 1;
220 	}
221 
222 	expand = 0;
223 	if ((flags & CFGA_FLAG_LIST_ALL) == CFGA_FLAG_LIST_ALL) {
224 		expand = 1;
225 	}
226 
227 	/*
228 	 * We expand published attachment points but not
229 	 * dynamic attachment points
230 	 */
231 
232 	if (!hba) { /* Stat a single device - no expansion for devices */
233 		cmd = SCFGA_STAT_DEV;
234 	} else if (!expand) { /* Stat only the HBA */
235 		cmd = SCFGA_STAT_BUS;
236 	} else { /* Expand HBA attachment point */
237 		cmd = SCFGA_STAT_ALL;
238 	}
239 
240 	if ((ret = apidt_create(ap_id, &apidt, errstring)) != SCFGA_OK) {
241 		return (err_cvt(ret));
242 	}
243 
244 	/*
245 	 * Currently only 1 option supported
246 	 */
247 	if (options)
248 		apidt.flags |= FLAG_USE_DIFORCE;
249 
250 	llp = NULL;
251 	nelem = 0;
252 
253 	ret = do_list(&apidt, cmd, &llp, &nelem, errstring);
254 	if (ret != SCFGA_OK) {
255 		goto out;
256 	}
257 
258 	assert(llp != NULL);
259 
260 	if (list_ext_postprocess(&llp, nelem, ap_id_list, nlistp,
261 	    errstring) != SCFGA_OK) {
262 		assert(*ap_id_list == NULL && *nlistp == 0);
263 		ret = SCFGA_LIB_ERR;
264 	} else {
265 		assert(*ap_id_list != NULL && *nlistp == nelem);
266 		ret = SCFGA_OK;
267 	}
268 
269 	/* FALLTHROUGH */
270 out:
271 	list_free(&llp);
272 	apidt_free(&apidt);
273 	return (err_cvt(ret));
274 }
275 
276 
277 /*ARGSUSED*/
278 cfga_err_t
cfga_help(struct cfga_msg * msgp,const char * options,cfga_flags_t flags)279 cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
280 {
281 	cfga_msg(msgp, MSG_HELP_HDR, MSG_HELP_USAGE, 0);
282 
283 	return (CFGA_OK);
284 }
285 
286 /*
287  * cfga_ap_id_cmp -- use default_ap_id_cmp() in libcfgadm
288  */
289