Add support for getting status (fan, temp, 5V and 12V levels) from

Promise Superswap enclosures.

Sponsored by: Advanis
This commit is contained in:
sos 2002-03-30 16:36:41 +00:00
parent 153d72abb2
commit 3e552821b9
4 changed files with 179 additions and 9 deletions

View File

@ -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

View File

@ -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)

View File

@ -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,16 +1128,109 @@ 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)
{

View File

@ -236,6 +236,8 @@ struct ata_cmd {
#define ATARAIDREBUILD 8
#define ATARAIDCREATE 9
#define ATARAIDDELETE 10
#define ATARAIDSTATUS 11
#define ATAENCSTAT 12
union {
struct {
@ -253,6 +255,12 @@ struct ata_cmd {
int interleave;
int unit;
} raid_setup;
struct {
int fan;
int temp;
int v05;
int v12;
} enclosure;
struct {
char ccb[16];
caddr_t data;