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(3CFGADM) 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 int
cfga_ap_id_cmp(const cfga_ap_log_id_t ap_id1,const cfga_ap_log_id_t ap_id2)347 cfga_ap_id_cmp(const cfga_ap_log_id_t ap_id1, const cfga_ap_log_id_t ap_id2)
348 {
349 int i = 0;
350 long long ret;
351
352 if (ap_id1 == ap_id2) {
353 return (0);
354 }
355
356 if (ap_id1 == NULL || ap_id2 == NULL) {
357 if (ap_id1 == NULL) {
358 /* Return a negative value */
359 return (0 - (uchar_t)ap_id2[0]);
360 } else {
361 return ((uchar_t)ap_id1[0]);
362 }
363 }
364
365 /*
366 * Search for first different char
367 */
368 while (ap_id1[i] == ap_id2[i] && ap_id1[i] != '\0')
369 i++;
370
371 if ((ap_id1[i] == '\0') &&
372 !(strncmp(&ap_id2[i], LUN_COMP_SEP, strlen(LUN_COMP_SEP)))) {
373 return (0);
374 } else if ((ap_id2[i] == '\0') &&
375 !(strncmp(&ap_id1[i], LUN_COMP_SEP, strlen(LUN_COMP_SEP)))) {
376 return (0);
377 }
378
379 /*
380 * If one of the char is a digit, back up to where the
381 * number started, compare the number.
382 */
383 if (isxdigit(ap_id1[i]) || isxdigit(ap_id2[i])) {
384 while ((i > 0) && isxdigit(ap_id1[i - 1]))
385 i--;
386
387 if (isxdigit(ap_id1[i]) && isxdigit(ap_id2[i])) {
388 ret = (strtoll((ap_id1 + i), NULL, 16)) -
389 (strtoll((ap_id2 + i), NULL, 16));
390 if (ret > 0) {
391 return (1);
392 } else if (ret < 0) {
393 return (-1);
394 } else {
395 return (0);
396 }
397 }
398 }
399
400 /* One of them isn't a number, compare the char */
401 return (ap_id1[i] - ap_id2[i]);
402 }
403