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