diff --git a/sys/dev/disk/ahci/ahci.c b/sys/dev/disk/ahci/ahci.c index f1111e1..5a6816d 100644 --- a/sys/dev/disk/ahci/ahci.c +++ b/sys/dev/disk/ahci/ahci.c @@ -608,6 +608,26 @@ ahci_port_link_pwr_mgmt(struct ahci_port *ap, int link_pwr_mgmt) ahci_os_unlock_port(ap); } +/* + * Return current link power state. + */ +int +ahci_port_link_pwr_state(struct ahci_port *ap) +{ + uint32_t r; + + r = ahci_pread(ap, AHCI_PREG_SSTS); + switch (r & SATA_PM_SSTS_IPM) { + case SATA_PM_SSTS_IPM_ACTIVE: + return 1; + case SATA_PM_SSTS_IPM_PARTIAL: + return 2; + case SATA_PM_SSTS_IPM_SLUMBER: + return 3; + default: + return 0; + } +} /* * Run the port / target state machine from a main context. diff --git a/sys/dev/disk/ahci/ahci.h b/sys/dev/disk/ahci/ahci.h index 123d681..ee02a85 100644 --- a/sys/dev/disk/ahci/ahci.h +++ b/sys/dev/disk/ahci/ahci.h @@ -507,6 +507,7 @@ void ahci_port_state_machine(struct ahci_port *ap, int initial); void ahci_port_free(struct ahci_softc *, u_int); int ahci_port_reset(struct ahci_port *, struct ata_port *at, int); void ahci_port_link_pwr_mgmt(struct ahci_port *, int link_pwr_mgmt); +int ahci_port_link_pwr_state(struct ahci_port *); u_int32_t ahci_read(struct ahci_softc *, bus_size_t); void ahci_write(struct ahci_softc *, bus_size_t, u_int32_t); diff --git a/sys/dev/disk/ahci/ahci_dragonfly.c b/sys/dev/disk/ahci/ahci_dragonfly.c index 633fdb7..c17ffd8 100644 --- a/sys/dev/disk/ahci/ahci_dragonfly.c +++ b/sys/dev/disk/ahci/ahci_dragonfly.c @@ -163,6 +163,22 @@ ahci_systcl_link_pwr_mgmt (SYSCTL_HANDLER_ARGS) return 0; } +static int +ahci_sysctl_link_pwr_state (SYSCTL_HANDLER_ARGS) +{ + struct ahci_port *ap = arg1; + const char *state_names[] = {"unknown", "active", "partial", "slumber"}; + char buf[16]; + int state; + + state = ahci_port_link_pwr_state(ap); + if (state < 0 || state >= sizeof(state_names) / sizeof(state_names[0])) + state = 0; + + ksnprintf(buf, sizeof(buf), "%s", state_names[state]); + return sysctl_handle_string(oidp, buf, sizeof(buf), req); +} + #if 0 static int @@ -241,8 +257,13 @@ ahci_os_start_port(struct ahci_port *ap) SYSCTL_CHILDREN(ap->sysctl_tree), OID_AUTO, "link_pwr_mgmt", CTLTYPE_INT | CTLFLAG_RW, ap, 0, ahci_systcl_link_pwr_mgmt, "I", - "Link power management " + "Link power management policy " "(0 = disabled, 1 = medium, 2 = aggressive)"); + SYSCTL_ADD_PROC(&ap->sysctl_ctx, + SYSCTL_CHILDREN(ap->sysctl_tree), OID_AUTO, + "link_pwr_state", CTLTYPE_STRING | CTLFLAG_RD, ap, 0, + ahci_sysctl_link_pwr_state, "A", + "Link power management state"); }