]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
Fix regression during add devices
[thirdparty/mdadm.git] / super-intel.c
index e609e0ca3a2dae9f80245cca78f8765ffebcc482..3fe304aad927f3e0077fd67bb9ebddd8f74c6bf4 100644 (file)
@@ -510,7 +510,8 @@ static const char *_sys_dev_type[] = {
        [SYS_DEV_UNKNOWN] = "Unknown",
        [SYS_DEV_SAS] = "SAS",
        [SYS_DEV_SATA] = "SATA",
-       [SYS_DEV_NVME] = "NVMe"
+       [SYS_DEV_NVME] = "NVMe",
+       [SYS_DEV_VMD] = "VMD"
 };
 
 const char *get_sys_dev_type(enum sys_dev_type type)
@@ -565,6 +566,10 @@ static int attach_hba_to_super(struct intel_super *super, struct sys_dev *device
        if (device->type != hba->type)
                return 2;
 
+       /* Always forbid spanning between VMD domains (seen as different controllers by mdadm) */
+       if (device->type == SYS_DEV_VMD && !path_attached_to_hba(device->path, hba->path))
+               return 2;
+
        /* Multiple same type HBAs can be used if they share the same OROM */
        const struct imsm_orom *device_orom = get_orom_by_device_id(device->dev_id);
 
@@ -1649,7 +1654,7 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
                        break;
                }
                sprintf(device, "/sys/dev/block/%d:%d/device/type", major, minor);
-               if (load_sys(device, buf) != 0) {
+               if (load_sys(device, buf, sizeof(buf)) != 0) {
                        if (verbose > 0)
                                pr_err("failed to read device type for %s\n",
                                        path);
@@ -1664,7 +1669,7 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
                        vendor[0] = '\0';
                        model[0] = '\0';
                        sprintf(device, "/sys/dev/block/%d:%d/device/vendor", major, minor);
-                       if (load_sys(device, buf) == 0) {
+                       if (load_sys(device, buf, sizeof(buf)) == 0) {
                                strncpy(vendor, buf, sizeof(vendor));
                                vendor[sizeof(vendor) - 1] = '\0';
                                c = (char *) &vendor[sizeof(vendor) - 1];
@@ -1673,7 +1678,7 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
 
                        }
                        sprintf(device, "/sys/dev/block/%d:%d/device/model", major, minor);
-                       if (load_sys(device, buf) == 0) {
+                       if (load_sys(device, buf, sizeof(buf)) == 0) {
                                strncpy(model, buf, sizeof(model));
                                model[sizeof(model) - 1] = '\0';
                                c = (char *) &model[sizeof(model) - 1];
@@ -1761,6 +1766,60 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
        return err;
 }
 
+static void print_vmd_attached_devs(struct sys_dev *hba)
+{
+       struct dirent *ent;
+       DIR *dir;
+       char path[292];
+       char link[256];
+       char *c, *rp;
+
+       if (hba->type != SYS_DEV_VMD)
+               return;
+
+       /* scroll through /sys/dev/block looking for devices attached to
+        * this hba
+        */
+       dir = opendir("/sys/bus/pci/drivers/nvme");
+       if (!dir)
+               return;
+
+       for (ent = readdir(dir); ent; ent = readdir(dir)) {
+               int n;
+
+               /* is 'ent' a device? check that the 'subsystem' link exists and
+                * that its target matches 'bus'
+                */
+               sprintf(path, "/sys/bus/pci/drivers/nvme/%s/subsystem",
+                       ent->d_name);
+               n = readlink(path, link, sizeof(link));
+               if (n < 0 || n >= (int)sizeof(link))
+                       continue;
+               link[n] = '\0';
+               c = strrchr(link, '/');
+               if (!c)
+                       continue;
+               if (strncmp("pci", c+1, strlen("pci")) != 0)
+                       continue;
+
+               sprintf(path, "/sys/bus/pci/drivers/nvme/%s", ent->d_name);
+               /* if not a intel NVMe - skip it*/
+               if (devpath_to_vendor(path) != 0x8086)
+                       continue;
+
+               rp = realpath(path, NULL);
+               if (!rp)
+                       continue;
+
+               if (path_attached_to_hba(rp, hba->path)) {
+                       printf(" NVMe under VMD : %s\n", rp);
+               }
+               free(rp);
+       }
+
+       closedir(dir);
+}
+
 static void print_found_intel_controllers(struct sys_dev *elem)
 {
        for (; elem; elem = elem->next) {
@@ -1771,7 +1830,12 @@ static void print_found_intel_controllers(struct sys_dev *elem)
                        fprintf(stderr, "SAS ");
                else if (elem->type == SYS_DEV_NVME)
                        fprintf(stderr, "NVMe ");
-               fprintf(stderr, "RAID controller");
+
+               if (elem->type == SYS_DEV_VMD)
+                       fprintf(stderr, "VMD domain");
+               else
+                       fprintf(stderr, "RAID controller");
+
                if (elem->pci_id)
                        fprintf(stderr, " at %s", elem->pci_id);
                fprintf(stderr, ".\n");
@@ -1935,8 +1999,10 @@ static int detail_platform_imsm(int verbose, int enumerate_only, char *controlle
                if (controller_path && (compare_paths(hba->path, controller_path) != 0))
                        continue;
                if (!find_imsm_capability(hba)) {
+                       char buf[PATH_MAX];
                        pr_err("imsm capabilities not found for controller: %s (type %s)\n",
-                               hba->path, get_sys_dev_type(hba->type));
+                                 hba->type == SYS_DEV_VMD ? vmd_domain_to_controller(hba, buf) : hba->path,
+                                 get_sys_dev_type(hba->type));
                        continue;
                }
                result = 0;
@@ -1951,13 +2017,27 @@ static int detail_platform_imsm(int verbose, int enumerate_only, char *controlle
        const struct orom_entry *entry;
 
        for (entry = orom_entries; entry; entry = entry->next) {
-               print_imsm_capability(&entry->orom);
+               if (entry->type == SYS_DEV_VMD) {
+                       for (hba = list; hba; hba = hba->next) {
+                               if (hba->type == SYS_DEV_VMD) {
+                                       char buf[PATH_MAX];
+                                       print_imsm_capability(&entry->orom);
+                                       printf(" I/O Controller : %s (%s)\n",
+                                               vmd_domain_to_controller(hba, buf), get_sys_dev_type(hba->type));
+                                       print_vmd_attached_devs(hba);
+                                       printf("\n");
+                               }
+                       }
+                       continue;
+               }
 
-               if (imsm_orom_is_nvme(&entry->orom)) {
+               print_imsm_capability(&entry->orom);
+               if (entry->type == SYS_DEV_NVME) {
                        for (hba = list; hba; hba = hba->next) {
                                if (hba->type == SYS_DEV_NVME)
                                        printf("    NVMe Device : %s\n", hba->path);
                        }
+                       printf("\n");
                        continue;
                }
 
@@ -2000,16 +2080,25 @@ static int export_detail_platform_imsm(int verbose, char *controller_path)
        for (hba = list; hba; hba = hba->next) {
                if (controller_path && (compare_paths(hba->path,controller_path) != 0))
                        continue;
-               if (!find_imsm_capability(hba) && verbose > 0)
-                       pr_err("IMSM_DETAIL_PLATFORM_ERROR=NO_IMSM_CAPABLE_DEVICE_UNDER_%s\n", hba->path);
+               if (!find_imsm_capability(hba) && verbose > 0) {
+                       char buf[PATH_MAX];
+                       pr_err("IMSM_DETAIL_PLATFORM_ERROR=NO_IMSM_CAPABLE_DEVICE_UNDER_%s\n",
+                       hba->type == SYS_DEV_VMD ? vmd_domain_to_controller(hba, buf) : hba->path);
+               }
                else
                        result = 0;
        }
 
        const struct orom_entry *entry;
 
-       for (entry = orom_entries; entry; entry = entry->next)
+       for (entry = orom_entries; entry; entry = entry->next) {
+               if (entry->type == SYS_DEV_VMD) {
+                       for (hba = list; hba; hba = hba->next)
+                               print_imsm_capability_export(&entry->orom);
+                       continue;
+               }
                print_imsm_capability_export(&entry->orom);
+       }
 
        return result;
 }
@@ -3862,12 +3951,14 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de
                if (devname) {
                        struct intel_hba *hba = super->hba;
 
-                       pr_err("%s is attached to Intel(R) %s RAID controller (%s),\n"
-                               "    but the container is assigned to Intel(R) %s RAID controller (",
+                       pr_err("%s is attached to Intel(R) %s %s (%s),\n"
+                               "    but the container is assigned to Intel(R) %s %s (",
                                devname,
                                get_sys_dev_type(hba_name->type),
+                               hba_name->type == SYS_DEV_VMD ? "domain" : "RAID controller",
                                hba_name->pci_id ? : "Err!",
-                               get_sys_dev_type(super->hba->type));
+                               get_sys_dev_type(super->hba->type),
+                               hba->type == SYS_DEV_VMD ? "domain" : "RAID controller");
 
                        while (hba) {
                                fprintf(stderr, "%s", hba->pci_id ? : "Err!");
@@ -3876,7 +3967,8 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de
                                hba = hba->next;
                        }
                        fprintf(stderr, ").\n"
-                               "    Mixing devices attached to different controllers is not allowed.\n");
+                               "    Mixing devices attached to different %s is not allowed.\n",
+                               hba_name->type == SYS_DEV_VMD ? "VMD domains" : "controllers");
                }
                return 2;
        }
@@ -5878,7 +5970,6 @@ count_volumes(struct intel_hba *hba, int dpa, int verbose)
 
        devid_list = entry->devid_list;
        for (dv = devid_list; dv; dv = dv->next) {
-
                struct md_list *devlist = NULL;
                struct sys_dev *device = device_by_id(dv->devid);
                char *hba_path;
@@ -5889,6 +5980,14 @@ count_volumes(struct intel_hba *hba, int dpa, int verbose)
                else
                        return 0;
 
+               /* VMD has one orom entry for all domain, but spanning is not allowed.
+                * VMD arrays should be counted per domain (controller), so skip
+                * domains that are not the given one.
+                */
+               if ((hba->type == SYS_DEV_VMD) &&
+                  (strncmp(device->path, hba->path, strlen(device->path)) != 0))
+                       continue;
+
                devlist = get_devices(hba_path);
                /* if no intel devices return zero volumes */
                if (devlist == NULL)
@@ -9150,7 +9249,7 @@ int validate_container_imsm(struct mdinfo *info)
                        return 1;
                }
 
-               if (orom != orom2) {
+               if ((orom != orom2) || ((hba->type == SYS_DEV_VMD) && (hba != hba2))) {
                        pr_err("WARNING - IMSM container assembled with disks under different HBAs!\n"
                                "       This operation is not supported and can lead to data loss.\n");
                        return 1;
@@ -10277,7 +10376,7 @@ int wait_for_reshape_imsm(struct mdinfo *sra, int ndata)
        if (sysfs_fd_get_ll(fd, &completed) < 0) {
                dprintf("cannot read reshape_position (no reshape in progres)\n");
                close(fd);
-               return 0;
+               return 1;
        }
 
        if (completed > position_to_set) {
@@ -10297,11 +10396,14 @@ int wait_for_reshape_imsm(struct mdinfo *sra, int ndata)
 
        do {
                char action[20];
-               sysfs_wait(fd, NULL);
+               int timeout = 3000;
+               sysfs_wait(fd, &timeout);
                if (sysfs_get_str(sra, NULL, "sync_action",
                                  action, 20) > 0 &&
-                               strncmp(action, "reshape", 7) != 0)
-                       break;
+                               strncmp(action, "reshape", 7) != 0) {
+                       close(fd);
+                       return -1;
+               }
                if (sysfs_fd_get_ll(fd, &completed) < 0) {
                        dprintf("cannot read reshape_position (in loop)\n");
                        close(fd);
@@ -10366,7 +10468,7 @@ int check_degradation_change(struct mdinfo *info,
  * Function:   imsm_manage_reshape
  * Description:        Function finds array under reshape and it manages reshape
  *             process. It creates stripes backups (if required) and sets
- *             checheckpoits.
+ *             checkpoints.
  * Parameters:
  *     afd             : Backup handle (nattive) - not used
  *     sra             : general array info
@@ -10496,7 +10598,7 @@ static int imsm_manage_reshape(
 
                start = current_position * 512;
 
-               /* allign reading start to old geometry */
+               /* align reading start to old geometry */
                start_buf_shift = start % old_data_stripe_length;
                start_src = start - start_buf_shift;
 
@@ -10563,7 +10665,7 @@ static int imsm_manage_reshape(
                sra->reshape_progress = next_step;
 
                /* wait until reshape finish */
-               if (wait_for_reshape_imsm(sra, ndata) < 0) {
+               if (wait_for_reshape_imsm(sra, ndata)) {
                        dprintf("wait_for_reshape_imsm returned error!\n");
                        goto abort;
                }
@@ -10601,6 +10703,10 @@ static int imsm_manage_reshape(
        ret_val = 1;
 abort:
        free(buf);
+       /* See Grow.c: abort_reshape() for further explanation */
+       sysfs_set_num(sra, NULL, "suspend_lo", 0x7FFFFFFFFFFFFFFFULL);
+       sysfs_set_num(sra, NULL, "suspend_hi", 0);
+       sysfs_set_num(sra, NULL, "suspend_lo", 0);
 
        return ret_val;
 }