aboutsummaryrefslogtreecommitdiffstats
path: root/main/dmraid/003-isw-probe-hpa.patch
blob: 93756a92556e7ee2f77051f0e61efd4eea6efb66 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
Probe isw disks with [some] HPA awareness, thanks to Robert Collins <robert@ubuntu.com>. (LP: #372170)
--- dmraid/lib/format/ataraid/isw.c
+++ 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 *
--- dmraid/lib/format/ataraid/isw.h
+++ 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);