Add support for getting status (fan, temp, 5V and 12V levels) from
Promise Superswap enclosures. Sponsored by: Advanis
This commit is contained in:
parent
153d72abb2
commit
3e552821b9
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user