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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include "cfga_fp.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 /*ARGSUSED*/
39 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)40 cfga_change_state(
41 	cfga_cmd_t state_change_cmd,
42 	const char *ap_id,
43 	const char *options,
44 	struct cfga_confirm *confp,
45 	struct cfga_msg *msgp,
46 	char **errstring,
47 	cfga_flags_t flags)
48 {
49 	apid_t		apidt = {NULL};
50 	fpcfga_ret_t	ret;
51 	la_wwn_t	pwwn;
52 	char *value, *hw_option, *hw_option_p;
53 	char *fp_cs_hw_opts[] = {"disable_rcm", "force_update",
54 		"no_update", "unusable_SCSI_LUN", "unusable_FCP_dev", NULL};
55 	HBA_HANDLE	handle;
56 	HBA_PORTATTRIBUTES	portAttrs;
57 	int			portIndex;
58 
59 	if (errstring != NULL) {
60 		*errstring = NULL;
61 	}
62 
63 	/* Check for super user priveleges */
64 	if (geteuid() != 0) {
65 		return (CFGA_PRIV);
66 	}
67 
68 	/* Only configure and unconfigure operations are supported */
69 	if (state_change_cmd != CFGA_CMD_CONFIGURE &&
70 	    state_change_cmd != CFGA_CMD_UNCONFIGURE) {
71 		return (CFGA_OPNOTSUPP);
72 	}
73 
74 	if ((ret = apidt_create(ap_id, &apidt, errstring)) != FPCFGA_OK) {
75 		return (err_cvt(ret));
76 	}
77 
78 	if (options != NULL) {
79 		hw_option = calloc(1, strlen(options) + 1);
80 		(void) snprintf(hw_option, strlen(options) + 1, "%s", options);
81 		hw_option_p = hw_option;
82 		/* Use getsubopt() if more options get added */
83 		while (*hw_option_p != '\0') {
84 			switch (getsubopt(&hw_option_p, fp_cs_hw_opts,
85 			    &value)) {
86 			case OPT_DISABLE_RCM :
87 				apidt.flags |= FLAG_DISABLE_RCM;
88 				break;
89 			case OPT_FORCE_UPDATE_REP :
90 				apidt.flags |= FLAG_FORCE_UPDATE_REP;
91 				break;
92 			case OPT_NO_UPDATE_REP :
93 				apidt.flags |= FLAG_NO_UPDATE_REP;
94 				break;
95 			case OPT_REMOVE_UNUSABLE_FCP_DEV :
96 			case OPT_REMOVE_UNUSABLE_SCSI_LUN:
97 				if (state_change_cmd != CFGA_CMD_UNCONFIGURE) {
98 					cfga_err(errstring, 0, ERRARG_OPT_INVAL,
99 					    options, 0);
100 					S_FREE(hw_option);
101 					apidt_free(&apidt);
102 					return (CFGA_ERROR);
103 				}
104 				apidt.flags |= FLAG_REMOVE_UNUSABLE_FCP_DEV;
105 				break;
106 			default :
107 				/* process unknonw option. */
108 				cfga_err(errstring, 0, ERRARG_OPT_INVAL,
109 				    options, 0);
110 				S_FREE(hw_option);
111 				apidt_free(&apidt);
112 				return (CFGA_ERROR);
113 			}
114 		}
115 		S_FREE(hw_option);
116 	}
117 
118 	if (options != NULL && apidt.flags == 0) {
119 		/* invalid option specified. */
120 		cfga_err(errstring, 0, ERRARG_OPT_INVAL, options, 0);
121 		apidt_free(&apidt);
122 		return (CFGA_ERROR);
123 	}
124 
125 	if (apidt.dyncomp != NULL) {	/* Was there a port WWN passed ? */
126 		/*
127 		 * Yes - so change state of the particular device
128 		 *
129 		 * First Get the WWN in la_wwn_t form
130 		 */
131 		if (cvt_dyncomp_to_lawwn(apidt.dyncomp, &pwwn)) {
132 			cfga_err(errstring, 0, ERR_APID_INVAL, 0);
133 			return (err_cvt(FPCFGA_LIB_ERR));
134 		}
135 
136 		if ((ret = findMatchingAdapterPort(apidt.xport_phys,
137 		    &handle, &portIndex, &portAttrs, errstring)) ==
138 		    FPCFGA_OK) {
139 			ret = dev_change_state(state_change_cmd, &apidt, &pwwn,
140 			    flags, errstring, handle, portAttrs);
141 			HBA_CloseAdapter(handle);
142 			HBA_FreeLibrary();
143 		}
144 	} else {
145 		/* Change state of all devices on FCA and the FCA itself */
146 		ret = fca_change_state(state_change_cmd, &apidt,
147 		    flags, errstring);
148 	}
149 
150 	apidt_free(&apidt);
151 	return (err_cvt(ret));
152 }
153 
154 
155 /*ARGSUSED*/
156 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)157 cfga_private_func(
158 	const char *func,
159 	const char *ap_id,
160 	const char *options,
161 	struct cfga_confirm *confp,
162 	struct cfga_msg *msgp,
163 	char **errstring,
164 	cfga_flags_t flags)
165 {
166 	if (errstring != NULL) {
167 		*errstring = NULL;
168 	}
169 
170 	if (geteuid() != 0) {
171 		return (CFGA_PRIV);
172 	}
173 
174 	return (CFGA_OPNOTSUPP);
175 }
176 
177 
178 /*ARGSUSED*/
179 cfga_err_t
cfga_test(const char * ap_id,const char * options,struct cfga_msg * msgp,char ** errstring,cfga_flags_t flags)180 cfga_test(
181 	const char *ap_id,
182 	const char *options,
183 	struct cfga_msg *msgp,
184 	char **errstring,
185 	cfga_flags_t flags)
186 {
187 	if (errstring != NULL) {
188 		*errstring = NULL;
189 	}
190 
191 	if (geteuid() != 0) {
192 		return (CFGA_PRIV);
193 	}
194 
195 	return (CFGA_OPNOTSUPP);
196 }
197 
198 
199 /*ARGSUSED*/
200 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)201 cfga_list_ext(
202 	const char *ap_id,
203 	cfga_list_data_t **ap_id_list,
204 	int *nlistp,
205 	const char *options,
206 	const char *listopts,
207 	char **errstring,
208 	cfga_flags_t flags)
209 {
210 	int fca, expand, nelem;
211 	ldata_list_t *ldatalistp = NULL;
212 	apid_t apidt = {NULL};
213 	fpcfga_cmd_t cmd;
214 	fpcfga_ret_t ret;
215 	char *value, *hw_option, *hw_option_p;
216 	uint_t fp_flags = 0;
217 	char *fp_list_hw_opts[] = {"devinfo_force", "show_SCSI_LUN",
218 		"show_FCP_dev", NULL};
219 
220 	if (errstring != NULL) {
221 		*errstring = NULL;
222 	}
223 
224 	/* Check for super user privileges */
225 	if (geteuid() != 0) {
226 		return (CFGA_PRIV);
227 	}
228 
229 	if (ap_id_list == NULL || nlistp == NULL) {
230 		return (CFGA_ERROR);
231 	}
232 
233 	*ap_id_list = NULL;
234 	*nlistp = 0;
235 
236 	if (options != NULL) {
237 		hw_option = calloc(1, strlen(options) + 1);
238 		(void) snprintf(hw_option, strlen(options) + 1, "%s", options);
239 		hw_option_p = hw_option;
240 		/* Use getsubopt() if more options get added */
241 		while (*hw_option_p != '\0') {
242 			switch (getsubopt(&hw_option_p, fp_list_hw_opts,
243 			    &value)) {
244 			case OPT_DEVINFO_FORCE :
245 				fp_flags |= FLAG_DEVINFO_FORCE;
246 				break;
247 			case OPT_FCP_DEV :
248 			case OPT_SHOW_SCSI_LUN:
249 				fp_flags |= FLAG_FCP_DEV;
250 				break;
251 			default :
252 				/* process unknonw option. */
253 				cfga_err(errstring, 0, ERRARG_OPT_INVAL,
254 				    options, 0);
255 				S_FREE(hw_option);
256 			return (CFGA_ERROR);
257 			}
258 		}
259 		S_FREE(hw_option);
260 	}
261 
262 	/* if force_devinfo is specified check uid = 0 or not. */
263 	if (((fp_flags & FLAG_DEVINFO_FORCE) == FLAG_DEVINFO_FORCE) &&
264 	    (geteuid() != 0)) {
265 		return (CFGA_PRIV);
266 	}
267 
268 	fca = 0;
269 	if (GET_DYN(ap_id) == NULL) {
270 		fca = 1;
271 	}
272 
273 	expand = 0;
274 	if ((flags & CFGA_FLAG_LIST_ALL) == CFGA_FLAG_LIST_ALL) {
275 		expand = 1;
276 	}
277 
278 	/*
279 	 * We expand published attachment points but not
280 	 * dynamic attachment points
281 	 */
282 
283 	if (!fca) { /* Stat a single device - no expansion for devices */
284 		cmd = FPCFGA_STAT_FC_DEV;
285 	} else if (!expand) { /* Stat only the HBA */
286 		cmd = FPCFGA_STAT_FCA_PORT;
287 	} else { /* Expand HBA attachment point */
288 		cmd = FPCFGA_STAT_ALL;
289 	}
290 
291 	ldatalistp = NULL;
292 	nelem = 0;
293 
294 	if ((fp_flags & FLAG_FCP_DEV) == FLAG_FCP_DEV) {
295 		ret = do_list_FCP_dev(ap_id, fp_flags, cmd, &ldatalistp, &nelem,
296 		    errstring);
297 		if (ret != FPCFGA_OK) {
298 			list_free(&ldatalistp);
299 			return (err_cvt(ret));
300 		}
301 	} else {
302 		if ((ret = apidt_create(ap_id, &apidt, errstring))
303 		    != FPCFGA_OK) {
304 			return (err_cvt(ret));
305 		}
306 
307 		if (options != NULL) {
308 			apidt.flags |= fp_flags;
309 		}
310 
311 		ret = do_list(&apidt, cmd, &ldatalistp, &nelem, errstring);
312 		if (ret != FPCFGA_OK) {
313 			list_free(&ldatalistp);
314 			apidt_free(&apidt);
315 			return (err_cvt(ret));
316 		}
317 		apidt_free(&apidt);
318 	}
319 
320 	assert(ldatalistp != NULL);
321 
322 	if (list_ext_postprocess(&ldatalistp, nelem, ap_id_list, nlistp,
323 	    errstring) != FPCFGA_OK) {
324 		assert(*ap_id_list == NULL && *nlistp == 0);
325 		ret = FPCFGA_LIB_ERR;
326 	} else {
327 		assert(*ap_id_list != NULL && *nlistp == nelem);
328 		ret = FPCFGA_OK;
329 	}
330 
331 	list_free(&ldatalistp);
332 	return (err_cvt(ret));
333 }
334 
335 
336 /*ARGSUSED*/
337 cfga_err_t
cfga_help(struct cfga_msg * msgp,const char * options,cfga_flags_t flags)338 cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
339 {
340 	cfga_msg(msgp, MSG_HELP_HDR, MSG_HELP_USAGE, 0);
341 
342 	return (CFGA_OK);
343 
344 }
345 
346 /*ARGSUSED*/
347 int
cfga_ap_id_cmp(const char * ap_id1,const char * ap_id2)348 cfga_ap_id_cmp(const char *ap_id1, const char *ap_id2)
349 {
350 	int i = 0;
351 	long long ret;
352 
353 	if (ap_id1 == ap_id2) {
354 		return (0);
355 	}
356 
357 	if (ap_id1 == NULL || ap_id2 == NULL) {
358 		if (ap_id1 == NULL) {
359 			/* Return a negative value */
360 			return (0 - (uchar_t)ap_id2[0]);
361 		} else {
362 			return ((uchar_t)ap_id1[0]);
363 		}
364 	}
365 
366 	/*
367 	 * Search for first different char
368 	 */
369 	while (ap_id1[i] == ap_id2[i] && ap_id1[i] != '\0')
370 		i++;
371 
372 	if ((ap_id1[i] == '\0') &&
373 	    !(strncmp(&ap_id2[i], LUN_COMP_SEP, strlen(LUN_COMP_SEP)))) {
374 		return (0);
375 	} else if ((ap_id2[i] == '\0') &&
376 	    !(strncmp(&ap_id1[i], LUN_COMP_SEP, strlen(LUN_COMP_SEP)))) {
377 		return (0);
378 	}
379 
380 	/*
381 	 * If one of the char is a digit, back up to where the
382 	 * number started, compare the number.
383 	 */
384 	if (isxdigit(ap_id1[i]) || isxdigit(ap_id2[i])) {
385 		while ((i > 0) && isxdigit(ap_id1[i - 1]))
386 			i--;
387 
388 		if (isxdigit(ap_id1[i]) && isxdigit(ap_id2[i])) {
389 			ret = (strtoll((ap_id1 + i), NULL, 16)) -
390 			    (strtoll((ap_id2 + i), NULL, 16));
391 			if (ret > 0) {
392 				return (1);
393 			} else if (ret < 0) {
394 				return (-1);
395 			} else {
396 				return (0);
397 			}
398 		}
399 	}
400 
401 	/* One of them isn't a number, compare the char */
402 	return (ap_id1[i] - ap_id2[i]);
403 }
404