Skip to content

Commit 9c9cc66

Browse files
committed
Support FS6706T, detect every AS67xx and FS67xx device separately
Looks like the Flashtor for 6 SSDs doesn't have any PCIe device that the *A*S67xx devices don't have. So now we painstakingly detect every AS67xx and FS67xx separately. On the upside, this allows exposing only the SATA LEDs that actually exist on each specific AS67xx device. This also means that the overrides (force_device kernel module argument) for those devices have changed and are now "AS6702", "AS6704", "AS6706" instead of "AS67xx" and "FS6706", "FS6712" instead of "FS67xx"
1 parent 157c69c commit 9c9cc66

File tree

2 files changed

+173
-31
lines changed

2 files changed

+173
-31
lines changed

README.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ On many systems, ASUSTOR uses a mix of IT87 and CPU GPIOs to control leds and bu
1515

1616
### Optional
1717

18-
- `it87` (AS6, AS61, AS62, AS66XX, AS67XX, AS54XX)
18+
- `it87` (AS6, AS61, AS62, AS66XX, AS67XX, AS54XX, FS67XX)
1919
- This project includes a patched version of `it87` called `asustor-it87` which skips fan pwm sanity checks
2020
and supports more variants of IT86XX and the IT87XX chips than the kernels `it87` driver.
2121
Support for timer-based blinking of up to two LEDs (only works on some models) has also been added.
@@ -52,8 +52,12 @@ The following DMI system-manufacturer / system-product-name combinations are cur
5252
* "Intel Corporation" / "Jasper Lake Client Platform"
5353
- These are the *Lockerstor Gen2* AS67xxT (AS6702T etc), *Nimbustor Gen2* AS54xxT (AS5402T etc)
5454
and *Flashstor* FS6706T/FS6712X devices.
55-
- Identified by `asustor` kernel module as **"AS67xx"** for *Lockerstor Gen2* and *Nimbustor Gen2*
56-
- **_or_** identified as **"FS67xx"** if it's a *Flashstor* device
55+
- Identified by `asustor` kernel module as:
56+
* **"AS6702"** for *Lockerstor Gen2* and *Nimbustor Gen2* with *two* SATA drives (AS6702T, AS5402T)
57+
* **"AS6704"** for *Lockerstor Gen2* and *Nimbustor Gen2* with *four* SATA drives (AS6704T, AS5404T)
58+
* **"AS6706"** for *Lockerstor Gen2* with *six* SATA drives (AS6706T)
59+
* **"FS6706"** for *Flashtor* with *six* slots for m.2 NVME SSDs (FS6706T)
60+
* **"FS6712"** for *Flashtor* with *twelve* slots for m.2 NVME SSDs (FS6712X)
5761

5862
## Features
5963

@@ -175,10 +179,10 @@ This can be done manually with `sudo modprobe asustor force_device=AS66xx`, or b
175179

176180
```
177181
# override device detection of the asustor kernel module
178-
options asustor force_device=FS67xx
182+
options asustor force_device=FS6712
179183
```
180184

181-
Please replace "FS67xx" with the device you want to try.
185+
Please replace "FS6712" with the device you want to try.
182186
See the [Compatiblity](#compatibility)-section above for how the `asustor` kernel module identifies devices.
183187
Alternatively, can use the following command to print module parameters, including the currently supported device names for `force_device`:
184188

asustor_main.c

Lines changed: 164 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,51 @@ static struct gpiod_lookup_table asustor_fs6700_gpio_leds_lookup = {
113113
},
114114
};
115115

116-
static struct gpiod_lookup_table asustor_6700_gpio_leds_lookup = {
116+
static struct gpiod_lookup_table asustor_as6702_gpio_leds_lookup = {
117+
.dev_id = "leds-gpio",
118+
.table = {
119+
// 0: AS6702T and AS5402T don't have a front panel to illuminate
120+
// 1: they don't have a LCD either
121+
GPIO_LOOKUP_IDX(GPIO_IT87, 56, NULL, 2, GPIO_ACTIVE_LOW), // blue:power
122+
GPIO_LOOKUP_IDX(GPIO_IT87, 8, NULL, 3, GPIO_ACTIVE_LOW), // red:power
123+
GPIO_LOOKUP_IDX(GPIO_IT87, 31, NULL, 4, GPIO_ACTIVE_LOW), // green:status
124+
GPIO_LOOKUP_IDX(GPIO_IT87, 49, NULL, 5, GPIO_ACTIVE_LOW), // red:status
125+
// 6
126+
GPIO_LOOKUP_IDX(GPIO_IT87, 21, NULL, 7, GPIO_ACTIVE_LOW), // green:usb
127+
GPIO_LOOKUP_IDX(GPIO_IT87, 55, NULL, 8, GPIO_ACTIVE_HIGH), // blue:lan
128+
GPIO_LOOKUP_IDX(GPIO_IT87, 12, NULL, 9, GPIO_ACTIVE_HIGH), // sata1:green:disk
129+
GPIO_LOOKUP_IDX(GPIO_IT87, 13, NULL, 10, GPIO_ACTIVE_LOW), // sata1:red:disk
130+
GPIO_LOOKUP_IDX(GPIO_IT87, 46, NULL, 11, GPIO_ACTIVE_HIGH), // sata2:green:disk
131+
GPIO_LOOKUP_IDX(GPIO_IT87, 47, NULL, 12, GPIO_ACTIVE_LOW), // sata2:red:disk
132+
{}
133+
},
134+
};
135+
136+
static struct gpiod_lookup_table asustor_as6704_gpio_leds_lookup = {
137+
.dev_id = "leds-gpio",
138+
.table = {
139+
GPIO_LOOKUP_IDX(GPIO_IT87, 29, NULL, 0, GPIO_ACTIVE_HIGH), // power:front_panel
140+
GPIO_LOOKUP_IDX(GPIO_IT87, 59, NULL, 1, GPIO_ACTIVE_HIGH), // power:lcd
141+
GPIO_LOOKUP_IDX(GPIO_IT87, 56, NULL, 2, GPIO_ACTIVE_LOW), // blue:power
142+
GPIO_LOOKUP_IDX(GPIO_IT87, 8, NULL, 3, GPIO_ACTIVE_LOW), // red:power
143+
GPIO_LOOKUP_IDX(GPIO_IT87, 31, NULL, 4, GPIO_ACTIVE_LOW), // green:status
144+
GPIO_LOOKUP_IDX(GPIO_IT87, 49, NULL, 5, GPIO_ACTIVE_LOW), // red:status
145+
// 6
146+
GPIO_LOOKUP_IDX(GPIO_IT87, 21, NULL, 7, GPIO_ACTIVE_LOW), // green:usb
147+
GPIO_LOOKUP_IDX(GPIO_IT87, 55, NULL, 8, GPIO_ACTIVE_HIGH), // blue:lan
148+
GPIO_LOOKUP_IDX(GPIO_IT87, 12, NULL, 9, GPIO_ACTIVE_HIGH), // sata1:green:disk
149+
GPIO_LOOKUP_IDX(GPIO_IT87, 13, NULL, 10, GPIO_ACTIVE_LOW), // sata1:red:disk
150+
GPIO_LOOKUP_IDX(GPIO_IT87, 46, NULL, 11, GPIO_ACTIVE_HIGH), // sata2:green:disk
151+
GPIO_LOOKUP_IDX(GPIO_IT87, 47, NULL, 12, GPIO_ACTIVE_LOW), // sata2:red:disk
152+
GPIO_LOOKUP_IDX(GPIO_IT87, 51, NULL, 13, GPIO_ACTIVE_HIGH), // sata3:green:disk
153+
GPIO_LOOKUP_IDX(GPIO_IT87, 52, NULL, 14, GPIO_ACTIVE_LOW), // sata3:red:disk
154+
GPIO_LOOKUP_IDX(GPIO_IT87, 63, NULL, 15, GPIO_ACTIVE_HIGH), // sata4:green:disk
155+
GPIO_LOOKUP_IDX(GPIO_IT87, 48, NULL, 16, GPIO_ACTIVE_LOW), // sata4:red:disk
156+
{}
157+
},
158+
};
159+
160+
static struct gpiod_lookup_table asustor_as6706_gpio_leds_lookup = {
117161
.dev_id = "leds-gpio",
118162
.table = {
119163
GPIO_LOOKUP_IDX(GPIO_IT87, 29, NULL, 0, GPIO_ACTIVE_HIGH), // power:front_panel
@@ -263,44 +307,111 @@ struct asustor_driver_data {
263307
struct gpiod_lookup_table *keys;
264308
};
265309

266-
#define VALID_OVERRIDE_NAMES "AS6xx, AS61xx, AS66xx, AS67xx, FS67xx"
310+
#define VALID_OVERRIDE_NAMES \
311+
"AS6xx, AS61xx, AS66xx, AS6702, AS6704, AS6706, FS6706, FS6712"
267312

268313
// NOTE: if you add another device here, update VALID_OVERRIDE_NAMES accordingly!
269314

270-
static struct asustor_driver_data asustor_fs6700_driver_data = {
271-
.name = "FS67xx",
272-
// FS67xx needs to match PCI devices because it has the same DMI data as *A*S67xx
315+
/*
316+
* Unfortunately, AS67xx and FS67xx can't be told apart by DMI, they all identify as
317+
* "Intel Corporation" - "Jasper Lake Client Platform", so we need to match PCI devices.
318+
*
319+
* How to tell AS67xx and FS6xx apart:
320+
*
321+
* only AS6702T/AS5402T has [8086:4dd3] Intel Corporation Jasper Lake SATA AHCI Controller
322+
* (only [AF]S67xx: [8086:4dc8] Intel Corporation Jasper Lake HD Audio
323+
* - but for now I think AS670xT vs AS540xT doesn't matter. Not sure if AS5404T has this; AS5402T doesn't)
324+
*
325+
* only AS6704T has [1b21:1164] ASMedia Technology Inc. ASM1164 Serial ATA AHCI Controller
326+
* - TODO: does AS5404T also use this? until disproven, I assume it does
327+
* only AS6706T has [1b21:1166] ASMedia Technology Inc. ASM1166 Serial ATA Controller
328+
*
329+
* only FS6712X has [1b21:2806] ASMedia Technology Inc. ASM2806 4-Port PCIe x2 Gen3 Packet Switch
330+
* (it doesn't have any SATA controller)
331+
* FS6706T does not have any SATA controller and no ASMedia PCIe packet switch either
332+
*/
333+
334+
static struct asustor_driver_data asustor_as6702_driver_data = {
335+
.name = "AS6702",
336+
.pci_matches = {
337+
// SATA controller [0106]: Intel Corporation Jasper Lake SATA AHCI Controller [8086:4dd3] (rev 01)
338+
// Both AS6702T and AS5402T use this SATA controller (the other devices don't)
339+
{ 0x8086, 0x4dd3, 1, 1 }
340+
},
341+
.leds = &asustor_as6702_gpio_leds_lookup,
342+
.keys = &asustor_6100_gpio_keys_lookup,
343+
};
344+
345+
static struct asustor_driver_data asustor_as6704_driver_data = {
346+
.name = "AS6704",
347+
.pci_matches = {
348+
// SATA controller: ASMedia Technology Inc. ASM1164 Serial ATA AHCI Controller [1b21:1164] (rev 02)
349+
// This SATA controller is used by AS6704T, and hopefully by AS5404T as well, but
350+
// not by any of the other AS67xx or FS67xx devices
351+
{ 0x1b21, 0x1164, 1, 1 }
352+
},
353+
.leds = &asustor_as6704_gpio_leds_lookup,
354+
.keys = &asustor_6100_gpio_keys_lookup,
355+
};
356+
357+
static struct asustor_driver_data asustor_as6706_driver_data = {
358+
.name = "AS6706",
359+
.pci_matches = {
360+
// SATA controller [0106]: ASMedia Technology Inc. ASM1166 Serial ATA Controller [1b21:1166] (rev 02)
361+
// only used by AS6706T; there (currently?) is no AS5406T
362+
{ 0x1b21, 0x1166, 1, 1 }
363+
// (BTW, AS6706T also has 5x "ASM2812 6-Port PCIe x4 Gen3 Packet Switch" [1b21:2812],
364+
// which thankfully is NOT the same one that FS6712 uses. Also it allows replacing the
365+
// m.2 NVME slots with a 10Gbit NIC, could be that then the packet switch goes away, IDK)
366+
},
367+
.leds = &asustor_as6706_gpio_leds_lookup,
368+
.keys = &asustor_6100_gpio_keys_lookup,
369+
};
370+
371+
static struct asustor_driver_data asustor_fs6712_driver_data = {
372+
.name = "FS6712",
273373
.pci_matches = {
274374
// PCI bridge: ASMedia Technology Inc. ASM2806 4-Port PCIe x2 Gen3 Packet Switch (rev 01)
275-
// FS6712X seems to have 15 of these, no idea about FS6706T (so I keep min_count at 1)
276-
// currently the upper limit doesn't matter so I just use DEVICE_COUNT_MAX
375+
// apparently only FS6712X uses this - 15 of those turn up in lspci, at least if
376+
// all m.2 NVME slots have a SSD installed. I guess it's safest to match that at least
377+
// one of these exist; upper limit doesn't matter, so just use DEVICE_COUNT_MAX
277378
{ 0x1b21, 0x2806, 1, DEVICE_COUNT_MAX },
278379
},
279380
.leds = &asustor_fs6700_gpio_leds_lookup,
280381
.keys = &asustor_fs6700_gpio_keys_lookup,
281382
};
282383

283-
static struct asustor_driver_data asustor_6700_driver_data = {
284-
.name = "AS67xx",
285-
// AS67xx needs to match PCI devices because it has the same DMI data as *F*S67xx
384+
static struct asustor_driver_data asustor_fs6706_driver_data = {
385+
.name = "FS6706",
286386
.pci_matches = {
287-
// PCI bridge: ASMedia Technology Inc. ASM2806 4-Port PCIe x2 Gen3 Packet Switch (rev 01)
288-
// *F*S67xx seems to use these, *A*S67xx doesn't, so expect 0
289-
// (BTW, AS6706T has 5x "ASM2812 6-Port PCIe x4 Gen3 Packet Switch" [1b21:2812], I hope *F*S6706T doesn't)
387+
// FS6706T doesn't have that ASMedia PCI bridge / PCIe Packet switch
290388
{ 0x1b21, 0x2806, 0, 0 },
389+
// .. it doesn't have any of the SATA controllers either
390+
{ 0x8086, 0x4dd3, 0, 0 }, // .. not the Intel one used by AS6702T/AS5402T
391+
{ 0x1b21, 0x1164, 0, 0 }, // .. neither the ASMedia one used by AS6704T
392+
{ 0x1b21, 0x1166, 0, 0 }, // .. nor the ASMedia one used by AS6706T
291393
},
292-
.leds = &asustor_6700_gpio_leds_lookup,
293-
.keys = &asustor_6100_gpio_keys_lookup,
394+
.leds = &asustor_fs6700_gpio_leds_lookup,
395+
.keys = &asustor_fs6700_gpio_keys_lookup,
294396
};
295397

398+
/*
399+
* It currently looks like the older systems are easier to tell apart, at least if one doesn't insist
400+
* on detecting the 2 vs 4 vs 6 drives versions (I only did this for AS67xx because I had to do the
401+
* advanced detection anyway)
402+
*/
403+
296404
static struct asustor_driver_data asustor_6600_driver_data = {
297405
// NOTE: This is (currently?) the same as for AS6700
298406
// because it seems to use the same GPIO numbers,
299407
// but listed extra for the different name
300408
.name = "AS66xx",
301409
// This (and the remaining systems) don't need to match PCI devices to be detected,
302410
// so they're not set here (and thus initialized to all-zero)
303-
.leds = &asustor_6700_gpio_leds_lookup,
411+
412+
// the LED GPIOs are the same as in AS67xx, so use the one from AS6704 which should work for
413+
// both AS6602T and AS6604T (an AS66xx with more than 4 drives doesn't seem to exist)
414+
.leds = &asustor_as6704_gpio_leds_lookup,
304415
.keys = &asustor_6100_gpio_keys_lookup,
305416
};
306417

@@ -316,34 +427,61 @@ static struct asustor_driver_data asustor_600_driver_data = {
316427
.keys = &asustor_600_gpio_keys_lookup,
317428
};
318429

319-
// NOTE: Don't use this table with dmi_first_match(), because it has two entries that
320-
// match the same (AS67xx and FS67xx). find_matching_asustor_system() handles
430+
// NOTE: Don't use this table with dmi_first_match(), because it has several entries that
431+
// match the same (for AS67xx and FS67xx). find_matching_asustor_system() handles
321432
// that by also matching PCI devices from asustor_driver_data::pci_matches.
322433
// This table only exists in this form (instead of just using an array of
323434
// asustor_driver_data) for MODULE_DEVICE_TABLE().
324435
static const struct dmi_system_id asustor_systems[] = {
325436
// NOTE: each entry in this table must have its own unique asustor_driver_data
326437
// (having a unique .name) set as .driver_data
438+
439+
// The following devices all use the same DMI matches and are actually told apart by
440+
// our custom matching logic in find_matching_asustor_system() also takes
441+
// driver_data->pci_matches[] into account.
442+
// See also the bigger comment above about AS67xx vs FS67xx
443+
{
444+
// NOTE: This not only matches (and works with) AS6702T (Lockerstor Gen2),
445+
// but also AS5402T (Nimbustor Gen2)
446+
.matches = {
447+
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
448+
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Jasper Lake Client Platform"),
449+
},
450+
.driver_data = &asustor_as6702_driver_data,
451+
},
452+
{
453+
// NOTE: This not only matches (and works with) AS6704T (Lockerstor Gen2),
454+
// but (hopefully!) also AS5404T (Nimbustor Gen2)
455+
.matches = {
456+
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
457+
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Jasper Lake Client Platform"),
458+
},
459+
.driver_data = &asustor_as6704_driver_data,
460+
},
327461
{
328-
// NOTE: yes, this is the same DMI match as the next entry, because just by DMI,
329-
// FS67xx and AS67xx can't be told apart. But our custom matching logic
330-
// in find_matching_asustor_system() also takes driver_data->pci_matches[]
331-
// into account, so that should be ok.
332462
.matches = {
333463
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
334464
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Jasper Lake Client Platform"),
335465
},
336-
.driver_data = &asustor_fs6700_driver_data,
466+
.driver_data = &asustor_as6706_driver_data,
337467
},
468+
// *F*S67xx:
338469
{
339-
// NOTE: This not only matches (and works with) AS670xT (Lockerstor Gen2),
340-
// but also AS540xT (Nimbustor Gen2)
341470
.matches = {
342471
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
343472
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Jasper Lake Client Platform"),
344473
},
345-
.driver_data = &asustor_6700_driver_data,
474+
.driver_data = &asustor_fs6706_driver_data,
346475
},
476+
{
477+
.matches = {
478+
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
479+
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Jasper Lake Client Platform"),
480+
},
481+
.driver_data = &asustor_fs6712_driver_data,
482+
},
483+
484+
// older devices can be matched only by DMI
347485
{
348486
.matches = {
349487
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"),

0 commit comments

Comments
 (0)