diff options
author | sos <sos@FreeBSD.org> | 2002-03-30 16:36:41 +0000 |
---|---|---|
committer | sos <sos@FreeBSD.org> | 2002-03-30 16:36:41 +0000 |
commit | 65dd7ee2d664fd3e803c25710ebb8cff700d4693 (patch) | |
tree | 9eb58c78c6a73f6a83116f480d13036d52b41301 /sys | |
parent | 59fa66220ea04959e377ec1831047b655bbe4da6 (diff) | |
download | FreeBSD-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.c | 161 | ||||
-rw-r--r-- | sys/sys/ata.h | 8 |
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; |