summaryrefslogtreecommitdiffstats
path: root/sys
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 /sys
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
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ata/ata-all.c161
-rw-r--r--sys/sys/ata.h8
2 files changed, 160 insertions, 9 deletions
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