From 191e6ddb1388236c5c54baf5020a87c996be941f Mon Sep 17 00:00:00 2001 From: Mateusz Kusiak Date: Mon, 29 Apr 2024 15:07:16 +0200 Subject: [PATCH 55/66] imsm: refactor RAID level handling Add imsm_level_ops struct for better handling and unifying raid level support. Add helper methods and move "orom_has_raid[...]" methods from header to source file. RAID 1e is not supported under Linux, remove RAID 1e associated code. Refactor imsm_analyze_change() and is_raid_level_supported(). Remove hardcoded check for 4 drives and make devNumChange a multiplier for RAID 10. Refactor printing supported raid levels. Signed-off-by: Mateusz Kusiak Signed-off-by: Mariusz Tkaczyk --- platform-intel.c | 57 ++++++++++++++++++++++++ platform-intel.h | 32 ++++++-------- super-intel.c | 111 ++++++++++++++++++++++++++++------------------- 3 files changed, 138 insertions(+), 62 deletions(-) diff --git a/platform-intel.c b/platform-intel.c index ac282bc5..40e8fb82 100644 --- a/platform-intel.c +++ b/platform-intel.c @@ -32,6 +32,63 @@ #define NVME_SUBSYS_PATH "/sys/devices/virtual/nvme-subsystem/" +static bool imsm_orom_has_raid0(const struct imsm_orom *orom) +{ + return imsm_rlc_has_bit(orom, IMSM_OROM_RLC_RAID0); +} + +static bool imsm_orom_has_raid1(const struct imsm_orom *orom) +{ + return imsm_rlc_has_bit(orom, IMSM_OROM_RLC_RAID1); +} + +static bool imsm_orom_has_raid10(const struct imsm_orom *orom) +{ + return imsm_rlc_has_bit(orom, IMSM_OROM_RLC_RAID10); +} + +static bool imsm_orom_has_raid5(const struct imsm_orom *orom) +{ + return imsm_rlc_has_bit(orom, IMSM_OROM_RLC_RAID5); +} + +/* IMSM platforms do not define how many disks are allowed for each level, + * but there are some global limitations we need to follow. + */ +static bool imsm_orom_support_raid_disks_count_raid0(const int raid_disks) +{ + return true; +} + +static bool imsm_orom_support_raid_disks_count_raid1(const int raid_disks) +{ + if (raid_disks == 2) + return true; + return false; +} + +static bool imsm_orom_support_raid_disks_count_raid5(const int raid_disks) +{ + if (raid_disks > 2) + return true; + return false; +} + +static bool imsm_orom_support_raid_disks_count_raid10(const int raid_disks) +{ + if (raid_disks == 4) + return true; + return false; +} + +struct imsm_level_ops imsm_level_ops[] = { + {0, imsm_orom_has_raid0, imsm_orom_support_raid_disks_count_raid0, "raid0"}, + {1, imsm_orom_has_raid1, imsm_orom_support_raid_disks_count_raid1, "raid1"}, + {5, imsm_orom_has_raid5, imsm_orom_support_raid_disks_count_raid5, "raid5"}, + {10, imsm_orom_has_raid10, imsm_orom_support_raid_disks_count_raid10, "raid10"}, + {-1, NULL, NULL, NULL} +}; + static int devpath_to_ll(const char *dev_path, const char *entry, unsigned long long *val); diff --git a/platform-intel.h b/platform-intel.h index 3c2bc595..dcc5aaa7 100644 --- a/platform-intel.h +++ b/platform-intel.h @@ -109,25 +109,21 @@ struct imsm_orom { #define IMSM_OROM_CAPABILITIES_TPV (1 << 10) } __attribute__((packed)); -static inline int imsm_orom_has_raid0(const struct imsm_orom *orom) -{ - return !!(orom->rlc & IMSM_OROM_RLC_RAID0); -} -static inline int imsm_orom_has_raid1(const struct imsm_orom *orom) -{ - return !!(orom->rlc & IMSM_OROM_RLC_RAID1); -} -static inline int imsm_orom_has_raid1e(const struct imsm_orom *orom) -{ - return !!(orom->rlc & IMSM_OROM_RLC_RAID1E); -} -static inline int imsm_orom_has_raid10(const struct imsm_orom *orom) -{ - return !!(orom->rlc & IMSM_OROM_RLC_RAID10); -} -static inline int imsm_orom_has_raid5(const struct imsm_orom *orom) +/* IMSM metadata requirements for each level */ +struct imsm_level_ops { + int level; + bool (*is_level_supported)(const struct imsm_orom *); + bool (*is_raiddisks_count_supported)(const int); + char *name; +}; + +extern struct imsm_level_ops imsm_level_ops[]; + +static inline bool imsm_rlc_has_bit(const struct imsm_orom *orom, const unsigned short bit) { - return !!(orom->rlc & IMSM_OROM_RLC_RAID5); + if (orom->rlc & bit) + return true; + return false; } /** diff --git a/super-intel.c b/super-intel.c index a7efc8df..da17265d 100644 --- a/super-intel.c +++ b/super-intel.c @@ -2681,6 +2681,15 @@ static int ahci_get_port_count(const char *hba_path, int *port_count) return host_base; } +static void print_imsm_level_capability(const struct imsm_orom *orom) +{ + int idx; + + for (idx = 0; imsm_level_ops[idx].name; idx++) + if (imsm_level_ops[idx].is_level_supported(orom)) + printf("%s ", imsm_level_ops[idx].name); +} + static void print_imsm_capability(const struct imsm_orom *orom) { printf(" Platform : Intel(R) "); @@ -2699,12 +2708,11 @@ static void print_imsm_capability(const struct imsm_orom *orom) printf(" Version : %d.%d.%d.%d\n", orom->major_ver, orom->minor_ver, orom->hotfix_ver, orom->build); } - printf(" RAID Levels :%s%s%s%s%s\n", - imsm_orom_has_raid0(orom) ? " raid0" : "", - imsm_orom_has_raid1(orom) ? " raid1" : "", - imsm_orom_has_raid1e(orom) ? " raid1e" : "", - imsm_orom_has_raid10(orom) ? " raid10" : "", - imsm_orom_has_raid5(orom) ? " raid5" : ""); + + printf(" RAID Levels : "); + print_imsm_level_capability(orom); + printf("\n"); + printf(" Chunk Sizes :%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", imsm_orom_has_chunk(orom, 2) ? " 2k" : "", imsm_orom_has_chunk(orom, 4) ? " 4k" : "", @@ -2739,12 +2747,11 @@ static void print_imsm_capability_export(const struct imsm_orom *orom) if (orom->major_ver || orom->minor_ver || orom->hotfix_ver || orom->build) printf("IMSM_VERSION=%d.%d.%d.%d\n", orom->major_ver, orom->minor_ver, orom->hotfix_ver, orom->build); - printf("IMSM_SUPPORTED_RAID_LEVELS=%s%s%s%s%s\n", - imsm_orom_has_raid0(orom) ? "raid0 " : "", - imsm_orom_has_raid1(orom) ? "raid1 " : "", - imsm_orom_has_raid1e(orom) ? "raid1e " : "", - imsm_orom_has_raid5(orom) ? "raid10 " : "", - imsm_orom_has_raid10(orom) ? "raid5 " : ""); + + printf("IMSM_SUPPORTED_RAID_LEVELS="); + print_imsm_level_capability(orom); + printf("\n"); + printf("IMSM_SUPPORTED_CHUNK_SIZES=%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", imsm_orom_has_chunk(orom, 2) ? "2k " : "", imsm_orom_has_chunk(orom, 4) ? "4k " : "", @@ -6992,26 +6999,41 @@ static unsigned long long merge_extents(struct intel_super *super, const bool ex return free_size - reservation_size; } -static int is_raid_level_supported(const struct imsm_orom *orom, int level, int raiddisks) +/** + * is_raid_level_supported() - check if this count of drives and level is supported by platform. + * @orom: hardware properties, could be NULL. + * @level: requested raid level. + * @raiddisks: requested disk count. + * + * IMSM UEFI/OROM does not provide information about supported count of raid disks + * for particular level. That is why it is hardcoded. + * It is recommended to not allow of usage other levels than supported, + * IMSM code is not tested against different level implementations. + * + * Return: true if supported, false otherwise. + */ +static bool is_raid_level_supported(const struct imsm_orom *orom, int level, int raiddisks) { - if (level < 0 || level == 6 || level == 4) - return 0; + int idx; - /* if we have an orom prevent invalid raid levels */ - if (orom) - switch (level) { - case 0: return imsm_orom_has_raid0(orom); - case 1: - if (raiddisks > 2) - return imsm_orom_has_raid1e(orom); - return imsm_orom_has_raid1(orom) && raiddisks == 2; - case 10: return imsm_orom_has_raid10(orom) && raiddisks == 4; - case 5: return imsm_orom_has_raid5(orom) && raiddisks > 2; - } - else - return 1; /* not on an Intel RAID platform so anything goes */ + for (idx = 0; imsm_level_ops[idx].name; idx++) { + if (imsm_level_ops[idx].level == level) + break; + } - return 0; + if (!imsm_level_ops[idx].name) + return false; + + if (!imsm_level_ops[idx].is_raiddisks_count_supported(raiddisks)) + return false; + + if (!orom) + return true; + + if (imsm_level_ops[idx].is_level_supported(orom)) + return true; + + return false; } static int @@ -11962,18 +11984,17 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, int change = -1; int check_devs = 0; int chunk; - /* number of added/removed disks in operation result */ - int devNumChange = 0; /* imsm compatible layout value for array geometry verification */ int imsm_layout = -1; + int raid_disks = geo->raid_disks; imsm_status_t rv; getinfo_super_imsm_volume(st, &info, NULL); - if (geo->level != info.array.level && geo->level >= 0 && + if (geo->level != info.array.level && geo->level >= IMSM_T_RAID0 && geo->level != UnSet) { switch (info.array.level) { - case 0: - if (geo->level == 5) { + case IMSM_T_RAID0: + if (geo->level == IMSM_T_RAID5) { change = CH_MIGRATION; if (geo->layout != ALGORITHM_LEFT_ASYMMETRIC) { pr_err("Error. Requested Layout not supported (left-asymmetric layout is supported only)!\n"); @@ -11982,20 +12003,20 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, } imsm_layout = geo->layout; check_devs = 1; - devNumChange = 1; /* parity disk added */ - } else if (geo->level == 10) { + raid_disks += 1; /* parity disk added */ + } else if (geo->level == IMSM_T_RAID10) { change = CH_TAKEOVER; check_devs = 1; - devNumChange = 2; /* two mirrors added */ + raid_disks *= 2; /* mirrors added */ imsm_layout = 0x102; /* imsm supported layout */ } break; - case 1: - case 10: + case IMSM_T_RAID1: + case IMSM_T_RAID10: if (geo->level == 0) { change = CH_TAKEOVER; check_devs = 1; - devNumChange = -(geo->raid_disks/2); + raid_disks /= 2; imsm_layout = 0; /* imsm raid0 layout */ } break; @@ -12011,10 +12032,10 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, if (geo->layout != info.array.layout && (geo->layout != UnSet && geo->layout != -1)) { change = CH_MIGRATION; - if (info.array.layout == 0 && info.array.level == 5 && + if (info.array.layout == 0 && info.array.level == IMSM_T_RAID5 && geo->layout == 5) { /* reshape 5 -> 4 */ - } else if (info.array.layout == 5 && info.array.level == 5 && + } else if (info.array.layout == 5 && info.array.level == IMSM_T_RAID5 && geo->layout == 0) { /* reshape 4 -> 5 */ geo->layout = 0; @@ -12033,7 +12054,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, if (geo->chunksize > 0 && geo->chunksize != UnSet && geo->chunksize != info.array.chunk_size) { - if (info.array.level == 10) { + if (info.array.level == IMSM_T_RAID10) { pr_err("Error. Chunk size change for RAID 10 is not supported.\n"); change = -1; goto analyse_change_exit; @@ -12058,14 +12079,16 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st, rv = imsm_analyze_expand(st, geo, &info, direction); if (rv != IMSM_STATUS_OK) goto analyse_change_exit; + raid_disks = geo->raid_disks; change = CH_ARRAY_SIZE; } chunk = geo->chunksize / 1024; + if (!validate_geometry_imsm(st, geo->level, imsm_layout, - geo->raid_disks + devNumChange, + raid_disks, &chunk, geo->size, INVALID_SECTORS, 0, 0, info.consistency_policy, 1)) -- 2.41.0