void-packages/srcpkgs/dmraid/patches/003-isw-probe-hpa.patch

144 lines
4.7 KiB
Diff

Probe isw disks with [some] HPA awareness, thanks to Robert Collins <robert@ubuntu.com>. (LP: #372170)
--- 1.0.0.rc16-3/dmraid/lib/format/ataraid/isw.c
+++ 1.0.0.rc16-3/dmraid/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 *
--- 1.0.0.rc16-3/dmraid/lib/format/ataraid/isw.h
+++ 1.0.0.rc16-3/dmraid/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);