public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [ANNOUNCE] Highpoint-Tech Plugin 0.0.1 for EVMS 2.3.0
@ 2004-03-14 14:04 Wilfried Weissmann
  0 siblings, 0 replies; only message in thread
From: Wilfried Weissmann @ 2004-03-14 14:04 UTC (permalink / raw)
  To: evms-devel; +Cc: Sergey Vlasov, Kernel Mailing List

[-- Attachment #1: Type: text/plain, Size: 1646 bytes --]

hi,

...so here comes 0.0.1! i have changed the device manager id to 3 
because of Kevin Corry suggested this and also added more pci-ids. you 
can override the id scan be setting "biosraid.ignore_pci_ids" to "1". 
but you still need the proper raid signatures on your disks to get a 
raid volume.
basic read/write tests on a fat partition worked fine, but i cannot do 
more right now. the fan of my graphiccard is broken and i replaced the 
cooler with cpu heatsink and attached it with a string to the board. 
looks pretty crude!

Changelog:
* use new list API
* migrate to evms 2.3.0
* support for HPT 370, 370A, 302, 371, 375, 372N chipsets
* remove disk if it cannot be added the discover() output_list
* make all global variables static
* add boolean "biosraid.ignore_pci_ids" config option to optionally
ignore the pci vendor and device ids of the ide controllers
* changed EVMS_DEVICE_MANAGER ID to 3


TODOs:
* access to the last sector (kernel 2.6 only)
* add mode raid levels
* create "whole disk" volume (currently only under .nodes)
* use sysfs for scanning
* more modular design to make it easier to add code for other controllers
* more testing

the next thing that i want to do is to implement the "whole disk" 
volume. it might be handy to have such a device for the grub bootloader 
and stuff. this also is a start for the last sector problem fix. the 
problem is that i should protect the sector #9 which contains the volume 
configuration. i do not think that it is possible to only write protect 
that sector but this would be a nice thing to do.
the patch that applies against evms 2.3.0 is attached...

greetings,
wilfried

[-- Attachment #2: evms-2.3.0-bios-0.0.1.patch --]
[-- Type: text/plain, Size: 50854 bytes --]

diff -Nurp evms-2.3.0/aclocal.m4 evms-2.3.0-bios/aclocal.m4
--- evms-2.3.0/aclocal.m4	2004-02-16 14:47:26.000000000 -0600
+++ evms-2.3.0-bios/aclocal.m4	2004-03-09 21:03:42.000000000 -0600
@@ -126,11 +126,16 @@ AC_ARG_ENABLE([rsct],
 			     [Disable the RSCT plugin]),
 	      [build_rsct="$enableval"],
 	      [build_rsct="yes"])
+ AC_ARG_ENABLE([bios],
+ 	      AC_HELP_STRING([--disable-bios],
+ 			     [Disable the BIOS plugin]),
+ 	      [build_bios="$enableval"],
+ 	      [build_bios="yes"])
 
 # Create the list of plugin directories to build. This is where each plugin
 # can specify its dependencies.
 plugin_dirs=""
-plugin_distdirs="bbr bbr_seg bsd csm disk dos drivelink ext2 gpt ha jfs lvm mac md multipath ogfs reiser replace rsct s390 snapshot swap xfs"
+plugin_distdirs="bbr bbr_seg bsd csm disk dos drivelink ext2 gpt ha jfs lvm mac md multipath ogfs reiser replace rsct s390 snapshot swap xfs bios"
 
 # BBR
 if test "$build_bbr" = "no"; then
@@ -340,6 +345,14 @@ else
 	AC_MSG_NOTICE([     building xfs])
 fi
 
+# bios
+if test "$build_bios" = "no"; then
+	AC_MSG_NOTICE([     not building bios ... disabled by user])
+else
+	plugin_dirs="$plugin_dirs bios"
+	AC_MSG_NOTICE([     building bios])
+fi
+
 AC_SUBST(plugin_dirs)
 AC_SUBST(plugin_distdirs)
 ])
diff -Nurp evms-2.3.0/configure evms-2.3.0-bios/configure
--- evms-2.3.0/configure	2004-03-02 21:19:10.000000000 -0600
+++ evms-2.3.0-bios/configure	2004-03-14 14:38:15.000000000 -0600
@@ -865,6 +865,7 @@ Optional Features:
   --disable-ogfs          Disable the OpenGFS FSIM
   --disable-reiser        Disable the ReiserFS FSIM
   --disable-xfs           Disable the XFS FSIM
+  --disable-bios          Disable the BIOS plugin
   --disable-swap          Disable the Swap FSIM
   --disable-replace       Disable the Replace plugin
   --disable-ha            Disable the HA plugin
@@ -10319,6 +10320,13 @@ if test "${enable_xfs+set}" = set; then
 else
   build_xfs="yes"
 fi;
+# Check whether --enable-bios or --disable-bios was given.
+if test "${enable_bios+set}" = set; then
+  enableval="$enable_bios"
+  build_bios="$enableval"
+else
+  build_bios="yes"
+fi;
 # Check whether --enable-swap or --disable-swap was given.
 if test "${enable_swap+set}" = set; then
   enableval="$enable_swap"
@@ -10351,7 +10359,7 @@ fi;
 # Create the list of plugin directories to build. This is where each plugin
 # can specify its dependencies.
 plugin_dirs=""
-plugin_distdirs="bbr bbr_seg bsd csm disk dos drivelink ext2 gpt ha jfs lvm mac md multipath ogfs reiser replace rsct s390 snapshot swap xfs"
+plugin_distdirs="bbr bbr_seg bsd csm disk dos drivelink ext2 gpt ha jfs lvm mac md multipath ogfs reiser replace rsct s390 snapshot swap xfs bios"
 
 # BBR
 if test "$build_bbr" = "no"; then
@@ -10619,6 +10627,16 @@ else
 echo "$as_me:      building xfs" >&6;}
 fi
 
+# BIOS
+if test "$build_bios" = "no"; then
+	{ echo "$as_me:$LINENO:      not building bios ... disabled by user" >&5
+echo "$as_me:      not building bios ... disabled by user" >&6;}
+else
+	plugin_dirs="$plugin_dirs bios"
+	{ echo "$as_me:$LINENO:      building bios" >&5
+echo "$as_me:      building bios" >&6;}
+fi
+
 
 
 
@@ -10724,7 +10742,7 @@ fi
 
 
 
-                                                                                                                                                                                                                                                                                                                                                                                  ac_config_files="$ac_config_files make.rules Makefile engine/Makefile engine/worker/Makefile plugins/Makefile plugins/bbr/Makefile plugins/bbr_seg/Makefile plugins/bsd/Makefile plugins/csm/Makefile plugins/disk/Makefile plugins/dos/Makefile plugins/drivelink/Makefile plugins/ext2/Makefile plugins/gpt/Makefile plugins/ha/Makefile plugins/jfs/Makefile plugins/lvm/Makefile plugins/mac/Makefile plugins/md/Makefile plugins/multipath/Makefile plugins/ogfs/Makefile plugins/reiser/Makefile plugins/replace/Makefile plugins/rsct/Makefile plugins/s390/Makefile plugins/snapshot/Makefile plugins/swap/Makefile plugins/xfs/Makefile ui/Makefile ui/cli/Makefile ui/gtk/Makefile ui/ncurses/Makefile ui/utils/Makefile include/Makefile doc/Makefile doc/man/Makefile tests/Makefile"
+                                                                                                                                                                                                                                                                                                                                                                                  ac_config_files="$ac_config_files make.rules Makefile engine/Makefile engine/worker/Makefile plugins/Makefile plugins/bbr/Makefile plugins/bbr_seg/Makefile plugins/bsd/Makefile plugins/csm/Makefile plugins/disk/Makefile plugins/dos/Makefile plugins/drivelink/Makefile plugins/ext2/Makefile plugins/gpt/Makefile plugins/ha/Makefile plugins/jfs/Makefile plugins/lvm/Makefile plugins/mac/Makefile plugins/md/Makefile plugins/multipath/Makefile plugins/ogfs/Makefile plugins/reiser/Makefile plugins/replace/Makefile plugins/rsct/Makefile plugins/s390/Makefile plugins/snapshot/Makefile plugins/swap/Makefile plugins/xfs/Makefile plugins/bios/Makefile ui/Makefile ui/cli/Makefile ui/gtk/Makefile ui/ncurses/Makefile ui/utils/Makefile include/Makefile doc/Makefile doc/man/Makefile tests/Makefile"
 
 
 cat >confcache <<\_ACEOF
@@ -11305,6 +11323,7 @@ do
   "plugins/snapshot/Makefile" ) CONFIG_FILES="$CONFIG_FILES plugins/snapshot/Makefile" ;;
   "plugins/swap/Makefile" ) CONFIG_FILES="$CONFIG_FILES plugins/swap/Makefile" ;;
   "plugins/xfs/Makefile" ) CONFIG_FILES="$CONFIG_FILES plugins/xfs/Makefile" ;;
+  "plugins/bios/Makefile" ) CONFIG_FILES="$CONFIG_FILES plugins/bios/Makefile" ;;
   "ui/Makefile" ) CONFIG_FILES="$CONFIG_FILES ui/Makefile" ;;
   "ui/cli/Makefile" ) CONFIG_FILES="$CONFIG_FILES ui/cli/Makefile" ;;
   "ui/gtk/Makefile" ) CONFIG_FILES="$CONFIG_FILES ui/gtk/Makefile" ;;
diff -Nurp evms-2.3.0/plugins/bios/Makefile.in evms-2.3.0-bios/plugins/bios/Makefile.in
--- evms-2.3.0/plugins/bios/Makefile.in	1969-12-31 18:00:00.000000000 -0600
+++ evms-2.3.0-bios/plugins/bios/Makefile.in	2004-03-14 14:38:15.000000000 -0600
@@ -0,0 +1,52 @@
+# Enterprise Volume Management System
+#
+# (C) Copyright IBM Corp. 2003
+#
+# This program is free software;  you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY;  without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+# the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program;  if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+include @top_srcdir@/make.rules
+
+NAME		= bios
+TARGET		= $(PLUGIN_TARGET)
+
+MAJOR_VERSION	= 0
+MINOR_VERSION	= 0
+PATCH_LEVEL	= 1
+
+EVMS_DEFS	+= -D_FILEOFFSET_BITS=64
+
+all: $(TARGET)
+
+$(TARGET): .depend .export $(OBJECTS)
+	$(BUILD_PLUGIN)
+
+install: all
+	$(MKINSTALLDIRS) $(DESTDIR)$(evmspluginsdir)
+	$(INSTALL) -m 755 $(TARGET) $(DESTDIR)$(evmspluginsdir)
+
+uninstall:
+	rm -f $(DESTDIR)$(evmspluginsdir)/$(TARGET)
+
+clean:
+	rm -f .depend .export $(OBJECTS) $(TARGET)
+
+distclean: clean
+	rm -f Makefile
+
+ifeq (.depend, $(wildcard .depend))
+include .depend
+endif
diff -Nurp evms-2.3.0/plugins/bios/bios.c evms-2.3.0-bios/plugins/bios/bios.c
--- evms-2.3.0/plugins/bios/bios.c	1969-12-31 18:00:00.000000000 -0600
+++ evms-2.3.0-bios/plugins/bios/bios.c	2004-03-14 14:38:15.000000000 -0600
@@ -0,0 +1,1323 @@
+/*
+ *   (C) Copyright IBM Corp. 2001, 2003
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * BIOS Disk Manager plugin.
+ *
+ * Wilfried Weissmann (c) 2004
+ *
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <mntent.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <glob.h>
+
+#include <plugin.h>
+#include <ldm_dpc.h>
+#include "bios.h"
+
+	/* list of the pci ids of the supported controllers */
+struct hptpci_s {
+	u_int16_t vendor;
+	u_int16_t device;
+} static hptpci[] = {
+	{ PCI_VENDOR_TRIONES, PCI_DEVICE_HPT370		},
+	{ PCI_VENDOR_TRIONES, PCI_DEVICE_HPT372A	},
+	{ PCI_VENDOR_TRIONES, PCI_DEVICE_HPT302		},
+	{ PCI_VENDOR_TRIONES, PCI_DEVICE_HPT371		},
+	{ PCI_VENDOR_TRIONES, PCI_DEVICE_HPT374		},
+	{ PCI_VENDOR_TRIONES, PCI_DEVICE_HPT372N	},
+};
+
+static engine_functions_t * EngFncs = NULL;
+
+static char * sysfs_mount_point; /* FIXME: use sysfs */
+
+static list_anchor_t scanlist=NULL;	/* list of disk attached to the hpt37x controller */
+
+static list_anchor_t raidlist=NULL;	/* list of detected raid volumes */
+
+/**
+ * isHardDisk
+ * @hd: pathname of HD in proc filesystem
+ *
+ * returns true if the device is a hard disk
+ **/
+static int isHardDisk(const char *hd) {
+	char buffer[50];
+	FILE *fd;
+
+	strncpy(buffer, hd, sizeof(buffer) - 1);
+	strncat(buffer, "/media", sizeof(buffer) - 1);
+	
+	fd=fopen(buffer, "r");
+
+	if( !fd ) {
+		return 0;
+	}
+
+	fgets(buffer, sizeof(buffer)-1, fd);
+
+	fclose(fd);
+
+	return strcmp(buffer, "disk\n")?0:1;
+}
+
+/**
+ * loadHPTConf
+ * @disk: disk structure of the harddisk
+ *
+ * loads the raid configuration data into the disk parameter structure
+ **/
+static int loadHPTConf(struct hptdisk * disk) {
+	struct stat stat;
+	int fd=open(disk->devname, O_RDONLY);
+
+	if(fd < 0) {
+		return 0; /* cannot open disk */
+	}
+
+	if(fstat(fd, &stat) == -1) goto err;
+
+	disk->minor=minor(stat.st_rdev);
+	disk->major=major(stat.st_rdev);
+
+	if(ioctl(fd, BLKSSZGET, &(disk->hardsector_size)) == -1) goto err;
+
+	if(ioctl(fd, BLKBSZGET, &(disk->block_size)) == -1) goto err;
+
+	if(lseek(fd, CONFIGOFFSET, SEEK_SET) == -1) goto err;
+
+	if(read(fd, (void *) &disk->superblock, sizeof(struct highpoint_raid_conf)) !=
+			sizeof(struct highpoint_raid_conf)) goto err;
+
+	close(fd);
+	return 1;
+
+err:
+	close(fd);
+	return 0;
+}
+
+static int compare_disk(void *disk1, void *disk2) {
+	return strcmp( ( (struct hptdisk *) disk1 )->devname,
+			( (struct hptdisk *) disk2 )->devname);
+}
+
+/**
+ * addDisk
+ * @name: device node of the harddisk (without heading "/dev/")
+ *
+ * allocates the disk structure and load the raid configuration data.
+ * if the disk is already in the scanlist then it is discarded.
+ **/
+static void addDisk(const char *name) {
+
+	struct hptdisk * disk=EngFncs->engine_alloc(sizeof(struct hptdisk));
+
+	if(!disk) {
+		return; /* Oops: out of memory! */
+	}
+
+	memset(disk, 0, sizeof(struct hptdisk));
+
+	strcpy(disk->devname, "/dev/");
+	strcat(disk->devname, name);
+
+	if(loadHPTConf(disk) && disk->superblock.magic == 0x5a7816f0 &&
+			!EngFncs->find_in_list(scanlist, disk, compare_disk) ) {
+		EngFncs->insert_thing(scanlist, disk, INSERT_AFTER, NULL);
+	} else {
+		EngFncs->engine_free(disk);		/* no config block => remove */
+	}
+}
+
+/**
+ * hpt370xScan
+ * @name: path to the controller directory in proc-fs
+ * @vendor: pci vendor id of the ide controller
+ * @device: pci device id of the ide controller
+ *
+ * scans the attached harddisks of the ide controller
+ **/
+static void hpt37xScan(const char *name, int vendor, int device) {
+	DIR *ctrldir;
+	struct dirent *dir;
+	char buffer[50]=IDEDIR "/";
+	char hdpath[50];
+	boolean ignorepciids;
+	int i;
+
+		/* default is to NOT ignore the PCI IDs */
+	if(EngFncs->get_config_bool(IGNORE_PCI_IDS, &ignorepciids) || !ignorepciids) {
+
+		for(i=0; i < sizeof(hptpci)/sizeof(struct hptpci_s); i++) {
+			if(hptpci[i].vendor == vendor &&
+					hptpci[i].device == device) {
+				break;
+			}
+		}
+
+		if (i >= sizeof(hptpci)/sizeof(struct hptpci_s)) return;
+
+	}
+
+	strncat(buffer, name, sizeof(buffer) - 1);
+
+	ctrldir=opendir(buffer);
+
+	if( !ctrldir ) {
+		perror(buffer);
+		return;
+	}
+
+	while( (dir = readdir(ctrldir)) ) {
+		if( (dir->d_type == DT_DIR) &&
+				!(strncmp(dir->d_name, "hd", 2)) ) {
+
+			strncpy(hdpath, buffer, sizeof(buffer) - 1);
+			strncat(hdpath, "/", sizeof(buffer) - 1);
+			strncat(hdpath, dir->d_name, sizeof(buffer) - 1);
+
+			if(isHardDisk(hdpath)) {
+				addDisk(dir->d_name);
+			}
+		}
+	}
+
+
+	closedir(ctrldir);
+}
+
+/**
+ * findIDECtrl
+ *
+ * scan for supported IDE controllers and datafill the scanlist with
+ * the attached harddisks
+ **/
+static int findIDECtrl() {
+	DIR *idedir;
+	struct dirent * dir;
+
+	idedir = opendir( IDEDIR );
+
+	if( ! idedir ) {
+		perror(IDEDIR);
+		return -1;
+	}
+
+	while( (dir = readdir(idedir)) ) {
+		if( (dir->d_type == DT_DIR) &&
+				!(strncmp(dir->d_name, "ide", 3)) ) {
+
+			char config[50]=IDEDIR "/";
+			FILE *fd;
+			int vendor, device;
+
+			strncat(config, dir->d_name, sizeof(config)-1);
+			strncat(config, "/config", sizeof(config)-1);
+
+			fd=fopen(config, "r");
+
+			if( !fd ) {
+				perror(config);
+				continue;
+			}
+
+			if( fscanf(fd, "pci bus %*i device %*i vendor %x device %x",
+				&vendor, &device) == 2) {
+
+				hpt37xScan(dir->d_name, vendor, device);
+			}
+
+			fclose(fd);
+		}
+	}
+
+	closedir(idedir);
+	return 0;
+}
+
+/**
+ * round_down
+ * @value:	Value (in sectors) to be rounded down.
+ * @boundary:	Boundary (in bytes) to round-down to.
+ *
+ * Given a value, round it down to be a multiple of the specified boundary size.
+ **/
+static inline sector_count_t round_down(sector_count_t value,
+					u_int32_t boundary)
+{
+	sector_count_t boundary_in_vsectors = ((sector_count_t)boundary) >>
+					      EVMS_VSECTOR_SIZE_SHIFT;
+	return (boundary > EVMS_VSECTOR_SIZE) ?
+	       (value & ~(boundary_in_vsectors - 1)) : value;
+}
+
+/**
+ * round_up
+ * @value:	Value (in sectors) to be rounded up.
+ * @boundary:	Boundary (in bytes) to round-up to.
+ *
+ * Given a value, round it up to be a multiple of the specified boundary size.
+ **/
+static inline sector_count_t round_up(sector_count_t value,
+				      u_int32_t boundary)
+{
+	sector_count_t boundary_in_vsectors = ((sector_count_t)boundary) >>
+					      EVMS_VSECTOR_SIZE_SHIFT;
+	sector_count_t temp_value = value + boundary_in_vsectors - 1;
+	return (boundary > EVMS_VSECTOR_SIZE) ?
+	       (temp_value & ~(boundary_in_vsectors - 1)) : value;
+}
+
+/**
+ * where_is_sysfs
+ *
+ * Is sysfs mounted. If so, return the mount point. The caller must free the
+ * returned string.
+ **/
+static boolean where_is_sysfs(char ** mount_name)
+{
+	boolean result = FALSE;
+	FILE * mount_records;
+	struct mntent * mount_entry;
+
+	LOG_ENTRY();
+
+	if (mount_name) {
+		*mount_name = NULL;
+	}
+
+	mount_records = setmntent(MOUNTED, "r");
+	if (mount_records == NULL) {
+		mount_records = setmntent("/proc/mounts", "r");
+	}
+	if (mount_records == NULL) {
+		LOG_ERROR("Could not get list of mounted devices.\n");
+		goto out;
+	}
+
+	while (!result && (mount_entry = getmntent(mount_records)) != NULL) {
+		if (strcmp(mount_entry->mnt_type, "sysfs") == 0) {
+			result = TRUE;
+			if (mount_name) {
+				*mount_name = strdup(mount_entry->mnt_dir);
+			}
+		}
+	}
+
+	endmntent(mount_records);
+
+out:
+	LOG_EXIT_BOOL(result);
+	return result;
+}
+
+static int LD_setup(engine_functions_t * engine_function_table)
+{
+	/* save info we get from the engine */
+	EngFncs = engine_function_table;
+
+	LOG_ENTRY();
+
+	where_is_sysfs(&sysfs_mount_point);
+	scanlist=EngFncs->allocate_list();
+	raidlist=EngFncs->allocate_list();
+
+	LOG_EXIT_INT(0);
+	return 0;
+}
+
+/**
+ * open_dev
+ *
+ * Open the specified disk. Use O_DIRECT to avoid caching. Use O_SYNC in case
+ * the kernel does not honor O_DIRECT. Use the Engine's service so we
+ * automatically get a dev-node in the /dev/evms/.nodes/ tree. Record the
+ * file handle in the disk's private data.
+ **/
+static int open_dev(storage_object_t * disk)
+{
+	int rc = 0;
+	int * fd = &((struct hptraid *)disk->private_data)->fd;
+
+	LOG_ENTRY();
+
+	if (*fd <= 0) {
+		*fd = EngFncs->open_object(disk, O_RDWR | O_DIRECT | O_SYNC);
+		if (*fd < 0) {
+			rc = -*fd;
+			LOG_DEBUG("Error opening disk %s: %d: %s\n",
+				  disk->name, rc, strerror(rc));
+		}
+	}
+
+	LOG_EXIT_INT(rc);
+	return rc;
+}
+
+/**
+ * close_dev
+ *
+ * Close the disk and clear the file handle.
+ **/
+static void close_dev(storage_object_t * disk)
+{
+	int * fd = &((struct hptraid *)disk->private_data)->fd;
+	int rc;
+
+	LOG_ENTRY();
+
+	if (*fd >= 0) {
+		rc = EngFncs->close_object(disk, *fd);
+		if (!rc) {
+			*fd = -1;
+		}
+	}
+
+	LOG_EXIT_VOID();
+}
+
+/**
+ * LD_cleanup
+ *
+ * Find any disks and close the device that was opended during discovery.
+ **/
+static void LD_cleanup(void)
+{
+	int rc;
+	list_anchor_t disk_list;
+	list_element_t disk_list_itr;
+	storage_object_t * disk;
+	struct hptraid * raid;
+
+	LOG_ENTRY();
+
+	/* Get a list of disks that are managed by this plug-in. */
+	rc = EngFncs->get_object_list(DISK, 0, my_plugin_record,
+				      NULL, 0, &disk_list);
+	if (!rc) {
+		/* Close any dev handles that might be open. */
+		LIST_FOR_EACH(disk_list, disk_list_itr, disk) {
+			raid = (struct hptraid *)disk->private_data;
+			if(raid->status == operational) {
+				EngFncs->dm_deactivate(disk);
+				EngFncs->dm_deallocate_targets(raid->dm_target);
+				close_dev(disk);
+			}
+			EngFncs->engine_free(disk->private_data);
+		}
+		EngFncs->destroy_list(disk_list);
+	}
+
+	EngFncs->destroy_list(raidlist);
+	EngFncs->destroy_list(scanlist);
+
+	if (sysfs_mount_point) {
+		free(sysfs_mount_point);
+		sysfs_mount_point = NULL;
+	}
+
+	LOG_EXIT_VOID();
+}
+
+/**
+ * get_block_size
+ *
+ * Use the BLKBSZGET ioctl to get the block-size for the specified disk.
+ **/
+static int get_block_size(storage_object_t * disk)
+{
+	int fd = ((struct hptraid *)disk->private_data)->fd;
+	int rc, block_size;
+
+	LOG_ENTRY();
+
+	rc = ioctl(fd, BLKBSZGET, &block_size);
+	if (rc) {
+		rc = errno;
+		LOG_ERROR("Error getting block size for disk %s: %d: %s.\n",
+			  disk->name, rc, strerror(rc));
+	} else {
+		LOG_DEBUG("Disk %s has block-size %d.\n",
+			  disk->name, block_size);
+		disk->geometry.block_size = block_size;
+	}
+
+	LOG_EXIT_INT(rc);
+	return rc;
+}
+
+/**
+ * set_block_size
+ *
+ * Use the BLKBSZSET ioctl to set the disk's block-size.
+ **/
+static int set_block_size(storage_object_t * disk, int block_size)
+{
+	int rc;
+	int fd = ((struct hptraid *)disk->private_data)->fd;
+
+	LOG_ENTRY();
+
+	rc = ioctl(fd, BLKBSZSET, &block_size);
+	if (rc) {
+		rc = errno;
+		LOG_ERROR("Error setting block size (%d) for disk %s: %d: "
+			  "%s.\n", block_size, disk->name, rc, strerror(rc));
+	} else {
+		LOG_DEBUG("Setting disk %s block-size to %d.\n",
+			  disk->name, block_size);
+		disk->geometry.block_size = block_size;
+	}
+
+	LOG_EXIT_INT(rc);
+	return rc;
+}
+
+/**
+ * create_logical_disk
+ *
+ * Allocate a new disk and initialize all fields.
+ **/
+static storage_object_t * create_logical_disk(struct hptraid * raid)
+{
+	storage_object_t * disk = NULL;
+	int rc;
+
+	LOG_ENTRY();
+
+	rc = EngFncs->allocate_logical_disk(raid->name, &disk);
+	if (rc) {
+		LOG_SERIOUS("Error allocating new disk object for disk %s: %d: "
+			    "%s.\n", raid->name, rc, EngFncs->strerror(rc));
+		goto out;
+	}
+
+	disk->data_type = DATA_TYPE;
+	disk->private_data = raid;
+	disk->plugin			= my_plugin_record;
+	disk->size=raid->sectors;
+	disk->geometry.cylinders=raid->sectors / ( 255 * 63 );
+	disk->geometry.heads=255;
+	disk->geometry.sectors_per_track=63;
+	disk->geometry.block_size=raid->block_size;
+	disk->geometry.bytes_per_sector=raid->hardsector_size;
+
+out:
+	LOG_EXIT_PTR(disk);
+	return disk;
+}
+
+/**
+ * hptRAIDScan
+ * @index: index number of the raid volume
+ *
+ * scans the "scanlist" of harddisks to detect hpt-raid volumes. return the
+ * allocated and datafilled hptraid structure and adds it to the raidlist.
+ * when no more volumes were found then NULL is returned. this function also
+ * detects "non-operatinal" volumes (e.g.: volumes with too less disks to
+ * become active).
+ **/
+static struct hptraid * hptRAIDScan(int index) {
+	struct hptdisk * current;
+	list_element_t disk_list_itr;
+	struct hptraid * raid=EngFncs->engine_alloc(sizeof(struct hptraid));
+
+	if(!raid) {
+		return NULL;
+	}
+
+	memset(raid, 0, sizeof(struct hptraid));
+
+	sprintf(raid->name, "hptraid%ip", index);
+
+	/* walk the scanlist of attached harddisks */
+	LIST_FOR_EACH(scanlist, disk_list_itr, current) {
+
+		if(current->claimed) continue;
+
+		/* unclaimed disk => scan */
+
+		if(raid->disks) {
+			/* raid is not empty => check magic cookie */
+			if(raid->magic_0 != current->superblock.magic_0) {
+				continue;
+			}
+		}
+		else {
+			/* raid is empty => accept any magic cookie */
+			raid->magic_0 = current->superblock.magic_0;
+		}
+
+			/* check for known raid types */
+		switch(current->superblock.type) {
+			case HPT_T_RAID_0:
+				break;
+			default:
+				continue;
+		}
+
+		if(current->superblock.disk_number > 8) {
+			continue;
+		}
+
+			/* add disk to raid volume */
+		raid->disk[current->superblock.disk_number]=current;
+			/* shift in sectors */
+		raid->stride=1<<current->superblock.raid0_shift;
+		raid->disks=current->superblock.raid_disks;
+			/* superblock contains size in sectors - 1 */
+		raid->sectors=current->superblock.total_secs;
+		raid->magic_1 = current->superblock.magic_1;
+		raid->hardsector_size=current->hardsector_size;
+		raid->block_size=current->block_size;
+
+		/*
+		 * FIXME: re-enable to access the last sector
+		 *
+		 * the device mapper is only happy if
+		 * (volume size)%(number of disks) == 0
+		 *
+		 * maybe we can lie to the device mapper and tell it
+		 * that the volume is bigger so that the expression from above
+		 * is true. then use the true values for the evms engine to get
+		 * the correct volume sizes.
+		 */
+#if 0
+		if (EngFncs->is_2_4_kernel()) {
+				/* round down to 1024 bytes boundary */
+#endif
+			raid->sectors += raid->sectors&1?1:0;
+#if 0
+		}
+		else {
+			raid->sectors++;
+		}
+#endif
+
+		current->claimed=1;
+	}
+
+	if(raid->disks == 0) {
+		EngFncs->engine_free(raid);
+		return NULL;
+	}
+
+	EngFncs->insert_thing(raidlist, raid, INSERT_AFTER, NULL);
+
+	return raid;
+}
+
+/**
+ * hptRAIDInit
+ * @raid: raid volume to be activated
+ * @output_list: output list for LD_discover()
+ *
+ * activate the raid volume and add is the the volume output_list
+ **/
+static int hptRAIDInit(struct hptraid * raid, list_anchor_t output_list) {
+	int disks=0, count;
+	storage_object_t * object;
+
+		/* raid is already running */
+	if(raid->status == operational) {
+		return 0;
+	}
+
+	for(count=0; count < 8; count++) {
+		if(raid->disk[count]) {
+			disks++;
+		}
+	}
+
+	if(raid->disks != disks) {	/* missing disks */
+		LOG_SERIOUS("Missing disks in %s (%i of %i).\n", raid->name, disks, raid->disks);
+		goto err;
+	}
+
+		/* datafill device mapper structures */
+	raid->dm_target = EngFncs->dm_allocate_target(DM_TARGET_STRIPE, 0,
+			raid->sectors, raid->disks, 0);
+
+	raid->dm_target->data.stripe->chunk_size=raid->stride;
+	raid->dm_target->data.stripe->num_stripes=raid->disks;
+	for(count=0; count < raid->disks; count++) {
+		struct dm_device * dm_device=raid->dm_target->data.stripe->devices+count;
+		struct hptdisk * hptdisk=raid->disk[count];
+		dm_device->major=hptdisk->major;
+		dm_device->minor=hptdisk->minor;
+		dm_device->start=count?10:0;
+	}
+
+	object=create_logical_disk(raid);
+	if(!object) {
+		LOG_SERIOUS("Failed to create %s.\n", raid->name);
+		goto err1;
+	}
+
+	if( EngFncs->dm_activate(object, raid->dm_target) ) {
+		LOG_SERIOUS("Failed to activate %s.\n", object->name);
+		goto err2;
+	}
+
+	LOG_DETAILS("New Logical Disk:\n");
+	LOG_DETAILS("  name:          %s\n", object->name);
+	LOG_DETAILS("  size:          %"PRIu64"\n", object->size);
+	LOG_DETAILS("  device-number: %x:%x\n", object->dev_major, object->dev_minor);
+	LOG_DETAILS("  geometry:\n");
+	LOG_DETAILS("    cylinders:   %"PRIu64"\n", object->geometry.cylinders);
+	LOG_DETAILS("    heads:       %d\n", object->geometry.heads);
+	LOG_DETAILS("    sectors:     %d\n", object->geometry.sectors_per_track);
+	LOG_DETAILS("    sector size: %d (bytes)\n", object->geometry.bytes_per_sector);
+	LOG_DETAILS("    block size:  %"PRIu64" (bytes)\n", object->geometry.block_size);
+
+	open_dev(object);
+
+	/* Insert the new disk into ouput list. */
+	if( ! EngFncs->insert_thing(output_list, object,
+				INSERT_AFTER, NULL) ) {
+		LOG_SERIOUS("Error adding new disk %s to output list. "
+			    "Deleting the disk.\n", object->name);
+		close_dev(object);
+		EngFncs->engine_free(object->private_data);
+		EngFncs->free_logical_disk(object);
+		goto err2;
+	}
+
+	raid->status=operational;
+	return 1;
+
+err2:
+	EngFncs->free_logical_disk(object);
+err1:
+	EngFncs->dm_deallocate_targets(raid->dm_target);
+err:
+	raid->status=broken;
+	return 0;
+}
+
+/**
+ * LD_discover
+ **/
+static int LD_discover(list_anchor_t input_list,
+		       list_anchor_t output_list,
+		       boolean final_call)
+{
+	int i;
+	struct hptraid * raid;
+
+	LOG_ENTRY();
+
+	findIDECtrl();	/* get list of scan devices */
+
+	for(i=0; (raid=hptRAIDScan(i)); i++) {
+		hptRAIDInit(raid, output_list);
+	}
+
+	i = EngFncs->list_count(output_list);
+	LOG_DEBUG("Discovered %d disks.\n", i);
+	LOG_EXIT_INT(0);
+	return 0;
+}
+
+/**
+ * get_alignment_size
+ *
+ * Return the size (in bytes) of the alignment restrictions for O_DIRECT. On
+ * 2.5 kernels, this will be the disk's hard-sector-size. On 2.4 kernels, this
+ * will be the disk's block-size. Since block-size can change at run-time,
+ * always check the current block-size. Also, since we want access to as much
+ * of the disk as possible, try to set the block-size to 1k if it isn't
+ * already.
+ **/
+static int get_alignment_size(storage_object_t * disk)
+{
+	int size;
+	int min_block_size = max(disk->geometry.bytes_per_sector, 1024);
+
+	LOG_ENTRY();
+
+	if (EngFncs->is_2_4_kernel()) {
+		get_block_size(disk);
+		size = disk->geometry.block_size;
+		if (size > min_block_size) {
+			set_block_size(disk, min_block_size);
+			size = disk->geometry.block_size;
+		}
+	} else {
+		size = disk->geometry.bytes_per_sector;
+	}
+
+	LOG_EXIT_INT(size);
+	return size;
+}
+
+/**
+ * get_aligned_buffer
+ * @offset:	Starting offset (in sectors) of engine I/O request.
+ * @count:	Size (in sectors) of engine I/O request.
+ * @align_size:	Size (in bytes) that the I/O must be aligned on.
+ * @local_offset:	Aligned starting offset (in sectors).
+ * @local_count:	Aligned I/O size (in sectors).
+ * @local_buffer:	New data buffer. Not aligned, but need to return this
+ *			pointer so it can be freed after using.
+ * @local_buffer_aligned:	Aligned data buffer. This points somewhere
+ *				within local_buffer.
+ *
+ * To use O_DIRECT, the buffer passed to read() or write() must be aligned on
+ * the device's block/sector size. The size and starting offset of the I/O must
+ * also be a multiple of the block/sector size.
+ **/
+static int get_aligned_buffer(lsn_t offset,
+			      sector_count_t count,
+			      int align_size,
+			      lsn_t * local_offset,
+			      sector_count_t * local_count,
+			      void ** local_buffer,
+			      void ** local_buffer_aligned)
+{
+	u_int32_t offset_diff, offset_diff_bytes;
+	u_int32_t local_buffer_bytes;
+	u_int32_t alignment_base, alignment_diff;
+	int rc = 0;
+
+	LOG_ENTRY();
+
+	/* Round down starting offset to the alignment size. */
+	*local_offset = round_down(offset, align_size);
+
+	/* Difference between real offset and local offset. */
+	offset_diff = offset - *local_offset;
+	offset_diff_bytes = offset_diff << EVMS_VSECTOR_SIZE_SHIFT;
+
+	/* Round up total count of sectors to alignment size. */
+	*local_count = round_up(count + offset_diff, align_size);
+
+	/* Allocate the buffer that will actually perform the I/O. This needs
+	 * to allocate enough extra to compensate for the alignment that will
+	 * occur next.
+	 */
+	local_buffer_bytes = *local_count << EVMS_VSECTOR_SIZE_SHIFT;
+	*local_buffer = EngFncs->engine_alloc(local_buffer_bytes +
+					      align_size - 1);
+	if (!*local_buffer) {
+		rc = ENOMEM;
+		goto out;
+	}
+
+	/* Align the buffer on hard-sector-size. */
+	alignment_base = (unsigned long)(*local_buffer) & (align_size - 1);
+	alignment_diff = (alignment_base + align_size - 1) & ~(align_size - 1);
+	alignment_diff -= alignment_base;
+	*local_buffer_aligned = *local_buffer + alignment_diff;
+
+	/* Sanity check */
+	if (((unsigned long)(*local_buffer_aligned) % align_size) != 0) {
+		LOG_ERROR("BUFFER NOT ALIGNED!!: buf: %p, size: %u\n",
+			  *local_buffer_aligned, align_size);
+	}
+
+out:
+	LOG_EXIT_INT(rc);
+	return rc;
+}
+
+/**
+ * LD_read
+ **/
+static int LD_read(storage_object_t * disk,
+		   lsn_t offset,
+		   sector_count_t count,
+		   void * buffer)
+{
+	void * local_buffer = NULL, * local_buffer_aligned;
+	lsn_t local_offset;
+	sector_count_t local_count;
+	int fd = ((struct hptraid *)disk->private_data)->fd;
+	int rc, align_size;
+
+	LOG_ENTRY();
+	LOG_DEBUG("Read disk:%s offset:%"PRIu64" count:%"PRIu64"\n",
+		  disk->name, offset, count);
+
+        if (offset + count > disk->size) {
+		LOG_ERROR("Read request past end of disk.\n");
+		rc = EINVAL;
+		goto out;
+	}
+
+	/* Make sure the disk is open. */
+	rc = open_dev(disk);
+	if (rc) {
+		goto out;
+	}
+
+	/* Get the alignment restriction for O_DIRECT. */
+	align_size = get_alignment_size(disk);
+
+	/* Get a data buffer aligned with this restriction. */
+	rc = get_aligned_buffer(offset, count, align_size,
+				&local_offset, &local_count,
+				&local_buffer, &local_buffer_aligned);
+	if (rc) {
+		goto out;
+	}
+
+	/* Send the read to the engine. */
+	rc = EngFncs->read_object(disk, fd, local_buffer_aligned,
+				  local_count << EVMS_VSECTOR_SIZE_SHIFT,
+				  local_offset << EVMS_VSECTOR_SIZE_SHIFT);
+	if (rc < 0) {
+		rc = -rc;
+		goto out;
+	}
+
+	/* Copy the data back to the caller's buffer. */
+	memcpy(buffer, local_buffer_aligned +
+		       ((offset - local_offset) << EVMS_VSECTOR_SIZE_SHIFT),
+	       count << EVMS_VSECTOR_SIZE_SHIFT);
+
+	rc = 0;
+
+out:
+	EngFncs->engine_free(local_buffer);
+	LOG_EXIT_INT(rc);
+	return rc;
+}
+
+/**
+ * LD_write
+ **/
+static int LD_write(storage_object_t * disk,
+		    lsn_t offset,
+		    sector_count_t count,
+		    void * buffer)
+{
+	void * local_buffer = NULL, * local_buffer_aligned;
+	lsn_t local_offset;
+	sector_count_t local_count;
+	int fd = ((struct hptraid *)disk->private_data)->fd;
+	int rc, align_size;
+
+	LOG_ENTRY();
+	LOG_DEBUG("Write disk:%s offset:%"PRIu64" count:%"PRIu64"\n",
+		  disk->name, offset, count);
+
+	if (offset + count > disk->size) {
+		LOG_ERROR("Write request past end of disk.\n");
+		rc = EINVAL;
+		goto out;
+	}
+
+	/* Make sure the disk is open. */
+	rc = open_dev(disk);
+	if (rc) {
+		goto out;
+	}
+
+	/* Get the alignment restriction for O_DIRECT. */
+	align_size = get_alignment_size(disk);
+
+	/* Get a data buffer aligned with this restriction. */
+	rc = get_aligned_buffer(offset, count, align_size,
+				&local_offset, &local_count,
+				&local_buffer, &local_buffer_aligned);
+	if (rc) {
+		goto out;
+	}
+
+	if (local_count != count) {
+		rc = EngFncs->read_object(disk, fd, local_buffer_aligned,
+					  local_count << EVMS_VSECTOR_SIZE_SHIFT,
+					  local_offset << EVMS_VSECTOR_SIZE_SHIFT);
+		if (rc < 0) {
+			rc = -rc;
+			goto out;
+		}
+	}
+	
+	/* Put user data at the right place in the buffer */
+	memcpy(local_buffer_aligned +
+	       ((offset - local_offset) << EVMS_VSECTOR_SIZE_SHIFT),
+	       buffer, count << EVMS_VSECTOR_SIZE_SHIFT);
+	
+	/* Send the write to the engine. */
+	rc = EngFncs->write_object(disk, fd, local_buffer_aligned,
+				   local_count << EVMS_VSECTOR_SIZE_SHIFT,
+				   local_offset << EVMS_VSECTOR_SIZE_SHIFT);
+	if (rc < 0) {
+		rc = -rc;
+		goto out;
+	}
+
+	rc = 0;
+
+out:
+	EngFncs->engine_free(local_buffer);
+	LOG_EXIT_INT(rc);
+	return rc;
+}
+
+/**
+ * LD_discard
+ *
+ * We don't expect to get called on this API. Just like commit.
+ **/
+static int LD_discard(list_anchor_t disks)
+{
+	LOG_ENTRY();
+	LOG_EXIT_INT(0);
+	return 0;
+}
+
+/**
+ * LD_add_sectors_to_kill_list
+ **/
+static int LD_add_sectors_to_kill_list(storage_object_t * disk,
+				       lsn_t lsn,
+				       sector_count_t count)
+{
+	int rc;
+	LOG_ENTRY();
+
+	if (lsn + count > disk->size) {
+		LOG_ERROR("Kill-sectors request past end of disk %s.\n",
+			  disk->name);
+		rc = EINVAL;
+	} else {
+		rc = EngFncs->add_sectors_to_kill_list(disk, lsn, count);
+	}
+
+	LOG_EXIT_INT(rc);
+	return rc;
+}
+
+/**
+ * LD_commit_changes
+ *
+ * Disk manager doesn't do anything during commit. Just return success.
+ **/
+static int LD_commit_changes(storage_object_t * disk, commit_phase_t phase)
+{
+	LOG_ENTRY();
+	LOG_EXIT_INT(0);
+	return 0;
+}
+
+/**
+ * LD_get_info
+ *
+ * Returns DISK specific information
+ **/
+static int LD_get_info(storage_object_t * disk,
+		       char * descriptor_name,
+		       extended_info_array_t ** info)
+{
+	extended_info_array_t * Info;
+	int index = 0, rc = EINVAL;
+
+	LOG_ENTRY();
+
+	if (!info) {
+		goto out;
+	}
+	*info = NULL;
+	
+        if (descriptor_name) {
+		goto out;
+	}
+	
+	Info = EngFncs->engine_alloc(sizeof(extended_info_array_t) +
+				     8 * sizeof(extended_info_t));
+	if (!Info) {
+		rc = ENOMEM;
+		goto out;
+	}
+		
+	SET_STRING(Info->info[index].name, "Name");
+	SET_STRING(Info->info[index].title, "Name");
+	SET_STRING(Info->info[index].desc, "EVMS name for the DISK storage object");
+	Info->info[index].type = EVMS_Type_String;
+	SET_STRING(Info->info[index].value.s, disk->name);
+	index++;
+
+	SET_STRING(Info->info[index].name, "Size");
+	SET_STRING(Info->info[index].title, "Size");
+	SET_STRING(Info->info[index].desc, "Size of the disk in sectors");
+	Info->info[index].type = EVMS_Type_Unsigned_Int64;
+	Info->info[index].unit = EVMS_Unit_Sectors;
+	Info->info[index].flags |= EVMS_EINFO_FLAGS_NO_UNIT_CONVERSION;
+	Info->info[index].value.ui64 = disk->size;
+	index++;
+
+	SET_STRING(Info->info[index].name, "Cyl");
+	SET_STRING(Info->info[index].title, "Cylinders");
+	SET_STRING(Info->info[index].desc, "Drive geometry -- number of cylinders");
+	Info->info[index].type = EVMS_Type_Unsigned_Int64;
+	Info->info[index].value.ui64 = disk->geometry.cylinders;
+	index++;
+
+	SET_STRING(Info->info[index].name, "Heads");
+	SET_STRING(Info->info[index].title, "Heads");
+	SET_STRING(Info->info[index].desc, "Drive geometry -- number of heads");
+	Info->info[index].type = EVMS_Type_Unsigned_Int32;
+	Info->info[index].value.ui32 = disk->geometry.heads;
+	index++;
+
+	SET_STRING(Info->info[index].name, "Sectors");
+	SET_STRING(Info->info[index].title, "Sectors");
+	SET_STRING(Info->info[index].desc, "Drive geometry -- sectors per track");
+	Info->info[index].type = EVMS_Type_Unsigned_Int32;
+	Info->info[index].value.ui32 = disk->geometry.sectors_per_track;
+	index++;
+
+	SET_STRING(Info->info[index].name, "SectorSize");
+	SET_STRING(Info->info[index].title, "Sector Size");
+	SET_STRING(Info->info[index].desc, "Number of bytes per sector");
+	Info->info[index].type = EVMS_Type_Unsigned_Int32;
+	Info->info[index].unit = EVMS_Unit_Bytes;
+	Info->info[index].value.ui32 = disk->geometry.bytes_per_sector;
+	index++;
+
+	SET_STRING(Info->info[index].name, "BlockSize");
+	SET_STRING(Info->info[index].title, "Block Size");
+	SET_STRING(Info->info[index].desc, "Number of bytes per block");
+	Info->info[index].type = EVMS_Type_Unsigned_Int64;
+	Info->info[index].unit = EVMS_Unit_Bytes;
+	Info->info[index].value.ui64 = disk->geometry.block_size;
+	index++;
+
+	SET_STRING(Info->info[index].name, "BootLimit");
+	SET_STRING(Info->info[index].title, "Boot Cylinder Limit");
+	SET_STRING(Info->info[index].desc, "LBA of the first sector above the boot cylinder limit for this drive");
+	Info->info[index].type = EVMS_Type_Unsigned_Int64;
+	Info->info[index].value.ui64 = disk->geometry.boot_cylinder_limit;
+	index++;
+
+	SET_STRING(Info->info[index].name, "Segments");
+	SET_STRING(Info->info[index].title, "Segments");
+	SET_STRING(Info->info[index].desc, "Number of segments discovered on the drive (metadata, data, freespace)");
+	Info->info[index].type = EVMS_Type_Unsigned_Int32;
+	Info->info[index].value.ui32 = EngFncs->list_count(disk->parent_objects);
+	index++;
+
+	Info->count = index;
+	*info = Info;
+	rc = 0;
+
+out:
+	LOG_EXIT_INT(rc);
+	return rc;
+}
+
+/**
+ * LD_get_plugin_info
+ *
+ * Returns plug-in specific information
+ **/
+static int LD_get_plugin_info(char * descriptor_name,
+			      extended_info_array_t ** info)
+{
+	int rc = EINVAL;
+	extended_info_array_t * Info;
+	char version_string[64];
+	char required_engine_api_version_string[64];
+	char required_plugin_api_version_string[64];
+
+	LOG_ENTRY();
+
+	if (!info) {
+		goto out;
+	}
+	*info = NULL;
+
+	if (descriptor_name) {
+		goto out;
+	}
+
+	Info = EngFncs->engine_alloc(sizeof(extended_info_array_t) +
+				     6 * sizeof(extended_info_t));
+	if (!Info) {
+		rc = ENOMEM;
+		goto out;
+	}
+
+	Info->count = 6;
+
+	sprintf(version_string, "%d.%d.%d",
+		MAJOR_VERSION, MINOR_VERSION, PATCH_LEVEL);
+
+	sprintf(required_engine_api_version_string, "%d.%d.%d",
+		my_plugin_record->required_engine_api_version.major,
+		my_plugin_record->required_engine_api_version.minor,
+		my_plugin_record->required_engine_api_version.patchlevel);
+
+	sprintf(required_plugin_api_version_string, "%d.%d.%d",
+		my_plugin_record->required_plugin_api_version.plugin.major,
+		my_plugin_record->required_plugin_api_version.plugin.minor,
+		my_plugin_record->required_plugin_api_version.plugin.patchlevel);
+
+	SET_STRING(Info->info[0].name, "Short Name");
+	SET_STRING(Info->info[0].title, "Short Name");
+	SET_STRING(Info->info[0].desc, "A short name given to this plugin");
+	Info->info[0].type = EVMS_Type_String;
+	SET_STRING(Info->info[0].value.s, my_plugin_record->short_name);
+
+	SET_STRING(Info->info[1].name, "Long Name");
+	SET_STRING(Info->info[1].title, "Long Name");
+	SET_STRING(Info->info[1].desc, "A long name given to this plugin");
+	Info->info[1].type = EVMS_Type_String;
+	SET_STRING(Info->info[1].value.s, my_plugin_record->long_name);
+
+	SET_STRING(Info->info[2].name, "Type");
+	SET_STRING(Info->info[2].title, "Plug-in Type");
+	SET_STRING(Info->info[2].desc, "There are various types of plugins, each responsible for some kind of storage object.");
+	Info->info[2].type = EVMS_Type_String;
+	SET_STRING(Info->info[2].value.s, "Device Manager");
+
+	SET_STRING(Info->info[3].name, "Version");
+	SET_STRING(Info->info[3].title, "Plugin Version");
+	SET_STRING(Info->info[3].desc, "Version number of this plug-in");
+	Info->info[3].type = EVMS_Type_String;
+	SET_STRING(Info->info[3].value.s, version_string);
+
+	SET_STRING(Info->info[4].name, "Required Engine Services Version");
+	SET_STRING(Info->info[4].title, "Required Engine Services Version");
+	SET_STRING(Info->info[4].desc, "Version of the Engine services that this plug-in requires. It will not run on older versions of the Engine services.");
+	Info->info[4].type = EVMS_Type_String;
+	SET_STRING(Info->info[4].value.s, required_engine_api_version_string);
+
+	SET_STRING(Info->info[5].name, "Required Plug-in API Version");
+	SET_STRING(Info->info[5].title, "Required Plug-in API Version");
+	SET_STRING(Info->info[5].desc, "Version of the Engine plug-in API that this plug-in requires. It will not run on older versions of the Engine plug-in API.");
+	Info->info[5].type = EVMS_Type_String;
+	SET_STRING(Info->info[5].value.s, required_plugin_api_version_string);
+
+	*info = Info;
+	rc = 0;
+
+out:
+	LOG_EXIT_INT(rc);
+	return rc;
+}
+
+/**
+ * LD_direct_plugin_communication
+ *
+ * Device-manager-specific commands for starting and stopping the cache, and
+ * opening and closing a disk.
+ **/
+static int LD_direct_plugin_communication(void * object,
+					  void * arg)
+{
+	int rc = 0;
+	storage_object_t * disk = object;
+	ldm_dpc_t * dcp = arg;
+
+	LOG_ENTRY();
+	if (disk) {
+		LOG_DEBUG("Action targeted at %s.\n", disk->name);
+	}
+
+	switch (dcp->function) {
+
+	case START_CACHE:
+		LOG_DEBUG("START_CACHE\n");
+		break;
+
+	case STOP_CACHE:
+		LOG_DEBUG("STOP_CACHE\n");
+		break;
+
+       	case LDM_CLOSE_DISK:
+		LOG_DEBUG("LDM_CLOSE_DISK\n");
+		close_dev(disk);
+		break;
+
+	case LDM_OPEN_DISK:
+		LOG_DEBUG("LDM_OPEN_DISK\n");
+		rc = open_dev(disk);
+		break;
+
+	default:
+		LOG_ERROR("%d is not a valid function code.\n", dcp->function);
+		rc = EINVAL;
+	}
+
+	LOG_EXIT_INT(rc);
+	return rc;
+}
+
+static plugin_functions_t ft_sysfs = {
+	.setup_evms_plugin		= LD_setup,
+	.cleanup_evms_plugin		= LD_cleanup,
+	.discover			= LD_discover,
+	.discard			= LD_discard,
+	.add_sectors_to_kill_list	= LD_add_sectors_to_kill_list,
+	.commit_changes			= LD_commit_changes,
+	.get_info			= LD_get_info,
+	.get_plugin_info		= LD_get_plugin_info,
+	.read				= LD_read,
+	.write				= LD_write,
+	.direct_plugin_communication	= LD_direct_plugin_communication
+};
+
+plugin_record_t LD_Plugin = {
+		/* FIXME: get official evms ids */
+	.id = SetPluginID((EVMS_OEM_IBM+1), EVMS_DEVICE_MANAGER, 3),
+	.version = {
+		.major		= MAJOR_VERSION,
+		.minor		= MINOR_VERSION,
+		.patchlevel	= PATCH_LEVEL
+	},
+	.required_engine_api_version = {
+		.major		= 13,
+		.minor		= 0,
+		.patchlevel	= 0
+	},
+	.required_plugin_api_version = {
+		.plugin = {
+			.major		= 11,
+			.minor		= 0,
+			.patchlevel	= 0
+		}
+	},
+	.short_name = "BIOSDskMgr",
+	.long_name = "BIOS Disk Manager",
+	.oem_name = "IBM",
+	.functions = {
+		.plugin = &ft_sysfs
+	},
+	.container_functions = NULL
+};
+
+plugin_record_t * my_plugin_record = &LD_Plugin;
+
+plugin_record_t * evms_plugin_records[] = { &LD_Plugin,
+					    NULL };
+
diff -Nurp evms-2.3.0/plugins/bios/bios.h evms-2.3.0-bios/plugins/bios/bios.h
--- evms-2.3.0/plugins/bios/bios.h	1969-12-31 18:00:00.000000000 -0600
+++ evms-2.3.0-bios/plugins/bios/bios.h	2004-03-13 20:12:32.000000000 -0600
@@ -0,0 +1,188 @@
+/*
+ *   (C) Copyright IBM Corp. 2001, 2003
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __BIOS_H__
+#define __BIOS_H__ 1
+
+#ifndef O_DIRECT
+#define O_DIRECT	0
+#endif
+
+#define BLKGETSIZE64	_IOR(0x12,114,size_t)
+#define BLKSSZGET	_IO(0x12,104)
+#define BLKBSZGET	_IOR(0x12,112,size_t)
+#define BLKBSZSET	_IOW(0x12,113,size_t)
+#define HDIO_GETGEO	0x0301
+#define HDIO_GETGEO_BIG	0x0330
+
+#define IGNORE_PCI_IDS	"biosraid.ignore_pci_ids"
+
+struct hd_geometry {
+	unsigned char heads;
+	unsigned char sectors;
+	unsigned short cylinders;
+	unsigned long start;
+};
+
+struct hd_big_geometry {
+	unsigned char heads;
+	unsigned char sectors;
+	unsigned int cylinders;
+	unsigned long start;
+};
+
+extern engine_functions_t *EngFncs;
+extern plugin_record_t    *my_plugin_record;
+
+/*-
+ * Copyright (c) 2000,2001 Søren Schmidt <sos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+                            
+struct highpoint_raid_conf
+{
+       int8_t  filler1[32];
+       u_int32_t       magic;
+#define HPT_MAGIC_OK   0x5a7816f0
+#define HPT_MAGIC_BAD  0x5a7816fd  
+
+       u_int32_t       magic_0;
+       u_int32_t       magic_1;
+       u_int32_t       order;  
+#define HPT_O_MIRROR   0x01  
+#define HPT_O_STRIPE   0x02
+#define HPT_O_OK       0x04
+
+       u_int8_t        raid_disks;
+       u_int8_t        raid0_shift; 
+       u_int8_t        type;
+#define HPT_T_RAID_0   0x00 
+#define HPT_T_RAID_1   0x01
+#define HPT_T_RAID_01_RAID_0   0x02
+#define HPT_T_SPAN             0x03
+#define HPT_T_RAID_3           0x04   
+#define HPT_T_RAID_5           0x05
+#define HPT_T_SINGLEDISK       0x06
+#define HPT_T_RAID_01_RAID_1   0x07
+
+       u_int8_t        disk_number;
+       u_int32_t       total_secs; 
+       u_int32_t       disk_mode;  
+       u_int32_t       boot_mode;
+       u_int8_t        boot_disk; 
+       u_int8_t        boot_protect;
+       u_int8_t        error_log_entries;
+       u_int8_t        error_log_index;  
+       struct
+       {
+               u_int32_t       timestamp;
+               u_int8_t        reason;   
+#define HPT_R_REMOVED          0xfe      
+#define HPT_R_BROKEN           0xff      
+
+               u_int8_t        disk;
+               u_int8_t        status;
+               u_int8_t        sectors;
+               u_int32_t       lba;
+       } errorlog[32];
+       u_int8_t        filler[60];
+};
+
+#define CONFIGOFFSET 4608
+
+/* HPT IDs from http://pciids.sf.net */
+#define PCI_VENDOR_TRIONES	0x1103
+#define PCI_DEVICE_HPT370	0x0004
+#define PCI_DEVICE_HPT372A	0x0005
+#define PCI_DEVICE_HPT302	0x0006
+#define PCI_DEVICE_HPT371	0x0007
+#define PCI_DEVICE_HPT374	0x0008
+#define PCI_DEVICE_HPT372N	0x0009
+
+#define IDEDIR "/proc/ide"
+
+/**
+ * hptdisk
+ *
+ * structure for defining a disk that is attachted to the HPT37x controller
+ **/
+struct hptdisk {
+	char devname[PATH_MAX];	/* define name of the disk */
+	char claimed;		/* set to true if the disk
+				   is attachted to a raid volume */
+	struct highpoint_raid_conf superblock;
+	int hardsector_size;
+	int32_t major;
+	int32_t minor;
+	int block_size;
+};
+
+/**
+ * hptraid
+ *
+ * structure for a hpt-raid volume
+ **/
+struct hptraid {
+	char name[PATH_MAX];	/* device name of volume */
+	unsigned int stride;	/* stripesize */
+	unsigned int disks;	/* number of disks in array */
+	u_int64_t sectors;	/* disksize in sectors */
+        u_int32_t magic_0;
+        u_int32_t magic_1;
+	u_int8_t type;		/* raid level (raid-0, raid-1, ...) */
+	u_int32_t hardsector_size;
+	int block_size;
+
+	enum {setup=0, operational, broken} status;
+
+	dm_target_t * dm_target;	/* data structure for the device
+					   mapper */
+	
+	struct hptdisk * disk[8];	/* pointers to the disks of the
+					   raid volume */
+
+	int fd;				/* filedestriptor for open_dev(),
+					   LD_read/write(), ... */
+};
+
+#endif
+

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2004-03-14 14:07 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-03-14 14:04 [ANNOUNCE] Highpoint-Tech Plugin 0.0.1 for EVMS 2.3.0 Wilfried Weissmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox