1 /*
2  * File...........: linux/drivers/s390/block/dasd_int.h
3  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
4  *                  Horst Hummel <Horst.Hummel@de.ibm.com>
5  * Bugreports.to..: <Linux390@de.ibm.com>
6  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
7  *
8  * $Revision: 1.36 $
9  *
10  * History of changes (starts July 2000)
11  * 02/01/01 added dynamic registration of ioctls
12  */
13 
14 #ifndef DASD_INT_H
15 #define DASD_INT_H
16 
17 #include <asm/dasd.h>
18 
19 #define CONFIG_DASD_DYNAMIC
20 
21 typedef int(*dasd_ioctl_fn_t) (void *inp, int no, long args);
22 int dasd_ioctl_no_register(struct module *, int no, dasd_ioctl_fn_t handler);
23 int dasd_ioctl_no_unregister(struct module *, int no, dasd_ioctl_fn_t handler);
24 
25 #define DASD_NAME "dasd"
26 #define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS))
27 
28 
29 #define DASD_FORMAT_INTENS_WRITE_RECZERO 0x01
30 #define DASD_FORMAT_INTENS_WRITE_HOMEADR 0x02
31 
32 #define DASD_STATE_DEL   -1     /* "unknown" */
33 #define DASD_STATE_NEW    0     /* memory for dasd_device_t and lowmem ccw/idals allocated */
34 #define DASD_STATE_BOXED  1     /* boxed dasd could not be analysed "plugged" */
35 #define DASD_STATE_KNOWN  2     /* major_info/devinfo/discipline/devfs-'device'/gendisk - "detected" */
36 #define DASD_STATE_ACCEPT 3     /* irq requested - "accepted" */
37 #define DASD_STATE_INIT   4     /* init_cqr started - "busy" */
38 #define DASD_STATE_READY  5     /* init finished  - "fenced(plugged)" */
39 #define DASD_STATE_ONLINE 6     /* unplugged "active" */
40 
41 #define DASD_HOTPLUG_EVENT_ADD        0
42 #define DASD_HOTPLUG_EVENT_REMOVE     1
43 #define DASD_HOTPLUG_EVENT_PARTCHK    2
44 #define DASD_HOTPLUG_EVENT_PARTREMOVE 3
45 
46 #define DASD_FORMAT_INTENS_WRITE_RECZERO 0x01
47 #define DASD_FORMAT_INTENS_WRITE_HOMEADR 0x02
48 #define DASD_FORMAT_INTENS_INVALIDATE    0x04
49 #define DASD_FORMAT_INTENS_CDL 0x08
50 #ifdef __KERNEL__
51 #include <linux/module.h>
52 #include <linux/version.h>
53 #include <linux/major.h>
54 #include <linux/wait.h>
55 #include <linux/blk.h>
56 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
57 #include <linux/blkdev.h>
58 #include <linux/devfs_fs_kernel.h>
59 #endif
60 #include <linux/genhd.h>
61 #include <linux/hdreg.h>
62 #include <linux/compatmac.h>
63 
64 #include <asm/ccwcache.h>
65 #include <asm/irq.h>
66 #include <asm/s390dyn.h>
67 #include <asm/todclk.h>
68 #include <asm/debug.h>
69 
70 /********************************************************************************
71  * SECTION: Kernel Version Compatibility section
72  ********************************************************************************/
73 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
74 typedef struct request *request_queue_t;
75 #define block_device_operations file_operations
76 #define __setup(x,y) struct dasd_device_t
77 #define devfs_register_blkdev(major,name,ops) register_blkdev(major,name,ops)
78 #define register_disk(dd,dev,partn,ops,size) \
79 do { \
80 	dd->sizes[MINOR(dev)] = size >> 1; \
81 	resetup_one_dev(dd,MINOR(dev)>>DASD_PARTN_BITS); \
82 } while(0)
83 #define init_waitqueue_head(x) do { *x = NULL; } while(0)
84 #define blk_cleanup_queue(x) do {} while(0)
85 #define blk_init_queue(x...) do {} while(0)
86 #define blk_queue_headactive(x...) do {} while(0)
87 #define blk_queue_make_request(x) do {} while(0)
88 #define list_empty(x) (0)
89 #define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \
90 do { \
91         blk_dev[d_major].request_fn = d_request_fn; \
92         blk_dev[d_major].queue = d_queue_fn; \
93         blk_dev[d_major].current_request = d_current; \
94 } while(0)
95 #define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \
96 	major:D_MAJOR, \
97 	major_name:D_NAME, \
98 	minor_shift:D_PARTN_BITS, \
99 	max_p:1 << D_PARTN_BITS, \
100 	max_nr:D_PER_MAJOR, \
101 	nr_real:D_PER_MAJOR,
102 static inline struct request *
dasd_next_request(request_queue_t * queue)103 dasd_next_request( request_queue_t *queue )
104 {
105     return *queue;
106 }
107 static inline void
dasd_dequeue_request(request_queue_t * q,struct request * req)108 dasd_dequeue_request( request_queue_t * q, struct request *req )
109 {
110         *q = req->next;
111         req->next = NULL;
112 }
113 
114 #else
115 #define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \
116 do { \
117         blk_dev[d_major].queue = d_queue_fn; \
118 } while(0)
119 #define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \
120 	major:D_MAJOR, \
121 	major_name:D_NAME, \
122 	minor_shift:D_PARTN_BITS, \
123 	max_p:1 << D_PARTN_BITS, \
124 	nr_real:D_PER_MAJOR, \
125         fops:&dasd_device_operations,
126 static inline struct request *
dasd_next_request(request_queue_t * queue)127 dasd_next_request( request_queue_t *queue )
128 {
129         return blkdev_entry_next_request(&queue->queue_head);
130 }
131 static inline void
dasd_dequeue_request(request_queue_t * q,struct request * req)132 dasd_dequeue_request( request_queue_t * q, struct request *req )
133 {
134         blkdev_dequeue_request (req);
135 }
136 #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) */
137 
138 /********************************************************************************
139  * SECTION: Type definitions
140  ********************************************************************************/
141 
142 typedef struct dasd_devreg_t {
143         devreg_t devreg; /* the devreg itself */
144         /* build a linked list of devregs, needed for cleanup */
145         struct list_head list;
146 } dasd_devreg_t;
147 
148 typedef struct {
149 	struct list_head list;
150 	struct module *owner;
151 	int no;
152 	dasd_ioctl_fn_t handler;
153 } dasd_ioctl_list_t;
154 
155 typedef enum {
156 	dasd_era_fatal = -1,	/* no chance to recover              */
157 	dasd_era_none = 0,	/* don't recover, everything alright */
158 	dasd_era_msg = 1,	/* don't recover, just report...     */
159 	dasd_era_recover = 2	/* recovery action recommended       */
160 } dasd_era_t;
161 
162 /* BIT DEFINITIONS FOR SENSE DATA */
163 #define DASD_SENSE_BIT_0 0x80
164 #define DASD_SENSE_BIT_1 0x40
165 #define DASD_SENSE_BIT_2 0x20
166 #define DASD_SENSE_BIT_3 0x10
167 
168 /*
169  * struct dasd_sizes_t
170  * represents all data needed to access dasd with properly set up sectors
171  */
172 typedef
173 struct dasd_sizes_t {
174 	unsigned long blocks; /* size of volume in blocks */
175 	unsigned int bp_block; /* bytes per block */
176 	unsigned int s2b_shift; /* log2 (bp_block/512) */
177         unsigned int pt_block; /* from which block to read the partn table */
178 } dasd_sizes_t;
179 
180 /*
181  * struct dasd_chanq_t
182  * represents a queue of channel programs related to a single device
183  */
184 typedef
185 struct dasd_chanq_t {
186 	ccw_req_t *head;
187 	ccw_req_t *tail;
188 } dasd_chanq_t;
189 
190 /*
191  * struct dasd_lowmem_t
192  * represents a queue of pages for lowmem request
193  */
194 typedef struct {
195         struct list_head list;
196 } dasd_lowmem_t;
197 
198 #define DASD_LOWMEM_PAGES 2     /* # of lowmem pages per device (min 2) */
199 
200 /********************************************************************************
201  * SECTION: MACROS
202  ********************************************************************************/
203 
204 /*
205  * CHECK_THEN_SET
206  *
207  * Change 'where' value from 'from' to 'to'.
208  ' BUG if the 'from' value doesn't match.
209  */
210 #define check_then_set(where,from,to) \
211 do { \
212         if ((*(where)) != (from) ) { \
213                 printk (KERN_ERR PRINTK_HEADER "was %d\n", *(where)); \
214                 BUG(); \
215         } \
216         (*(where)) = (to); \
217 } while(0)
218 
219 
220 /********************************************************************************
221  * SECION: MACROs for klogd and s390 debug feature (dbf)
222  ********************************************************************************/
223 
224 #define DBF_DEV_EVENT(d_level, d_device, d_str, d_data...) \
225 do { \
226         if (d_device->debug_area != NULL) \
227                 debug_sprintf_event(d_device->debug_area, \
228                                     d_level, \
229                                     d_str "\n", \
230                                     d_data); \
231 } while(0)
232 
233 #define DBF_DEV_EXC(d_level, d_device, d_str, d_data...) \
234 do { \
235         if (d_device->debug_area != NULL) \
236                 debug_sprintf_exception(d_device->debug_area, \
237                                         d_level, \
238                                         d_str "\n", \
239                                         d_data); \
240 } while(0)
241 
242 #define DBF_EVENT(d_level, d_str, d_data...)\
243 do { \
244         if (dasd_debug_area != NULL) \
245                 debug_sprintf_event(dasd_debug_area, \
246                                     d_level,\
247                                     d_str "\n", \
248                                     d_data); \
249 } while(0)
250 
251 #define DBF_EXC(d_level, d_str, d_data...)\
252 do { \
253         if (dasd_debug_area != NULL) \
254                 debug_sprintf_exception(dasd_debug_area, \
255                                         d_level,\
256                                         d_str "\n", \
257                                         d_data); \
258 } while(0)
259 
260 /* definition of dbf debug levels */
261 #define	DBF_EMERG	0	/* system is unusable		*/
262 #define	DBF_ALERT	1	/* action must be taken immediately	*/
263 #define	DBF_CRIT	2	/* critical conditions		*/
264 #define	DBF_ERR  	3	/* error conditions			*/
265 #define	DBF_WARNING	4	/* warning conditions		*/
266 #define	DBF_NOTICE	5	/* normal but significant condition	*/
267 #define	DBF_INFO	6	/* informational			*/
268 #define	DBF_DEBUG	6	/* debug-level messages		*/
269 
270 /* messages to be written via klogd and dbf */
271 #define DEV_MESSAGE(d_loglevel,d_device,d_string,d_args...)\
272 do { \
273         int d_devno = d_device->devinfo.devno; \
274         int d_irq = d_device->devinfo.irq; \
275         char *d_name = d_device->name; \
276         int d_major = MAJOR(d_device->kdev); \
277         int d_minor = MINOR(d_device->kdev); \
278 \
279         printk(d_loglevel PRINTK_HEADER \
280                " /dev/%-7s(%3d:%3d),%04x@%02x: " \
281                d_string "\n", \
282                d_name, \
283                d_major, \
284                d_minor, \
285                d_devno, \
286                d_irq, \
287                d_args); \
288 \
289         DBF_DEV_EVENT(DBF_ALERT, \
290                       d_device, \
291                       d_string, \
292                       d_args); \
293 } while(0)
294 
295 /* general messages to be written via klogd and dbf */
296 #define MESSAGE(d_loglevel,d_string,d_args...)\
297 do { \
298         printk(d_loglevel PRINTK_HEADER \
299                " " d_string "\n", \
300                d_args); \
301 \
302         DBF_EVENT(DBF_ALERT, \
303                   d_string, \
304                   d_args); \
305 } while(0)
306 
307 /* general messages to be written via klogd only */
308 #define MESSAGE_LOG(d_loglevel,d_string,d_args...)\
309 do { \
310         printk(d_loglevel PRINTK_HEADER \
311                " " d_string "\n", \
312                d_args); \
313 } while(0)
314 
315 struct dasd_device_t;
316 struct request;
317 
318 /********************************************************************************
319  * SECTION: signatures for the functions of dasd_discipline_t
320  * make typecasts much easier
321  ********************************************************************************/
322 
323 typedef int    (*dasd_ck_id_fn_t)              (s390_dev_info_t *);
324 typedef int    (*dasd_ck_characteristics_fn_t) (struct dasd_device_t *);
325 typedef int    (*dasd_fill_geometry_fn_t)      (struct dasd_device_t *,
326                                                 struct hd_geometry *);
327 typedef int    (*dasd_do_analysis_fn_t)        (struct dasd_device_t *);
328 typedef int    (*dasd_io_starter_fn_t)         (ccw_req_t *);
329 typedef int    (*dasd_io_stopper_fn_t)         (ccw_req_t *);
330 typedef int    (*dasd_info_fn_t)               (struct dasd_device_t *,
331                                                 dasd_information2_t *);
332 typedef int    (*dasd_use_count_fn_t)          (int);
333 typedef int    (*dasd_get_attrib_fn_t)         (struct dasd_device_t *,
334                                                 struct attrib_data_t *);
335 typedef int    (*dasd_set_attrib_fn_t)         (struct dasd_device_t *,
336                                                 struct attrib_data_t *);
337 typedef void   (*dasd_int_handler_fn_t)        (int irq, void *,
338                                                 struct pt_regs *);
339 typedef void   (*dasd_dump_sense_fn_t)         (struct dasd_device_t *,
340                                                 ccw_req_t *);
341 typedef ccw_req_t *(*dasd_format_fn_t)         (struct dasd_device_t *,
342                                                 struct format_data_t *);
343 typedef ccw_req_t *(*dasd_init_analysis_fn_t ) (struct dasd_device_t *);
344 typedef ccw_req_t *(*dasd_cp_builder_fn_t)     (struct dasd_device_t *,
345                                                 struct request *);
346 typedef ccw_req_t *(*dasd_reserve_fn_t)        (struct dasd_device_t *);
347 typedef ccw_req_t *(*dasd_release_fn_t)        (struct dasd_device_t *);
348 typedef ccw_req_t *(*dasd_steal_lock_fn_t)     (struct dasd_device_t *);
349 typedef ccw_req_t *(*dasd_merge_cp_fn_t)       (struct dasd_device_t *);
350 typedef ccw_req_t *(*dasd_erp_action_fn_t)     (ccw_req_t * cqr);
351 typedef ccw_req_t *(*dasd_erp_postaction_fn_t) (ccw_req_t * cqr);
352 typedef ccw_req_t *(*dasd_read_stats_fn_t)     (struct dasd_device_t *);
353 
354 typedef dasd_rssd_perf_stats_t * (*dasd_ret_stats_fn_t)     (ccw_req_t *);
355 typedef dasd_era_t               (*dasd_error_examine_fn_t) (ccw_req_t *,
356                                                              devstat_t * stat);
357 typedef dasd_erp_action_fn_t     (*dasd_error_analyse_fn_t) (ccw_req_t *);
358 typedef dasd_erp_postaction_fn_t (*dasd_erp_analyse_fn_t)   (ccw_req_t *);
359 
360 /*
361  * the dasd_discipline_t is
362  * sth like a table of virtual functions, if you think of dasd_eckd
363  * inheriting dasd...
364  * no, currently we are not planning to reimplement the driver in C++
365  */
366 typedef struct dasd_discipline_t {
367         struct module *owner;
368 	char ebcname[8]; /* a name used for tagging and printks */
369         char name[8];		/* a name used for tagging and printks */
370 	int max_blocks;	/* maximum number of blocks to be chained */
371 	dasd_ck_id_fn_t              id_check;	            /* check sense data */
372 	dasd_ck_characteristics_fn_t check_characteristics; /* check the characteristics */
373 	dasd_init_analysis_fn_t      init_analysis;	    /* start the analysis of the volume */
374 	dasd_do_analysis_fn_t        do_analysis;	    /* complete the analysis of the volume */
375 	dasd_fill_geometry_fn_t      fill_geometry;	    /* set up hd_geometry */
376 	dasd_io_starter_fn_t         start_IO;
377 	dasd_io_stopper_fn_t         term_IO;
378         dasd_format_fn_t             format_device;	    /* format the device */
379 	dasd_error_examine_fn_t      examine_error;
380 	dasd_error_analyse_fn_t      erp_action;
381 	dasd_erp_analyse_fn_t        erp_postaction;
382         dasd_cp_builder_fn_t         build_cp_from_req;
383         dasd_dump_sense_fn_t         dump_sense;
384         dasd_int_handler_fn_t        int_handler;
385         dasd_reserve_fn_t            reserve;
386         dasd_release_fn_t            release;
387         dasd_steal_lock_fn_t         steal_lock;
388         dasd_merge_cp_fn_t           merge_cp;
389         dasd_info_fn_t               fill_info;
390         dasd_read_stats_fn_t         read_stats;
391         dasd_ret_stats_fn_t          ret_stats;             /* return performance statistics */
392         dasd_get_attrib_fn_t         get_attrib;            /* get attributes (cache operations */
393         dasd_set_attrib_fn_t         set_attrib;            /* set attributes (cache operations */
394 	struct list_head list;	/* used for list of disciplines */
395 } dasd_discipline_t;
396 
397 /* dasd_range_t are used for ordering the DASD devices */
398 typedef struct dasd_range_t {
399 	unsigned int from;	/* first DASD in range */
400 	unsigned int to;	/* last DASD in range */
401 	char discipline[4];	/* placeholder to force discipline */
402         int features;
403 	struct list_head list;	/* next one in linked list */
404 } dasd_range_t;
405 
406 
407 
408 #define DASD_MAJOR_INFO_REGISTERED 1
409 #define DASD_MAJOR_INFO_IS_STATIC 2
410 
411 typedef struct major_info_t {
412 	struct list_head list;
413 	struct dasd_device_t **dasd_device;
414 	int flags;
415 	struct gendisk gendisk; /* actually contains the major number */
416 } __attribute__ ((packed)) major_info_t;
417 
418 typedef struct dasd_device_t {
419 	s390_dev_info_t devinfo;
420 	dasd_discipline_t *discipline;
421 	int level;
422         atomic_t open_count;
423         kdev_t kdev;
424         major_info_t *major_info;
425 	struct dasd_chanq_t queue;
426         wait_queue_head_t wait_q;
427         request_queue_t *request_queue;
428         struct timer_list timer;             /* used for start_IO */
429         struct timer_list late_timer;        /* to get late devices online */
430         struct timer_list blocking_timer;    /* used for ERP */
431 	devstat_t dev_status; /* needed ONLY!! for request_irq */
432         dasd_sizes_t sizes;
433         char name[16]; /* The name of the device in /dev */
434 	char *private;	/* to be used by the discipline internally */
435 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
436         devfs_handle_t devfs_entry;
437 #endif /* LINUX_IS_24 */
438 	struct tq_struct bh_tq;
439         atomic_t bh_scheduled;
440         debug_info_t *debug_area;
441         dasd_profile_info_t profile;
442         ccw_req_t *init_cqr;
443         atomic_t plugged;
444         int stopped;                         /* device (do_IO) was stopped */
445         struct list_head lowmem_pool;
446 }  dasd_device_t;
447 
448 /* reasons why device (do_IO) was stopped */
449 #define DASD_STOPPED_NOT_ACC 1         /* not accessible */
450 #define DASD_STOPPED_PENDING 2         /* long busy */
451 
452 
453 int  dasd_init               (void);
454 void dasd_discipline_add     (dasd_discipline_t *);
455 void dasd_discipline_del     (dasd_discipline_t *);
456 int  dasd_start_IO           (ccw_req_t *);
457 int  dasd_term_IO            (ccw_req_t *);
458 void dasd_int_handler        (int , void *, struct pt_regs *);
459 void dasd_free_request       (ccw_req_t *, dasd_device_t *);
460 int  dasd_oper_handler       (int irq, devreg_t * devreg);
461 void dasd_schedule_bh        (dasd_device_t *);
462 void dasd_schedule_bh_timed  (unsigned long);
463 int  dasd_sleep_on_req       (ccw_req_t*);
464 int  dasd_set_normalized_cda (ccw1_t * cp, unsigned long address,
465                               ccw_req_t* request,
466                               dasd_device_t* device );
467 ccw_req_t *     dasd_default_erp_action     (ccw_req_t *);
468 ccw_req_t *     dasd_default_erp_postaction (ccw_req_t *);
469 inline void     dasd_chanq_deq              (dasd_chanq_t *, ccw_req_t *);
470 inline void     dasd_chanq_enq              (dasd_chanq_t *, ccw_req_t *);
471 inline void     dasd_chanq_enq_head         (dasd_chanq_t *, ccw_req_t *);
472 ccw_req_t *     dasd_alloc_request          (char *, int, int, dasd_device_t *);
473 dasd_device_t * dasd_device_from_kdev       (kdev_t kdev);
474 
475 extern debug_info_t *dasd_debug_area;
476 extern int (*genhd_dasd_name) (char *, int, int, struct gendisk *);
477 extern int (*genhd_dasd_ioctl) (struct inode *inp, struct file *filp,
478                                 unsigned int no, unsigned long data);
479 
480 #endif /* __KERNEL__ */
481 
482 #endif				/* DASD_H */
483 
484 /*
485  * Overrides for Emacs so that we follow Linus's tabbing style.
486  * Emacs will notice this stuff at the end of the file and automatically
487  * adjust the settings for this buffer only.  This must remain at the end
488  * of the file.
489  * ---------------------------------------------------------------------------
490  * Local variables:
491  * c-indent-level: 4
492  * c-brace-imaginary-offset: 0
493  * c-brace-offset: -4
494  * c-argdecl-indent: 4
495  * c-label-offset: -4
496  * c-continued-statement-offset: 4
497  * c-continued-brace-offset: 0
498  * indent-tabs-mode: nil
499  * tab-width: 8
500  * End:
501  */
502