@@ -504,8 +504,8 @@ def create_vdev_id(server):
504504 "F8X1" :[20 ],
505505 "F8X2" :[20 ,20 ],
506506 "F8X3" :[20 ,20 ,20 ],
507- # "NVME-F8X1":[20],
508- # "NVME-F8X2":[20,20],
507+ "NVME-F8X1" :[20 ],
508+ "NVME-F8X2" :[20 ,20 ],
509509 "NVME-F8X3" :[20 ,20 ,20 ]
510510 },
511511 "STUDIO" :{
@@ -715,6 +715,151 @@ def alias_f8(server,alias_template,phy_order):
715715 }
716716 vdev_id_str = ""
717717
718+ # ── ordering helpers (shared by all NVME-F8X* special cases) ──
719+ def _order_desc (targets , expected ):
720+ """Bays 1-12 pattern: simple descending (highest target = bay 1)."""
721+ if len (targets ) >= expected :
722+ return sorted (targets , reverse = True )[:expected ]
723+ elif targets :
724+ base = min (targets )
725+ return sorted (range (base , base + expected ), reverse = True )
726+ return [100000 + j for j in range (expected )]
727+
728+ def _order_reverse_group_asc (targets , expected ):
729+ """Bays 13-20 pattern: reverse port-group order, ascending within groups of 4."""
730+ if len (targets ) >= expected :
731+ st = sorted (targets )[:expected ]
732+ elif targets :
733+ base = min (targets )
734+ st = list (range (base , base + expected ))
735+ else :
736+ return [100000 + j for j in range (expected )]
737+ groups = [st [k :k + 4 ] for k in range (0 , len (st ), 4 )]
738+ groups .reverse ()
739+ return [t for g in groups for t in g ]
740+
741+ def _alias (row , bay , bus , target ):
742+ return "alias {r}-{b} /dev/disk/by-path/pci-{addr}-scsi-0:0:{t}:0\n " .format (
743+ r = row , b = bay , addr = bus , t = target )
744+
745+ # ── NVME-F8X1 special case ──────────────────────────────────────────────
746+ # NVME-F8X1 has 2x 9600-16i: one for NVMe, one for HDD (SAS).
747+ # Single row of 20 bays:
748+ #
749+ # Row 1: HDD-16i (bays 1-12) + NVMe-16i (bays 13-20)
750+ #
751+ # HBA role identification:
752+ # The 16i with more discovered scsi targets → HDD (12 bays)
753+ # The 16i with fewer discovered scsi targets → NVMe (8 bays)
754+ # ────────────────────────────────────────────────────────────────────────
755+ if server .get ("Chassis Size" ) == "NVME-F8X1" :
756+ hba_16i_list = [h for h in server .get ("HBA" , []) if h .get ("Model" ) == "9600-16i" ]
757+
758+ if len (hba_16i_list ) == 2 :
759+ t_16i = {}
760+ for h in hba_16i_list :
761+ t_16i [h ["Bus Address" ]] = _discover_scsi_targets (h ["Bus Address" ])
762+
763+ # More targets → HDD (12 bays), fewer → NVMe (8 bays)
764+ sorted_16i = sorted (
765+ hba_16i_list ,
766+ key = lambda h : (- len (t_16i [h ["Bus Address" ]]), h .get ("Bus Address" , "" ))
767+ )
768+ hba_hdd = sorted_16i [0 ] # more targets = HDD
769+ hba_nvme = sorted_16i [1 ] # fewer targets = NVMe
770+
771+ log ("NVME-F8X1 HBA roles:" )
772+ log (" HDD (16i) = {b} ({n} targets)" .format (b = hba_hdd ["Bus Address" ], n = len (t_16i [hba_hdd ["Bus Address" ]])))
773+ log (" NVMe (16i) = {b} ({n} targets)" .format (b = hba_nvme ["Bus Address" ], n = len (t_16i [hba_nvme ["Bus Address" ]])))
774+
775+ ord_hdd = _order_desc (t_16i [hba_hdd ["Bus Address" ]], 12 )
776+ ord_nvme = _order_reverse_group_asc (t_16i [hba_nvme ["Bus Address" ]], 8 )
777+
778+ bus_hdd = hba_hdd ["Bus Address" ]
779+ bus_nvme = hba_nvme ["Bus Address" ]
780+
781+ # Row 1: HDD-16i (bays 1-12) + NVMe-16i (bays 13-20)
782+ for j in range (12 ):
783+ vdev_id_str += _alias (1 , j + 1 , bus_hdd , ord_hdd [j ])
784+ for j in range (8 ):
785+ vdev_id_str += _alias (1 , j + 13 , bus_nvme , ord_nvme [j ])
786+
787+ log ("\n " )
788+ return vdev_id_str
789+ else :
790+ log ("WARNING: NVME-F8X1 expected 2x 9600-16i but found: {m}" .format (
791+ m = ", " .join (h .get ("Model" ,"?" ) + " @ " + h .get ("Bus Address" ,"?" ) for h in server .get ("HBA" ,[]))
792+ ))
793+ log (" Falling back to generic F8 mapping" )
794+
795+ # ── NVME-F8X2 special case ──────────────────────────────────────────────
796+ # NVME-F8X2 has 2x 9600-16i (NVMe) + 1x 9600-24i (HDD/SAS).
797+ # Two rows of 20 bays:
798+ #
799+ # Row 1: 24i (bays 1-12 HDD) + NVMe-16i #1 (bays 13-20)
800+ # Row 2: 24i (bays 1-12 HDD) + NVMe-16i #2 (bays 13-20)
801+ #
802+ # HBA role identification:
803+ # 9600-24i → HDD (all 24 HDD bays across both rows)
804+ # 9600-16i's → NVMe (8 each); higher bus address → row 1, lower → row 2
805+ # ────────────────────────────────────────────────────────────────────────
806+ elif server .get ("Chassis Size" ) == "NVME-F8X2" :
807+ hba_24i = None
808+ hba_16i_list = []
809+ for h in list (server .get ("HBA" , [])):
810+ if h .get ("Model" ) == "9600-24i" and hba_24i is None :
811+ hba_24i = h
812+ elif h .get ("Model" ) == "9600-16i" :
813+ hba_16i_list .append (h )
814+
815+ if hba_24i is not None and len (hba_16i_list ) == 2 :
816+ t_24i = _discover_scsi_targets (hba_24i ["Bus Address" ])
817+ t_16i = {}
818+ for h in hba_16i_list :
819+ t_16i [h ["Bus Address" ]] = _discover_scsi_targets (h ["Bus Address" ])
820+
821+ # Sort NVMe 16i's by bus address: higher → row 1, lower → row 2
822+ sorted_nvme = sorted (
823+ hba_16i_list ,
824+ key = lambda h : h .get ("Bus Address" , "" ),
825+ reverse = True
826+ )
827+ hba_nvme_1 = sorted_nvme [0 ] # higher bus addr → row 1
828+ hba_nvme_2 = sorted_nvme [1 ] # lower bus addr → row 2
829+
830+ log ("NVME-F8X2 HBA roles:" )
831+ log (" HDD (24i) = {b} ({n} targets)" .format (b = hba_24i ["Bus Address" ], n = len (t_24i )))
832+ log (" NVMe #1 (16i) = {b} ({n} targets) [row 1]" .format (b = hba_nvme_1 ["Bus Address" ], n = len (t_16i [hba_nvme_1 ["Bus Address" ]])))
833+ log (" NVMe #2 (16i) = {b} ({n} targets) [row 2]" .format (b = hba_nvme_2 ["Bus Address" ], n = len (t_16i [hba_nvme_2 ["Bus Address" ]])))
834+
835+ ord_hdd = _order_desc (t_24i , 24 )
836+ ord_nvme_1 = _order_reverse_group_asc (t_16i [hba_nvme_1 ["Bus Address" ]], 8 )
837+ ord_nvme_2 = _order_reverse_group_asc (t_16i [hba_nvme_2 ["Bus Address" ]], 8 )
838+
839+ bus_hdd = hba_24i ["Bus Address" ]
840+ bus_nvme_1 = hba_nvme_1 ["Bus Address" ]
841+ bus_nvme_2 = hba_nvme_2 ["Bus Address" ]
842+
843+ # Row 1: 24i (bays 1-12 HDD) + NVMe-16i #1 (bays 13-20)
844+ for j in range (12 ):
845+ vdev_id_str += _alias (1 , j + 1 , bus_hdd , ord_hdd [j ])
846+ for j in range (8 ):
847+ vdev_id_str += _alias (1 , j + 13 , bus_nvme_1 , ord_nvme_1 [j ])
848+
849+ # Row 2: 24i (bays 1-12 HDD) + NVMe-16i #2 (bays 13-20)
850+ for j in range (12 ):
851+ vdev_id_str += _alias (2 , j + 1 , bus_hdd , ord_hdd [j + 12 ])
852+ for j in range (8 ):
853+ vdev_id_str += _alias (2 , j + 13 , bus_nvme_2 , ord_nvme_2 [j ])
854+
855+ log ("\n " )
856+ return vdev_id_str
857+ else :
858+ log ("WARNING: NVME-F8X2 expected 2x 9600-16i + 1x 9600-24i but found: {m}" .format (
859+ m = ", " .join (h .get ("Model" ,"?" ) + " @ " + h .get ("Bus Address" ,"?" ) for h in server .get ("HBA" ,[]))
860+ ))
861+ log (" Falling back to generic F8 mapping" )
862+
718863 # ── NVME-F8X3 special case ──────────────────────────────────────────────
719864 # NVME-F8X3 has 1x 9600-16i + 3x 9600-24i. Physical cabling splits
720865 # multiple HBAs across each row (multi-HBA-per-row):
@@ -735,7 +880,7 @@ def alias_f8(server,alias_template,phy_order):
735880 # higher bus address → 24i_A (row 1-2 overlap)
736881 # lower bus address → 24i_C (row 2-3 overlap)
737882 # ────────────────────────────────────────────────────────────────────────
738- if server .get ("Chassis Size" ) == "NVME-F8X3" :
883+ elif server .get ("Chassis Size" ) == "NVME-F8X3" :
739884 hba_16i = None
740885 hba_24i_list = []
741886 for h in list (server .get ("HBA" , [])):
@@ -772,29 +917,6 @@ def alias_f8(server,alias_template,phy_order):
772917 log (" 24i_B = {b} ({n} targets)" .format (b = hba_24i_B ["Bus Address" ], n = len (t_24i [hba_24i_B ["Bus Address" ]])))
773918 log (" 24i_C = {b} ({n} targets)" .format (b = hba_24i_C ["Bus Address" ], n = len (t_24i [hba_24i_C ["Bus Address" ]])))
774919
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-
798920 # ── compute ordered target lists per HBA ──
799921 ord_16i = _order_desc (t_16i , 12 )
800922 ord_24i_A = _order_reverse_group_asc (t_24i [hba_24i_A ["Bus Address" ]], 12 )
@@ -807,10 +929,6 @@ def alias_f8(server,alias_template,phy_order):
807929 bus_24i_B = hba_24i_B ["Bus Address" ]
808930 bus_24i_C = hba_24i_C ["Bus Address" ]
809931
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-
814932 # Row 1: 16i (bays 1-12) + 24i_A (bays 13-20)
815933 for j in range (12 ):
816934 vdev_id_str += _alias (1 , j + 1 , bus_16i , ord_16i [j ])
0 commit comments