diff options
Diffstat (limited to 'include/asm-s390/dasd.h')
-rw-r--r-- | include/asm-s390/dasd.h | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/include/asm-s390/dasd.h b/include/asm-s390/dasd.h new file mode 100644 index 000000000..ea5e43eae --- /dev/null +++ b/include/asm-s390/dasd.h @@ -0,0 +1,339 @@ +/* + * File...........: linux/drivers/s390/block/dasd.c + * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> + * Bugreports.to..: <Linux390@de.ibm.com> + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 + * + * History of changes (starts July 2000) + */ + +#ifndef DASD_H +#define DASD_H + +#include <linux/ioctl.h> +#include <asm/irq.h> + +#define IOCTL_LETTER 'D' +/* Disable the volume (for Linux) */ +#define BIODASDDISABLE _IO(IOCTL_LETTER,0) +/* Enable the volume (for Linux) */ +#define BIODASDENABLE _IO(IOCTL_LETTER,1) +/* Issue a reserve/release command, rsp. */ +#define BIODASDRSRV _IO(IOCTL_LETTER,2) /* reserve */ +#define BIODASDRLSE _IO(IOCTL_LETTER,3) /* release */ +#define BIODASDSLCK _IO(IOCTL_LETTER,4) /* steal lock */ +/* Read sense ID infpormation */ +#define BIODASDRSID _IOR(IOCTL_LETTER,0,senseid_t) +/* Format the volume or an extent */ +#define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) +/* translate blocknumber of partition to absolute */ +#define BIODASDRWTB _IOWR(IOCTL_LETTER,0,int) + +#define DASD_NAME "dasd" +#define DASD_PARTN_BITS 2 +#define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS)) + +/* + * struct format_data_t + * represents all data necessary to format a dasd + */ +typedef struct format_data_t { + int start_unit; /* from track */ + int stop_unit; /* to track */ + int blksize; /* sectorsize */ + int intensity; /* 0: normal, 1:record zero, 3:home address, 4 invalidate tracks */ +} __attribute__ ((packed)) format_data_t; + +#define DASD_FORMAT_DEFAULT_START_UNIT 0 +#define DASD_FORMAT_DEFAULT_STOP_UNIT -1 +#define DASD_FORMAT_DEFAULT_BLOCKSIZE -1 +#define DASD_FORMAT_DEFAULT_INTENSITY -1 + +#ifdef __KERNEL__ +#include <linux/version.h> +#include <linux/major.h> +#include <linux/wait.h> +#include <asm/ccwcache.h> +#include <linux/blk.h> +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) +#include <linux/blkdev.h> +#include <linux/devfs_fs_kernel.h> +#endif +#include <linux/genhd.h> +#include <linux/hdreg.h> +#include <linux/compatmac.h> + +#include <asm/s390dyn.h> +#include <asm/todclk.h> +#include <asm/debug.h> + +/* Kernel Version Compatibility section */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) +typedef struct request *request_queue_t; +#define block_device_operations file_operations +#define __setup(x,y) struct dasd_device_t +#define devfs_register_blkdev(major,name,ops) register_blkdev(major,name,ops) +#define register_disk(dd,dev,partn,ops,size) \ +do { \ + dd->sizes[MINOR(dev)] = size >> 1; \ + resetup_one_dev(dd,MINOR(dev)>>DASD_PARTN_BITS); \ +} while(0) +#define init_waitqueue_head(x) do { *x = NULL; } while(0) +#define blk_cleanup_queue(x) do {} while(0) +#define blk_init_queue(x...) do {} while(0) +#define blk_queue_headactive(x...) do {} while(0) +#define blk_queue_make_request(x) do {} while(0) +#define list_empty(x) (0) +#define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \ +do { \ + blk_dev[d_major].request_fn = d_request_fn; \ + blk_dev[d_major].queue = d_queue_fn; \ + blk_dev[d_major].current_request = d_current; \ +} while(0) +#define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \ + major:D_MAJOR, \ + major_name:D_NAME, \ + minor_shift:D_PARTN_BITS, \ + max_p:1 << D_PARTN_BITS, \ + max_nr:D_PER_MAJOR, \ + nr_real:D_PER_MAJOR, +static inline struct request * +dasd_next_request( request_queue_t *queue ) +{ + return *queue; +} +static inline void +dasd_dequeue_request( request_queue_t * q, struct request *req ) +{ + *q = req->next; + req->next = NULL; +} +#else +#define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \ +do { \ + blk_dev[d_major].queue = d_queue_fn; \ +} while(0) +#define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \ + major:D_MAJOR, \ + major_name:D_NAME, \ + minor_shift:D_PARTN_BITS, \ + max_p:1 << D_PARTN_BITS, \ + nr_real:D_PER_MAJOR, +static inline struct request * +dasd_next_request( request_queue_t *queue ) +{ + return blkdev_entry_next_request(&queue->queue_head); +} +static inline void +dasd_dequeue_request( request_queue_t * q, struct request *req ) +{ + blkdev_dequeue_request (req); +} +#endif + +/* dasd_range_t are used for dynamic device att-/detachment */ +typedef struct dasd_devreg_t { + devreg_t devreg; /* the devreg itself */ + /* build a linked list of devregs, needed for cleanup */ + struct dasd_devreg_t *next; +} dasd_devreg_t; + +typedef enum { + dasd_era_fatal = -1, /* no chance to recover */ + dasd_era_none = 0, /* don't recover, everything alright */ + dasd_era_msg = 1, /* don't recover, just report... */ + dasd_era_recover = 2 /* recovery action recommended */ +} dasd_era_t; + +/* BIT DEFINITIONS FOR SENSE DATA */ +#define DASD_SENSE_BIT_0 0x80 +#define DASD_SENSE_BIT_1 0x40 +#define DASD_SENSE_BIT_2 0x20 +#define DASD_SENSE_BIT_3 0x10 + +#define check_then_set(where,from,to) \ +do { \ + if ((*(where)) != (from) ) { \ + printk (KERN_ERR PRINTK_HEADER "was %d\n", *(where)); \ + BUG(); \ + } \ + (*(where)) = (to); \ +} while (0) + +#define DASD_MESSAGE(d_loglevel,d_device,d_string,d_args...)\ +do { \ + int d_devno = d_device->devinfo.devno; \ + int d_irq = d_device->devinfo.irq; \ + char *d_name = d_device->name; \ + int d_major = MAJOR(d_device->kdev); \ + int d_minor = MINOR(d_device->kdev); \ + printk(d_loglevel PRINTK_HEADER \ + "/dev/%s(%d:%d), 0x%04X on SCH 0x%x:" \ + d_string "\n",d_name,d_major,d_minor,d_devno,d_irq,d_args ); \ +} while(0) + +/* + * struct dasd_sizes_t + * represents all data needed to access dasd with properly set up sectors + */ +typedef +struct dasd_sizes_t { + unsigned long blocks; /* size of volume in blocks */ + unsigned int bp_block; /* bytes per block */ + unsigned int s2b_shift; /* log2 (bp_block/512) */ +} dasd_sizes_t; + +/* + * struct dasd_chanq_t + * represents a queue of channel programs related to a single device + */ +typedef +struct dasd_chanq_t { + ccw_req_t *head; + ccw_req_t *tail; +} dasd_chanq_t; + +struct dasd_device_t; +struct request; + +/* + * signatures for the functions of dasd_discipline_t + * make typecasts much easier + */ +typedef ccw_req_t *(*dasd_erp_action_fn_t) (ccw_req_t * cqr); +typedef ccw_req_t *(*dasd_erp_postaction_fn_t) (ccw_req_t * cqr); + +typedef int (*dasd_ck_id_fn_t) (s390_dev_info_t *); +typedef int (*dasd_ck_characteristics_fn_t) (struct dasd_device_t *); +typedef int (*dasd_fill_geometry_fn_t) (struct dasd_device_t *, struct hd_geometry *); +typedef ccw_req_t *(*dasd_format_fn_t) (struct dasd_device_t *, struct format_data_t *); +typedef ccw_req_t *(*dasd_init_analysis_fn_t) (struct dasd_device_t *); +typedef int (*dasd_do_analysis_fn_t) (struct dasd_device_t *); +typedef int (*dasd_io_starter_fn_t) (ccw_req_t *); +typedef void (*dasd_int_handler_fn_t)(int irq, void *, struct pt_regs *); +typedef dasd_era_t (*dasd_error_examine_fn_t) (ccw_req_t *, devstat_t * stat); +typedef dasd_erp_action_fn_t (*dasd_error_analyse_fn_t) (ccw_req_t *); +typedef dasd_erp_postaction_fn_t (*dasd_erp_analyse_fn_t) (ccw_req_t *); +typedef ccw_req_t *(*dasd_cp_builder_fn_t)(struct dasd_device_t *,struct request *); +typedef char *(*dasd_dump_sense_fn_t)(struct dasd_device_t *,ccw_req_t *); +typedef ccw_req_t *(*dasd_reserve_fn_t)(struct dasd_device_t *); +typedef ccw_req_t *(*dasd_release_fn_t)(struct dasd_device_t *); +typedef ccw_req_t *(*dasd_merge_cp_fn_t)(struct dasd_device_t *); + + +/* + * the dasd_discipline_t is + * sth like a table of virtual functions, if you think of dasd_eckd + * inheriting dasd... + * no, currently we are not planning to reimplement the driver in C++ + */ +typedef struct dasd_discipline_t { + char ebcname[8]; /* a name used for tagging and printks */ + char name[8]; /* a name used for tagging and printks */ + + dasd_ck_id_fn_t id_check; /* to check sense data */ + dasd_ck_characteristics_fn_t check_characteristics; /* to check the characteristics */ + dasd_init_analysis_fn_t init_analysis; /* to start the analysis of the volume */ + dasd_do_analysis_fn_t do_analysis; /* to complete the analysis of the volume */ + dasd_fill_geometry_fn_t fill_geometry; /* to set up hd_geometry */ + dasd_io_starter_fn_t start_IO; + dasd_format_fn_t format_device; /* to format the device */ + dasd_error_examine_fn_t examine_error; + dasd_error_analyse_fn_t erp_action; + dasd_erp_analyse_fn_t erp_postaction; + dasd_cp_builder_fn_t build_cp_from_req; + dasd_dump_sense_fn_t dump_sense; + dasd_int_handler_fn_t int_handler; + dasd_reserve_fn_t reserve; + dasd_release_fn_t release; + dasd_merge_cp_fn_t merge_cp; + + struct dasd_discipline_t *next; /* used for list of disciplines */ +} dasd_discipline_t; + +typedef struct major_info_t { + struct major_info_t *next; + struct dasd_device_t **dasd_device; + struct gendisk gendisk; /* actually contains the major number */ +} __attribute__ ((packed)) major_info_t; + +typedef struct dasd_profile_info_t { + unsigned long dasd_io_reqs; /* number of requests processed at all */ + unsigned long dasd_io_secs[32]; /* histogram of request's sizes */ + unsigned long dasd_io_times[32]; /* histogram of requests's times */ + unsigned long dasd_io_timps[32]; /* histogram of requests's times per sector */ + unsigned long dasd_io_time1[32]; /* histogram of time from build to start */ + unsigned long dasd_io_time2[32]; /* histogram of time from start to irq */ + unsigned long dasd_io_time2ps[32]; /* histogram of time from start to irq */ + unsigned long dasd_io_time3[32]; /* histogram of time from irq to end */ +} dasd_profile_info_t; + +typedef struct dasd_device_t { + s390_dev_info_t devinfo; + dasd_discipline_t *discipline; + int level; + int open_count; + kdev_t kdev; + major_info_t *major_info; + struct dasd_chanq_t queue; + wait_queue_head_t wait_q; + request_queue_t request_queue; + devstat_t dev_status; /* needed ONLY!! for request_irq */ + dasd_sizes_t sizes; + char name[16]; /* The name of the device in /dev */ + char *private; /* to be used by the discipline internally */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) + devfs_handle_t devfs_entry; +#endif /* LINUX_IS_24 */ + struct tq_struct bh_tq; + atomic_t bh_scheduled; + debug_info_t *debug_area; + dasd_profile_info_t profile; + struct proc_dir_entry *proc_dir; /* directory node */ + struct proc_dir_entry *proc_info; /* information from dasd_device_t */ + struct proc_dir_entry *proc_stats; /* statictics information */ +} dasd_device_t; + +/* dasd_device_t.level can be: */ +#define DASD_DEVICE_LEVEL_UNKNOWN 0x00 +#define DASD_DEVICE_LEVEL_RECOGNIZED 0x01 +#define DASD_DEVICE_LEVEL_ANALYSIS_PENDING 0x02 +#define DASD_DEVICE_LEVEL_ANALYSIS_PREPARED 0x04 +#define DASD_DEVICE_LEVEL_ANALYSED 0x08 +#define DASD_DEVICE_LEVEL_PARTITIONED 0x10 + +int dasd_init (void); +void dasd_discipline_enq (dasd_discipline_t *); +int dasd_discipline_deq(dasd_discipline_t *); +int dasd_start_IO (ccw_req_t *); +void dasd_int_handler (int , void *, struct pt_regs *); +ccw_req_t *default_erp_action (ccw_req_t *); +ccw_req_t *default_erp_postaction (ccw_req_t *); +int dasd_chanq_deq (dasd_chanq_t *, ccw_req_t *); +ccw_req_t *dasd_alloc_request (char *, int, int); +void dasd_free_request (ccw_req_t *); +int (*genhd_dasd_name) (char *, int, int, struct gendisk *); +int dasd_oper_handler (int irq, devreg_t * devreg); + +#endif /* __KERNEL__ */ + +#endif /* DASD_H */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 4 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -4 + * c-argdecl-indent: 4 + * c-label-offset: -4 + * c-continued-statement-offset: 4 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ |