xref: /illumos-gate/usr/src/lib/cfgadm_plugins/scsi/SUNW,SPARC-Enterprise/common/opl_dev_led.c (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
109fe1b16Sdnielsen /*
209fe1b16Sdnielsen  * CDDL HEADER START
309fe1b16Sdnielsen  *
409fe1b16Sdnielsen  * The contents of this file are subject to the terms of the
509fe1b16Sdnielsen  * Common Development and Distribution License (the "License").
609fe1b16Sdnielsen  * You may not use this file except in compliance with the License.
709fe1b16Sdnielsen  *
809fe1b16Sdnielsen  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
909fe1b16Sdnielsen  * or http://www.opensolaris.org/os/licensing.
1009fe1b16Sdnielsen  * See the License for the specific language governing permissions
1109fe1b16Sdnielsen  * and limitations under the License.
1209fe1b16Sdnielsen  *
1309fe1b16Sdnielsen  * When distributing Covered Code, include this CDDL HEADER in each
1409fe1b16Sdnielsen  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1509fe1b16Sdnielsen  * If applicable, add the following below this CDDL HEADER, with the
1609fe1b16Sdnielsen  * fields enclosed by brackets "[]" replaced with your own identifying
1709fe1b16Sdnielsen  * information: Portions Copyright [yyyy] [name of copyright owner]
1809fe1b16Sdnielsen  *
1909fe1b16Sdnielsen  * CDDL HEADER END
2009fe1b16Sdnielsen  */
2109fe1b16Sdnielsen 
2209fe1b16Sdnielsen /*
2309fe1b16Sdnielsen  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
2409fe1b16Sdnielsen  * Use is subject to license terms.
2509fe1b16Sdnielsen  */
2609fe1b16Sdnielsen 
2709fe1b16Sdnielsen #include <stdio.h>
2809fe1b16Sdnielsen #include <strings.h>
2909fe1b16Sdnielsen #include <libgen.h>
3009fe1b16Sdnielsen #include <cfga_scsi.h>
31*7b77b017Sjimand #include <sys/scfd/opcioif.h>
3209fe1b16Sdnielsen 
3309fe1b16Sdnielsen 
3409fe1b16Sdnielsen #define	SCF_DRV		"/devices/pseudo/scfd@200:rasctl"
3509fe1b16Sdnielsen #define	SCFRETRY	3
3609fe1b16Sdnielsen #define	SCFIOCWAIT	3
3709fe1b16Sdnielsen 
3809fe1b16Sdnielsen 
3909fe1b16Sdnielsen #define	OPL_LOCATOR_OPT	0
4009fe1b16Sdnielsen #define	OPL_LED_OPT	1
4109fe1b16Sdnielsen #define	OPL_MODE_OPT	2
4209fe1b16Sdnielsen char *opl_opts[] = {
4309fe1b16Sdnielsen 	"locator",
4409fe1b16Sdnielsen 	"led",
4509fe1b16Sdnielsen 	"mode",
4609fe1b16Sdnielsen 	NULL
4709fe1b16Sdnielsen };
4809fe1b16Sdnielsen 
4909fe1b16Sdnielsen 
5009fe1b16Sdnielsen static scfga_ret_t
opl_get_scf_logical_disk(const apid_t * apidp,char ** errstring,scfiocgetdiskled_t * scf_disk)5109fe1b16Sdnielsen opl_get_scf_logical_disk(const apid_t *apidp, char **errstring,
5209fe1b16Sdnielsen 					scfiocgetdiskled_t *scf_disk)
5309fe1b16Sdnielsen {
5409fe1b16Sdnielsen 	int len;
5509fe1b16Sdnielsen 	char *phys_path;
5609fe1b16Sdnielsen 	char *strptr;
5709fe1b16Sdnielsen 
5809fe1b16Sdnielsen 	phys_path  = strdup(apidp->path);
5909fe1b16Sdnielsen 	if (phys_path == NULL) {
6009fe1b16Sdnielsen 		cfga_err(errstring, ENOMEM, ERR_OP_FAILED, 0);
6109fe1b16Sdnielsen 		return (SCFGA_ERR);
6209fe1b16Sdnielsen 	}
6309fe1b16Sdnielsen 	scf_disk->path[0] = '\0';
6409fe1b16Sdnielsen 	if ((strptr = strstr(phys_path, ":")) != NULL) {
6509fe1b16Sdnielsen 		strptr[0] = '\0';
6609fe1b16Sdnielsen 		len = snprintf((char *)scf_disk->path, sizeof (scf_disk->path),
6709fe1b16Sdnielsen 			"%s", (char *)(phys_path));
6809fe1b16Sdnielsen 		if (len >= sizeof (scf_disk->path)) {
6909fe1b16Sdnielsen 			free(phys_path);
7009fe1b16Sdnielsen 			cfga_err(errstring, 0, ERR_OP_FAILED, 0);
7109fe1b16Sdnielsen 			return (SCFGA_ERR);
7209fe1b16Sdnielsen 		}
7309fe1b16Sdnielsen 	} else {
7409fe1b16Sdnielsen 		free(phys_path);
7509fe1b16Sdnielsen 		cfga_err(errstring, 0, ERR_UNKNOWN, 0);
7609fe1b16Sdnielsen 		return (SCFGA_ERR);
7709fe1b16Sdnielsen 	}
7809fe1b16Sdnielsen 	free(phys_path);
7909fe1b16Sdnielsen 
8009fe1b16Sdnielsen 	return (SCFGA_OK);
8109fe1b16Sdnielsen }
8209fe1b16Sdnielsen 
8309fe1b16Sdnielsen 
8409fe1b16Sdnielsen /*
8509fe1b16Sdnielsen  * Open the SCF driver and use the ioctl interface to set or get the status.
8609fe1b16Sdnielsen  *
8709fe1b16Sdnielsen  * Returns 0 on success. Returns OP_FAILED on error.
8809fe1b16Sdnielsen  */
8909fe1b16Sdnielsen static scfga_ret_t
opl_disk_led_control(apid_t * apidp,char ** errstring,struct cfga_msg * msgp,int request,scfiocgetdiskled_t * scf_disk)9009fe1b16Sdnielsen opl_disk_led_control(apid_t *apidp, char **errstring, struct cfga_msg *msgp,
9109fe1b16Sdnielsen 	int request, scfiocgetdiskled_t *scf_disk)
9209fe1b16Sdnielsen {
9309fe1b16Sdnielsen 	scfga_ret_t	retval;
9409fe1b16Sdnielsen 	int		scf_fd = -1;
9509fe1b16Sdnielsen 	int		retry = 0;
9609fe1b16Sdnielsen 
9709fe1b16Sdnielsen 	/* paranoid check */
9809fe1b16Sdnielsen 	if ((apidp == NULL) || (msgp == NULL) || (scf_disk == NULL)) {
9909fe1b16Sdnielsen 		cfga_err(errstring, 0, ERR_UNKNOWN, 0, 0);
10009fe1b16Sdnielsen 		return (SCFGA_ERR);
10109fe1b16Sdnielsen 	}
10209fe1b16Sdnielsen 
10309fe1b16Sdnielsen 	retval = opl_get_scf_logical_disk((const apid_t *)apidp, errstring,
10409fe1b16Sdnielsen 					scf_disk);
10509fe1b16Sdnielsen 	if (retval != SCFGA_OK) {
10609fe1b16Sdnielsen 		/* errstring is set in opl_get_scf_logical_disk */
10709fe1b16Sdnielsen 		return (retval);
10809fe1b16Sdnielsen 	}
10909fe1b16Sdnielsen 
11009fe1b16Sdnielsen 	/* Open a file descriptor for the scf driver. */
11109fe1b16Sdnielsen 	scf_fd = open(SCF_DRV, O_RDWR);
11209fe1b16Sdnielsen 	if (scf_fd < 0) {
11309fe1b16Sdnielsen 		cfga_err(errstring, errno, ERRARG_OPEN, SCF_DRV, 0);
11409fe1b16Sdnielsen 		return (SCFGA_LIB_ERR);
11509fe1b16Sdnielsen 	}
11609fe1b16Sdnielsen 
11709fe1b16Sdnielsen 	/*
11809fe1b16Sdnielsen 	 * Use the ioctl interface with the SCF driver to get/set the
11909fe1b16Sdnielsen 	 * hdd locator indicator.
12009fe1b16Sdnielsen 	 */
12109fe1b16Sdnielsen 	errno = 0;
12209fe1b16Sdnielsen 	while (ioctl(scf_fd, request, scf_disk) < 0) {
12309fe1b16Sdnielsen 		/* Check Retry Error Number */
12409fe1b16Sdnielsen 		if (errno != EBUSY && errno != EIO) {
12509fe1b16Sdnielsen 			break;
12609fe1b16Sdnielsen 		}
12709fe1b16Sdnielsen 
12809fe1b16Sdnielsen 		/* Check Retry Times */
12909fe1b16Sdnielsen 		if (++retry > SCFRETRY) {
13009fe1b16Sdnielsen 			break;
13109fe1b16Sdnielsen 		}
13209fe1b16Sdnielsen 		errno = 0;
13309fe1b16Sdnielsen 
13409fe1b16Sdnielsen 		(void) sleep(SCFIOCWAIT);
13509fe1b16Sdnielsen 	}
13609fe1b16Sdnielsen 	(void) close(scf_fd);
13709fe1b16Sdnielsen 
13809fe1b16Sdnielsen 	if ((errno != 0) || (retry > SCFRETRY)) {
13909fe1b16Sdnielsen 		cfga_err(errstring, errno, ERR_OP_FAILED, 0, 0);
14009fe1b16Sdnielsen 		return (SCFGA_LIB_ERR);
14109fe1b16Sdnielsen 	}
14209fe1b16Sdnielsen 	return (SCFGA_OK);
14309fe1b16Sdnielsen }
14409fe1b16Sdnielsen 
14509fe1b16Sdnielsen /*
14609fe1b16Sdnielsen  * Print the value of the hard disk locator in a human friendly form.
14709fe1b16Sdnielsen  */
14809fe1b16Sdnielsen static void
opl_print_locator(apid_t * apidp,struct cfga_msg * msgp,unsigned char led)14909fe1b16Sdnielsen opl_print_locator(apid_t *apidp, struct cfga_msg *msgp, unsigned char led)
15009fe1b16Sdnielsen {
15109fe1b16Sdnielsen 	led_modeid_t mode = LED_MODE_UNK;
15209fe1b16Sdnielsen 
15309fe1b16Sdnielsen 	if ((msgp == NULL) || (msgp->message_routine == NULL)) {
15409fe1b16Sdnielsen 		return;
15509fe1b16Sdnielsen 	}
15609fe1b16Sdnielsen 
15709fe1b16Sdnielsen 	cfga_msg(msgp, MSG_LED_HDR, 0);
15809fe1b16Sdnielsen 	switch ((int)led) {
15909fe1b16Sdnielsen 	case SCF_DISK_LED_ON:
16009fe1b16Sdnielsen 		mode = LED_MODE_FAULTED;
16109fe1b16Sdnielsen 		break;
16209fe1b16Sdnielsen 
16309fe1b16Sdnielsen 	case SCF_DISK_LED_OFF:
16409fe1b16Sdnielsen 		mode = LED_MODE_OFF;
16509fe1b16Sdnielsen 		break;
16609fe1b16Sdnielsen 
16709fe1b16Sdnielsen 	case SCF_DISK_LED_BLINK:
16809fe1b16Sdnielsen 		mode = LED_MODE_ON;
16909fe1b16Sdnielsen 		break;
17009fe1b16Sdnielsen 
17109fe1b16Sdnielsen 	default:
17209fe1b16Sdnielsen 		mode = LED_MODE_UNK;
17309fe1b16Sdnielsen 	}
17409fe1b16Sdnielsen 	cfga_led_msg(msgp, apidp, LED_STR_LOCATOR, mode);
17509fe1b16Sdnielsen }
17609fe1b16Sdnielsen 
17709fe1b16Sdnielsen /*
17809fe1b16Sdnielsen  * Print the value of the hard disk fault LED in a human friendly form.
17909fe1b16Sdnielsen  */
18009fe1b16Sdnielsen static void
opl_print_led(apid_t * apidp,struct cfga_msg * msgp,unsigned char led)18109fe1b16Sdnielsen opl_print_led(apid_t *apidp, struct cfga_msg *msgp, unsigned char led)
18209fe1b16Sdnielsen {
18309fe1b16Sdnielsen 	led_modeid_t mode = LED_MODE_UNK;
18409fe1b16Sdnielsen 
18509fe1b16Sdnielsen 	if ((msgp == NULL) || (msgp->message_routine == NULL)) {
18609fe1b16Sdnielsen 		return;
18709fe1b16Sdnielsen 	}
18809fe1b16Sdnielsen 
18909fe1b16Sdnielsen 	cfga_msg(msgp, MSG_LED_HDR, 0);
19009fe1b16Sdnielsen 	switch ((int)led) {
19109fe1b16Sdnielsen 	case SCF_DISK_LED_ON:
19209fe1b16Sdnielsen 		mode = LED_MODE_ON;
19309fe1b16Sdnielsen 		break;
19409fe1b16Sdnielsen 
19509fe1b16Sdnielsen 	case SCF_DISK_LED_OFF:
19609fe1b16Sdnielsen 		mode = LED_MODE_OFF;
19709fe1b16Sdnielsen 		break;
19809fe1b16Sdnielsen 
19909fe1b16Sdnielsen 	case SCF_DISK_LED_BLINK:
20009fe1b16Sdnielsen 		mode = LED_MODE_BLINK;
20109fe1b16Sdnielsen 		break;
20209fe1b16Sdnielsen 
20309fe1b16Sdnielsen 	default:
20409fe1b16Sdnielsen 		mode = LED_MODE_UNK;
20509fe1b16Sdnielsen 	}
20609fe1b16Sdnielsen 	cfga_led_msg(msgp, apidp, LED_STR_FAULT, mode);
20709fe1b16Sdnielsen }
20809fe1b16Sdnielsen 
20909fe1b16Sdnielsen static scfga_ret_t
opl_setlocator(const char * mode,apid_t * apidp,char ** errstring,struct cfga_msg * msgp)21009fe1b16Sdnielsen opl_setlocator(
21109fe1b16Sdnielsen 	const char *mode,
21209fe1b16Sdnielsen 	apid_t *apidp,
21309fe1b16Sdnielsen 	char **errstring,
21409fe1b16Sdnielsen 	struct cfga_msg *msgp)
21509fe1b16Sdnielsen {
21609fe1b16Sdnielsen 	scfga_ret_t retval;
21709fe1b16Sdnielsen 	scfiocgetdiskled_t scf_disk;
21809fe1b16Sdnielsen 
21909fe1b16Sdnielsen 	if (strcmp(mode, "on") == 0) {
22009fe1b16Sdnielsen 		scf_disk.led = SCF_DISK_LED_BLINK;
22109fe1b16Sdnielsen 	} else if (strcmp(mode, "off") == 0) {
22209fe1b16Sdnielsen 		scf_disk.led = SCF_DISK_LED_OFF;
22309fe1b16Sdnielsen 	} else {
22409fe1b16Sdnielsen 		cfga_err(errstring, 0, ERRARG_OPT_INVAL, mode, 0);
22509fe1b16Sdnielsen 		return (SCFGA_ERR);
22609fe1b16Sdnielsen 	}
22709fe1b16Sdnielsen 
22809fe1b16Sdnielsen 	retval = opl_disk_led_control(apidp, errstring, msgp,
22909fe1b16Sdnielsen 					SCFIOCSETDISKLED, &scf_disk);
23009fe1b16Sdnielsen 
23109fe1b16Sdnielsen 	return (retval);
23209fe1b16Sdnielsen }
23309fe1b16Sdnielsen 
23409fe1b16Sdnielsen 
23509fe1b16Sdnielsen static scfga_ret_t
opl_getled(int print_switch,apid_t * apidp,char ** errstring,struct cfga_msg * msgp)23609fe1b16Sdnielsen opl_getled(
23709fe1b16Sdnielsen 	int print_switch,
23809fe1b16Sdnielsen 	apid_t *apidp,
23909fe1b16Sdnielsen 	char **errstring,
24009fe1b16Sdnielsen 	struct cfga_msg *msgp)
24109fe1b16Sdnielsen {
24209fe1b16Sdnielsen 	scfga_ret_t retval;
24309fe1b16Sdnielsen 	scfiocgetdiskled_t scf_disk;
24409fe1b16Sdnielsen 
24509fe1b16Sdnielsen 	(void) memset((void *)&scf_disk, 0, sizeof (scf_disk));
24609fe1b16Sdnielsen 
24709fe1b16Sdnielsen 	retval = opl_disk_led_control(apidp, errstring, msgp,
24809fe1b16Sdnielsen 				SCFIOCGETDISKLED, &scf_disk);
24909fe1b16Sdnielsen 	if (retval != SCFGA_OK) {
25009fe1b16Sdnielsen 		return (retval);
25109fe1b16Sdnielsen 	}
25209fe1b16Sdnielsen 	if (print_switch == OPL_LED_OPT) {
25309fe1b16Sdnielsen 		opl_print_led(apidp, msgp, scf_disk.led);
25409fe1b16Sdnielsen 	} else {
25509fe1b16Sdnielsen 		opl_print_locator(apidp, msgp, scf_disk.led);
25609fe1b16Sdnielsen 	}
25709fe1b16Sdnielsen 
25809fe1b16Sdnielsen 	return (SCFGA_OK);
25909fe1b16Sdnielsen }
26009fe1b16Sdnielsen 
26109fe1b16Sdnielsen 
26209fe1b16Sdnielsen static scfga_ret_t
opl_setled(const char * mode,apid_t * apidp,char ** errstring,struct cfga_msg * msgp)26309fe1b16Sdnielsen opl_setled(
26409fe1b16Sdnielsen 	const char *mode,
26509fe1b16Sdnielsen 	apid_t *apidp,
26609fe1b16Sdnielsen 	char **errstring,
26709fe1b16Sdnielsen 	struct cfga_msg *msgp)
26809fe1b16Sdnielsen {
26909fe1b16Sdnielsen 	scfga_ret_t retval;
27009fe1b16Sdnielsen 	scfiocgetdiskled_t scf_disk;
27109fe1b16Sdnielsen 
27209fe1b16Sdnielsen 	(void) memset((void *)&scf_disk, 0, sizeof (scf_disk));
27309fe1b16Sdnielsen 
27409fe1b16Sdnielsen 	if (strcmp(mode, "on") == 0) {
27509fe1b16Sdnielsen 		scf_disk.led = SCF_DISK_LED_ON;
27609fe1b16Sdnielsen 	} else if (strcmp(mode, "off") == 0) {
27709fe1b16Sdnielsen 		scf_disk.led = SCF_DISK_LED_OFF;
27809fe1b16Sdnielsen 	} else if (strcmp(mode, "blink") == 0) {
27909fe1b16Sdnielsen 		scf_disk.led = SCF_DISK_LED_BLINK;
28009fe1b16Sdnielsen 	} else {
28109fe1b16Sdnielsen 		cfga_err(errstring, 0, ERRARG_OPT_INVAL, mode, 0);
28209fe1b16Sdnielsen 		return (SCFGA_ERR);
28309fe1b16Sdnielsen 	}
28409fe1b16Sdnielsen 
28509fe1b16Sdnielsen 	retval = opl_disk_led_control(apidp, errstring, msgp,
28609fe1b16Sdnielsen 					SCFIOCSETDISKLED, &scf_disk);
28709fe1b16Sdnielsen 	return (retval);
28809fe1b16Sdnielsen }
28909fe1b16Sdnielsen 
29009fe1b16Sdnielsen /*
29109fe1b16Sdnielsen  * The func argument is a string in one of the two following forms:
29209fe1b16Sdnielsen  *	led=LED[,mode=MODE]
29309fe1b16Sdnielsen  *	locator[=on|off]
29409fe1b16Sdnielsen  * which can generically be thought of as:
29509fe1b16Sdnielsen  *	name=value[,name=value]
29609fe1b16Sdnielsen  * So first, split the function based on the comma into two name-value
29709fe1b16Sdnielsen  * pairs.
29809fe1b16Sdnielsen  */
29909fe1b16Sdnielsen /*ARGSUSED*/
30009fe1b16Sdnielsen scfga_ret_t
plat_dev_led(const char * func,scfga_cmd_t cmd,apid_t * apidp,prompt_t * argsp,cfga_flags_t flags,char ** errstring)30109fe1b16Sdnielsen plat_dev_led(
30209fe1b16Sdnielsen 	const char *func,
30309fe1b16Sdnielsen 	scfga_cmd_t cmd,
30409fe1b16Sdnielsen 	apid_t *apidp,
30509fe1b16Sdnielsen 	prompt_t *argsp,
30609fe1b16Sdnielsen 	cfga_flags_t flags,
30709fe1b16Sdnielsen 	char **errstring)
30809fe1b16Sdnielsen {
30909fe1b16Sdnielsen 	scfga_ret_t retval = SCFGA_ERR;
31009fe1b16Sdnielsen 	char *optptr = (char *)func;
31109fe1b16Sdnielsen 	char *value = NULL;
31209fe1b16Sdnielsen 
31309fe1b16Sdnielsen 	int opt_locator = 0;
31409fe1b16Sdnielsen 	int opt_led = 0;
31509fe1b16Sdnielsen 	int opt_mode = 0;
31609fe1b16Sdnielsen 	char *locator_value = NULL;
31709fe1b16Sdnielsen 	char *led_value = NULL;
31809fe1b16Sdnielsen 	char *mode_value = NULL;
31909fe1b16Sdnielsen 
32009fe1b16Sdnielsen 	if (func == NULL) {
32109fe1b16Sdnielsen 		return (SCFGA_ERR);
32209fe1b16Sdnielsen 	}
32309fe1b16Sdnielsen 
32409fe1b16Sdnielsen 	while (*optptr != '\0') {
32509fe1b16Sdnielsen 		switch (getsubopt(&optptr, opl_opts, &value)) {
32609fe1b16Sdnielsen 		case OPL_LOCATOR_OPT:
32709fe1b16Sdnielsen 			opt_locator++;
32809fe1b16Sdnielsen 			locator_value = value;
32909fe1b16Sdnielsen 			break;
33009fe1b16Sdnielsen 		case OPL_LED_OPT:
33109fe1b16Sdnielsen 			opt_led++;
33209fe1b16Sdnielsen 			led_value = value;
33309fe1b16Sdnielsen 			break;
33409fe1b16Sdnielsen 		case OPL_MODE_OPT:
33509fe1b16Sdnielsen 			opt_mode++;
33609fe1b16Sdnielsen 			mode_value = value;
33709fe1b16Sdnielsen 			break;
33809fe1b16Sdnielsen 		default:
33909fe1b16Sdnielsen 			cfga_err(errstring, 0, ERR_CMD_INVAL, 0);
34009fe1b16Sdnielsen 			return (SCFGA_OPNOTSUPP);
34109fe1b16Sdnielsen 			break;
34209fe1b16Sdnielsen 		}
34309fe1b16Sdnielsen 	}
34409fe1b16Sdnielsen 
34509fe1b16Sdnielsen 	if (!opt_locator && !opt_led) {
34609fe1b16Sdnielsen 		cfga_err(errstring, 0, ERR_CMD_INVAL, 0);
34709fe1b16Sdnielsen 		return (SCFGA_ERR);
34809fe1b16Sdnielsen 	}
34909fe1b16Sdnielsen 
35009fe1b16Sdnielsen 	if (opt_locator) {
35109fe1b16Sdnielsen 		if ((opt_locator > 1) || opt_led || opt_mode ||
35209fe1b16Sdnielsen 			(strncmp(func, "locator", strlen("locator")) != 0) ||
35309fe1b16Sdnielsen 			(locator_value &&
35409fe1b16Sdnielsen 			(strcmp(locator_value, "blink") == 0))) {
35509fe1b16Sdnielsen 			cfga_err(errstring, 0, ERR_CMD_INVAL, 0);
35609fe1b16Sdnielsen 			return (SCFGA_ERR);
35709fe1b16Sdnielsen 		}
35809fe1b16Sdnielsen 
35909fe1b16Sdnielsen 		/* Options are sane so set or get the locator. */
36009fe1b16Sdnielsen 		if (locator_value) {
36109fe1b16Sdnielsen 			retval = opl_setlocator(locator_value, apidp,
36209fe1b16Sdnielsen 				errstring, argsp->msgp);
36309fe1b16Sdnielsen 		} else {
36409fe1b16Sdnielsen 			retval = opl_getled(OPL_LOCATOR_OPT, apidp, errstring,
36509fe1b16Sdnielsen 				argsp->msgp);
36609fe1b16Sdnielsen 		}
36709fe1b16Sdnielsen 	}
36809fe1b16Sdnielsen 	if (opt_led) {
36909fe1b16Sdnielsen 		if ((opt_led > 1) || (opt_mode > 1) || (opt_locator) ||
37009fe1b16Sdnielsen 				(strncmp(func, "led", strlen("led")) != 0) ||
37109fe1b16Sdnielsen 				(!led_value || strcmp(led_value, "fault")) ||
37209fe1b16Sdnielsen 				(opt_mode && !mode_value)) {
37309fe1b16Sdnielsen 
37409fe1b16Sdnielsen 			cfga_err(errstring, 0, ERR_CMD_INVAL, 0);
37509fe1b16Sdnielsen 			return (SCFGA_ERR);
37609fe1b16Sdnielsen 		}
37709fe1b16Sdnielsen 
37809fe1b16Sdnielsen 		/* options are sane so go ahead and set or get the led */
37909fe1b16Sdnielsen 		if (mode_value != NULL) {
38009fe1b16Sdnielsen 			retval = opl_setled(mode_value, apidp, errstring,
38109fe1b16Sdnielsen 				argsp->msgp);
38209fe1b16Sdnielsen 		} else {
38309fe1b16Sdnielsen 			retval = opl_getled(OPL_LED_OPT, apidp, errstring,
38409fe1b16Sdnielsen 				argsp->msgp);
38509fe1b16Sdnielsen 		}
38609fe1b16Sdnielsen 	}
38709fe1b16Sdnielsen 	return (retval);
38809fe1b16Sdnielsen 
38909fe1b16Sdnielsen }
390