]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
IMSM - allow assembling any imsm array even without OROM.
[thirdparty/mdadm.git] / super-intel.c
index 2f04302d5e29de622e763844c086ab418c4b7242..202b83fcbaf2d4fd6c00064edfc94553bd03127e 100644 (file)
@@ -433,7 +433,7 @@ struct imsm_update_activate_spare {
 struct geo_params {
        int dev_id;
        char *dev_name;
-       long long size;
+       unsigned long long size;
        int level;
        int layout;
        int chunksize;
@@ -685,12 +685,12 @@ static __u32 __gen_imsm_checksum(struct imsm_super *mpb)
        __u32 *p = (__u32 *) mpb;
        __u32 sum = 0;
 
-        while (end--) {
-                sum += __le32_to_cpu(*p);
+       while (end--) {
+               sum += __le32_to_cpu(*p);
                p++;
        }
 
-        return sum - __le32_to_cpu(mpb->check_sum);
+       return sum - __le32_to_cpu(mpb->check_sum);
 }
 
 static size_t sizeof_imsm_map(struct imsm_map *map)
@@ -1567,7 +1567,7 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
        unsigned long port_mask = (1 << port_count) - 1;
 
        if (port_count > (int)sizeof(port_mask) * 8) {
-               if (verbose)
+               if (verbose > 0)
                        pr_err("port_count %d out of range\n", port_count);
                return 2;
        }
@@ -1600,14 +1600,14 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
 
                /* retrieve the scsi device type */
                if (asprintf(&device, "/sys/dev/block/%d:%d/device/xxxxxxx", major, minor) < 0) {
-                       if (verbose)
+                       if (verbose > 0)
                                pr_err("failed to allocate 'device'\n");
                        err = 2;
                        break;
                }
                sprintf(device, "/sys/dev/block/%d:%d/device/type", major, minor);
                if (load_sys(device, buf) != 0) {
-                       if (verbose)
+                       if (verbose > 0)
                                pr_err("failed to read device type for %s\n",
                                        path);
                        err = 2;
@@ -1660,7 +1660,7 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
                /* chop device path to 'host%d' and calculate the port number */
                c = strchr(&path[hba_len], '/');
                if (!c) {
-                       if (verbose)
+                       if (verbose > 0)
                                pr_err("%s - invalid path name\n", path + hba_len);
                        err = 2;
                        break;
@@ -1669,7 +1669,7 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
                if (sscanf(&path[hba_len], "host%d", &port) == 1)
                        port -= host_base;
                else {
-                       if (verbose) {
+                       if (verbose > 0) {
                                *c = '/'; /* repair the full string */
                                pr_err("failed to determine port number for %s\n",
                                        path);
@@ -1798,7 +1798,42 @@ static void print_imsm_capability(const struct imsm_orom *orom)
        return;
 }
 
-static int detail_platform_imsm(int verbose, int enumerate_only)
+static void print_imsm_capability_export(const struct imsm_orom *orom)
+{
+       printf("MD_FIRMWARE_TYPE=imsm\n");
+       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_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("IMSM_2TB_VOLUMES=%s\n",(orom->attr & IMSM_OROM_ATTR_2TB) ? "yes" : "no");
+       printf("IMSM_2TB_DISKS=%s\n",(orom->attr & IMSM_OROM_ATTR_2TB_DISK) ? "yes" : "no");
+       printf("IMSM_MAX_DISKS=%d\n",orom->tds);
+       printf("IMSM_MAX_VOLUMES_PER_ARRAY=%d\n",orom->vpa);
+       printf("IMSM_MAX_VOLUMES_PER_CONTROLLER=%d\n",orom->vphba);
+}
+
+static int detail_platform_imsm(int verbose, int enumerate_only, char *controller_path)
 {
        /* There are two components to imsm platform support, the ahci SATA
         * controller and the option-rom.  To find the SATA controller we
@@ -1815,7 +1850,7 @@ static int detail_platform_imsm(int verbose, int enumerate_only)
        struct sys_dev *list, *hba;
        int host_base = 0;
        int port_count = 0;
-       int result=0;
+       int result=1;
 
        if (enumerate_only) {
                if (check_env("IMSM_NO_PLATFORM"))
@@ -1829,6 +1864,8 @@ static int detail_platform_imsm(int verbose, int enumerate_only)
                                result = 2;
                                break;
                        }
+                       else
+                               result = 0;
                }
                free_sys_dev(&list);
                return result;
@@ -1836,41 +1873,78 @@ static int detail_platform_imsm(int verbose, int enumerate_only)
 
        list = find_intel_devices();
        if (!list) {
-               if (verbose)
+               if (verbose > 0)
                        pr_err("no active Intel(R) RAID "
                                "controller found.\n");
                free_sys_dev(&list);
                return 2;
-       } else if (verbose)
+       } else if (verbose > 0)
                print_found_intel_controllers(list);
 
        for (hba = list; hba; hba = hba->next) {
+               if (controller_path && (compare_paths(hba->path,controller_path) != 0))
+                       continue;
                orom = find_imsm_capability(hba->type);
                if (!orom)
                        pr_err("imsm capabilities not found for controller: %s (type %s)\n",
                                hba->path, get_sys_dev_type(hba->type));
-               else
+               else {
+                       result = 0;
                        print_imsm_capability(orom);
+                       printf(" I/O Controller : %s (%s)\n",
+                               hba->path, get_sys_dev_type(hba->type));
+                       if (hba->type == SYS_DEV_SATA) {
+                               host_base = ahci_get_port_count(hba->path, &port_count);
+                               if (ahci_enumerate_ports(hba->path, port_count, host_base, verbose)) {
+                                       if (verbose > 0)
+                                               pr_err("failed to enumerate "
+                                                       "ports on SATA controller at %s.\n", hba->pci_id);
+                                       result |= 2;
+                               }
+                       }
+               }
+       }
+
+       if (controller_path && result == 1)
+               pr_err("no active Intel(R) RAID "
+                               "controller found under %s\n",controller_path);
+
+       free_sys_dev(&list);
+       return result;
+}
+
+static int export_detail_platform_imsm(int verbose, char *controller_path)
+{
+       const struct imsm_orom *orom;
+       struct sys_dev *list, *hba;
+       int result=1;
+
+       list = find_intel_devices();
+       if (!list) {
+               if (verbose > 0)
+                       pr_err("IMSM_DETAIL_PLATFORM_ERROR=NO_INTEL_DEVICES\n");
+               result = 2;
+               free_sys_dev(&list);
+               return result;
        }
 
        for (hba = list; hba; hba = hba->next) {
-               printf(" I/O Controller : %s (%s)\n",
-                       hba->path, get_sys_dev_type(hba->type));
-
-               if (hba->type == SYS_DEV_SATA) {
-                       host_base = ahci_get_port_count(hba->path, &port_count);
-                       if (ahci_enumerate_ports(hba->path, port_count, host_base, verbose)) {
-                               if (verbose)
-                                       pr_err("failed to enumerate "
-                                               "ports on SATA controller at %s.", hba->pci_id);
-                               result |= 2;
-                       }
+               if (controller_path && (compare_paths(hba->path,controller_path) != 0))
+                       continue;
+               orom = find_imsm_capability(hba->type);
+               if (!orom) {
+                       if (verbose > 0)
+                               pr_err("IMSM_DETAIL_PLATFORM_ERROR=NO_IMSM_CAPABLE_DEVICE_UNDER_%s\n",hba->path);
+               }
+               else {
+                       print_imsm_capability_export(orom);
+                       result = 0;
                }
        }
 
-       free_sys_dev(&list);
        return result;
 }
+
 #endif
 
 static int match_home_imsm(struct supertype *st, char *homehost)
@@ -2950,7 +3024,8 @@ static size_t disks_to_mpb_size(int disks)
        return size;
 }
 
-static __u64 avail_size_imsm(struct supertype *st, __u64 devsize)
+static __u64 avail_size_imsm(struct supertype *st, __u64 devsize,
+                            unsigned long long data_offset)
 {
        if (devsize < (MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS))
                return 0;
@@ -2987,17 +3062,18 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst)
        struct intel_super *first = st->sb;
        struct intel_super *sec = tst->sb;
 
-        if (!first) {
-                st->sb = tst->sb;
-                tst->sb = NULL;
-                return 0;
-        }
+       if (!first) {
+               st->sb = tst->sb;
+               tst->sb = NULL;
+               return 0;
+       }
        /* in platform dependent environment test if the disks
         * use the same Intel hba
+        * If not on Intel hba at all, allow anything.
         */
        if (!check_env("IMSM_NO_PLATFORM")) {
-               if (!first->hba || !sec->hba ||
-                   (first->hba->type != sec->hba->type))  {
+               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,
@@ -4251,7 +4327,6 @@ static int get_super_block(struct intel_super **super_list, int devnum, char *de
        struct intel_super*s = NULL;
        char nm[32];
        int dfd = -1;
-       int rv;
        int err = 0;
        int retry;
 
@@ -4268,13 +4343,7 @@ static int get_super_block(struct intel_super **super_list, int devnum, char *de
                goto error;
        }
 
-       rv = find_intel_hba_capability(dfd, s, devname);
-       /* no orom/efi or non-intel hba of the disk */
-       if (rv != 0) {
-               err = 4;
-               goto error;
-       }
-
+       find_intel_hba_capability(dfd, s, devname);
        err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
 
        /* retry the load if we might have raced against mdmon */
@@ -4486,7 +4555,8 @@ static int check_name(struct intel_super *super, char *name, int quiet)
 
 static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
                                  unsigned long long size, char *name,
-                                 char *homehost, int *uuid)
+                                 char *homehost, int *uuid,
+                                 long long data_offset)
 {
        /* We are creating a volume inside a pre-existing container.
         * so st->sb is already set.
@@ -4597,7 +4667,8 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info));
        map->failed_disk_num = ~0;
        if (info->level > 0)
-               map->map_state = IMSM_T_STATE_UNINITIALIZED;
+               map->map_state = (info->state ? IMSM_T_STATE_NORMAL
+                                 : IMSM_T_STATE_UNINITIALIZED);
        else
                map->map_state = info->failed_disks ? IMSM_T_STATE_FAILED :
                                                      IMSM_T_STATE_NORMAL;
@@ -4644,7 +4715,8 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
 
 static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
                           unsigned long long size, char *name,
-                          char *homehost, int *uuid)
+                          char *homehost, int *uuid,
+                          unsigned long long data_offset)
 {
        /* This is primarily called by Create when creating a new array.
         * We will then get add_to_super called for each component, and then
@@ -4659,8 +4731,14 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
        size_t mpb_size;
        char *version;
 
+       if (data_offset != INVALID_SECTORS) {
+               fprintf(stderr, Name ": data-offset not supported by imsm\n");
+               return 0;
+       }
+
        if (st->sb)
-               return init_super_imsm_volume(st, info, size, name, homehost, uuid);
+               return init_super_imsm_volume(st, info, size, name, homehost, uuid,
+                                             data_offset);
 
        if (info)
                mpb_size = disks_to_mpb_size(info->nr_disks);
@@ -4854,7 +4932,8 @@ int mark_spare(struct dl *disk)
 }
 
 static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
-                            int fd, char *devname)
+                            int fd, char *devname,
+                            unsigned long long data_offset)
 {
        struct intel_super *super = st->sb;
        struct dl *dd;
@@ -5175,7 +5254,7 @@ static int write_init_super_imsm(struct supertype *st)
        } else {
                struct dl *d;
                for (d = super->disks; d; d = d->next)
-                       Kill(d->devname, NULL, 0, 1, 1);
+                       Kill(d->devname, NULL, 0, -1, 1);
                return write_super_imsm(st, 1);
        }
 }
@@ -5204,7 +5283,9 @@ static int imsm_bbm_log_size(struct imsm_super *mpb)
 #ifndef MDASSEMBLE
 static int validate_geometry_imsm_container(struct supertype *st, int level,
                                            int layout, int raiddisks, int chunk,
-                                           unsigned long long size, char *dev,
+                                           unsigned long long size,
+                                           unsigned long long data_offset,
+                                           char *dev,
                                            unsigned long long *freesize,
                                            int verbose)
 {
@@ -5220,7 +5301,7 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
 
        fd = open(dev, O_RDONLY|O_EXCL, 0);
        if (fd < 0) {
-               if (verbose)
+               if (verbose > 0)
                        pr_err("imsm: Cannot open %s: %s\n",
                                dev, strerror(errno));
                return 0;
@@ -5234,7 +5315,7 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
         * note that there is no fd for the disks in array.
         */
        super = alloc_super();
-       rv = find_intel_hba_capability(fd, super, verbose ? dev : NULL);
+       rv = find_intel_hba_capability(fd, super, verbose > 0 ? dev : NULL);
        if (rv != 0) {
 #if DEBUG
                char str[256];
@@ -5266,7 +5347,7 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
                }
        }
 
-       *freesize = avail_size_imsm(st, ldsize >> 9);
+       *freesize = avail_size_imsm(st, ldsize >> 9, data_offset);
        free_imsm(super);
 
        return 1;
@@ -5763,7 +5844,7 @@ validate_geometry_imsm_orom(struct intel_super *super, int level, int layout,
                return 0;
        }
 
-        /* capabilities of OROM tested - copied from validate_geometry_imsm_volume */
+       /* capabilities of OROM tested - copied from validate_geometry_imsm_volume */
        if (!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" : "");
@@ -5803,7 +5884,9 @@ validate_geometry_imsm_orom(struct intel_super *super, int level, int layout,
  */
 static int validate_geometry_imsm_volume(struct supertype *st, int level,
                                         int layout, int raiddisks, int *chunk,
-                                        unsigned long long size, char *dev,
+                                        unsigned long long size,
+                                        unsigned long long data_offset,
+                                        char *dev,
                                         unsigned long long *freesize,
                                         int verbose)
 {
@@ -6086,6 +6169,7 @@ static int reserve_space(struct supertype *st, int raiddisks,
 
 static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                                  int raiddisks, int *chunk, unsigned long long size,
+                                 unsigned long long data_offset,
                                  char *dev, unsigned long long *freesize,
                                  int verbose)
 {
@@ -6101,7 +6185,8 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                /* Must be a fresh device to add to a container */
                return validate_geometry_imsm_container(st, level, layout,
                                                        raiddisks,
-                                                       chunk?*chunk:0, size,
+                                                       chunk?*chunk:0,
+                                                       size, data_offset,
                                                        dev, freesize,
                                                        verbose);
        }
@@ -6144,6 +6229,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                /* creating in a given container */
                return validate_geometry_imsm_volume(st, level, layout,
                                                     raiddisks, chunk, size,
+                                                    data_offset,
                                                     dev, freesize, verbose);
        }
 
@@ -6188,7 +6274,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                        close(cfd);
                        return validate_geometry_imsm_volume(st, level, layout,
                                                             raiddisks, chunk,
-                                                            size, dev,
+                                                            size, data_offset, dev,
                                                             freesize, 1)
                                ? 1 : -1;
                }
@@ -9307,7 +9393,7 @@ static int imsm_reshape_is_allowed_on_container(struct supertype *st,
                "st->devnum = (%i)\n",
                st->devnum);
 
-       if (geo->size != -1 ||
+       if (geo->size > 0 ||
            geo->level != UnSet ||
            geo->layout != UnSet ||
            geo->chunksize != 0 ||
@@ -9647,9 +9733,9 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
        int data_disks;
        struct imsm_dev *dev;
        struct intel_super *super;
-       long long current_size;
+       unsigned long long current_size;
        unsigned long long free_size;
-       long long max_size;
+       unsigned long long max_size;
        int rv;
 
        getinfo_super_imsm_volume(st, &info, NULL);
@@ -9737,16 +9823,23 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
         */
        current_size = info.custom_array_size / data_disks;
 
-       if (geo->size > 0) {
+       if ((geo->size > 0) && (geo->size != MAX_SIZE)) {
                /* align component size
                 */
                geo->size = imsm_component_size_aligment_check(
                                    get_imsm_raid_level(dev->vol.map),
                                    chunk * 1024,
                                    geo->size * 2);
+               if (geo->size == 0) {
+                       pr_err("Error. Size expansion is " \
+                                  "supported only (current size is %llu, " \
+                                  "requested size /rounded/ is 0).\n",
+                                  current_size);
+                       goto analyse_change_exit;
+               }
        }
 
-       if ((current_size != geo->size) && (geo->size >= 0)) {
+       if ((current_size != geo->size) && (geo->size > 0)) {
                if (change != -1) {
                        pr_err("Error. Size change should be the only "
                                "one at a time.\n");
@@ -9776,7 +9869,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                                        chunk * 1024,
                                        max_size);
                }
-               if (geo->size == 0) {
+               if (geo->size == MAX_SIZE) {
                        /* requested size change to the maximum available size
                         */
                        if (max_size == 0) {
@@ -9823,7 +9916,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                                    imsm_layout,
                                    geo->raid_disks + devNumChange,
                                    &chunk,
-                                   geo->size,
+                                   geo->size, INVALID_SECTORS,
                                    0, 0, 1))
                change = -1;
 
@@ -9881,7 +9974,8 @@ int imsm_takeover(struct supertype *st, struct geo_params *geo)
        return 0;
 }
 
-static int imsm_reshape_super(struct supertype *st, long long size, int level,
+static int imsm_reshape_super(struct supertype *st, unsigned long long size,
+                             int level,
                              int layout, int chunksize, int raid_disks,
                              int delta_disks, char *backup, char *dev,
                              int direction, int verbose)
@@ -10389,6 +10483,7 @@ struct superswitch super_imsm = {
        .add_to_super   = add_to_super_imsm,
        .remove_from_super = remove_from_super_imsm,
        .detail_platform = detail_platform_imsm,
+       .export_detail_platform = export_detail_platform_imsm,
        .kill_subarray = kill_subarray_imsm,
        .update_subarray = update_subarray_imsm,
        .load_container = load_container_imsm,