summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2002-03-30 16:36:41 +0000
committersos <sos@FreeBSD.org>2002-03-30 16:36:41 +0000
commit65dd7ee2d664fd3e803c25710ebb8cff700d4693 (patch)
tree9eb58c78c6a73f6a83116f480d13036d52b41301
parent59fa66220ea04959e377ec1831047b655bbe4da6 (diff)
downloadFreeBSD-src-65dd7ee2d664fd3e803c25710ebb8cff700d4693.zip
FreeBSD-src-65dd7ee2d664fd3e803c25710ebb8cff700d4693.tar.gz
Add support for getting status (fan, temp, 5V and 12V levels) from
Promise Superswap enclosures. Sponsored by: Advanis
-rw-r--r--sbin/atacontrol/atacontrol.88
-rw-r--r--sbin/atacontrol/atacontrol.c11
-rw-r--r--sys/dev/ata/ata-all.c161
-rw-r--r--sys/sys/ata.h8
4 files changed, 179 insertions, 9 deletions
diff --git a/sbin/atacontrol/atacontrol.8 b/sbin/atacontrol/atacontrol.8
index 6d8bd53..44aad43 100644
--- a/sbin/atacontrol/atacontrol.8
+++ b/sbin/atacontrol/atacontrol.8
@@ -65,6 +65,9 @@
.Ic cap
.Ar channel device
.Nm
+.Ic enclosure
+.Ar channel device
+.Nm
.Ic list
.Sh DESCRIPTION
.Nm
@@ -145,6 +148,11 @@ the device name and manufacture/version strings are shown.
Show detailed info about the device on
.Ar channel device
where device is 0 for master and 1 for slave.
+.It Ic enclosure
+Show detailed info about the encolsure on
+.Ar channel device
+where device is 0 for master and 1 for slave.
+Fan RPM speed, enclosure temperature, 5V and 12V levels are shown.
.It Ic list
Show info about all attached devices on all active controllers.
.El
diff --git a/sbin/atacontrol/atacontrol.c b/sbin/atacontrol/atacontrol.c
index e339a25..9fe2201 100644
--- a/sbin/atacontrol/atacontrol.c
+++ b/sbin/atacontrol/atacontrol.c
@@ -272,6 +272,17 @@ main(int argc, char **argv)
else if (!strcmp(argv[1], "cap") && argc == 4) {
ata_cap_print(fd, iocmd.channel, atoi(argv[3]));
}
+ else if (!strcmp(argv[1], "enclosure") && argc == 4) {
+ iocmd.device = atoi(argv[3]);
+ iocmd.cmd = ATAENCSTAT;
+ if (ioctl(fd, IOCATA, &iocmd) < 0)
+ err(1, "ioctl(ATAENCSTAT)");
+ printf("fan RPM: %d temp: %.1f 5V: %.2f 12V: %.2f\n",
+ iocmd.u.enclosure.fan,
+ (double)iocmd.u.enclosure.temp / 10,
+ (double)iocmd.u.enclosure.v05 / 1000,
+ (double)iocmd.u.enclosure.v12 / 1000);
+ }
else if (!strcmp(argv[1], "detach") && argc == 3) {
iocmd.cmd = ATADETACH;
if (ioctl(fd, IOCATA, &iocmd) < 0)
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c
index 2196c9b..813bb82 100644
--- a/sys/dev/ata/ata-all.c
+++ b/sys/dev/ata/ata-all.c
@@ -80,6 +80,7 @@ static void bswap(int8_t *, int);
static void btrim(int8_t *, int);
static void bpack(int8_t *, int8_t *, int);
static void ata_change_mode(struct ata_device *, int);
+static u_int8_t ata_drawersensor(struct ata_device *, int, u_int8_t, u_int8_t);
/* sysctl vars */
SYSCTL_NODE(_hw, OID_AUTO, ata, CTLFLAG_RD, 0, "ATA driver parameters");
@@ -363,6 +364,48 @@ ataioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct thread *td)
sizeof(struct ata_params));
return 0;
+ case ATAENCSTAT: {
+ struct ata_device *atadev;
+ u_int8_t id1, id2, cnt, div;
+ int fan, temp;
+
+ if (!device || !(ch = device_get_softc(device)))
+ return ENXIO;
+
+ ATA_SLEEPLOCK_CH(ch, ATA_ACTIVE);
+
+ if (iocmd->device == SLAVE)
+ atadev = &ch->device[SLAVE];
+ else
+ atadev = &ch->device[MASTER];
+
+ ata_drawersensor(atadev, 1, 0x4e, 0);
+ id1 = ata_drawersensor(atadev, 0, 0x4f, 0);
+ ata_drawersensor(atadev, 1, 0x4e, 0x80);
+ id2 = ata_drawersensor(atadev, 0, 0x4f, 0);
+ if (id1 != 0xa3 || id2 != 0x5c)
+ return ENXIO;
+
+ div = 1 << (((ata_drawersensor(atadev, 0, 0x5d, 0)&0x20)>>3) +
+ ((ata_drawersensor(atadev, 0, 0x47, 0)&0x30)>>4) + 1);
+ cnt = ata_drawersensor(atadev, 0, 0x28, 0);
+ if (cnt == 0xff)
+ fan = 0;
+ else
+ fan = 1350000 / cnt / div;
+ ata_drawersensor(atadev, 1, 0x4e, 0x01);
+ temp = (ata_drawersensor(atadev, 0, 0x50, 0) * 10) +
+ (ata_drawersensor(atadev, 0, 0x50, 0) & 0x80 ? 5 : 0);
+
+ iocmd->u.enclosure.fan = fan;
+ iocmd->u.enclosure.temp = temp;
+ iocmd->u.enclosure.v05 = ata_drawersensor(atadev, 0, 0x23, 0) * 27;
+ iocmd->u.enclosure.v12 = ata_drawersensor(atadev, 0, 0x24, 0) * 61;
+
+ ATA_UNLOCK_CH(ch);
+ return 0;
+ }
+
#ifdef DEV_ATADISK
case ATARAIDREBUILD:
return ata_raid_rebuild(iocmd->channel);
@@ -505,6 +548,16 @@ ata_boot_attach(void)
ad_attach(&ch->device[MASTER]);
if (ch->devices & ATA_ATA_SLAVE)
ad_attach(&ch->device[SLAVE]);
+ if (ctlr >= 2) {
+ u_int8_t id1, id2, fan;
+
+ ata_drawersensor(&ch->device[MASTER], 1, 0x4e, 0);
+ id1 = ata_drawersensor(&ch->device[MASTER], 0, 0x4f, 0);
+ ata_drawersensor(&ch->device[MASTER], 1, 0x4e, 0x80);
+ id2 = ata_drawersensor(&ch->device[MASTER], 0, 0x4f, 0);
+ fan = ata_drawersensor(&ch->device[MASTER], 0, 0x28, 0);
+ printf("winbond ID 0x%02x 0x%02x 0x%02x\n", id1, id2, fan);
+ }
}
ata_raid_attach();
#endif
@@ -1064,12 +1117,9 @@ ata_command(struct ata_device *atadev, u_int8_t command,
return error;
}
-void
-ata_drawerleds(struct ata_device *atadev, u_int8_t color)
+static void
+ata_drawer_start(struct ata_device *atadev)
{
- u_int8_t count, drive;
-
- /* magic sequence to set the LED color on the Promise SuperSwap */
ATA_INB(atadev->channel->r_io, ATA_DRIVE);
DELAY(1);
ATA_OUTB(atadev->channel->r_io, ATA_DRIVE, ATA_D_IBM | atadev->unit);
@@ -1078,17 +1128,110 @@ ata_drawerleds(struct ata_device *atadev, u_int8_t color)
DELAY(1);
ATA_OUTB(atadev->channel->r_io, ATA_DRIVE, ATA_D_IBM | atadev->unit);
DELAY(1);
- count = ATA_INB(atadev->channel->r_io, ATA_COUNT);
+ ATA_INB(atadev->channel->r_io, ATA_COUNT);
DELAY(1);
- drive = ATA_INB(atadev->channel->r_io, ATA_DRIVE);
- DELAY(1);
- ATA_OUTB(atadev->channel->r_io, ATA_COUNT, color);
+ ATA_INB(atadev->channel->r_io, ATA_DRIVE);
DELAY(1);
+}
+
+static void
+ata_drawer_end(struct ata_device *atadev)
+{
ATA_OUTB(atadev->channel->r_io, ATA_DRIVE, ATA_D_IBM | atadev->unit);
DELAY(1);
}
static void
+ata_chip_start(struct ata_device *atadev)
+{
+ ATA_OUTB(atadev->channel->r_io, ATA_SECTOR, 0x0b);
+ ATA_OUTB(atadev->channel->r_io, ATA_SECTOR, 0x0a);
+ DELAY(25);
+ ATA_OUTB(atadev->channel->r_io, ATA_SECTOR, 0x08);
+}
+
+static void
+ata_chip_end(struct ata_device *atadev)
+{
+ ATA_OUTB(atadev->channel->r_io, ATA_SECTOR, 0x08);
+ DELAY(64);
+ ATA_OUTB(atadev->channel->r_io, ATA_SECTOR, 0x0a);
+ DELAY(25);
+ ATA_OUTB(atadev->channel->r_io, ATA_SECTOR, 0x0b);
+ DELAY(64);
+}
+
+static u_int8_t
+ata_chip_rdbit(struct ata_device *atadev)
+{
+ u_int8_t val;
+
+ ATA_OUTB(atadev->channel->r_io, ATA_SECTOR, 0);
+ DELAY(64);
+ ATA_OUTB(atadev->channel->r_io, ATA_SECTOR, 0x02);
+ DELAY(25);
+ val = ATA_INB(atadev->channel->r_io, ATA_SECTOR) & 0x01;
+ DELAY(38);
+ return val;
+}
+
+static void
+ata_chip_wrbit(struct ata_device *atadev, u_int8_t data)
+{
+ ATA_OUTB(atadev->channel->r_io, ATA_SECTOR, 0x08 | (data & 0x01));
+ DELAY(64);
+ ATA_OUTB(atadev->channel->r_io, ATA_SECTOR, 0x08 | 0x02 | (data & 0x01));
+ DELAY(64);
+}
+
+static u_int8_t
+ata_chip_rw(struct ata_device *atadev, int rw, u_int8_t val)
+{
+ int i;
+
+ if (rw) {
+ for (i = 0; i < 8; i++)
+ ata_chip_wrbit(atadev, (val & (0x80 >> i)) ? 1 : 0);
+ }
+ else {
+ for (i = 0; i < 8; i++)
+ val = (val << 1) | ata_chip_rdbit(atadev);
+ }
+ ata_chip_wrbit(atadev, 0);
+ return val;
+}
+
+static u_int8_t
+ata_drawersensor(struct ata_device *atadev, int rw, u_int8_t idx, u_int8_t data)
+{
+ ata_drawer_start(atadev);
+ ata_chip_start(atadev);
+ ata_chip_rw(atadev, 1, 0x5a);
+ ata_chip_rw(atadev, 1, idx);
+ if (rw) {
+ ata_chip_rw(atadev, 1, data);
+ }
+ else {
+ ata_chip_end(atadev);
+ ata_chip_start(atadev);
+ ata_chip_rw(atadev, 1, 0x5b);
+ data = ata_chip_rw(atadev, 0, 0);
+ }
+ ata_chip_end(atadev);
+ ata_drawer_end(atadev);
+ return data;
+}
+
+void
+ata_drawerleds(struct ata_device *atadev, u_int8_t color)
+{
+ ata_drawer_start(atadev);
+ ATA_OUTB(atadev->channel->r_io, ATA_COUNT, color);
+ DELAY(1);
+ ata_drawer_end(atadev);
+}
+
+static void
ata_change_mode(struct ata_device *atadev, int mode)
{
int umode, wmode, pmode;
diff --git a/sys/sys/ata.h b/sys/sys/ata.h
index 40d1cc5..82c79c1 100644
--- a/sys/sys/ata.h
+++ b/sys/sys/ata.h
@@ -236,6 +236,8 @@ struct ata_cmd {
#define ATARAIDREBUILD 8
#define ATARAIDCREATE 9
#define ATARAIDDELETE 10
+#define ATARAIDSTATUS 11
+#define ATAENCSTAT 12
union {
struct {
@@ -254,6 +256,12 @@ struct ata_cmd {
int unit;
} raid_setup;
struct {
+ int fan;
+ int temp;
+ int v05;
+ int v12;
+ } enclosure;
+ struct {
char ccb[16];
caddr_t data;
int count;
OpenPOWER on IntegriCloud