Probe isw disks with [some] HPA awareness, thanks to Robert Collins . (LP: #372170) --- a/1.0.0.rc16/lib/format/ataraid/isw.c +++ b/1.0.0.rc16/lib/format/ataraid/isw.c @@ -353,6 +353,7 @@ raiddev(struct isw *isw, unsigned i) enum convert { FULL, FIRST, LAST }; #if BYTE_ORDER == LITTLE_ENDIAN # define to_cpu(x, y) +# define CVT16(x) #else /* * We can differ from the read_raid_dev template here, @@ -547,15 +548,16 @@ disk_ok(struct lib_context *lc, struct d } static void * -isw_read_metadata(struct lib_context *lc, struct dev_info *di, - size_t * sz, uint64_t * offset, union read_info *info) +isw_try_sboffset(struct lib_context *lc, struct dev_info *di, + size_t * sz, uint64_t * offset, union read_info *info, + uint64_t const isw_sboffset) { size_t size = ISW_DISK_BLOCK_SIZE; - uint64_t isw_sboffset = ISW_CONFIGOFFSET(di); struct isw *isw; + uint64_t temp_isw_sboffset = isw_sboffset; if (!(isw = alloc_private_and_read(lc, handler, size, - di->path, isw_sboffset))) + di->path, temp_isw_sboffset))) goto out; /* @@ -565,9 +567,15 @@ isw_read_metadata(struct lib_context *lc to_cpu(isw, FIRST); /* Check Signature and read optional extended metadata. */ - if (!is_isw(lc, di, isw) || - !isw_read_extended(lc, di, &isw, &isw_sboffset, &size)) + if (!is_isw(lc, di, isw)) { + log_dbg(lc, "not isw at %ld", isw_sboffset); goto bad; + } + if (!isw_read_extended(lc, di, &isw, &temp_isw_sboffset, &size)) { + log_err(lc, "isw metadata, but extended read failed at %ld", + isw_sboffset); + goto bad; + } /* * Now that we made sure, that we've got all the @@ -578,6 +586,8 @@ isw_read_metadata(struct lib_context *lc if (disk_ok(lc, di, isw)) { *sz = size; *offset = info->u64 = isw_sboffset; + log_dbg(lc, "isw metadata found at %ld from probe at %ld\n", + *offset, isw_sboffset); goto out; } @@ -589,6 +599,54 @@ out: return (void *) isw; } +/* HPA on a disk shifts everything down. This is a 'works-enough' approach to + * handling that. There is a better long term approach requiring kernel + * patches - see the lkml patches for alt_size. + */ +static void * +isw_try_hpa(struct lib_context *lc, struct dev_info *di, + size_t * sz, uint64_t * offset, union read_info *info) +{ + struct isw10 *isw10; + void *result = NULL; + uint64_t actual_offset; + if (!(isw10 = alloc_private_and_read(lc, handler, ISW_DISK_BLOCK_SIZE, + di->path, ISW_10_CONFIGOFFSET(di)))) + goto out; + if (strncmp((const char *)isw10->sig, ISW10_SIGNATURE, ISW10_SIGNATURE_SIZE)) + goto out_free; + log_dbg(lc, "Found isw 10 gafr signature."); + CVT16(isw10->offset); + actual_offset = isw10->offset + 2; + log_dbg(lc, "isw 10 sector offset calculated at %hd.", actual_offset); + if (actual_offset > di->sectors) + goto out_free; + result = isw_try_sboffset(lc, di, sz, offset, info, + ISW_SECTOR_TO_OFFSET(di->sectors - actual_offset)); + out_free: + dbg_free(isw10); + out: + return result; +} + + +static void * +isw_read_metadata(struct lib_context *lc, struct dev_info *di, + size_t * sz, uint64_t * offset, union read_info *info) +{ + void *result; + if ((result = isw_try_sboffset( + lc, di, sz, offset, info, ISW_CONFIGOFFSET(di)))) + return result; + if ((result = isw_try_hpa(lc, di, sz, offset, info))) + return result; + log_dbg(lc, "isw trying hard coded -2115 offset."); + if ((result = isw_try_sboffset( + lc, di, sz, offset, info, (di->sectors - 2115)*512))) + return result; + return NULL; +} + static int setup_rd(struct lib_context *lc, struct raid_dev *rd, struct dev_info *di, void *meta, union read_info *info); static struct raid_dev * --- a/1.0.0.rc16/lib/format/ataraid/isw.h +++ b/1.0.0.rc16/lib/format/ataraid/isw.h @@ -36,8 +36,11 @@ /* Intel metadata offset in bytes */ #define ISW_CONFIGSECTOR(di) ((di)->sectors - 2) -#define ISW_CONFIGOFFSET(di) (ISW_CONFIGSECTOR(di) << 9) +#define ISW_SECTOR_TO_OFFSET(sector) ((sector) << 9) +#define ISW_CONFIGOFFSET(di) (ISW_SECTOR_TO_OFFSET(ISW_CONFIGSECTOR(di))) #define ISW_DATAOFFSET 0 /* Data offset in sectors */ +#define ISW_10_CONFIGSECTOR(di) ((di)->sectors - 1) +#define ISW_10_CONFIGOFFSET(di) (ISW_SECTOR_TO_OFFSET(ISW_10_CONFIGSECTOR(di))) #define MPB_SIGNATURE "Intel Raid ISM Cfg Sig. " #define MPB_SIGNATURE_SIZE (sizeof(MPB_SIGNATURE) - 1) @@ -222,6 +225,14 @@ struct isw { // here comes isw_dev[num_raid_devs] } __attribute__ ((packed)); +#define ISW10_SIGNATURE "$GAFR\x10" +#define ISW10_SIGNATURE_SIZE (sizeof(ISW10_SIGNATURE) - 1) +struct isw10 { + int8_t sig[ISW10_SIGNATURE_SIZE]; + uint32_t offset; /* offset to real data, in sectors back */ +} __attribute__ ((packed)); + + #endif int register_isw(struct lib_context *lc);