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 #include "cfga_scsi.h"
31 
32 /*
33  * This file contains the entry points to the plug-in as defined in the
34  * config_admin(3X) man page.
35  */
36 
37 /*
38  * Set the version number
39  */
40 int cfga_version = CFGA_HSL_V2;
41 
42 /*
43  * For debugging - higher values increase verbosity
44  */
45 int _scfga_debug = 0;
46 
47 #pragma init(_cfgadm_scsi_init)
48 
49 static void
50 _cfgadm_scsi_init()
51 {
52 	char *tstr;
53 
54 	if (tstr = getenv("SCFGA_DEBUG")) {
55 		_scfga_debug = atoi(tstr);
56 	}
57 }
58 
59 /*ARGSUSED*/
60 cfga_err_t
61 cfga_change_state(
62 	cfga_cmd_t state_change_cmd,
63 	const char *ap_id,
64 	const char *options,
65 	struct cfga_confirm *confp,
66 	struct cfga_msg *msgp,
67 	char **errstring,
68 	cfga_flags_t flags)
69 {
70 	apid_t apidt = {NULL};
71 	scfga_ret_t ret;
72 
73 	if (errstring != NULL) {
74 		*errstring = NULL;
75 	}
76 
77 	/*
78 	 * All sub-commands which can change state of device require
79 	 * root privileges.
80 	 */
81 	if (geteuid() != 0) {
82 		return (CFGA_PRIV);
83 	}
84 
85 	if (options != NULL && strcmp(options, OPT_DISABLE_RCM) != 0) {
86 		cfga_err(errstring, 0, ERRARG_OPT_INVAL, options, 0);
87 		return (CFGA_ERROR);
88 	}
89 
90 	if ((ret = apidt_create(ap_id, &apidt, errstring)) != SCFGA_OK) {
91 		return (err_cvt(ret));
92 	}
93 
94 	if (options != NULL)
95 		apidt.flags |= FLAG_DISABLE_RCM;
96 
97 	/* A dynamic component indicates a device, else it is the bus */
98 	if (apidt.dyncomp != NULL) {
99 		ret = dev_change_state(state_change_cmd, &apidt, flags,
100 		    errstring);
101 	} else {
102 		ret = bus_change_state(state_change_cmd, &apidt, confp, flags,
103 		    errstring);
104 	}
105 
106 	apidt_free(&apidt);
107 	return (err_cvt(ret));
108 }
109 
110 /*ARGSUSED*/
111 cfga_err_t
112 cfga_private_func(
113 	const char *func,
114 	const char *ap_id,
115 	const char *options,
116 	struct cfga_confirm *confp,
117 	struct cfga_msg *msgp,
118 	char **errstring,
119 	cfga_flags_t flags)
120 {
121 	apid_t apidt = {NULL};
122 	prompt_t args = {NULL};
123 	scfga_ret_t ret;
124 
125 	if (errstring != NULL)
126 		*errstring = NULL;
127 
128 	if (geteuid() != 0) {
129 		return (CFGA_PRIV);
130 	}
131 
132 	if (func == NULL) {
133 		return (CFGA_ERROR);
134 	}
135 
136 	if (options != NULL && strcmp(options, OPT_DISABLE_RCM) != 0) {
137 		cfga_err(errstring, 0, ERRARG_OPT_INVAL, options, 0);
138 		return (CFGA_ERROR);
139 	}
140 
141 	if ((ret = apidt_create(ap_id, &apidt, errstring)) != SCFGA_OK) {
142 		return (err_cvt(ret));
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
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
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
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