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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
29 * This file contains the entry points to the plug-in as defined in the
30 * config_admin(3X) man page.
34 * Set the version number
36 int cfga_version
= CFGA_HSL_V2
;
41 cfga_cmd_t state_change_cmd
,
44 struct cfga_confirm
*confp
,
45 struct cfga_msg
*msgp
,
49 apid_t apidt
= {NULL
};
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
};
56 HBA_PORTATTRIBUTES portAttrs
;
59 if (errstring
!= NULL
) {
63 /* Check for super user priveleges */
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
);
74 if ((ret
= apidt_create(ap_id
, &apidt
, errstring
)) != FPCFGA_OK
) {
75 return (err_cvt(ret
));
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
,
86 case OPT_DISABLE_RCM
:
87 apidt
.flags
|= FLAG_DISABLE_RCM
;
89 case OPT_FORCE_UPDATE_REP
:
90 apidt
.flags
|= FLAG_FORCE_UPDATE_REP
;
92 case OPT_NO_UPDATE_REP
:
93 apidt
.flags
|= FLAG_NO_UPDATE_REP
;
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
,
104 apidt
.flags
|= FLAG_REMOVE_UNUSABLE_FCP_DEV
;
107 /* process unknonw option. */
108 cfga_err(errstring
, 0, ERRARG_OPT_INVAL
,
118 if (options
!= NULL
&& apidt
.flags
== 0) {
119 /* invalid option specified. */
120 cfga_err(errstring
, 0, ERRARG_OPT_INVAL
, options
, 0);
125 if (apidt
.dyncomp
!= NULL
) { /* Was there a port WWN passed ? */
127 * Yes - so change state of the particular device
129 * First Get the WWN in la_wwn_t form
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
));
136 if ((ret
= findMatchingAdapterPort(apidt
.xport_phys
,
137 &handle
, &portIndex
, &portAttrs
, errstring
)) ==
139 ret
= dev_change_state(state_change_cmd
, &apidt
, &pwwn
,
140 flags
, errstring
, handle
, portAttrs
);
141 HBA_CloseAdapter(handle
);
145 /* Change state of all devices on FCA and the FCA itself */
146 ret
= fca_change_state(state_change_cmd
, &apidt
,
151 return (err_cvt(ret
));
161 struct cfga_confirm
*confp
,
162 struct cfga_msg
*msgp
,
166 if (errstring
!= NULL
) {
170 if (geteuid() != 0) {
174 return (CFGA_OPNOTSUPP
);
183 struct cfga_msg
*msgp
,
187 if (errstring
!= NULL
) {
191 if (geteuid() != 0) {
195 return (CFGA_OPNOTSUPP
);
203 cfga_list_data_t
**ap_id_list
,
206 const char *listopts
,
210 int fca
, expand
, nelem
;
211 ldata_list_t
*ldatalistp
= NULL
;
212 apid_t apidt
= {NULL
};
215 char *value
, *hw_option
, *hw_option_p
;
217 char *fp_list_hw_opts
[] = {"devinfo_force", "show_SCSI_LUN",
218 "show_FCP_dev", NULL
};
220 if (errstring
!= NULL
) {
224 /* Check for super user privileges */
225 if (geteuid() != 0) {
229 if (ap_id_list
== NULL
|| nlistp
== NULL
) {
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
,
244 case OPT_DEVINFO_FORCE
:
245 fp_flags
|= FLAG_DEVINFO_FORCE
;
248 case OPT_SHOW_SCSI_LUN
:
249 fp_flags
|= FLAG_FCP_DEV
;
252 /* process unknonw option. */
253 cfga_err(errstring
, 0, ERRARG_OPT_INVAL
,
262 /* if force_devinfo is specified check uid = 0 or not. */
263 if (((fp_flags
& FLAG_DEVINFO_FORCE
) == FLAG_DEVINFO_FORCE
) &&
269 if (GET_DYN(ap_id
) == NULL
) {
274 if ((flags
& CFGA_FLAG_LIST_ALL
) == CFGA_FLAG_LIST_ALL
) {
279 * We expand published attachment points but not
280 * dynamic attachment points
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
;
294 if ((fp_flags
& FLAG_FCP_DEV
) == FLAG_FCP_DEV
) {
295 ret
= do_list_FCP_dev(ap_id
, fp_flags
, cmd
, &ldatalistp
, &nelem
,
297 if (ret
!= FPCFGA_OK
) {
298 list_free(&ldatalistp
);
299 return (err_cvt(ret
));
302 if ((ret
= apidt_create(ap_id
, &apidt
, errstring
))
304 return (err_cvt(ret
));
307 if (options
!= NULL
) {
308 apidt
.flags
|= fp_flags
;
311 ret
= do_list(&apidt
, cmd
, &ldatalistp
, &nelem
, errstring
);
312 if (ret
!= FPCFGA_OK
) {
313 list_free(&ldatalistp
);
315 return (err_cvt(ret
));
320 assert(ldatalistp
!= NULL
);
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
;
327 assert(*ap_id_list
!= NULL
&& *nlistp
== nelem
);
331 list_free(&ldatalistp
);
332 return (err_cvt(ret
));
338 cfga_help(struct cfga_msg
*msgp
, const char *options
, cfga_flags_t flags
)
340 cfga_msg(msgp
, MSG_HELP_HDR
, MSG_HELP_USAGE
, 0);
348 cfga_ap_id_cmp(const char *ap_id1
, const char *ap_id2
)
353 if (ap_id1
== ap_id2
) {
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]);
362 return ((uchar_t
)ap_id1
[0]);
367 * Search for first different char
369 while (ap_id1
[i
] == ap_id2
[i
] && ap_id1
[i
] != '\0')
372 if ((ap_id1
[i
] == '\0') &&
373 !(strncmp(&ap_id2
[i
], LUN_COMP_SEP
, strlen(LUN_COMP_SEP
)))) {
375 } else if ((ap_id2
[i
] == '\0') &&
376 !(strncmp(&ap_id1
[i
], LUN_COMP_SEP
, strlen(LUN_COMP_SEP
)))) {
381 * If one of the char is a digit, back up to where the
382 * number started, compare the number.
384 if (isxdigit(ap_id1
[i
]) || isxdigit(ap_id2
[i
])) {
385 while ((i
> 0) && isxdigit(ap_id1
[i
- 1]))
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));
393 } else if (ret
< 0) {
401 /* One of them isn't a number, compare the char */
402 return (ap_id1
[i
] - ap_id2
[i
]);