Skip to content

Commit 1aafac2

Browse files
committed
Merge branches 'f8x3-2.0' and 'unraid-homelab-x15' into build
2 parents 93556aa + 5c33d35 commit 1aafac2

4 files changed

Lines changed: 307 additions & 18 deletions

File tree

dalias/example_config/NVME-F8X3

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
1-1
2+
1-2
3+
1-3
4+
1-4
5+
1-5
6+
1-6
7+
1-7
8+
1-8
9+
1-9
10+
1-10
11+
1-11
12+
1-12
13+
1-13
14+
1-14
15+
1-15
16+
1-16
17+
1-17
18+
1-18
19+
1-19
20+
1-20
21+
2-1
22+
2-2
23+
2-3
24+
2-4
25+
2-5
26+
2-6
27+
2-7
28+
2-8
29+
2-9
30+
2-10
31+
2-11
32+
2-12
33+
2-13
34+
2-14
35+
2-15
36+
2-16
37+
2-17
38+
2-18
39+
2-19
40+
2-20
41+
3-1
42+
3-2
43+
3-3
44+
3-4
45+
3-5
46+
3-6
47+
3-7
48+
3-8
49+
3-9
50+
3-10
51+
3-11
52+
3-12
53+
3-13
54+
3-14
55+
3-15
56+
3-16
57+
3-17
58+
3-18
59+
3-19
60+
3-20

tools/dmap

Lines changed: 220 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ def create_vdev_id(server):
436436
"SAS9305-16i" : [2,3,1,0, 6,7,5,4, 18,19,17,16, 22,23,21,20],
437437
"SAS9305-24i": [2,3,1,0, 6,7,5,4, 18,19,17,16, 22,23,21,20, 10,11,9,8, 14,15,13,12],
438438
"AVAGO3108MegaRAID": [25,31,37,43, 26,32,38,44, 27,33,39,45, 28,34,41,46, 29,35,40,47, 30,36,42,48],
439-
"9600-24i": [27,28,29,30,31,32,33,34,35,36,37,38,39,41,41,42,43,44,45,46,47,48,49,50],
439+
"9600-24i": [27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50],
440440
#"9600-16i": [27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42]
441441
"9600-16i": [59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74]
442442
}
@@ -503,7 +503,10 @@ def create_vdev_id(server):
503503
"F8":{
504504
"F8X1":[20],
505505
"F8X2":[20,20],
506-
"F8X3":[20,20,20]
506+
"F8X3":[20,20,20],
507+
# "NVME-F8X1":[20],
508+
# "NVME-F8X2":[20,20],
509+
"NVME-F8X3":[20,20,20]
507510
},
508511
"STUDIO":{
509512
"STUDIO8":[4,4],
@@ -660,7 +663,7 @@ def create_vdev_id(server):
660663
vdev_id_str += alias_destroyinator(server,alias_template,phy_order)
661664
elif server["Alias Style"] == "F8":
662665
# we are using the DESTROYINATOR ailiasing scheme.
663-
vdev_id_str += alias_f8(server,alias_template)
666+
vdev_id_str += alias_f8(server,alias_template,phy_order)
664667
elif server["Alias Style"] == "HOMELAB" and server["Chassis Size"] == "HL4":
665668
vdev_id_str += alias_hl4()
666669
elif server["Alias Style"] == "HOMELAB" and server["Chassis Size"] == "HL8":
@@ -677,7 +680,27 @@ def create_vdev_id(server):
677680

678681
return vdev_id_str
679682

680-
def alias_f8(server,alias_template):
683+
def alias_f8(server,alias_template,phy_order):
684+
def _discover_scsi_targets(bus_addr: str):
685+
"""Return sorted unique SCSI target IDs visible under /dev/disk/by-path for a given PCI bus address."""
686+
import glob
687+
targets = set()
688+
pattern = f"/dev/disk/by-path/pci-{bus_addr}-scsi-0:0:*:0"
689+
for p in glob.glob(pattern):
690+
# Ignore partition symlinks
691+
if "-part" in p:
692+
continue
693+
base = os.path.basename(p)
694+
# pci-0000:01:00.0-scsi-0:0:109:0
695+
m = re.search(r"-scsi-0:0:(\d+):0$", base)
696+
if not m:
697+
continue
698+
targets.add(int(m.group(1)))
699+
return sorted(targets)
700+
701+
def _scsi_path_exists(bus_addr: str, target: int) -> bool:
702+
return os.path.exists(f"/dev/disk/by-path/pci-{bus_addr}-scsi-0:0:{target}:0")
703+
681704
# Cables are installed into a 24i card with port 5 unused
682705
# Order is as follows:
683706
# P0 -> X-1 to X-3 (SSDs)
@@ -688,32 +711,213 @@ def alias_f8(server,alias_template):
688711
# P5 -> UNUSED
689712
f8_order = {
690713
"SAS9305-24i": [0,1,3,2, 4,5,7,6, 8,9,11,10, 20,21,23,22, 16,17,19,18, 12,13,15,14],
691-
"9600-24i": [30,29,28,27, 34,33,32,31, 46,45,44,43, 42,41,41,39, 38,37,36,35, 50,49,48,47]
714+
"9600-24i": [30,29,28,27, 34,33,32,31, 46,45,44,43, 42,41,40,39, 38,37,36,35, 50,49,48,47]
692715
}
693716
vdev_id_str = ""
694-
for i in range(0,len(server["HBA"])):
695-
if server["HBA"][i]["Model"] in ["9361-16i","9361-24i"]:
696-
hmap = hwraid_map(server["HBA"][i],server)
697-
count = alias_template[server["Alias Style"]][server["Chassis Size"]][i]
717+
718+
# ── NVME-F8X3 special case ──────────────────────────────────────────────
719+
# NVME-F8X3 has 1x 9600-16i + 3x 9600-24i. Physical cabling splits
720+
# multiple HBAs across each row (multi-HBA-per-row):
721+
#
722+
# Row 1: 16i (bays 1-12) + 24i_A (bays 13-20)
723+
# Row 2: 24i_B (bays 1-12) + 24i_A (bays 13-16) + 24i_C (bays 17-20)
724+
# Row 3: 24i_B (bays 1-12) + 24i_C (bays 13-20)
725+
#
726+
# Target ordering (derived from dalias):
727+
# Bays 1-12 (16i / 24i_B): simple descending (reverse sorted targets)
728+
# Bays 13-20 (24i_A / 24i_C): reverse port-group order, ascending within
729+
# groups of 4
730+
#
731+
# HBA role identification:
732+
# 16i – only 9600-16i on the board (12 bays)
733+
# 24i_B (full) – the 9600-24i with the most targets (24 bays)
734+
# 24i_A / 24i_C – the two 12-target 9600-24is;
735+
# higher bus address → 24i_A (row 1-2 overlap)
736+
# lower bus address → 24i_C (row 2-3 overlap)
737+
# ────────────────────────────────────────────────────────────────────────
738+
if server.get("Chassis Size") == "NVME-F8X3":
739+
hba_16i = None
740+
hba_24i_list = []
741+
for h in list(server.get("HBA", [])):
742+
if h.get("Model") == "9600-16i" and hba_16i is None:
743+
hba_16i = h
744+
elif h.get("Model") == "9600-24i":
745+
hba_24i_list.append(h)
746+
747+
if hba_16i is not None and len(hba_24i_list) == 3:
748+
# ── discover targets for every controller ──
749+
t_16i = _discover_scsi_targets(hba_16i["Bus Address"])
750+
t_24i = {}
751+
for h in hba_24i_list:
752+
t_24i[h["Bus Address"]] = _discover_scsi_targets(h["Bus Address"])
753+
754+
# ── identify roles ──
755+
# 24i_B = the one with the most discovered targets (uses all 6 ports → 24 bays)
756+
hba_24i_list_sorted = sorted(
757+
hba_24i_list,
758+
key=lambda h: (-len(t_24i[h["Bus Address"]]), h.get("Bus Address", ""))
759+
)
760+
hba_24i_B = hba_24i_list_sorted[0]
761+
# Remaining two: higher bus address → 24i_A, lower → 24i_C
762+
remaining = sorted(
763+
hba_24i_list_sorted[1:],
764+
key=lambda h: h.get("Bus Address", "")
765+
)
766+
hba_24i_C = remaining[0] # lower bus addr
767+
hba_24i_A = remaining[1] # higher bus addr
768+
769+
log("NVME-F8X3 HBA roles:")
770+
log(" 16i = {b} ({n} targets)".format(b=hba_16i["Bus Address"], n=len(t_16i)))
771+
log(" 24i_A = {b} ({n} targets)".format(b=hba_24i_A["Bus Address"], n=len(t_24i[hba_24i_A["Bus Address"]])))
772+
log(" 24i_B = {b} ({n} targets)".format(b=hba_24i_B["Bus Address"], n=len(t_24i[hba_24i_B["Bus Address"]])))
773+
log(" 24i_C = {b} ({n} targets)".format(b=hba_24i_C["Bus Address"], n=len(t_24i[hba_24i_C["Bus Address"]])))
774+
775+
# ── ordering helpers ──
776+
def _order_desc(targets, expected):
777+
"""Bays 1-12 pattern: simple descending (highest target = bay 1)."""
778+
if len(targets) >= expected:
779+
return sorted(targets, reverse=True)[:expected]
780+
elif targets:
781+
base = min(targets)
782+
return sorted(range(base, base + expected), reverse=True)
783+
return [100000 + j for j in range(expected)]
784+
785+
def _order_reverse_group_asc(targets, expected):
786+
"""Bays 13-20 pattern: reverse port-group order, ascending within groups of 4."""
787+
if len(targets) >= expected:
788+
st = sorted(targets)[:expected]
789+
elif targets:
790+
base = min(targets)
791+
st = list(range(base, base + expected))
792+
else:
793+
return [100000 + j for j in range(expected)]
794+
groups = [st[k:k+4] for k in range(0, len(st), 4)]
795+
groups.reverse()
796+
return [t for g in groups for t in g]
797+
798+
# ── compute ordered target lists per HBA ──
799+
ord_16i = _order_desc(t_16i, 12)
800+
ord_24i_A = _order_reverse_group_asc(t_24i[hba_24i_A["Bus Address"]], 12)
801+
ord_24i_B = _order_desc(t_24i[hba_24i_B["Bus Address"]], 24)
802+
ord_24i_C = _order_reverse_group_asc(t_24i[hba_24i_C["Bus Address"]], 12)
803+
804+
# ── build the 60-bay alias map (3 rows × 20 bays) ──
805+
bus_16i = hba_16i["Bus Address"]
806+
bus_24i_A = hba_24i_A["Bus Address"]
807+
bus_24i_B = hba_24i_B["Bus Address"]
808+
bus_24i_C = hba_24i_C["Bus Address"]
809+
810+
def _alias(row, bay, bus, target):
811+
return "alias {r}-{b} /dev/disk/by-path/pci-{addr}-scsi-0:0:{t}:0\n".format(
812+
r=row, b=bay, addr=bus, t=target)
813+
814+
# Row 1: 16i (bays 1-12) + 24i_A (bays 13-20)
815+
for j in range(12):
816+
vdev_id_str += _alias(1, j + 1, bus_16i, ord_16i[j])
817+
for j in range(8):
818+
vdev_id_str += _alias(1, j + 13, bus_24i_A, ord_24i_A[j])
819+
820+
# Row 2: 24i_B (bays 1-12) + 24i_A (bays 13-16) + 24i_C (bays 17-20)
821+
for j in range(12):
822+
vdev_id_str += _alias(2, j + 1, bus_24i_B, ord_24i_B[j])
823+
for j in range(4):
824+
vdev_id_str += _alias(2, j + 13, bus_24i_A, ord_24i_A[j + 8])
825+
for j in range(4):
826+
vdev_id_str += _alias(2, j + 17, bus_24i_C, ord_24i_C[j])
827+
828+
# Row 3: 24i_B (bays 1-12) + 24i_C (bays 13-20)
829+
for j in range(12):
830+
vdev_id_str += _alias(3, j + 1, bus_24i_B, ord_24i_B[j + 12])
831+
for j in range(8):
832+
vdev_id_str += _alias(3, j + 13, bus_24i_C, ord_24i_C[j + 4])
833+
834+
log("\n")
835+
return vdev_id_str
836+
else:
837+
log("WARNING: NVME-F8X3 expected 1x 9600-16i + 3x 9600-24i but found: {m}".format(
838+
m=", ".join(h.get("Model","?") + " @ " + h.get("Bus Address","?") for h in server.get("HBA",[]))
839+
))
840+
log(" Falling back to generic F8 mapping")
841+
842+
hbas = list(server.get("HBA", []))
843+
844+
for i in range(0,len(hbas)):
845+
counts = alias_template[server["Alias Style"]][server["Chassis Size"]]
846+
if i >= len(counts):
847+
log(
848+
"WARNING - More HBAs detected than template supports for {cs}. Ignoring extra controller: {model} @ {bus}".format(
849+
cs=server["Chassis Size"],
850+
model=hbas[i].get("Model","?"),
851+
bus=hbas[i].get("Bus Address","?")
852+
)
853+
)
854+
continue
855+
hba = hbas[i]
856+
if hba["Model"] in ["9361-16i","9361-24i"]:
857+
hmap = hwraid_map(hba,server)
858+
bus_addr = hba["Bus Address"]
859+
discovered_targets = None
860+
if hba["Model"] in ["9600-24i","9600-16i"]:
861+
# On some platforms/drivers the visible SCSI target IDs are not stable (e.g. 109-128).
862+
# Prefer discovering the actual by-path targets per controller bus address.
863+
discovered_targets = _discover_scsi_targets(bus_addr)
864+
count = counts[i]
698865
for j in range(0,count):
699-
if server["HBA"][i]["Model"]=="SAS9305-24i":
866+
if hba["Model"]=="SAS9305-24i":
700867
# The default case for ailiasing hba cards.
701868
vdev_id_str += (
702869
"alias {i}-{j} /dev/disk/by-path/pci-{addr}-sas-phy{p}-lun-0\n".format(
703-
i=i+1,j=j+1,addr=server["HBA"][i]["Bus Address"],p=f8_order[server["HBA"][i]["Model"]][j]
870+
i=i+1,j=j+1,addr=hba["Bus Address"],p=f8_order[hba["Model"]][j]
704871
)
705872
)
706-
elif server["HBA"][i]["Model"] in ["9600-24i"]:
707-
# alias 9600 style cards, and attempt hardware raid cards with warning.
873+
elif hba["Model"] in ["9600-24i"]:
874+
# Prefer the traditional F8 cabling map if those targets exist; otherwise fall back
875+
# to discovered SCSI targets (platform-dependent target numbering).
876+
mapped_target = f8_order[hba["Model"]][j]
877+
if not _scsi_path_exists(bus_addr, mapped_target):
878+
if discovered_targets:
879+
if j < len(discovered_targets):
880+
mapped_target = discovered_targets[j]
881+
else:
882+
# Pad beyond currently-visible targets (empty bays). Keeps row width stable for lsdev.
883+
mapped_target = discovered_targets[-1] + (j - (len(discovered_targets) - 1))
884+
vdev_id_str += (
885+
"alias {i}-{j} /dev/disk/by-path/pci-{addr}-scsi-0:0:{p}:0\n".format(
886+
i=i+1,j=j+1,addr=bus_addr,p=mapped_target
887+
)
888+
)
889+
elif hba["Model"] in ["9600-16i"]:
890+
# Prefer discovered targets when available to avoid duplicates and platform-specific numbering.
891+
if discovered_targets:
892+
ordered_targets = discovered_targets
893+
if j < len(ordered_targets):
894+
mapped_target = ordered_targets[j]
895+
else:
896+
# Beyond discovered targets = empty bay. Use impossible target ID to avoid duplicates.
897+
mapped_target = 100000 + j
898+
else:
899+
po = phy_order.get(hba["Model"], [])
900+
if j < len(po):
901+
mapped_target = po[j]
902+
else:
903+
log(
904+
"WARNING - No mapping for {model} {bus} slot {slot}; leaving bay empty".format(
905+
model=hba.get("Model","?"),
906+
bus=bus_addr,
907+
slot=j+1
908+
)
909+
)
910+
# Use an impossible target id so the by-path won't exist.
911+
mapped_target = 100000 + j
708912
vdev_id_str += (
709913
"alias {i}-{j} /dev/disk/by-path/pci-{addr}-scsi-0:0:{p}:0\n".format(
710-
i=i+1,j=j+1,addr=server["HBA"][i]["Bus Address"],p=f8_order[server["HBA"][i]["Model"]][j]
914+
i=i+1,j=j+1,addr=bus_addr,p=mapped_target
711915
)
712916
)
713-
elif server["HBA"][i]["Model"] in ["9361-24i"]:
917+
elif hba["Model"] in ["9361-24i"]:
714918
vdev_id_str += (
715919
"alias {i}-{j} /dev/disk/by-path/pci-{addr}-scsi-0:0:{p}:0\n".format(
716-
i=i+1,j=j+1,addr=server["HBA"][i]["Bus Address"],p=hmap[j]
920+
i=i+1,j=j+1,addr=hba["Bus Address"],p=hmap[j]
717921
)
718922
)
719923
if hmap[j] == 99:

tools/lsdev

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,10 @@ def build_server(options):
369369
"F8":{
370370
"F8X1":[20],
371371
"F8X2":[20,20],
372-
"F8X3":[20,20,20]
372+
"F8X3":[20,20,20],
373+
# "NVME-F8X1":[20],
374+
# "NVME-F8X2":[20,20],
375+
"NVME-F8X3":[20,20,20]
373376
},
374377
"SSG-6048R-E1CR24H":{
375378
"SSG-6048R-E1CR24H":[4,4,4,4,4,4]

tools/server_identifier

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ g_product_lut_idx = {
2323
"ALIAS_STYLE": 4
2424
}
2525

26-
g_chassis_sizes = ["?","AV15","Q30","S45","XL60","F8X1","F8X2","F8X3","2U","2UGW","1UGW","F2","HL15","VM8","VM16","VM32","HL4","HL8","PRO4","PRO8","PRO15","STUDIO8","STUDIO15","HL15_BEAST","F16","VM2","2UGW_REV2","X15"]
26+
# g_chassis_sizes = ["?","AV15","Q30","S45","XL60","F8X1","F8X2","F8X3","NVME-F8X1","NVME-F8X2","NVME-F8X3","2U","2UGW","1UGW","F2","HL15","VM8","VM16","VM32","HL4","HL8","PRO4","PRO8","PRO15","STUDIO8","STUDIO15","HL15_BEAST","F16","VM2"]
27+
g_chassis_sizes = ["?","AV15","Q30","S45","XL60","F8X1","F8X2","F8X3","NVME-F8X3","2U","2UGW","1UGW","F2","HL15","VM8","VM16","VM32","HL4","HL8","PRO4","PRO8","PRO15","STUDIO8","STUDIO15","HL15_BEAST","F16","VM2","2UGW_REV2","X15"]
2728

2829
g_mobo_to_version_lut = {
2930
"Base": ["X11SPH-nCTF","X11SSH-CTF","X11SSM-F","ME03-CE0-000","MS03-6L0-000","MS73-HB0-000","MZ73-LM0-000","MC13-LE1-000","B550I AORUS PRO","EC266D2I-2T/AQC","ROMED8-2T/BCM","ROMED8-2T", "ProArt X870E-CREATOR WIFI","MH53-G40-000", "MW34-SP0-000"],
@@ -116,6 +117,27 @@ g_product_lut = {
116117
"Storinator-F8X3-Enhanced-AMD": [g_mobo_to_version_lut["Enhanced-AMD"] ,3,0,"F8X1","F8"],
117118
"Storinator-F8X3-Turbo": [g_mobo_to_version_lut["Turbo"] ,3,0,"F8X1","F8"],
118119
"Storinator-F8X3-Turbo-G": [g_mobo_to_version_lut["Turbo-G"] ,3,0,"F8X1","F8"],
120+
121+
# "Storinator-NVME-F8X1-Base-B": [g_mobo_to_version_lut["Base-B"] ,1,1,"NVME-F8X1","F8"],
122+
# "Storinator-NVME-F8X1-Enhanced": [g_mobo_to_version_lut["Enhanced"] ,1,1,"NVME-F8X1","F8"],
123+
# "Storinator-NVME-F8X1-Enhanced-S": [g_mobo_to_version_lut["Enhanced-S"] ,1,1,"NVME-F8X1","F8"],
124+
# "Storinator-NVME-F8X1-Enhanced-AMD": [g_mobo_to_version_lut["Enhanced-AMD"] ,1,1,"NVME-F8X1","F8"],
125+
# "Storinator-NVME-F8X1-Turbo": [g_mobo_to_version_lut["Turbo"] ,1,1,"NVME-F8X1","F8"],
126+
# "Storinator-NVME-F8X1-Turbo-G": [g_mobo_to_version_lut["Turbo-G"] ,1,1,"NVME-F8X1","F8"],
127+
128+
# "Storinator-NVME-F8X2-Base-B": [g_mobo_to_version_lut["Base-B"] ,2,1,"NVME-F8X2","F8"],
129+
# "Storinator-NVME-F8X2-Enhanced": [g_mobo_to_version_lut["Enhanced"] ,2,1,"NVME-F8X2","F8"],
130+
# "Storinator-NVME-F8X2-Enhanced-S": [g_mobo_to_version_lut["Enhanced-S"] ,2,1,"NVME-F8X2","F8"],
131+
# "Storinator-NVME-F8X2-Enhanced-AMD": [g_mobo_to_version_lut["Enhanced-AMD"] ,2,1,"NVME-F8X2","F8"],
132+
# "Storinator-NVME-F8X2-Turbo": [g_mobo_to_version_lut["Turbo"] ,2,1,"NVME-F8X2","F8"],
133+
# "Storinator-NVME-F8X2-Turbo-G": [g_mobo_to_version_lut["Turbo-G"] ,2,1,"NVME-F8X2","F8"],
134+
135+
"Storinator-NVME-F8X3-Base-B": [g_mobo_to_version_lut["Base-B"] ,3,1,"NVME-F8X3","F8"],
136+
"Storinator-NVME-F8X3-Enhanced": [g_mobo_to_version_lut["Enhanced"] ,3,1,"NVME-F8X3","F8"],
137+
"Storinator-NVME-F8X3-Enhanced-S": [g_mobo_to_version_lut["Enhanced-S"] ,3,1,"NVME-F8X3","F8"],
138+
"Storinator-NVME-F8X3-Enhanced-AMD": [g_mobo_to_version_lut["Enhanced-AMD"] ,3,1,"NVME-F8X3","F8"],
139+
"Storinator-NVME-F8X3-Turbo": [g_mobo_to_version_lut["Turbo"] ,3,1,"NVME-F8X3","F8"],
140+
"Storinator-NVME-F8X3-Turbo-G": [g_mobo_to_version_lut["Turbo-G"] ,3,1,"NVME-F8X3","F8"],
119141

120142
"Storinator-H8-AV15-Base-B": [g_mobo_to_version_lut["Base-B"] ,0,1,"AV15","STORINATOR"],
121143
"Storinator-H8-AV15-Enhanced": [g_mobo_to_version_lut["Enhanced"] ,0,1,"AV15","STORINATOR"],

0 commit comments

Comments
 (0)