Skip to content
Permalink
Browse files

9815 Want basic AHCI enclosure services

Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Rob Johnston <rob.johnston@joyent.com>
Reviewed by: Yuri Pankov <yuripv@yuripv.net>
Approved by: Dan McDonald <danmcd@joyent.com>
  • Loading branch information...
rmustacc committed Sep 8, 2018
1 parent 9a48f6c commit fd6d41c5025e9fb45a115fc82d86e9983d1e9fd6
@@ -21,7 +21,7 @@

#
# Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2017, Joyent, Inc.
# Copyright (c) 2018, Joyent, Inc.
# Copyright (c) 2012 by Delphix. All rights reserved.
# Copyright (c) 2013 DEY Storage Systems, Inc. All rights reserved.
# Copyright 2014 Garrett D'Amore <garrett@damore.org>
@@ -62,6 +62,7 @@ COMMON_SUBDIRS= \
adbgen \
acct \
acctadm \
ahciem \
arch \
asa \
ast \
@@ -0,0 +1,39 @@
#
# This file and its contents are supplied under the terms of the
# Common Development and Distribution License ("CDDL"), version 1.0.
# You may only use this file in accordance with the terms of version
# 1.0 of the CDDL.
#
# A full copy of the text of the CDDL should have accompanied this
# source. A copy of the CDDL is also available via the Internet at
# http://www.illumos.org/license/CDDL.
#

#
# Copyright (c) 2018, Joyent, Inc.
#

PROG= ahciem
LINTPROGS= $(PROG:%=%.ln)

include ../Makefile.cmd

ROOTCMDDIR = $(ROOTLIB)/ahci
CPPFLAGS += -I$(SRC)/uts/common/
CFLAGS += $(CCVERBOSE)
LDLIBS += -ldevinfo

.KEEP_STATE:

all: $(PROG)

install: all $(ROOTCMD)

clean:

%.ln: %.c
$(LINT.c) $< $(LDLIBS)

lint: $(LINTPROGS)

include ../Makefile.targ
@@ -0,0 +1,302 @@
/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* http://www.illumos.org/license/CDDL.
*/

/*
* Copyright (c) 2018 Joyent, Inc.
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <stdlib.h>
#include <err.h>
#include <libgen.h>
#include <libdevinfo.h>

#include <sys/sata/adapters/ahci/ahciem.h>

#define AHCIEM_IDENT "ident"
#define AHCIEM_FAULT "fault"
#define AHCIEM_NOACTIVITY "noactivity"
#define AHCIEM_DEFAULT "default"
#define AHCIEM_UNKNOWN "unknown"

#define EXIT_USAGE 2

static const char *ahciem_progname;

typedef struct {
boolean_t ahci_set;
ahci_em_led_state_t ahci_led;
int ahci_argc;
char **ahci_argv;
boolean_t *ahci_found;
int ahci_err;
} ahciem_t;

static void
ahciem_usage(const char *fmt, ...)
{
if (fmt != NULL) {
va_list ap;

va_start(ap, fmt);
vwarnx(fmt, ap);
va_end(ap);
}

(void) fprintf(stderr, "Usage: %s [-s mode] [port]\n"
"\n"
"\t-s mode\t\tset LED to mode\n",
ahciem_progname);
}

static const char *
ahciem_led_to_string(uint_t led)
{
switch (led) {
case AHCI_EM_LED_IDENT_ENABLE:
return (AHCIEM_IDENT);
case AHCI_EM_LED_FAULT_ENABLE:
return (AHCIEM_FAULT);
case AHCI_EM_LED_ACTIVITY_DISABLE:
return (AHCIEM_NOACTIVITY);
case (AHCI_EM_LED_IDENT_ENABLE | AHCI_EM_LED_FAULT_ENABLE):
return (AHCIEM_IDENT "," AHCIEM_FAULT);
case (AHCI_EM_LED_IDENT_ENABLE | AHCI_EM_LED_ACTIVITY_DISABLE):
return (AHCIEM_IDENT "," AHCIEM_NOACTIVITY);
case (AHCI_EM_LED_FAULT_ENABLE | AHCI_EM_LED_ACTIVITY_DISABLE):
return (AHCIEM_FAULT "," AHCIEM_NOACTIVITY);
/* BEGIN CSTYLED */
case (AHCI_EM_LED_IDENT_ENABLE | AHCI_EM_LED_FAULT_ENABLE |
AHCI_EM_LED_ACTIVITY_DISABLE):
return (AHCIEM_IDENT "," AHCIEM_FAULT "," AHCIEM_NOACTIVITY);
/* END CSTYLED */
case 0:
return (AHCIEM_DEFAULT);
default:
return (AHCIEM_UNKNOWN);
}
}

static boolean_t
ahciem_match(ahciem_t *ahci, const char *port)
{
int i;

if (ahci->ahci_argc == 0)
return (B_TRUE);

for (i = 0; i < ahci->ahci_argc; i++) {
size_t len = strlen(ahci->ahci_argv[i]);

/*
* Perform a partial match on the base name. This allows us to
* match all of a controller by using a string like "ahci0".
*/
if (strncmp(ahci->ahci_argv[i], port, len) == 0) {
ahci->ahci_found[i] = B_TRUE;
return (B_TRUE);
}

}

return (B_FALSE);
}

static ahci_em_led_state_t
ahciem_parse(const char *arg)
{
if (strcmp(arg, AHCIEM_IDENT) == 0) {
return (AHCI_EM_LED_IDENT_ENABLE);
} else if (strcmp(arg, AHCIEM_FAULT) == 0) {
return (AHCI_EM_LED_FAULT_ENABLE);
} else if (strcmp(arg, AHCIEM_NOACTIVITY) == 0) {
return (AHCI_EM_LED_ACTIVITY_DISABLE);
} else if (strcmp(arg, AHCIEM_DEFAULT) == 0) {
return (0);
}

errx(EXIT_USAGE, "invalid LED mode with -s: %s", arg);
}

static void
ahciem_set(ahciem_t *ahci, const char *portstr, int fd, int port)
{
ahci_ioc_em_set_t set;

bzero(&set, sizeof (set));

set.aiems_port = port;
set.aiems_op = AHCI_EM_IOC_SET_OP_SET;
set.aiems_leds = ahci->ahci_led;

if (ioctl(fd, AHCI_EM_IOC_SET, &set) != 0) {
warn("failed to set LEDs on %s", portstr);
ahci->ahci_err = 1;
}
}

static int
ahciem_devinfo(di_node_t node, void *arg)
{
char *driver, *mpath, *fullpath;
const char *sup;
int inst, fd;
uint_t i;
ahciem_t *ahci = arg;
di_minor_t m;
ahci_ioc_em_get_t get;

if ((driver = di_driver_name(node)) == NULL)
return (DI_WALK_CONTINUE);
if (strcmp(driver, "ahci") != 0)
return (DI_WALK_CONTINUE);
inst = di_instance(node);

m = DI_MINOR_NIL;
while ((m = di_minor_next(node, m)) != DI_MINOR_NIL) {
char *mname = di_minor_name(m);

if (mname != NULL && strcmp("devctl", mname) == 0)
break;
}

if (m == DI_MINOR_NIL) {
warnx("encountered ahci%d without devctl node", inst);
return (DI_WALK_PRUNECHILD);
}

if ((mpath = di_devfs_minor_path(m)) == NULL) {
warnx("failed to get path for ahci%d devctl minor", inst);
return (DI_WALK_PRUNECHILD);
}

if (asprintf(&fullpath, "/devices/%s", mpath) == -1) {
warn("failed to construct /devices path from %s", mpath);
return (DI_WALK_PRUNECHILD);
}

if ((fd = open(fullpath, O_RDWR)) < 0) {
warn("failed to open ahci%d devctl path %s", inst, fullpath);
goto out;
}

bzero(&get, sizeof (get));
if (ioctl(fd, AHCI_EM_IOC_GET, &get) != 0) {
warn("failed to get AHCI enclosure information for ahci%d",
inst);
ahci->ahci_err = 1;
goto out;
}

if ((get.aiemg_flags & AHCI_EM_FLAG_CONTROL_ACTIVITY) != 0) {
sup = ahciem_led_to_string(AHCI_EM_LED_IDENT_ENABLE |
AHCI_EM_LED_FAULT_ENABLE | AHCI_EM_LED_ACTIVITY_DISABLE);
} else {
sup = ahciem_led_to_string(AHCI_EM_LED_IDENT_ENABLE |
AHCI_EM_LED_FAULT_ENABLE);
}

for (i = 0; i < AHCI_EM_IOC_MAX_PORTS; i++) {
char port[64];
const char *state;

if (((1 << i) & get.aiemg_nports) == 0)
continue;

(void) snprintf(port, sizeof (port), "ahci%d/%u", inst, i);
if (!ahciem_match(ahci, port))
continue;

if (ahci->ahci_set) {
ahciem_set(ahci, port, fd, i);
continue;
}

state = ahciem_led_to_string(get.aiemg_status[i]);
(void) printf("%-20s %-12s %s,default\n", port, state, sup);
}

out:
free(fullpath);
return (DI_WALK_PRUNECHILD);
}

int
main(int argc, char *argv[])
{
int c, i, ret;
di_node_t root;
ahciem_t ahci;

ahciem_progname = basename(argv[0]);

bzero(&ahci, sizeof (ahciem_t));
while ((c = getopt(argc, argv, ":s:")) != -1) {
switch (c) {
case 's':
ahci.ahci_set = B_TRUE;
ahci.ahci_led = ahciem_parse(optarg);
break;
case ':':
ahciem_usage("option -%c requires an operand\n",
optopt);
return (EXIT_USAGE);
case '?':
default:
ahciem_usage("unknown option: -%c\n", optopt);
return (EXIT_USAGE);
}
}

argc -= optind;
argv += optind;
ahci.ahci_argc = argc;
ahci.ahci_argv = argv;
if (argc > 0) {
ahci.ahci_found = calloc(argc, sizeof (boolean_t));
if (ahci.ahci_found == NULL) {
err(EXIT_FAILURE, "failed to alloc memory for %d "
"booleans", argc);
}
}

if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
err(EXIT_FAILURE, "failed to open devinfo tree");
}

if (!ahci.ahci_set) {
(void) printf("%-20s %-12s %s\n", "PORT", "ACTIVE",
"SUPPORTED");
}

if (di_walk_node(root, DI_WALK_CLDFIRST, &ahci,
ahciem_devinfo) != 0) {
err(EXIT_FAILURE, "failed to walk devinfo tree");
}

ret = ahci.ahci_err;
for (i = 0; i < argc; i++) {
if (ahci.ahci_found[i])
continue;
warnx("failed to find ahci enclosure port \"%s\"",
ahci.ahci_argv[i]);
ret = 1;
}

return (ret);
}
@@ -21,6 +21,7 @@

#
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, Joyent, Inc.
#

#
@@ -39,11 +40,13 @@ set name=variant.arch value=i386
dir path=kernel group=sys
dir path=kernel/drv group=sys
dir path=kernel/drv/$(ARCH64) group=sys
dir path=usr/lib/ahci
dir path=usr/share/man
dir path=usr/share/man/man7d
driver name=ahci alias=pciclass,010601 class=scsi-self-identifying \
perms="* 0644 root sys"
file path=kernel/drv/$(ARCH64)/ahci group=sys
file path=usr/lib/ahci/ahciem mode=0555
file path=usr/share/man/man7d/ahci.7d
legacy pkg=SUNWahci \
desc="Advanced Host Controller Interface (AHCI) SATA HBA Driver" \
Oops, something went wrong.

0 comments on commit fd6d41c

Please sign in to comment.
You can’t perform that action at this time.