Pass a name and flags precisely describing the current model and its

features via a new bootinfo node (currently Synology only). This allows
for example the configuration of model-specific temperature I2C sensors
and fan control.
Support for the Synology DS207 and DS209 drive LEDs and wait until the
2nd drive is completely powered up.
This commit is contained in:
phx 2015-09-30 14:14:32 +00:00
parent 5428e90392
commit 97d339f97e
6 changed files with 205 additions and 27 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: bootinfo.h,v 1.8 2011/01/11 06:57:35 nisimura Exp $ */
/* $NetBSD: bootinfo.h,v 1.9 2015/09/30 14:14:32 phx Exp $ */
/*
* Copyright (c) 1997
@ -45,6 +45,7 @@ struct btinfo_common {
#define BTINFO_NET 7
#define BTINFO_PRODFAMILY 8
#define BTINFO_MODULELIST 9
#define BTINFO_MODEL 10
struct btinfo_magic {
struct btinfo_common common;
@ -91,6 +92,20 @@ struct btinfo_prodfamily {
char name[24];
};
struct btinfo_model {
struct btinfo_common common;
char name[28];
unsigned flags; /* model specific flags */
/* Synology flags: */
#define BI_MODEL_CPLDVER_MASK 0x07
#define BI_MODEL_CPLD207 0x08
#define BI_MODEL_CPLD209 0x10
#define BI_MODEL_CPLD406 0x18
#define BI_MODEL_CPLD407 0x20
#define BI_MODEL_CPLD_MASK 0x38
#define BI_MODEL_THERMAL 0x40
};
struct btinfo_modulelist {
struct btinfo_common common;
int num;

View File

@ -1,4 +1,4 @@
/* $NetBSD: brdsetup.c,v 1.35 2014/08/08 21:18:10 joerg Exp $ */
/* $NetBSD: brdsetup.c,v 1.36 2015/09/30 14:14:32 phx Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
@ -111,7 +111,14 @@ static unsigned mpc107memsize(void);
#define IOMEGA_PACKETSIZE 8
/* NH230/231 GPIO */
#define NHGPIO_WRITE(x) *((uint8_t *)0x70000000) = x
#define NHGPIO_WRITE(x) *((volatile uint8_t *)0x70000000) = (x)
/* Synology CPLD (2007 and newer models) */
#define SYNOCPLD_READ(r) *((volatile uint8_t *)0xff000000 + (r))
#define SYNOCPLD_WRITE(r,x) do { \
*((volatile uint8_t *)0xff000000 + (r)) = (x); \
delay(10); \
} while(0)
static struct brdprop brdlist[] = {
{
@ -719,47 +726,183 @@ synobrdfix(struct brdprop *brd)
send_sat("247");
}
#define SYNO_FAN_TIMEOUT 500 /* 500ms to turn the fan off */
#define SYNO_DISK_DELAY 30 /* 30 seconds to power up 2nd disk */
void
synopcifix(struct brdprop *brd)
{
static const char csmodel[4][7] = {
"CS406e", "CS406", "RS406", "CS407e"
static const char models207[4][7] = {
"???", "DS107e", "DS107", "DS207"
};
volatile uint8_t *cpld = (volatile uint8_t *)0xff000000;
uint8_t pwrstate;
static const char models209[2][7] = {
"DS109j", "DS209j"
};
static const char models406[3][7] = {
"CS406e", "CS406", "RS406"
};
static const char models407[4][7] = {
"???", "CS407e", "CS407", "RS407"
};
extern struct btinfo_model bi_model;
const char *model_name;
unsigned cpld, version, flags;
uint8_t v, status;
int i;
if (nata > 1) {
/*
* Determine if a CPLD is present and whether is has 4-bit
* (models 107, 207, 209) or 8-bit (models 406, 407) registers.
* The register set repeats every 16 bytes.
*/
cpld = 0;
flags = 0;
version = 0;
model_name = NULL;
SYNOCPLD_WRITE(0, 0x00); /* LEDs blinking yellow (default) */
v = SYNOCPLD_READ(0);
if (v != 0x00) {
v &= 0xf0;
if (v != 0x00 || (SYNOCPLD_READ(16 + 0) & 0xf0) != v)
goto cpld_done;
cpld4bits:
/* 4-bit registers assumed, make LEDs solid yellow */
SYNOCPLD_WRITE(0, 0x50);
v = SYNOCPLD_READ(0) & 0xf0;
if (v != 0x50 || (SYNOCPLD_READ(32 + 0) & 0xf0) != v)
goto cpld_done;
v = SYNOCPLD_READ(2) & 0xf0;
if ((SYNOCPLD_READ(48 + 2) & 0xf0) != v)
goto cpld_done;
version = (v >> 4) & 7;
/*
* Try to determine whether it is a 207-style or 209-style
* CPLD register set, by turning the fan off and check if
* either bit 5 or bit 4 changes from 0 to 1 to indicate
* the fan is stopped.
*/
status = SYNOCPLD_READ(3) & 0xf0;
SYNOCPLD_WRITE(3, 0x00); /* fan off */
for (i = 0; i < SYNO_FAN_TIMEOUT * 100; i++) {
delay(10);
v = SYNOCPLD_READ(3) & 0xf0;
if ((status & 0x20) == 0 && (v & 0x20) != 0) {
/* set x07 model */
v = SYNOCPLD_READ(1) >> 6;
model_name = models207[v];
cpld = BI_MODEL_CPLD207;
/* XXXX DS107v2/v3 have no thermal sensor */
flags |= BI_MODEL_THERMAL;
break;
}
if ((status & 0x10) == 0 && (v & 0x10) != 0) {
/* set x09 model */
v = SYNOCPLD_READ(1) >> 7;
model_name = models209[v];
cpld = BI_MODEL_CPLD209;
if (v == 1) /* DS209j */
flags |= BI_MODEL_THERMAL;
break;
}
/* XXX What about DS108j? Does it have a CPLD? */
}
/* turn the fan on again */
SYNOCPLD_WRITE(3, status);
if (i >= SYNO_FAN_TIMEOUT * 100)
goto cpld_done; /* timeout: no valid CPLD */
} else {
if (SYNOCPLD_READ(16 + 0) != v)
goto cpld4bits;
/* 8-bit registers assumed, make LEDs solid yellow */
SYNOCPLD_WRITE(0, 0x55);
v = SYNOCPLD_READ(0);
if (v != 0x55)
goto cpld4bits; /* try 4 bits instead */
if (SYNOCPLD_READ(32 + 0) != v)
goto cpld_done;
v = SYNOCPLD_READ(2);
if (SYNOCPLD_READ(48 + 2) != v)
goto cpld_done;
version = v & 3;
if ((v & 0x0c) != 0x0c) {
/* set 406 model */
model_name = models406[(v >> 2) & 3];
cpld = BI_MODEL_CPLD406;
} else {
/* set 407 model */
model_name = models407[v >> 6];
cpld = BI_MODEL_CPLD407;
flags |= BI_MODEL_THERMAL;
}
}
printf("CPLD V%s%u detected for model %s\n",
cpld < BI_MODEL_CPLD406 ? "" : "1.",
version, model_name);
if (cpld == BI_MODEL_CPLD406 || cpld == BI_MODEL_CPLD407) {
/*
* CS/RS stations power-up their disks one after another.
* We have to watch over the current power state in a CPLD
* register, until all disks become available.
*/
printf("CPLD V1.%d for model %s\n", cpld[2] & 3,
csmodel[(cpld[2] & 0x0c) >> 2]);
cpld[0] = 0x00; /* all drive LEDs blinking yellow */
do {
delay(1000 * 1000);
pwrstate = cpld[1];
printf("Power state: %02x\r", pwrstate);
} while (pwrstate != 0xff);
v = SYNOCPLD_READ(1);
printf("Power state: %02x\r", v);
} while (v != 0xff);
putchar('\n');
} else if (model_name != NULL && model_name[2] == '2') {
/*
* DS207 and DS209 have a second SATA disk, which is started
* with several seconds delay, but no CPLD register to
* monitor the power state. So all we can do is to
* wait some more seconds during SATA-init.
*/
sata_delay[1] = SYNO_DISK_DELAY;
}
cpld_done:
if (model_name != NULL) {
snprintf(bi_model.name, sizeof(bi_model.name), "%s", model_name);
bi_model.flags = cpld | version | flags;
} else
printf("No CPLD found. DS101/DS106.\n");
}
void
synolaunch(struct brdprop *brd)
{
volatile uint8_t *cpld = (volatile uint8_t *)0xff000000;
extern struct btinfo_model bi_model;
struct dkdev_ata *sata1, *sata2;
unsigned cpld;
if (nata > 1) {
/* enable drive LEDs for active disk drives on CS/RS models */
cpld = bi_model.flags & BI_MODEL_CPLD_MASK;
if (cpld == BI_MODEL_CPLD406 || cpld == BI_MODEL_CPLD407) {
/* set drive LEDs for active disk drives on CS/RS models */
sata1 = lata[0].drv;
sata2 = lata[1].drv;
cpld[0] = (sata1->presense[0] ? 0x80 : 0xc0) |
SYNOCPLD_WRITE(0, (sata1->presense[0] ? 0x80 : 0xc0) |
(sata1->presense[1] ? 0x20 : 0x30) |
(sata2->presense[0] ? 0x08 : 0x0c) |
(sata2->presense[1] ? 0x02 : 0x03);
(sata2->presense[1] ? 0x02 : 0x03));
} else if (cpld == BI_MODEL_CPLD207 || cpld == BI_MODEL_CPLD209) {
/* set drive LEDs for DS207 and DS209 models */
sata1 = lata[0].drv;
SYNOCPLD_WRITE(0, (sata1->presense[0] ? 0x80 : 0xc0) |
(sata1->presense[1] ? 0x20 : 0x30));
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: globals.h,v 1.20 2015/09/29 15:12:52 phx Exp $ */
/* $NetBSD: globals.h,v 1.21 2015/09/30 14:14:32 phx Exp $ */
#ifdef DEBUG
#define DPRINTF(x) printf x
@ -197,6 +197,8 @@ struct fs_ops *dsk_fsops(struct open_file *);
DSK_DECL(pciide);
DSK_DECL(siisata);
extern int sata_delay[4];
/* status */
#define ATA_STS_BUSY 0x80
#define ATA_STS_DRDY 0x40

View File

@ -1,4 +1,4 @@
/* $NetBSD: main.c,v 1.26 2014/08/05 17:55:20 joerg Exp $ */
/* $NetBSD: main.c,v 1.27 2015/09/30 14:14:32 phx Exp $ */
/*-
* Copyright (c) 2007 The NetBSD Foundation, Inc.
@ -72,6 +72,7 @@ struct btinfo_memory bi_mem;
struct btinfo_console bi_cons;
struct btinfo_clock bi_clk;
struct btinfo_prodfamily bi_fam;
struct btinfo_model bi_model;
struct btinfo_bootpath bi_path;
struct btinfo_rootdevice bi_rdev;
struct btinfo_net bi_net;
@ -362,6 +363,7 @@ main(int argc, char *argv[], char *bootargs_start, char *bootargs_end)
/* need to pass this MAC address to kernel */
bi_add(&bi_net, BTINFO_NET, sizeof(bi_net));
}
bi_add(&bi_model, BTINFO_MODEL, sizeof(bi_model));
if (modules_enabled) {
if (fsmod != NULL)

View File

@ -1,4 +1,4 @@
/* $NetBSD: siisata.c,v 1.5 2012/01/22 13:08:17 phx Exp $ */
/* $NetBSD: siisata.c,v 1.6 2015/09/30 14:14:32 phx Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
@ -45,6 +45,8 @@ static int satapresense(struct dkdev_ata *, int);
static uint32_t pciiobase = PCI_XIOBASE;
int sata_delay[4] = { 3, 3, 3, 3 }; /* drive power-up delay per channel */
int
siisata_match(unsigned tag, void *data)
{
@ -110,13 +112,24 @@ siisata_init(unsigned tag, void *data)
for (n = 0; n < nchan; n++) {
l->presense[n] = satapresense(l, n);
if (l->presense[n] == 0) {
DPRINTF(("port %d not present\n", n));
l->presense[n] = 0;
continue;
/* wait some seconds to power-up the drive */
for (retries = 0; retries < sata_delay[n]; retries++) {
wakeup_drive(l, n);
printf("Waiting %2d seconds for powering up "
"port %d.\r", sata_delay[n] - retries, n);
delay(1000 * 1000);
if ((l->presense[n] = satapresense(l, n)) != 0)
break;
}
putchar('\n');
if (l->presense[n] == 0) {
DPRINTF(("port %d not present\n", n));
continue;
}
}
if (atachkpwr(l, n) != ATA_PWR_ACTIVE) {
/* drive is probably sleeping, wake it up */
for (retries = 0; retries < 10; retries++) {
for (retries = 0; retries < 20; retries++) {
wakeup_drive(l, n);
DPRINTF(("port %d spinning up...\n", n));
delay(1000 * 1000);
@ -127,10 +140,11 @@ siisata_init(unsigned tag, void *data)
} else {
/* check to see whether soft reset works */
DPRINTF(("port %d active\n", n));
for (retries = 0; retries < 10; retries++) {
for (retries = 0; retries < 20; retries++) {
l->presense[n] = perform_atareset(l, n);
if (l->presense[n] != 0)
break;
wakeup_drive(l, n);
DPRINTF(("port %d cold-starting...\n", n));
delay(1000 * 1000);
}

View File

@ -16,3 +16,5 @@
A default command line can be saved to flash as initrd image.
1.10: Read correct MAC address from flash on QNAP-TS systems with re(4)
NIC.
1.11: Pass precise model information and flags with bootinfo.
Synology DS207/209 LED and 2nd disk power-up support.