diff --git a/Makefile b/Makefile index afbd712..7f27aa4 100644 --- a/Makefile +++ b/Makefile @@ -76,23 +76,28 @@ OBJS = mdadm.o config.o mdstat.o ReadMe.o util.o Manage.o Assemble.o Build.o \ Create.o Detail.o Examine.o Grow.o Monitor.o dlink.o Kill.o Query.o \ Incremental.o \ mdopen.o super0.o super1.o super-ddf.o super-intel.o bitmap.o \ - restripe.o sysfs.o sha1.o mapfile.o crc32.o sg_io.o msg.o + restripe.o sysfs.o sha1.o mapfile.o crc32.o sg_io.o msg.o \ + platform-intel.o probe_roms.o + SRCS = mdadm.c config.c mdstat.c ReadMe.c util.c Manage.c Assemble.c Build.c \ Create.c Detail.c Examine.c Grow.c Monitor.c dlink.c Kill.c Query.c \ Incremental.c \ mdopen.c super0.c super1.c super-ddf.c super-intel.c bitmap.c \ - restripe.c sysfs.c sha1.c mapfile.c crc32.c sg_io.c msg.c + restripe.c sysfs.c sha1.c mapfile.c crc32.c sg_io.c msg.c \ + platform-intel.c probe_roms.c MON_OBJS = mdmon.o monitor.o managemon.o util.o mdstat.o sysfs.o config.o \ Kill.o sg_io.o dlink.o ReadMe.o super0.o super1.o super-intel.o \ - super-ddf.o sha1.o crc32.o msg.o Monitor.o bitmap.o + super-ddf.o sha1.o crc32.o msg.o Monitor.o bitmap.o \ + platform-intel.o probe_roms.o STATICSRC = pwgr.c STATICOBJS = pwgr.o ASSEMBLE_SRCS := mdassemble.c Assemble.c Manage.c config.c dlink.c util.c \ - super0.c super1.c super-ddf.c super-intel.c sha1.c crc32.c sg_io.c mdstat.c + super0.c super1.c super-ddf.c super-intel.c sha1.c crc32.c sg_io.c mdstat.c \ + platform-intel.c probe_roms.c ASSEMBLE_AUTO_SRCS := mdopen.c sysfs.c ASSEMBLE_FLAGS:= $(CFLAGS) -DMDASSEMBLE ifdef MDASSEMBLE_AUTO diff --git a/platform-intel.h b/platform-intel.h index c126482..bbdc9f9 100644 --- a/platform-intel.h +++ b/platform-intel.h @@ -17,6 +17,7 @@ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ #include +#include /* The IMSM OROM Version Table definition */ struct imsm_orom { @@ -78,6 +79,42 @@ struct imsm_orom { __u32 reserved2; } __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) +{ + return !!(orom->rlc & IMSM_OROM_RLC_RAID5); +} + +/** + * imsm_orom_has_chunk - check if the orom supports the given chunk size + * @orom: orom pointer from find_imsm_orom + * @chunk: chunk size in kibibytes + */ +static inline int imsm_orom_has_chunk(const struct imsm_orom *orom, int chunk) +{ + int fs = ffs(chunk); + + if (!fs) + return 0; + fs--; /* bit num to bit index */ + return !!(orom->sss & (1 << (fs - 1))); +} + struct sys_dev { char *path; struct sys_dev *next; diff --git a/super-intel.c b/super-intel.c index 7066e8e..abc3206 100644 --- a/super-intel.c +++ b/super-intel.c @@ -21,6 +21,7 @@ #include "mdadm.h" #include "mdmon.h" #include "sha1.h" +#include "platform-intel.h" #include #include #include @@ -230,6 +231,8 @@ struct intel_super { struct dl *add; /* list of disks to add while mdmon active */ struct dl *missing; /* disks removed while we weren't looking */ struct bbm_log *bbm_log; + const char *hba; /* device path of the raid controller for this metadata */ + const struct imsm_orom *orom; /* platform firmware support */ }; struct extent { @@ -1505,6 +1508,10 @@ static void __free_imsm(struct intel_super *super, int free_disks) free(super->dev_tbl[i]); super->dev_tbl[i] = NULL; } + if (super->hba) { + free((void *) super->hba); + super->hba = NULL; + } } static void free_imsm(struct intel_super *super) @@ -1533,6 +1540,22 @@ static struct intel_super *alloc_super(int creating_imsm) super->creating_imsm = creating_imsm; super->current_vol = -1; super->create_offset = ~((__u32 ) 0); + if (!check_env("IMSM_NO_PLATFORM")) + super->orom = find_imsm_orom(); + if (super->orom) { + struct sys_dev *list, *ent; + + /* find the first intel ahci controller */ + list = find_driver_devices("pci", "ahci"); + for (ent = list; ent; ent = ent->next) + if (devpath_to_vendor(ent->path) == 0x8086) + break; + if (ent) { + super->hba = ent->path; + ent->path = NULL; + } + free_sys_dev(&list); + } } return super; @@ -1817,9 +1840,9 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info, unsigned long long array_blocks; size_t size_old, size_new; - if (mpb->num_raid_devs >= 2) { + if (super->orom && mpb->num_raid_devs >= super->orom->vpa) { fprintf(stderr, Name": This imsm-container already has the " - "maximum of 2 volumes\n"); + "maximum of %d volumes\n", super->orom->vpa); return 0; } @@ -2014,6 +2037,16 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk, int rv; struct stat stb; + /* if we are on an RAID enabled platform check that the disk is + * attached to the raid controller + */ + if (super->hba && !disk_attached_to_hba(fd, super->hba)) { + fprintf(stderr, + Name ": %s is not attached to the raid controller: %s\n", + devname ? : "disk", super->hba); + return 1; + } + if (super->current_vol >= 0) return add_to_super_imsm_volume(st, dk, fd, devname); @@ -2282,12 +2315,25 @@ static int validate_geometry_imsm_container(struct supertype *st, int level, { int fd; unsigned long long ldsize; + const struct imsm_orom *orom; if (level != LEVEL_CONTAINER) return 0; if (!dev) return 1; + if (check_env("IMSM_NO_PLATFORM")) + orom = NULL; + else + orom = find_imsm_orom(); + if (orom && raiddisks > orom->tds) { + if (verbose) + fprintf(stderr, Name ": %d exceeds maximum number of" + " platform supported disks: %d\n", + raiddisks, orom->tds); + return 0; + } + fd = open(dev, O_RDONLY|O_EXCL, 0); if (fd < 0) { if (verbose) @@ -2408,6 +2454,30 @@ static unsigned long long merge_extents(struct intel_super *super, int sum_exten return maxsize - reserve; } +static int is_raid_level_supported(const struct imsm_orom *orom, int level, int raiddisks) +{ + if (level < 0 || level == 6 || level == 4) + return 0; + + /* 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); + else + return imsm_orom_has_raid1(orom); + case 10: return imsm_orom_has_raid10(orom); + case 5: return imsm_orom_has_raid5(orom); + } + else + return 1; /* not on an Intel RAID platform so anything goes */ + + return 0; +} + +#define vprintf(fmt, arg...) (void) (verbose && fprintf(stderr, Name fmt, ##arg)) /* validate_geometry_imsm_volume - lifted from validate_geometry_ddf_bvd * FIX ME add ahci details */ @@ -2425,20 +2495,29 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level, struct extent *e; int i; - if (level == LEVEL_CONTAINER) - return 0; - - if (level == 1 && raiddisks > 2) { - if (verbose) - fprintf(stderr, Name ": imsm does not support more " - "than 2 in a raid1 configuration\n"); - return 0; - } - /* We must have the container info already read in. */ if (!super) return 0; + if (!is_raid_level_supported(super->orom, level, raiddisks)) { + vprintf(": platform does not support raid level: %d\n", level); + return 0; + } + if (super->orom && !imsm_orom_has_chunk(super->orom, chunk)) { + vprintf(": platform does not support a chunk size of: %d\n", chunk); + return 0; + } + if (layout != imsm_level_to_layout(level)) { + if (level == 5) + vprintf(": imsm raid 5 only supports the left-asymmetric layout\n"); + else if (level == 10) + vprintf(": imsm raid 10 only supports the n2 layout\n"); + else + vprintf(": imsm unknown layout %#x for this raid level %d\n", + layout, level); + return 0; + } + if (!dev) { /* General test: make sure there is space for * 'raiddisks' device extents of size 'size' at a given