summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2008-12-08 16:59:18 -0700
committerDan Williams <dan.j.williams@intel.com>2008-12-08 16:59:18 -0700
commit88c32bb1ec5d0c12eb557c4f46832fa4e1076784 (patch)
tree937a3f618adcb035b81e9a69e64bd0056f466679
parent25921536da17d72dccc9aed736ce5f26ba08b4cb (diff)
downloadmdadm-88c32bb1ec5d0c12eb557c4f46832fa4e1076784.tar.gz
mdadm-88c32bb1ec5d0c12eb557c4f46832fa4e1076784.tar.xz
mdadm-88c32bb1ec5d0c12eb557c4f46832fa4e1076784.zip
imsm: validate arrays being created against firmware capabilities
These checks are only enabled when platform support for imsm is found, i.e. ahci driver is loaded and talking to an Intel(R) controller, and the option rom header is located. They can be turned off by setting the environment variable IMSM_NO_PLATFORM to 1. Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r--Makefile13
-rw-r--r--platform-intel.h37
-rw-r--r--super-intel.c99
3 files changed, 135 insertions, 14 deletions
diff --git a/Makefile b/Makefile
index afbd712..7f27aa4 100644
--- a/Makefile
+++ b/Makefile
@@ -76,23 +76,28 @@ OBJS = mdadm.o config.o mdstat.o ReadMe.o util.o Manage.o Assemble.o Build.o \
Create.o Detail.o Examine.o Grow.o Monitor.o dlink.o Kill.o Query.o \
Incremental.o \
mdopen.o super0.o super1.o super-ddf.o super-intel.o bitmap.o \
- restripe.o sysfs.o sha1.o mapfile.o crc32.o sg_io.o msg.o
+ restripe.o sysfs.o sha1.o mapfile.o crc32.o sg_io.o msg.o \
+ platform-intel.o probe_roms.o
+
SRCS = mdadm.c config.c mdstat.c ReadMe.c util.c Manage.c Assemble.c Build.c \
Create.c Detail.c Examine.c Grow.c Monitor.c dlink.c Kill.c Query.c \
Incremental.c \
mdopen.c super0.c super1.c super-ddf.c super-intel.c bitmap.c \
- restripe.c sysfs.c sha1.c mapfile.c crc32.c sg_io.c msg.c
+ restripe.c sysfs.c sha1.c mapfile.c crc32.c sg_io.c msg.c \
+ platform-intel.c probe_roms.c
MON_OBJS = mdmon.o monitor.o managemon.o util.o mdstat.o sysfs.o config.o \
Kill.o sg_io.o dlink.o ReadMe.o super0.o super1.o super-intel.o \
- super-ddf.o sha1.o crc32.o msg.o Monitor.o bitmap.o
+ super-ddf.o sha1.o crc32.o msg.o Monitor.o bitmap.o \
+ platform-intel.o probe_roms.o
STATICSRC = pwgr.c
STATICOBJS = pwgr.o
ASSEMBLE_SRCS := mdassemble.c Assemble.c Manage.c config.c dlink.c util.c \
- super0.c super1.c super-ddf.c super-intel.c sha1.c crc32.c sg_io.c mdstat.c
+ super0.c super1.c super-ddf.c super-intel.c sha1.c crc32.c sg_io.c mdstat.c \
+ platform-intel.c probe_roms.c
ASSEMBLE_AUTO_SRCS := mdopen.c sysfs.c
ASSEMBLE_FLAGS:= $(CFLAGS) -DMDASSEMBLE
ifdef MDASSEMBLE_AUTO
diff --git a/platform-intel.h b/platform-intel.h
index c126482..bbdc9f9 100644
--- a/platform-intel.h
+++ b/platform-intel.h
@@ -17,6 +17,7 @@
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <asm/types.h>
+#include <strings.h>
/* The IMSM OROM Version Table definition */
struct imsm_orom {
@@ -78,6 +79,42 @@ struct imsm_orom {
__u32 reserved2;
} __attribute__((packed));
+static inline int imsm_orom_has_raid0(const struct imsm_orom *orom)
+{
+ return !!(orom->rlc & IMSM_OROM_RLC_RAID0);
+}
+static inline int imsm_orom_has_raid1(const struct imsm_orom *orom)
+{
+ return !!(orom->rlc & IMSM_OROM_RLC_RAID1);
+}
+static inline int imsm_orom_has_raid1e(const struct imsm_orom *orom)
+{
+ return !!(orom->rlc & IMSM_OROM_RLC_RAID1E);
+}
+static inline int imsm_orom_has_raid10(const struct imsm_orom *orom)
+{
+ return !!(orom->rlc & IMSM_OROM_RLC_RAID10);
+}
+static inline int imsm_orom_has_raid5(const struct imsm_orom *orom)
+{
+ return !!(orom->rlc & IMSM_OROM_RLC_RAID5);
+}
+
+/**
+ * imsm_orom_has_chunk - check if the orom supports the given chunk size
+ * @orom: orom pointer from find_imsm_orom
+ * @chunk: chunk size in kibibytes
+ */
+static inline int imsm_orom_has_chunk(const struct imsm_orom *orom, int chunk)
+{
+ int fs = ffs(chunk);
+
+ if (!fs)
+ return 0;
+ fs--; /* bit num to bit index */
+ return !!(orom->sss & (1 << (fs - 1)));
+}
+
struct sys_dev {
char *path;
struct sys_dev *next;
diff --git a/super-intel.c b/super-intel.c
index 7066e8e..abc3206 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -21,6 +21,7 @@
#include "mdadm.h"
#include "mdmon.h"
#include "sha1.h"
+#include "platform-intel.h"
#include <values.h>
#include <scsi/sg.h>
#include <ctype.h>
@@ -230,6 +231,8 @@ struct intel_super {
struct dl *add; /* list of disks to add while mdmon active */
struct dl *missing; /* disks removed while we weren't looking */
struct bbm_log *bbm_log;
+ const char *hba; /* device path of the raid controller for this metadata */
+ const struct imsm_orom *orom; /* platform firmware support */
};
struct extent {
@@ -1505,6 +1508,10 @@ static void __free_imsm(struct intel_super *super, int free_disks)
free(super->dev_tbl[i]);
super->dev_tbl[i] = NULL;
}
+ if (super->hba) {
+ free((void *) super->hba);
+ super->hba = NULL;
+ }
}
static void free_imsm(struct intel_super *super)
@@ -1533,6 +1540,22 @@ static struct intel_super *alloc_super(int creating_imsm)
super->creating_imsm = creating_imsm;
super->current_vol = -1;
super->create_offset = ~((__u32 ) 0);
+ if (!check_env("IMSM_NO_PLATFORM"))
+ super->orom = find_imsm_orom();
+ if (super->orom) {
+ struct sys_dev *list, *ent;
+
+ /* find the first intel ahci controller */
+ list = find_driver_devices("pci", "ahci");
+ for (ent = list; ent; ent = ent->next)
+ if (devpath_to_vendor(ent->path) == 0x8086)
+ break;
+ if (ent) {
+ super->hba = ent->path;
+ ent->path = NULL;
+ }
+ free_sys_dev(&list);
+ }
}
return super;
@@ -1817,9 +1840,9 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
unsigned long long array_blocks;
size_t size_old, size_new;
- if (mpb->num_raid_devs >= 2) {
+ if (super->orom && mpb->num_raid_devs >= super->orom->vpa) {
fprintf(stderr, Name": This imsm-container already has the "
- "maximum of 2 volumes\n");
+ "maximum of %d volumes\n", super->orom->vpa);
return 0;
}
@@ -2014,6 +2037,16 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
int rv;
struct stat stb;
+ /* if we are on an RAID enabled platform check that the disk is
+ * attached to the raid controller
+ */
+ if (super->hba && !disk_attached_to_hba(fd, super->hba)) {
+ fprintf(stderr,
+ Name ": %s is not attached to the raid controller: %s\n",
+ devname ? : "disk", super->hba);
+ return 1;
+ }
+
if (super->current_vol >= 0)
return add_to_super_imsm_volume(st, dk, fd, devname);
@@ -2282,12 +2315,25 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
{
int fd;
unsigned long long ldsize;
+ const struct imsm_orom *orom;
if (level != LEVEL_CONTAINER)
return 0;
if (!dev)
return 1;
+ if (check_env("IMSM_NO_PLATFORM"))
+ orom = NULL;
+ else
+ orom = find_imsm_orom();
+ if (orom && raiddisks > orom->tds) {
+ if (verbose)
+ fprintf(stderr, Name ": %d exceeds maximum number of"
+ " platform supported disks: %d\n",
+ raiddisks, orom->tds);
+ return 0;
+ }
+
fd = open(dev, O_RDONLY|O_EXCL, 0);
if (fd < 0) {
if (verbose)
@@ -2408,6 +2454,30 @@ static unsigned long long merge_extents(struct intel_super *super, int sum_exten
return maxsize - reserve;
}
+static int is_raid_level_supported(const struct imsm_orom *orom, int level, int raiddisks)
+{
+ if (level < 0 || level == 6 || level == 4)
+ return 0;
+
+ /* if we have an orom prevent invalid raid levels */
+ if (orom)
+ switch (level) {
+ case 0: return imsm_orom_has_raid0(orom);
+ case 1:
+ if (raiddisks > 2)
+ return imsm_orom_has_raid1e(orom);
+ else
+ return imsm_orom_has_raid1(orom);
+ case 10: return imsm_orom_has_raid10(orom);
+ case 5: return imsm_orom_has_raid5(orom);
+ }
+ else
+ return 1; /* not on an Intel RAID platform so anything goes */
+
+ return 0;
+}
+
+#define vprintf(fmt, arg...) (void) (verbose && fprintf(stderr, Name fmt, ##arg))
/* validate_geometry_imsm_volume - lifted from validate_geometry_ddf_bvd
* FIX ME add ahci details
*/
@@ -2425,19 +2495,28 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
struct extent *e;
int i;
- if (level == LEVEL_CONTAINER)
+ /* We must have the container info already read in. */
+ if (!super)
return 0;
- if (level == 1 && raiddisks > 2) {
- if (verbose)
- fprintf(stderr, Name ": imsm does not support more "
- "than 2 in a raid1 configuration\n");
+ if (!is_raid_level_supported(super->orom, level, raiddisks)) {
+ vprintf(": platform does not support raid level: %d\n", level);
return 0;
}
-
- /* We must have the container info already read in. */
- if (!super)
+ if (super->orom && !imsm_orom_has_chunk(super->orom, chunk)) {
+ vprintf(": platform does not support a chunk size of: %d\n", chunk);
return 0;
+ }
+ if (layout != imsm_level_to_layout(level)) {
+ if (level == 5)
+ vprintf(": imsm raid 5 only supports the left-asymmetric layout\n");
+ else if (level == 10)
+ vprintf(": imsm raid 10 only supports the n2 layout\n");
+ else
+ vprintf(": imsm unknown layout %#x for this raid level %d\n",
+ layout, level);
+ return 0;
+ }
if (!dev) {
/* General test: make sure there is space for