]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
Create: improve messages from validate_geometry.
[thirdparty/mdadm.git] / super-intel.c
index b4540137570402a8f1a27dec2936159ea6c8b60e..e9d9af80343a3b7d4fb3d31632c9839d021504a2 100644 (file)
 
 /* Define all supported attributes that have to be accepted by mdadm
  */
-#define MPB_ATTRIB_SUPPORTED           MPB_ATTRIB_CHECKSUM_VERIFY | \
+#define MPB_ATTRIB_SUPPORTED          (MPB_ATTRIB_CHECKSUM_VERIFY | \
                                        MPB_ATTRIB_2TB             | \
                                        MPB_ATTRIB_2TB_DISK        | \
                                        MPB_ATTRIB_RAID0           | \
                                        MPB_ATTRIB_RAID1           | \
                                        MPB_ATTRIB_RAID10          | \
                                        MPB_ATTRIB_RAID5           | \
-                                       MPB_ATTRIB_EXP_STRIPE_SIZE
+                                       MPB_ATTRIB_EXP_STRIPE_SIZE)
+
+/* Define attributes that are unused but not harmful */
+#define MPB_ATTRIB_IGNORED             (MPB_ATTRIB_NEVER_USE)
 
 #define MPB_SECTOR_CNT 2210
 #define IMSM_RESERVED_SECTORS 4096
@@ -830,7 +833,16 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl)
        struct extent *rv, *e;
        int i;
        int memberships = count_memberships(dl, super);
-       __u32 reservation = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS;
+       __u32 reservation;
+
+       /* trim the reserved area for spares, so they can join any array
+        * regardless of whether the OROM has assigned sectors from the
+        * IMSM_RESERVED_SECTORS region
+        */
+       if (dl->index == -1)
+               reservation = MPB_SECTOR_CNT;
+       else
+               reservation = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS;
 
        rv = malloc(sizeof(struct extent) * (memberships + 1));
        if (!rv)
@@ -1056,18 +1068,20 @@ static void print_imsm_dev(struct intel_super *super,
        printf("    Dirty State : %s\n", dev->vol.dirty ? "dirty" : "clean");
 }
 
-static void print_imsm_disk(struct imsm_super *mpb, int index, __u32 reserved)
+static void print_imsm_disk(struct imsm_disk *disk, int index, __u32 reserved)
 {
-       struct imsm_disk *disk = __get_imsm_disk(mpb, index);
        char str[MAX_RAID_SERIAL_LEN + 1];
        __u64 sz;
 
-       if (index < 0 || !disk)
+       if (index < -1 || !disk)
                return;
 
        printf("\n");
        snprintf(str, MAX_RAID_SERIAL_LEN + 1, "%s", disk->serial);
-       printf("  Disk%02d Serial : %s\n", index, str);
+       if (index >= 0)
+               printf("  Disk%02d Serial : %s\n", index, str);
+       else
+               printf("    Disk Serial : %s\n", str);
        printf("          State :%s%s%s\n", is_spare(disk) ? " spare" : "",
                                            is_configured(disk) ? " active" : "",
                                            is_failed(disk) ? " failed" : "");
@@ -1141,11 +1155,14 @@ void examine_migr_rec_imsm(struct intel_super *super)
 static int imsm_check_attributes(__u32 attributes)
 {
        int ret_val = 1;
-       __u32 not_supported = (MPB_ATTRIB_SUPPORTED)^0xffffffff;
+       __u32 not_supported = MPB_ATTRIB_SUPPORTED^0xffffffff;
+
+       not_supported &= ~MPB_ATTRIB_IGNORED;
 
        not_supported &= attributes;
        if (not_supported) {
-               fprintf(stderr, Name "(IMSM): Unsupported attributes : %x\n", not_supported);
+               fprintf(stderr, Name "(IMSM): Unsupported attributes : %x\n",
+                       (unsigned)__le32_to_cpu(not_supported));
                if (not_supported & MPB_ATTRIB_CHECKSUM_VERIFY) {
                        dprintf("\t\tMPB_ATTRIB_CHECKSUM_VERIFY \n");
                        not_supported ^= MPB_ATTRIB_CHECKSUM_VERIFY;
@@ -1248,7 +1265,7 @@ static void examine_super_imsm(struct supertype *st, char *homehost)
        printf("    MPB Sectors : %d\n", mpb_sectors(mpb));
        printf("          Disks : %d\n", mpb->num_disks);
        printf("   RAID Devices : %d\n", mpb->num_raid_devs);
-       print_imsm_disk(mpb, super->disks->index, reserved);
+       print_imsm_disk(__get_imsm_disk(mpb, super->disks->index), super->disks->index, reserved);
        if (super->bbm_log) {
                struct bbm_log *log = super->bbm_log;
 
@@ -1273,28 +1290,12 @@ static void examine_super_imsm(struct supertype *st, char *homehost)
        for (i = 0; i < mpb->num_disks; i++) {
                if (i == super->disks->index)
                        continue;
-               print_imsm_disk(mpb, i, reserved);
+               print_imsm_disk(__get_imsm_disk(mpb, i), i, reserved);
        }
-       for (dl = super->disks ; dl; dl = dl->next) {
-               struct imsm_disk *disk;
-               char str[MAX_RAID_SERIAL_LEN + 1];
-               __u64 sz;
 
-               if (dl->index >= 0)
-                       continue;
-
-               disk = &dl->disk;
-               printf("\n");
-               snprintf(str, MAX_RAID_SERIAL_LEN + 1, "%s", disk->serial);
-               printf("    Disk Serial : %s\n", str);
-               printf("          State :%s%s%s\n", is_spare(disk) ? " spare" : "",
-                      is_configured(disk) ? " active" : "",
-                      is_failed(disk) ? " failed" : "");
-               printf("             Id : %08x\n", __le32_to_cpu(disk->scsi_id));
-               sz = __le32_to_cpu(disk->total_blocks) - reserved;
-               printf("    Usable Size : %llu%s\n", (unsigned long long)sz,
-                      human_size(sz * 512));
-       }
+       for (dl = super->disks; dl; dl = dl->next)
+               if (dl->index == -1)
+                       print_imsm_disk(&dl->disk, -1, reserved);
 
        examine_migr_rec_imsm(super);
 }
@@ -2268,7 +2269,8 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
                info->disk.major = dl->major;
                info->disk.minor = dl->minor;
                info->disk.number = dl->index;
-               info->disk.raid_disk = dl->index;
+               info->disk.raid_disk = get_imsm_disk_slot(map_to_analyse,
+                                                         dl->index);
        }
 
        info->data_offset         = __le32_to_cpu(map_to_analyse->pba_of_lba0);
@@ -2873,7 +2875,6 @@ static void serialcpy(__u8 *dest, __u8 *src)
        strncpy((char *) dest, (char *) src, MAX_RAID_SERIAL_LEN);
 }
 
-#ifndef MDASSEMBLE
 static struct dl *serial_to_dl(__u8 *serial, struct intel_super *super)
 {
        struct dl *dl;
@@ -2884,7 +2885,6 @@ static struct dl *serial_to_dl(__u8 *serial, struct intel_super *super)
 
        return dl;
 }
-#endif
 
 static struct imsm_disk *
 __serial_to_disk(__u8 *serial, struct imsm_super *mpb, int *idx)
@@ -3442,7 +3442,6 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de
        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
  * the mpb being uptodate, which it is at load time.
@@ -3478,6 +3477,7 @@ static int find_missing(struct intel_super *super)
        return 0;
 }
 
+#ifndef MDASSEMBLE
 static struct intel_disk *disk_list_get(__u8 *serial, struct intel_disk *disk_list)
 {
        struct intel_disk *idisk = disk_list;
@@ -4131,12 +4131,40 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
                memset(mpb_new + size_old, 0, size_round - size_old);
        }
        super->current_vol = idx;
-       /* when creating the first raid device in this container set num_disks
-        * to zero, i.e. delete this spare and add raid member devices in
-        * add_to_super_imsm_volume()
+
+       /* handle 'failed_disks' by either:
+        * a) create dummy disk entries in the table if this the first
+        *    volume in the array.  We add them here as this is the only
+        *    opportunity to add them. add_to_super_imsm_volume()
+        *    handles the non-failed disks and continues incrementing
+        *    mpb->num_disks.
+        * b) validate that 'failed_disks' matches the current number
+        *    of missing disks if the container is populated
         */
-       if (super->current_vol == 0)
+       if (super->current_vol == 0) {
                mpb->num_disks = 0;
+               for (i = 0; i < info->failed_disks; i++) {
+                       struct imsm_disk *disk;
+
+                       mpb->num_disks++;
+                       disk = __get_imsm_disk(mpb, i);
+                       disk->status = CONFIGURED_DISK | FAILED_DISK;
+                       disk->scsi_id = __cpu_to_le32(~(__u32)0);
+                       snprintf((char *) disk->serial, MAX_RAID_SERIAL_LEN,
+                                "missing:%d", i);
+               }
+               find_missing(super);
+       } else {
+               int missing = 0;
+               struct dl *d;
+
+               for (d = super->missing; d; d = d->next)
+                       missing++;
+               if (info->failed_disks > missing) {
+                       fprintf(stderr, Name": unable to add 'missing' disk to container\n");
+                       return 0;
+               }
+       }
 
        if (!check_name(super, name, 0))
                return 0;
@@ -4168,15 +4196,14 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        vol = &dev->vol;
        vol->migr_state = 0;
        set_migr_type(dev, MIGR_INIT);
-       vol->dirty = 0;
+       vol->dirty = !info->state;
        vol->curr_migr_unit = 0;
        map = get_imsm_map(dev, 0);
        map->pba_of_lba0 = __cpu_to_le32(super->create_offset);
        map->blocks_per_member = __cpu_to_le32(info_to_blocks_per_member(info));
        map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info));
        map->failed_disk_num = ~0;
-       map->map_state = info->level ? IMSM_T_STATE_UNINITIALIZED :
-                                      IMSM_T_STATE_NORMAL;
+       map->map_state = info->failed_disks ? IMSM_T_STATE_DEGRADED : IMSM_T_STATE_NORMAL;
        map->ddf = 1;
 
        if (info->level == 1 && info->raid_disks > 2) {
@@ -4284,9 +4311,10 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
 {
        struct intel_super *super = st->sb;
        struct imsm_super *mpb = super->anchor;
-       struct dl *dl;
+       struct imsm_disk *_disk;
        struct imsm_dev *dev;
        struct imsm_map *map;
+       struct dl *dl, *df;
        int slot;
 
        dev = get_imsm_dev(super, super->current_vol);
@@ -4330,15 +4358,40 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
                        devname);
                return 1;
        }
-       set_imsm_ord_tbl_ent(map, dk->number, dl->index);
+       set_imsm_ord_tbl_ent(map, dk->raid_disk, dl->index);
        dl->disk.status = CONFIGURED_DISK;
 
+       /* update size of 'missing' disks to be at least as large as the
+        * largest acitve member (we only have dummy missing disks when
+        * creating the first volume)
+        */
+       if (super->current_vol == 0) {
+               for (df = super->missing; df; df = df->next) {
+                       if (dl->disk.total_blocks > df->disk.total_blocks)
+                               df->disk.total_blocks = dl->disk.total_blocks;
+                       _disk = __get_imsm_disk(mpb, df->index);
+                       *_disk = df->disk;
+               }
+       }
+
+       /* refresh unset/failed slots to point to valid 'missing' entries */
+       for (df = super->missing; df; df = df->next)
+               for (slot = 0; slot < mpb->num_disks; slot++) {
+                       __u32 ord = get_imsm_ord_tbl_ent(dev, slot, -1);
+
+                       if ((ord & IMSM_ORD_REBUILD) == 0)
+                               continue;
+                       set_imsm_ord_tbl_ent(map, slot, df->index | IMSM_ORD_REBUILD);
+                       dprintf("set slot:%d to missing disk:%d\n", slot, df->index);
+                       break;
+               }
+
        /* if we are creating the first raid device update the family number */
        if (super->current_vol == 0) {
                __u32 sum;
                struct imsm_dev *_dev = __get_imsm_dev(mpb, 0);
-               struct imsm_disk *_disk = __get_imsm_disk(mpb, dl->index);
 
+               _disk = __get_imsm_disk(mpb, dl->index);
                if (!_dev || !_disk) {
                        fprintf(stderr, Name ": BUG mpb setup error\n");
                        return 1;
@@ -4354,6 +4407,37 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
        return 0;
 }
 
+/* mark_spare()
+ *   Function marks disk as spare and restores disk serial
+ *   in case it was previously marked as failed by takeover operation
+ * reruns:
+ *   -1 : critical error
+ *    0 : disk is marked as spare but serial is not set
+ *    1 : success
+ */
+int mark_spare(struct dl *disk)
+{
+       __u8 serial[MAX_RAID_SERIAL_LEN];
+       int ret_val = -1;
+
+       if (!disk)
+               return ret_val;
+
+       ret_val = 0;
+       if (!imsm_read_serial(disk->fd, NULL, serial)) {
+               /* Restore disk serial number, because takeover marks disk
+                * as failed and adds to serial ':0' before it becomes
+                * a spare disk.
+                */
+               serialcpy(disk->serial, serial);
+               serialcpy(disk->disk.serial, serial);
+               ret_val = 1;
+       }
+       disk->disk.status = SPARE_DISK;
+       disk->index = -1;
+
+       return ret_val;
+}
 
 static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
                             int fd, char *devname)
@@ -4391,7 +4475,6 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
        memset(dd, 0, sizeof(*dd));
        dd->major = major(stb.st_rdev);
        dd->minor = minor(stb.st_rdev);
-       dd->index = -1;
        dd->devname = devname ? strdup(devname) : NULL;
        dd->fd = fd;
        dd->e = NULL;
@@ -4408,7 +4491,7 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
        size /= 512;
        serialcpy(dd->disk.serial, dd->serial);
        dd->disk.total_blocks = __cpu_to_le32(size);
-       dd->disk.status = SPARE_DISK;
+       mark_spare(dd);
        if (sysfs_disk_to_scsi_id(fd, &id) == 0)
                dd->disk.scsi_id = __cpu_to_le32(id);
        else
@@ -4451,9 +4534,8 @@ static int remove_from_super_imsm(struct supertype *st, mdu_disk_info_t *dk)
        memset(dd, 0, sizeof(*dd));
        dd->major = dk->major;
        dd->minor = dk->minor;
-       dd->index = -1;
        dd->fd = -1;
-       dd->disk.status = SPARE_DISK;
+       mark_spare(dd);
        dd->action = DISK_REMOVE;
 
        dd->next = super->disk_mgmt_list;
@@ -4577,7 +4659,7 @@ static int write_super_imsm(struct supertype *st, int doclose)
 
        /* write the mpb for disks that compose raid devices */
        for (d = super->disks; d ; d = d->next) {
-               if (d->index < 0)
+               if (d->index < 0 || is_failed(&d->disk))
                        continue;
                if (store_imsm_mpb(d->fd, mpb))
                        fprintf(stderr, "%s: failed for device %d:%d %s\n",
@@ -4926,28 +5008,19 @@ static int imsm_default_chunk(const struct imsm_orom *orom)
 }
 
 #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 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);
+       /* check/set platform and metadata limits/defaults */
+       if (super->orom && raiddisks > super->orom->dpa) {
+               pr_vrb(": platform supports a maximum of %d disks per array\n",
+                      super->orom->dpa);
                return 0;
        }
 
         /* capabilities of OROM tested - copied from validate_geometry_imsm_volume */
-       if (super->orom && (!is_raid_level_supported(super->orom, level,
-                                                    raiddisks))) {
+       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" : "");
                return 0;
@@ -4997,6 +5070,12 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
        if (!super)
                return 0;
 
+       if (mpb->num_raid_devs > 0 && mpb->num_disks != raiddisks) {
+               fprintf(stderr, Name ": the option-rom requires all "
+                       "member disks to be a member of all volumes.\n");
+               return 0;
+       }
+
        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");
@@ -5290,7 +5369,8 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                        return validate_geometry_imsm_volume(st, level, layout,
                                                             raiddisks, chunk,
                                                             size, dev,
-                                                            freesize, verbose);
+                                                            freesize, 1)
+                               ? 1 : -1;
                }
        }
 
@@ -5380,10 +5460,8 @@ static int kill_subarray_imsm(struct supertype *st)
                struct dl *d;
 
                for (d = super->disks; d; d = d->next)
-                       if (d->index > -2) {
-                               d->index = -1;
-                               d->disk.status = SPARE_DISK;
-                       }
+                       if (d->index > -2)
+                               mark_spare(d);
        }
 
        super->updates_pending++;
@@ -5842,6 +5920,8 @@ 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);
@@ -5854,6 +5934,11 @@ 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)
@@ -6960,8 +7045,7 @@ static int apply_takeover_update(struct imsm_update_takeover *u,
                                        if (du->index > idx)
                                                du->index--;
                                /* mark as spare disk */
-                               dm->disk.status = SPARE_DISK;
-                               dm->index = -1;
+                               mark_spare(dm);
                        }
                }
                /* update map */