/* -*- linux-c -*- */
/*
 *   Copyright (c) International Business Machines  Corp., 2000
 *
 *   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
 */
/*
 * linux/include/linux/evms/evms.h
 *
 * EVMS kernel header file
 *
 */

#ifndef __EVMS_INCLUDED__
#define __EVMS_INCLUDED__ 1

#include <linux/blkdev.h>
#include <linux/genhd.h>
#include <linux/slab.h>
#include <linux/wait.h>

/**
 * version info 
 **/
#define EVMS_MAJOR_VERSION              1
#define EVMS_MINOR_VERSION              2
#define EVMS_PATCHLEVEL_VERSION         1

/**
 * general defines section
 **/
#define FALSE                           0
#define TRUE                            1

#define MAX_EVMS_VOLUMES                256
#define EVMS_VOLUME_NAME_SIZE           127
#define IBM_OEM_ID                      8112
#define EVMS_INITIAL_CRC                0xFFFFFFFF
#define EVMS_MAGIC_CRC			0x31415926
#define EVMS_VSECTOR_SIZE               512
#define EVMS_VSECTOR_SIZE_SHIFT         9

#define DEV_PATH			"/dev"
#define EVMS_DIR_NAME			"evms"
#define EVMS_DEV_NAME			"block_device"
#define EVMS_DEV_NODE_PATH		DEV_PATH "/" EVMS_DIR_NAME "/"
#define EVMS_DEVICE_NAME		DEV_PATH "/" EVMS_DIR_NAME "/" EVMS_DEV_NAME

/**
 * kernel logging levels defines 
 **/
#define EVMS_INFO_CRITICAL              0
#define EVMS_INFO_SERIOUS               1
#define EVMS_INFO_ERROR                 2
#define EVMS_INFO_WARNING               3
#define EVMS_INFO_DEFAULT               5
#define EVMS_INFO_DETAILS               6
#define EVMS_INFO_DEBUG                 7
#define EVMS_INFO_EXTRA                 8
#define EVMS_INFO_ENTRY_EXIT            9
#define EVMS_INFO_EVERYTHING            10

/**
 * kernel logging level	variable
 **/
extern int evms_info_level;

/**
 * LOG MACROS to make evms log messages 
 * look much cleaner in the source.
 **/
#define EVMS_LOG_PREFIX "evms: "
#define evmsLOG(info_level, prspec)	{ if (evms_info_level >= info_level) printk prspec; }
#define LOG_CRITICAL(msg, args...)	evmsLOG(EVMS_INFO_CRITICAL,   (KERN_CRIT    EVMS_LOG_PREFIX LOG_PREFIX msg, ## args))
#define LOG_SERIOUS(msg, args...)	evmsLOG(EVMS_INFO_SERIOUS,    (KERN_ERR     EVMS_LOG_PREFIX LOG_PREFIX msg, ## args))
#define LOG_ERROR(msg, args...)		evmsLOG(EVMS_INFO_ERROR,      (KERN_ERR     EVMS_LOG_PREFIX LOG_PREFIX msg, ## args))
#define LOG_WARNING(msg, args...)	evmsLOG(EVMS_INFO_WARNING,    (KERN_WARNING EVMS_LOG_PREFIX LOG_PREFIX msg, ## args))
#define LOG_DEFAULT(msg, args...)	evmsLOG(EVMS_INFO_DEFAULT,    (KERN_INFO    EVMS_LOG_PREFIX LOG_PREFIX msg, ## args))
#define LOG_DETAILS(msg, args...)	evmsLOG(EVMS_INFO_DETAILS,    (KERN_INFO    EVMS_LOG_PREFIX LOG_PREFIX msg, ## args))
#define LOG_DEBUG(msg, args...)		evmsLOG(EVMS_INFO_DEBUG,      (KERN_INFO    EVMS_LOG_PREFIX LOG_PREFIX msg, ## args))
#define LOG_EXTRA(msg, args...)		evmsLOG(EVMS_INFO_EXTRA,      (KERN_INFO    EVMS_LOG_PREFIX LOG_PREFIX msg, ## args))
#define LOG_ENTRY_EXIT(msg, args...)	evmsLOG(EVMS_INFO_ENTRY_EXIT, (KERN_INFO    EVMS_LOG_PREFIX LOG_PREFIX msg, ## args))
#define LOG_EVERYTHING(msg, args...)	evmsLOG(EVMS_INFO_EVERYTHING, (KERN_INFO    EVMS_LOG_PREFIX LOG_PREFIX msg, ## args))

/**
 * Macros to cleanly print 64-bit numbers on both 32-bit and 64-bit machines.
 * Use these in place of %Ld, %Lu, and %Lx.
 **/
#if BITS_PER_LONG > 32
#define PFD64 "%ld"
#define PFU64 "%lu"
#define PFX64 "%lx"
#else
#define PFD64 "%Ld"
#define PFU64 "%Lu"
#define PFX64 "%Lx"
#endif

/**
 * helpful PROCFS macro
 **/
#define PROCPRINT(msg, args...) (sz += sprintf(page + sz, msg, ## args));\
			if (sz < off)\
				off -= sz, sz = 0;\
			else if (sz >= off + count)\
				goto out

/**
 * PluginID convenience macros
 *
 * An EVMS PluginID is a 32-bit number with the following bit positions:
 * Top 16 bits: OEM identifier. See IBM_OEM_ID.
 * Next 4 bits: Plugin type identifier. See evms_plugin_code.
 * Lowest 12 bits: Individual plugin identifier within a given plugin type.
 **/
#define SetPluginID(oem, type, id) ((oem << 16) | (type << 12) | id)
#define GetPluginOEM(pluginid) (pluginid >> 16)
#define GetPluginType(pluginid) ((pluginid >> 12) & 0xf)
#define GetPluginID(pluginid) (pluginid & 0xfff)

/**
 * enum evms_plugin_type - evms plugin types
 **/
enum evms_plugin_code {
	EVMS_NO_PLUGIN = 0,
	EVMS_DEVICE_MANAGER,
	EVMS_SEGMENT_MANAGER,
	EVMS_REGION_MANAGER,
	EVMS_FEATURE,
	EVMS_ASSOCIATIVE_FEATURE,
	EVMS_FILESYSTEM_INTERFACE_MODULE,
	EVMS_CLUSTER_MANAGER_INTERFACE_MODULE,
	EVMS_DISTRIBUTED_LOCK_MANAGER_INTERFACE_MODULE
};

/**
 * struct evms_version - 
 * @major:	changes when incompatible difference are introduced
 * @minor:	changes when additions are made
 * @patchlevel:	reflects bug level fixes within a particular major/minor pair
 *
 * generic versioning info used by EVMS
 **/
struct evms_version {
	u32 major;
	u32 minor;
	u32 patchlevel;
};

/**
 * struct evms_plugin_header - kernel plugin header record
 * @id: 			plugin id
 * @version: 			plugin version
 * @required_services_version: 	required common services version
 * @fops: 			table of function operations
 *
 * kernel plugin header record
 **/
struct evms_plugin_header {
	u32 id;
	struct evms_version version;
	struct evms_version required_services_version;
	struct evms_plugin_fops *fops;
};

/**
 * struct evms_feature_header - EVMS generic on-disk header for features
 * @signature: 			unique magic number
 * @crc: 			structure's crc
 * @version: 			feature header version
 * @engine_version: 		created by this evms engine version
 * @flags: 			feature characteristics, bit definitions below.
 * @feature_id: 		indicates which feature this header is describing
 * @sequence_number: 		describes most recent copy of redundant metadata
 * @alignment_padding: 		used when objects are moved between different sized devices
 * @feature_data1_start_lsn: 	object relative start of 1st copy feature data
 * @feature_data1_size: 	size of 1st copy of feature data
 * @feature_data2_start_lsn: 	object relative start of 2nd copy feature data
 * @feature_data2_size: 	size of 2nd copy of feature data
 * @volume_serial_number: 	unique/persistent volume identifier
 * @volume_system_id: 		unique/persistent minor number
 * @object_depth: 		depth of object in volume tree
 * @object_name: 		object's name
 * @volume_name: 		volume name object is a part of
 * @pad: 			padding to make structure be 512 byte aligned
 *
 * generic on-disk header used to describe any EVMS feature
 * NOTE: 2nd copy of feature data is optional, if used set start_lsn to 0.
 **/
struct evms_feature_header {
	u32 signature;
	u32 crc;
	struct evms_version version;
	struct evms_version engine_version;
	u32 flags;
	u32 feature_id;
	u64 sequence_number;
	u64 alignment_padding;
	u64 feature_data1_start_lsn;
	u64 feature_data1_size;
	u64 feature_data2_start_lsn;
	u64 feature_data2_size;
	u64 volume_serial_number;
	u32 volume_system_id;
	u32 object_depth;
	u8 object_name[EVMS_VOLUME_NAME_SIZE + 1];
	u8 volume_name[EVMS_VOLUME_NAME_SIZE + 1];
	u8 pad[152];
};

/**
 * field evms_feature_header.signature majic number
 **/
#define EVMS_FEATURE_HEADER_SIGNATURE           0x54414546	/* FEAT */
/**
 * field evms_feature_header.flags defines
 **/
#define EVMS_FEATURE_ACTIVE                     (1<<0)
#define EVMS_FEATURE_VOLUME_COMPLETE            (1<<1)
#define EVMS_VOLUME_DATA_OBJECT			(1<<16)
#define EVMS_VOLUME_DATA_STOP			(1<<17)
/**
 * struct evms_feature_header version info
 **/
#define EVMS_FEATURE_HEADER_MAJOR	3
#define EVMS_FEATURE_HEADER_MINOR	0
#define EVMS_FEATURE_HEADER_PATCHLEVEL	0

/**
 * EVMS specific error codes 
 **/
#define EVMS_FEATURE_FATAL_ERROR                257
#define EVMS_VOLUME_FATAL_ERROR                 258
#define EVMS_FEATURE_INCOMPLETE_ERROR		259

/**
 * struct evms_volume_info - exported volume info
 * @volume_sn: 		unique volume identifier
 * @volume_minor: 	persistent device minor assigned to this volume
 * @volume_name: 	persistent name assigned to this volume
 *
 * a collection of volume specific info
 **/
struct evms_volume_info {
	u64 volume_sn;
	u32 volume_minor;
	u8 volume_name[EVMS_VOLUME_NAME_SIZE + 1];
};

/**
 * struct evms_logical_node - generic kernel storage object
 * @total_vsectors: 	  0 size of this object in 512 byte units
 * @plugin: 		  8 plugin that created/owns/manages this storage object
 * @private: 		 12 location for owner to store private info
 * @flags: 		 16 storage object characteristics (set/used by plugins)
 *	   		    bit definitions located in evms_common.h
 * @iflags: 		 20 internal flags (used exclusively by the framework, not for plugins to use/set)
 *	    		    bit definitions below.
 * @hardsector_size: 	 24 assumed physical sector size of underlying device
 * @block_size: 	 28 default block size for this object
 * @system_id: 		 32 system indicator (set by the segment manager)
 * @volume_info: 	 36 persistent volume info, used only by EVMS volumes
 * @feature_header: 	 40 generic on-disk metadata describing any EVMS feature
 * @next: 		 44 linked list field
 * @name: 		 48 storage object name
 *			176
 *
 * generic kernel storage object
 */
struct evms_logical_node {
	u64 total_vsectors;
	struct evms_plugin_header *plugin;
	void *private;
	u32 flags;
	u32 iflags;
	int hardsector_size;
	int block_size;
	u32 system_id;
	struct evms_volume_info *volume_info;
	struct evms_feature_header *feature_header;
	struct evms_logical_node *next;
	u8 name[EVMS_VOLUME_NAME_SIZE + 1];
};

/**
 * fields evms_logical_node.flags & evms_logical_volume.flags defines
 **/
#define EVMS_FLAGS_WIDTH                   	32
#define EVMS_VOLUME_FLAG                        (1<<0)
#define EVMS_VOLUME_PARTIAL_FLAG                (1<<1)
#define EVMS_VOLUME_PARTIAL			(1<<1)
#define EVMS_VOLUME_SET_READ_ONLY               (1<<2)
#define EVMS_VOLUME_READ_ONLY               	(1<<2)
/**
 * these bits define volume status 
 **/
#define EVMS_MEDIA_CHANGED			(1<<20)
#define EVMS_DEVICE_UNPLUGGED			(1<<21)
/**
 * these bits used for removable status 
 **/
#define EVMS_DEVICE_MEDIA_PRESENT		(1<<24)
#define EVMS_DEVICE_PRESENT			(1<<25)
#define EVMS_DEVICE_LOCKABLE			(1<<26)
#define EVMS_DEVICE_REMOVABLE			(1<<27)

/**
 * fields evms_logical_node.iflags defines
 **/
#define EVMS_FEATURE_BOTTOM			(1<<0)
#define EVMS_TOP_SEGMENT			(1<<1)

/**
 * macro to obtain a node's name from either EVMS or compatibility volumes
 **/
#define EVMS_GET_NODE_NAME(node)	((node->flags & EVMS_VOLUME_FLAG) ? \
					 node->volume_info->volume_name :    \
					 node->name)

/**
 * macro used to transform to/from userland device handles and device storage object nodes
 **/
#define EVMS_HANDLE_KEY         0x0123456789ABCDEF
#define DEV_HANDLE_TO_NODE(handle) ((struct evms_logical_node *)(unsigned long)((handle) ^ EVMS_HANDLE_KEY))
#define NODE_TO_DEV_HANDLE(node) (((u64)(unsigned long)(node)) ^ EVMS_HANDLE_KEY)

/**
 * struct evms_logical_volume - logical volume info
 * @name: 			logical volume name
 * @node: 			logical volume storage object
 * @flags: 			characteristics of logical volume
 * @quiesced: 			quiesce state info
 * @vfs_quiesced: 		vfs quiesce state info
 * @opens:			count of times the volume has been opened
 * @requests_in_progress: 	count of in-flight I/Os
 * @wait_queue: 		used when volume is quiesced
 * @devfs_handle: 		handle for devfs
 * @request_queue: 		unique request queue
 *
 * contains all the fields needed to manage to a logical volume
 **/
struct evms_logical_volume {
	u8 *name;
	struct evms_logical_node *node;
	int flags;
	int quiesced;
	int vfs_quiesced;
	atomic_t opens;
	atomic_t requests_in_progress;
	wait_queue_head_t wait_queue;
	devfs_handle_t devfs_handle;
	request_queue_t request_queue;
};

/**
 * field evms_logical_volume.flags defines 
 **/
/**
 * queued flags bits 
 **/
#define EVMS_REQUESTED_DELETE			(1<<5)
#define EVMS_REQUESTED_QUIESCE			(1<<6)
#define EVMS_REQUESTED_VFS_QUIESCE		(1<<7)
/**
 * this bit indicates corruption 
 **/
#define EVMS_VOLUME_CORRUPT			(1<<8)
/**
 * these bits define the source of the corruption 
 **/
#define EVMS_VOLUME_SOFT_DELETED               	(1<<9)
#define EVMS_DEVICE_UNAVAILABLE			(1<<10)

/*
 * The following function table is used for all plugins.
 */
/**
 * struct evms_plugin_fops - evms plugin's table of function operations
 * @discover: 		volume discovery entry point
 * @end_discover: 	final discovery entry point
 * @delete: 		delete volume entry point
 * @read: 		asynchronous read entry point
 * @write: 		asynchronous write entry point
 * @init_io: 		synchronous io entry point
 * @ioctl: 		generic ioctl entry point
 * @direct_ioctl: 	non-generic ioctl entry point
 *
 * evms plugin's table of function operations
 **/
struct evms_plugin_fops {
	int (*discover) (struct evms_logical_node **);
	int (*end_discover) (struct evms_logical_node **);
	int (*delete) (struct evms_logical_node *);
	void (*read) (struct evms_logical_node *, struct buffer_head *);
	void (*write) (struct evms_logical_node *, struct buffer_head *);
	int (*init_io) (struct evms_logical_node *, int, u64,
			u64, void *);
	int (*ioctl) (struct evms_logical_node *, struct inode *,
		      struct file *, u32, unsigned long);
	int (*direct_ioctl) (struct inode *, struct file *,
			     u32, unsigned long);
};

/**
 * convenience macros to use plugin's fops entry points  
 **/
#define DISCOVER(node, list) ((node)->plugin->fops->discover(list))
#define END_DISCOVER(node, list) ((node)->plugin->fops->end_discover(list))
#define DELETE(node) ((node)->plugin->fops->delete(node))
#define R_IO(node, bh)  ((node)->plugin->fops->read(node, bh))
#define W_IO(node, bh)  ((node)->plugin->fops->write(node, bh))
#define INIT_IO(node, rw_flag, start_sec, num_secs, buf_addr) ((node)->plugin->fops->init_io(node, rw_flag, start_sec, num_secs, buf_addr))
#define IOCTL(node, inode, file, cmd, arg)    ((node)->plugin->fops->ioctl(node, inode, file, cmd, arg))
#define DIRECT_IOCTL(reg_record, inode, file, cmd, arg)   ((reg_record)->plugin->fops->direct_ioctl(inode, file, cmd, arg))

/**
 * struct evms_list_node - generic non-imbedded list node object
 * @item:	ptr to object in list
 * @next:	ptr to next item in list
 *
 * light weight generic non-imbedded list object definition
 **/
struct evms_list_node {
	void *item;
	struct evms_list_node *next;
};

/**
 * struct evms_pool_mgmt - anchor block for private pool management
 * @cachep: 		kmem_cache_t variable
 * @member_size: 	size of each element in the pool
 * @head:
 * @waiters: 		count of waiters
 * @wait_queue: 	list of waiters
 * @name: 		name of the pool (must be less than 20 chars)
 *
 * anchor block for private pool management
 **/
struct evms_pool_mgmt {
	kmem_cache_t *cachep;
	int member_size;
	void *head;
	atomic_t waiters;
	wait_queue_head_t wait_queue;
	u8 *name;
};

/*
 * Notes:  
 *	All of the following kernel thread functions belong to EVMS base.
 *	These functions were copied from md_core.c
 */
#define EVMS_THREAD_WAKEUP 0
/**
 * struct evms_thread
 * @run:	
 * @data:	
 * @wqueue:	thread wait queue
 * @flags:	thread attributes
 * @event:	event completion
 * @tsk:	task info
 * @name:	thread name
 *
 * data structure for creating/managing a kernel thread
 **/
struct evms_thread {
	void (*run) (void *data);
	void *data;
	wait_queue_head_t wqueue;
	unsigned long flags;
	struct completion *event;
	struct task_struct *tsk;
	const u8 *name;
};

/**
 * EVMS (common services) exported functions prototypes 
 *
 * since these function names are global, evms_cs_ has been prepended
 * to each function name, to ensure they do not collide with any
 * other global functions in the kernel.
 **/
#define EVMS_COMMON_SERVICES_MAJOR              0
#define EVMS_COMMON_SERVICES_MINOR              6
#define EVMS_COMMON_SERVICES_PATCHLEVEL         0

extern int evms_cs_check_version(struct evms_version *, struct evms_version *);
extern int evms_cs_allocate_logical_node(struct evms_logical_node **);
extern void evms_cs_deallocate_volume_info(struct evms_logical_node *);
extern void evms_cs_deallocate_logical_node(struct evms_logical_node *);
extern int evms_cs_register_plugin(struct evms_plugin_header *);
extern int evms_cs_unregister_plugin(struct evms_plugin_header *);
extern int evms_cs_add_logical_node_to_list(struct evms_logical_node **,
				     struct evms_logical_node *);
extern int evms_cs_remove_logical_node_from_list(struct evms_logical_node **,
					  struct evms_logical_node *);
extern int evms_cs_kernel_ioctl(struct evms_logical_node *, u32, unsigned long);
inline unsigned long evms_cs_size_in_vsectors(long long);
inline int evms_cs_log2(long long);
extern u32 evms_cs_calculate_crc(u32, void *, u32);
#define EVMS_BLOCKABLE TRUE
extern struct evms_pool_mgmt *evms_cs_create_pool(int, u8 *,
						  void (*ctor)(void *, kmem_cache_t *,
							       unsigned long),
						  void (*dtor)(void *, kmem_cache_t *,
							       unsigned long));
extern void *evms_cs_allocate_from_pool(struct evms_pool_mgmt *, int);
extern void evms_cs_deallocate_to_pool(struct evms_pool_mgmt *, void *);
extern void evms_cs_destroy_pool(struct evms_pool_mgmt *);
extern int evms_cs_register_for_end_io_notification(void *,
						    struct buffer_head *,
						    void *callback_function);
extern struct evms_list_node **evms_cs_lookup_item_in_list(struct evms_list_node **,
							   void *);
extern int evms_cs_add_item_to_list(struct evms_list_node **, void *);
extern int evms_cs_remove_item_from_list(struct evms_list_node **, void *);
extern int evms_cs_register_device(struct evms_logical_node *);
extern int evms_cs_unregister_device(struct evms_logical_node *);
extern int evms_cs_find_next_device(struct evms_logical_node *,
				    struct evms_logical_node **);
extern void evms_cs_signal_event(int);
extern struct evms_thread *evms_cs_register_thread(void (*run)(void *),
						   void *data, const u8 *name);
extern void evms_cs_unregister_thread(struct evms_thread *thread);
extern void evms_cs_wakeup_thread(struct evms_thread *thread);
extern void evms_cs_interrupt_thread(struct evms_thread *thread);
extern struct proc_dir_entry *evms_cs_get_evms_proc_dir(void);
extern int evms_cs_volume_request_in_progress(kdev_t, int, int *);
extern void evms_cs_invalidate_volume(struct evms_logical_node *topmost_node);

/* EVMS exported global variables */
extern struct evms_pool_mgmt *evms_bh_pool;
extern u8 *evms_primary_string;
extern u8 *evms_secondary_string;

/* Have to include this at the end, since it depends
 * on structures and definitions in this file.
 */
#include <linux/evms/evms_ioctl.h>

#endif

