]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
FIX: After discarding array give chance monitor to remove it
[thirdparty/mdadm.git] / super-intel.c
index e5a53a4165c19139803b13fef8741e409c151ee6..62ccd150db6e7e316e4d8d01ee5553ad7eb366cb 100644 (file)
@@ -383,7 +383,6 @@ const char *get_sys_dev_type(enum sys_dev_type type)
        return _sys_dev_type[type];
 }
 
-#ifndef MDASSEMBLE
 static struct intel_hba * alloc_intel_hba(struct sys_dev *device)
 {
        struct intel_hba *result = malloc(sizeof(*result));
@@ -407,7 +406,6 @@ static struct intel_hba * find_intel_hba(struct intel_hba *hba, struct sys_dev *
        return result;
 }
 
-
 static int attach_hba_to_super(struct intel_super *super, struct sys_dev *device)
 {
        struct intel_hba *hba;
@@ -473,9 +471,11 @@ static struct sys_dev* find_disk_attached_hba(int fd, const char *devname)
 
        return NULL;
 }
-#endif /* MDASSEMBLE */
 
 
+static int find_intel_hba_capability(int fd, struct intel_super *super,
+                                    char *devname);
+
 static struct supertype *match_metadata_desc_imsm(char *arg)
 {
        struct supertype *st;
@@ -1346,6 +1346,39 @@ static int ahci_get_port_count(const char *hba_path, int *port_count)
        return host_base;
 }
 
+static void print_imsm_capability(const struct imsm_orom *orom)
+{
+       printf("       Platform : Intel(R) Matrix Storage Manager\n");
+       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("    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" : "",
+              imsm_orom_has_chunk(orom, 8) ? " 8k" : "",
+              imsm_orom_has_chunk(orom, 16) ? " 16k" : "",
+              imsm_orom_has_chunk(orom, 32) ? " 32k" : "",
+              imsm_orom_has_chunk(orom, 64) ? " 64k" : "",
+              imsm_orom_has_chunk(orom, 128) ? " 128k" : "",
+              imsm_orom_has_chunk(orom, 256) ? " 256k" : "",
+              imsm_orom_has_chunk(orom, 512) ? " 512k" : "",
+              imsm_orom_has_chunk(orom, 1024*1) ? " 1M" : "",
+              imsm_orom_has_chunk(orom, 1024*2) ? " 2M" : "",
+              imsm_orom_has_chunk(orom, 1024*4) ? " 4M" : "",
+              imsm_orom_has_chunk(orom, 1024*8) ? " 8M" : "",
+              imsm_orom_has_chunk(orom, 1024*16) ? " 16M" : "",
+              imsm_orom_has_chunk(orom, 1024*32) ? " 32M" : "",
+              imsm_orom_has_chunk(orom, 1024*64) ? " 64M" : "");
+       printf("      Max Disks : %d\n", orom->tds);
+       printf("    Max Volumes : %d\n", orom->vpa);
+       return;
+}
+
 static int detail_platform_imsm(int verbose, int enumerate_only)
 {
        /* There are two components to imsm platform support, the ahci SATA
@@ -1366,9 +1399,20 @@ static int detail_platform_imsm(int verbose, int enumerate_only)
        int result=0;
 
        if (enumerate_only) {
-               if (check_env("IMSM_NO_PLATFORM") || find_imsm_orom())
+               if (check_env("IMSM_NO_PLATFORM"))
                        return 0;
-               return 2;
+               list = find_intel_devices();
+               if (!list)
+                       return 2;
+               for (hba = list; hba; hba = hba->next) {
+                       orom = find_imsm_capability(hba->type);
+                       if (!orom) {
+                               result = 2;
+                               break;
+                       }
+               }
+               free_sys_dev(&list);
+               return result;
        }
 
        list = find_intel_devices();
@@ -1381,43 +1425,15 @@ static int detail_platform_imsm(int verbose, int enumerate_only)
        } else if (verbose)
                print_found_intel_controllers(list);
 
-       orom = find_imsm_orom();
-       if (!orom) {
-               free_sys_dev(&list);
-               if (verbose)
-                       fprintf(stderr, Name ": imsm option-rom not found\n");
-               return 2;
+       for (hba = list; hba; hba = hba->next) {
+               orom = find_imsm_capability(hba->type);
+               if (!orom)
+                       fprintf(stderr, Name ": imsm capabilities not found for controller: %s (type %s)\n",
+                               hba->path, get_sys_dev_type(hba->type));
+               else
+                       print_imsm_capability(orom);
        }
 
-       printf("       Platform : Intel(R) Matrix Storage Manager\n");
-       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("    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" : "",
-              imsm_orom_has_chunk(orom, 8) ? " 8k" : "",
-              imsm_orom_has_chunk(orom, 16) ? " 16k" : "",
-              imsm_orom_has_chunk(orom, 32) ? " 32k" : "",
-              imsm_orom_has_chunk(orom, 64) ? " 64k" : "",
-              imsm_orom_has_chunk(orom, 128) ? " 128k" : "",
-              imsm_orom_has_chunk(orom, 256) ? " 256k" : "",
-              imsm_orom_has_chunk(orom, 512) ? " 512k" : "",
-              imsm_orom_has_chunk(orom, 1024*1) ? " 1M" : "",
-              imsm_orom_has_chunk(orom, 1024*2) ? " 2M" : "",
-              imsm_orom_has_chunk(orom, 1024*4) ? " 4M" : "",
-              imsm_orom_has_chunk(orom, 1024*8) ? " 8M" : "",
-              imsm_orom_has_chunk(orom, 1024*16) ? " 16M" : "",
-              imsm_orom_has_chunk(orom, 1024*32) ? " 32M" : "",
-              imsm_orom_has_chunk(orom, 1024*64) ? " 64M" : "");
-       printf("      Max Disks : %d\n", orom->tds);
-       printf("    Max Volumes : %d\n", orom->vpa);
-
        for (hba = list; hba; hba = hba->next) {
                printf(" I/O Controller : %s (%s)\n",
                        hba->path, get_sys_dev_type(hba->type));
@@ -1430,11 +1446,6 @@ static int detail_platform_imsm(int verbose, int enumerate_only)
                                                "ports on SATA controller at %s.", hba->pci_id);
                                result |= 2;
                        }
-               } else if (hba->type == SYS_DEV_SAS) {
-                               if (verbose)
-                                       fprintf(stderr, Name ": failed to enumerate "
-                                               "devices on SAS controller at %s.", hba->pci_id);
-                               result |= 2;
                }
        }
 
@@ -1689,8 +1700,6 @@ static __u64 blocks_per_migr_unit(struct imsm_dev *dev)
                migr_chunk = migr_strip_blocks_resync(dev);
                disks = imsm_num_data_members(dev, 0);
                blocks_per_unit = stripes_per_unit * migr_chunk * disks;
-               if (migr_type(dev) == MIGR_GEN_MIGR)
-                       return blocks_per_unit;
                stripe = __le32_to_cpu(map->blocks_per_strip) * disks;
                segment = blocks_per_unit / stripe;
                block_rel = blocks_per_unit - segment * stripe;
@@ -1841,6 +1850,12 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
                        int used_disks;
 
                        info->reshape_progress = blocks_per_unit * units;
+
+                       /* checkpoint is written per disks unit
+                        * recalculate it to reshape position
+                        */
+                       used_disks = imsm_num_data_members(dev, 0);
+                       info->reshape_progress *= used_disks;
                        dprintf("IMSM: General Migration checkpoint : %llu "
                               "(%llu) -> read reshape progress : %llu\n",
                                units, blocks_per_unit, info->reshape_progress);
@@ -2196,6 +2211,19 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst)
                 tst->sb = NULL;
                 return 0;
         }
+       /* in platform dependent environment test if the disks
+        * use the same Intel hba
+        */
+       if (!check_env("IMSM_NO_PLATFORM")) {
+               if (!first->hba || !sec->hba ||
+                   (first->hba->type != sec->hba->type))  {
+                       fprintf(stderr,
+                               "HBAs of devices does not match %s != %s\n",
+                               first->hba ? get_sys_dev_type(first->hba->type) : NULL,
+                               sec->hba ? get_sys_dev_type(sec->hba->type) : NULL);
+                       return 3;
+               }
+       }
 
        /* if an anchor does not have num_raid_devs set then it is a free
         * floating spare
@@ -2603,7 +2631,7 @@ struct bbm_log *__get_imsm_bbm_log(struct imsm_super *mpb)
 static void __free_imsm(struct intel_super *super, int free_disks);
 
 /* load_imsm_mpb - read matrix metadata
- * allocates super->mpb to be freed by free_super
+ * allocates super->mpb to be freed by free_imsm
  */
 static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
 {
@@ -2655,6 +2683,10 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
        }
 
        __free_imsm(super, 0);
+       /*  reload capability and hba */
+
+       /* capability and hba must be updated with new super allocation */
+       find_intel_hba_capability(fd, super, devname);
        super->len = ROUND_UP(anchor->mpb_size, 512);
        if (posix_memalign(&super->buf, 512, super->len) != 0) {
                if (devname)
@@ -2778,6 +2810,8 @@ static void __free_imsm(struct intel_super *super, int free_disks)
                free(super->buf);
                super->buf = NULL;
        }
+       /* unlink capability description */
+       super->orom = NULL;
        if (free_disks)
                free_imsm_disks(super);
        free_devlist(super);
@@ -2817,13 +2851,66 @@ static struct intel_super *alloc_super(void)
                memset(super, 0, sizeof(*super));
                super->current_vol = -1;
                super->create_offset = ~((__u32 ) 0);
-               if (!check_env("IMSM_NO_PLATFORM"))
-                       super->orom = find_imsm_orom();
        }
-
        return super;
 }
 
+/*
+ * find and allocate hba and OROM/EFI based on valid fd of RAID component device
+ */
+static int find_intel_hba_capability(int fd, struct intel_super *super, char *devname)
+{
+       struct sys_dev *hba_name;
+       int rv = 0;
+
+       if ((fd < 0) || check_env("IMSM_NO_PLATFORM")) {
+               super->orom = NULL;
+               super->hba = NULL;
+               return 0;
+       }
+       hba_name = find_disk_attached_hba(fd, NULL);
+       if (!hba_name) {
+               if (devname)
+                       fprintf(stderr,
+                               Name ": %s is not attached to Intel(R) RAID controller.\n",
+                               devname);
+               return 1;
+       }
+       rv = attach_hba_to_super(super, hba_name);
+       if (rv == 2) {
+               if (devname) {
+                       struct intel_hba *hba = super->hba;
+
+                       fprintf(stderr, Name ": %s is attached to Intel(R) %s RAID "
+                               "controller (%s),\n"
+                               "    but the container is assigned to Intel(R) "
+                               "%s RAID controller (",
+                               devname,
+                               hba_name->path,
+                               hba_name->pci_id ? : "Err!",
+                               get_sys_dev_type(hba_name->type));
+
+                       while (hba) {
+                               fprintf(stderr, "%s", hba->pci_id ? : "Err!");
+                               if (hba->next)
+                                       fprintf(stderr, ", ");
+                               hba = hba->next;
+                       }
+
+                       fprintf(stderr, ").\n"
+                               "    Mixing devices attached to different controllers "
+                               "is not allowed.\n");
+               }
+               free_sys_dev(&hba_name);
+               return 2;
+       }
+       super->orom = find_imsm_capability(hba_name->type);
+       free_sys_dev(&hba_name);
+       if (!super->orom)
+               return 3;
+       return 0;
+}
+
 #ifndef MDASSEMBLE
 /* find_missing - helper routine for load_super_imsm_all that identifies
  * disks that have disappeared from the system.  This routine relies on
@@ -3204,6 +3291,7 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
                struct intel_super *s = alloc_super();
                char nm[32];
                int dfd;
+               int rv;
 
                err = 1;
                if (!s)
@@ -3217,6 +3305,11 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
                if (dfd < 0)
                        goto error;
 
+               rv = find_intel_hba_capability(dfd, s, devname);
+               /* no orom/efi or non-intel hba of the disk */
+               if (rv != 0)
+                       goto error;
+
                err = load_and_parse_mpb(dfd, s, NULL, 1);
 
                /* retry the load if we might have raced against mdmon */
@@ -3291,7 +3384,19 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
                        sizeof(*super));
                return 1;
        }
-
+       /* Load hba and capabilities if they exist.
+        * But do not preclude loading metadata in case capabilities or hba are
+        * non-compliant and ignore_hw_compat is set.
+        */
+       rv = find_intel_hba_capability(fd, super, devname);
+       /* no orom/efi or non-intel hba of the disk */
+       if ((rv != 0) && (st->ignore_hw_compat == 0)) {
+               if (devname)
+                       fprintf(stderr,
+                               Name ": No OROM/EFI properties for %s\n", devname);
+               free_imsm(super);
+               return 2;
+       }
        rv = load_and_parse_mpb(fd, super, devname, 0);
 
        if (rv) {
@@ -3684,43 +3789,12 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
         * We do not need to test disks attachment for container based additions,
         * they shall be already tested when container was created/assembled.
         */
-       if ((fd != -1) && !check_env("IMSM_NO_PLATFORM")) {
-               struct sys_dev *hba_name;
-               struct intel_hba *hba;
-
-               hba_name = find_disk_attached_hba(fd, NULL);
-               if (!hba_name) {
-                       fprintf(stderr,
-                               Name ": %s is not attached to Intel(R) RAID controller.\n",
-                               devname ? : "disk");
-                       return 1;
-               }
-               rv = attach_hba_to_super(super, hba_name);
-               switch (rv) {
-               case 2:
-                       fprintf(stderr, Name ": %s is attached to Intel(R) %s RAID "
-                               "controller (%s),\n    but the container is assigned to Intel(R) "
-                               "%s RAID controller (",
-                               devname,
-                               get_sys_dev_type(hba_name->type),
-                               hba_name->pci_id ? : "Err!",
-                               get_sys_dev_type(hba_name->type));
-
-                       hba = super->hba;
-                       while (hba) {
-                               fprintf(stderr, "%s", hba->pci_id ? : "Err!");
-                               if (hba->next)
-                                       fprintf(stderr, ", ");
-                               hba = hba->next;
-                       }
-
-                       fprintf(stderr, ").\n"
-                               "    Mixing devices attached to different controllers "
-                               "is not allowed.\n");
-                       free_sys_dev(&hba_name);
-                       return 1;
-               }
-               free_sys_dev(&hba_name);
+       rv = find_intel_hba_capability(fd, super, devname);
+       /* no orom/efi or non-intel hba of the disk */
+       if (rv != 0) {
+               dprintf("capability: %p fd: %d ret: %d\n",
+                       super->orom, fd, rv);
+               return 1;
        }
 
        if (super->current_vol >= 0)
@@ -3765,6 +3839,7 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
        } else {
                dd->next = super->disks;
                super->disks = dd;
+               super->updates_pending++;
        }
 
        return 0;
@@ -4052,25 +4127,14 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
 {
        int fd;
        unsigned long long ldsize;
-       const struct imsm_orom *orom;
+       struct intel_super *super=NULL;
+       int rv = 0;
 
        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)
@@ -4082,9 +4146,45 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
                close(fd);
                return 0;
        }
+
+       /* capabilities retrieve could be possible
+        * note that there is no fd for the disks in array.
+        */
+       super = alloc_super();
+       if (!super) {
+               fprintf(stderr,
+                       Name ": malloc of %zu failed.\n",
+                       sizeof(*super));
+               close(fd);
+               return 0;
+       }
+
+       rv = find_intel_hba_capability(fd, super, verbose ? dev : NULL);
+       if (rv != 0) {
+#if DEBUG
+               char str[256];
+               fd2devname(fd, str);
+               dprintf("validate_geometry_imsm_container: fd: %d %s orom: %p rv: %d raiddisk: %d\n",
+                       fd, str, super->orom, rv, raiddisks);
+#endif
+               /* no orom/efi or non-intel hba of the disk */
+               close(fd);
+               free_imsm(super);
+               return 0;
+       }
        close(fd);
+       if (super->orom && raiddisks > super->orom->tds) {
+               if (verbose)
+                       fprintf(stderr, Name ": %d exceeds maximum number of"
+                               " platform supported disks: %d\n",
+                               raiddisks, super->orom->tds);
+
+               free_imsm(super);
+               return 0;
+       }
 
        *freesize = avail_size_imsm(st, ldsize >> 9);
+       free_imsm(super);
 
        return 1;
 }
@@ -4219,12 +4319,30 @@ static int is_raid_level_supported(const struct imsm_orom *orom, int level, int
        return 0;
 }
 
+
 #define pr_vrb(fmt, arg...) (void) (verbose && fprintf(stderr, Name fmt, ##arg))
+/*
+ * validate volume parameters with OROM/EFI capabilities
+ */
 static int
 validate_geometry_imsm_orom(struct intel_super *super, int level, int layout,
                            int raiddisks, int *chunk, int verbose)
 {
-       if (!is_raid_level_supported(super->orom, level, raiddisks)) {
+#if DEBUG
+       verbose = 1;
+#endif
+       /* validate container capabilities */
+       if (super->orom && raiddisks > super->orom->tds) {
+               if (verbose)
+                       fprintf(stderr, Name ": %d exceeds maximum number of"
+                               " platform supported disks: %d\n",
+                               raiddisks, super->orom->tds);
+               return 0;
+       }
+
+        /* capabilities of OROM tested - copied from validate_geometry_imsm_volume */
+       if (super->orom && (!is_raid_level_supported(super->orom, level,
+                                                    raiddisks))) {
                pr_vrb(": platform does not support raid%d with %d disk%s\n",
                        level, raiddisks, raiddisks > 1 ? "s" : "");
                return 0;
@@ -4248,7 +4366,6 @@ validate_geometry_imsm_orom(struct intel_super *super, int level, int layout,
                                layout, level);
                return 0;
        }
-
        return 1;
 }
 
@@ -4274,9 +4391,11 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
        if (!super)
                return 0;
 
-       if (!validate_geometry_imsm_orom(super, level, layout, raiddisks, chunk, verbose))
+       if (!validate_geometry_imsm_orom(super, level, layout, raiddisks, chunk, verbose)) {
+               fprintf(stderr, Name ": RAID gemetry validation failed. "
+                       "Cannot proceed with the action(s).\n");
                return 0;
-
+       }
        if (!dev) {
                /* General test:  make sure there is space for
                 * 'raiddisks' device extents of size 'size' at a given
@@ -4483,7 +4602,8 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
        struct mdinfo *sra;
        int is_member = 0;
 
-       /* if given unused devices create a container 
+       /* load capability
+        * if given unused devices create a container
         * if given given devices in a container create a member volume
         */
        if (level == LEVEL_CONTAINER) {
@@ -4813,7 +4933,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                struct imsm_map *map;
                struct imsm_map *map2;
                struct mdinfo *this;
-               int slot;
+               int slot, chunk;
                char *ep;
 
                if (subarray &&
@@ -4834,7 +4954,23 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                                dev->volume);
                        continue;
                }
+               /* do not publish arrays that are not support by controller's
+                * OROM/EFI
+                */
 
+               chunk = __le16_to_cpu(map->blocks_per_strip) >> 1;
+#ifndef MDASSEMBLE
+               if (!validate_geometry_imsm_orom(super,
+                                                get_imsm_raid_level(map), /* RAID level */
+                                                imsm_level_to_layout(get_imsm_raid_level(map)),
+                                                map->num_members, /* raid disks */
+                                                &chunk,
+                                                1 /* verbose */)) {
+                       fprintf(stderr, Name ": RAID gemetry validation failed. "
+                               "Cannot proceed with the action(s).\n");
+                       continue;
+               }
+#endif /* MDASSEMBLE */
                this = malloc(sizeof(*this));
                if (!this) {
                        fprintf(stderr, Name ": failed to allocate %zu bytes\n",
@@ -5081,8 +5217,6 @@ static int mark_failure(struct imsm_dev *dev, struct imsm_disk *disk, int idx)
        __u32 ord;
        int slot;
        struct imsm_map *map;
-       char buf[MAX_RAID_SERIAL_LEN+3];
-       unsigned int len, shift = 0;
 
        /* new failures are always set in map[0] */
        map = get_imsm_map(dev, 0);
@@ -5095,11 +5229,6 @@ static int mark_failure(struct imsm_dev *dev, struct imsm_disk *disk, int idx)
        if (is_failed(disk) && (ord & IMSM_ORD_REBUILD))
                return 0;
 
-       sprintf(buf, "%s:0", disk->serial);
-       if ((len = strlen(buf)) >= MAX_RAID_SERIAL_LEN)
-               shift = len - MAX_RAID_SERIAL_LEN + 1;
-       strncpy((char *)disk->serial, &buf[shift], MAX_RAID_SERIAL_LEN);
-
        disk->status |= FAILED_DISK;
        set_imsm_ord_tbl_ent(map, slot, idx | IMSM_ORD_REBUILD);
        if (map->failed_disk_num == 0xff)