summaryrefslogtreecommitdiff
path: root/linux/src/drivers/block/ide.h
blob: 28e371bf6052a03fc460125900fd3a409d6e9a40 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
/*
 *  linux/drivers/block/ide.h
 *
 *  Copyright (C) 1994, 1995  Linus Torvalds & authors
 */

#include <linux/config.h>

/*
 * This is the multiple IDE interface driver, as evolved from hd.c.  
 * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
 * There can be up to two drives per interface, as per the ATA-2 spec.
 *
 * Primary i/f:    ide0: major=3;  (hda)         minor=0; (hdb)         minor=64
 * Secondary i/f:  ide1: major=22; (hdc or hd1a) minor=0; (hdd or hd1b) minor=64
 * Tertiary i/f:   ide2: major=33; (hde)         minor=0; (hdf)         minor=64
 * Quaternary i/f: ide3: major=34; (hdg)         minor=0; (hdh)         minor=64
 */

/******************************************************************************
 * IDE driver configuration options (play with these as desired):
 * 
 * REALLY_SLOW_IO can be defined in ide.c and ide-cd.c, if necessary
 */
#undef REALLY_FAST_IO			/* define if ide ports are perfect */
#define INITIAL_MULT_COUNT	16	/* off=0; on=2,4,8,16,32, etc.. */

#ifndef SUPPORT_SLOW_DATA_PORTS		/* 1 to support slow data ports */
#define SUPPORT_SLOW_DATA_PORTS	1	/* 0 to reduce kernel size */
#endif
#ifndef SUPPORT_VLB_SYNC		/* 1 to support weird 32-bit chips */
#define SUPPORT_VLB_SYNC	1	/* 0 to reduce kernel size */
#endif
#ifndef DISK_RECOVERY_TIME		/* off=0; on=access_delay_time */
#define DISK_RECOVERY_TIME	0	/*  for hardware that needs it */
#endif
#ifndef OK_TO_RESET_CONTROLLER		/* 1 needed for good error recovery */
#define OK_TO_RESET_CONTROLLER	1	/* 0 for use with AH2372A/B interface */
#endif
#ifndef FAKE_FDISK_FOR_EZDRIVE		/* 1 to help linux fdisk with EZDRIVE */
#define FAKE_FDISK_FOR_EZDRIVE 	1	/* 0 to reduce kernel size */
#endif
#ifndef FANCY_STATUS_DUMPS		/* 1 for human-readable drive errors */
#define FANCY_STATUS_DUMPS	1	/* 0 to reduce kernel size */
#endif

#ifdef CONFIG_BLK_DEV_CMD640
#if 0	/* change to 1 when debugging cmd640 problems */
void cmd640_dump_regs (void);
#define CMD640_DUMP_REGS cmd640_dump_regs() /* for debugging cmd640 chipset */
#endif
#endif  /* CONFIG_BLK_DEV_CMD640 */

#if	defined(CONFIG_BLK_DEV_IDECD) || defined(CONFIG_BLK_DEV_IDETAPE) || \
	defined(CONFIG_BLK_DEV_IDEFLOPPY) || defined(CONFIG_BLK_DEV_IDESCSI)
#define CONFIG_BLK_DEV_IDEATAPI 1
#endif

/*
 * IDE_DRIVE_CMD is used to implement many features of the hdparm utility
 */
#define IDE_DRIVE_CMD		99	/* (magic) undef to reduce kernel size*/

/*
 *  "No user-serviceable parts" beyond this point  :)
 *****************************************************************************/

#if defined(CONFIG_BLK_DEV_IDESCSI) && !defined(CONFIG_SCSI)
#error "SCSI must also be selected"
#endif

typedef unsigned char	byte;	/* used everywhere */

/*
 * Probably not wise to fiddle with these
 */
#define ERROR_MAX	8	/* Max read/write errors per sector */
#define ERROR_RESET	3	/* Reset controller every 4th retry */
#define ERROR_RECAL	1	/* Recalibrate every 2nd retry */

/*
 * Ensure that various configuration flags have compatible settings
 */
#ifdef REALLY_SLOW_IO
#undef REALLY_FAST_IO
#endif

/*
 * Definitions for accessing IDE controller registers
 */

#define HWIF(drive)		((ide_hwif_t *)((drive)->hwif))
#define HWGROUP(drive)		((ide_hwgroup_t *)(HWIF(drive)->hwgroup))

#define IDE_DATA_OFFSET		(0)
#define IDE_ERROR_OFFSET	(1)
#define IDE_NSECTOR_OFFSET	(2)
#define IDE_SECTOR_OFFSET	(3)
#define IDE_LCYL_OFFSET		(4)
#define IDE_HCYL_OFFSET		(5)
#define IDE_SELECT_OFFSET	(6)
#define IDE_STATUS_OFFSET	(7)
#define IDE_FEATURE_OFFSET	IDE_ERROR_OFFSET
#define IDE_COMMAND_OFFSET	IDE_STATUS_OFFSET

#define IDE_DATA_REG		(HWIF(drive)->io_base+IDE_DATA_OFFSET)
#define IDE_ERROR_REG		(HWIF(drive)->io_base+IDE_ERROR_OFFSET)
#define IDE_NSECTOR_REG		(HWIF(drive)->io_base+IDE_NSECTOR_OFFSET)
#define IDE_SECTOR_REG		(HWIF(drive)->io_base+IDE_SECTOR_OFFSET)
#define IDE_LCYL_REG		(HWIF(drive)->io_base+IDE_LCYL_OFFSET)
#define IDE_HCYL_REG		(HWIF(drive)->io_base+IDE_HCYL_OFFSET)
#define IDE_SELECT_REG		(HWIF(drive)->io_base+IDE_SELECT_OFFSET)
#define IDE_STATUS_REG		(HWIF(drive)->io_base+IDE_STATUS_OFFSET)
#define IDE_CONTROL_REG		(HWIF(drive)->ctl_port)
#define IDE_FEATURE_REG		IDE_ERROR_REG
#define IDE_COMMAND_REG		IDE_STATUS_REG
#define IDE_ALTSTATUS_REG	IDE_CONTROL_REG
#define IDE_IREASON_REG		IDE_NSECTOR_REG
#define IDE_BCOUNTL_REG		IDE_LCYL_REG
#define IDE_BCOUNTH_REG		IDE_HCYL_REG

#ifdef REALLY_FAST_IO
#define OUT_BYTE(b,p)		outb((b),(p))
#define IN_BYTE(p)		(byte)inb(p)
#else
#define OUT_BYTE(b,p)		outb_p((b),(p))
#define IN_BYTE(p)		(byte)inb_p(p)
#endif /* REALLY_FAST_IO */

#define GET_ERR()		IN_BYTE(IDE_ERROR_REG)
#define GET_STAT()		IN_BYTE(IDE_STATUS_REG)
#define OK_STAT(stat,good,bad)	(((stat)&((good)|(bad)))==(good))
#define BAD_R_STAT		(BUSY_STAT   | ERR_STAT)
#define BAD_W_STAT		(BAD_R_STAT  | WRERR_STAT)
#define BAD_STAT		(BAD_R_STAT  | DRQ_STAT)
#define DRIVE_READY		(READY_STAT  | SEEK_STAT)
#define DATA_READY		(DRQ_STAT)

/*
 * Some more useful definitions
 */
#define IDE_MAJOR_NAME	"ide"	/* the same for all i/f; see also genhd.c */
#define MAJOR_NAME	IDE_MAJOR_NAME
#define PARTN_BITS	6	/* number of minor dev bits for partitions */
#define PARTN_MASK	((1<<PARTN_BITS)-1)	/* a useful bit mask */
#define MAX_DRIVES	2	/* per interface; 2 assumed by lots of code */
#ifndef MAX_HWIFS
#define MAX_HWIFS	4	/* an arbitrary, but realistic limit */
#endif
#define SECTOR_WORDS	(512 / 4)	/* number of 32bit words per sector */

/*
 * Timeouts for various operations:
 */
#define WAIT_DRQ	(1*HZ)		/* 1s - spec allows up to 20ms, but CF
					 * cards and SSD drives need more */
#ifdef CONFIG_APM
#define WAIT_READY	(5*HZ)		/* 5sec - some laptops are very slow */
#else
#define WAIT_READY	(3*HZ/100)	/* 30msec - should be instantaneous */
#endif /* CONFIG_APM */
#define WAIT_PIDENTIFY	(1*HZ)	/* 1sec   - should be less than 3ms (?) */
#define WAIT_WORSTCASE	(30*HZ)	/* 30sec  - worst case when spinning up */
#define WAIT_CMD	(10*HZ)	/* 10sec  - maximum wait for an IRQ to happen */

#if defined(CONFIG_BLK_DEV_HT6560B) || defined(CONFIG_BLK_DEV_PROMISE)
#define SELECT_DRIVE(hwif,drive)				\
{								\
	if (hwif->selectproc)					\
		hwif->selectproc(drive);			\
	else							\
		OUT_BYTE((drive)->select.all, hwif->io_base+IDE_SELECT_OFFSET); \
}
#else
#define SELECT_DRIVE(hwif,drive)  OUT_BYTE((drive)->select.all, hwif->io_base+IDE_SELECT_OFFSET);
#endif	/* CONFIG_BLK_DEV_HT6560B || CONFIG_BLK_DEV_PROMISE */
		
#ifdef CONFIG_BLK_DEV_IDETAPE
#include "ide-tape.h"
#endif /* CONFIG_BLK_DEV_IDETAPE */

#ifdef CONFIG_BLK_DEV_IDECD

struct atapi_request_sense {
	unsigned char error_code : 7;
	unsigned char valid      : 1;
	byte reserved1;
	unsigned char sense_key  : 4;
	unsigned char reserved2  : 1;
	unsigned char ili        : 1;
	unsigned char reserved3  : 2;
	byte info[4];
	byte sense_len;
	byte command_info[4];
	byte asc;
	byte ascq;
	byte fru;
	byte sense_key_specific[3];
};

struct packet_command {
	unsigned char *buffer;
	int buflen;
	int stat;
	struct atapi_request_sense *sense_data;
	unsigned char c[12];
};


/* Structure of a MSF cdrom address. */
struct atapi_msf {
	byte reserved;
	byte minute;
	byte second;
	byte frame;
};


/* Space to hold the disk TOC. */

#define MAX_TRACKS 99
struct atapi_toc_header {
	unsigned short toc_length;
	byte first_track;
	byte last_track;
};

struct atapi_toc_entry {
	byte reserved1;
	unsigned control : 4;
	unsigned adr     : 4;
	byte track;
	byte reserved2;
	union {
		unsigned lba;
		struct atapi_msf msf;
	} addr;
};

struct atapi_toc {
	int    last_session_lba;
	int    xa_flag;
	unsigned capacity;
	struct atapi_toc_header hdr;
	struct atapi_toc_entry  ent[MAX_TRACKS+1];
	  /* One extra for the leadout. */
};


/* This structure is annoyingly close to, but not identical with,
   the cdrom_subchnl structure from cdrom.h. */
struct atapi_cdrom_subchnl 
{
	u_char  acdsc_reserved;
	u_char  acdsc_audiostatus;
	u_short acdsc_length;
	u_char  acdsc_format;

	u_char  acdsc_adr:	4;
	u_char  acdsc_ctrl:	4;
	u_char  acdsc_trk;
	u_char  acdsc_ind;
	union {
		struct atapi_msf msf;
		int	lba;
	} acdsc_absaddr;
	union {
		struct atapi_msf msf;
		int	lba;
	} acdsc_reladdr;
};


/* Extra per-device info for cdrom drives. */
struct cdrom_info {

	/* Buffer for table of contents.  NULL if we haven't allocated
	   a TOC buffer for this device yet. */

	struct atapi_toc *toc;

	/* Sector buffer.  If a read request wants only the first part
	   of a cdrom block, we cache the rest of the block here,
	   in the expectation that that data is going to be wanted soon.
	   SECTOR_BUFFERED is the number of the first buffered sector,
	   and NSECTORS_BUFFERED is the number of sectors in the buffer.
	   Before the buffer is allocated, we should have
	   SECTOR_BUFFER == NULL and NSECTORS_BUFFERED == 0. */

	unsigned long sector_buffered;
	unsigned long nsectors_buffered;
	char *sector_buffer;

	/* The result of the last successful request sense command
	   on this device. */
	struct atapi_request_sense sense_data;

	int max_sectors;
};

#endif /* CONFIG_BLK_DEV_IDECD */

/*
 * Now for the data we need to maintain per-drive:  ide_drive_t
 */

typedef enum {ide_disk, ide_cdrom, ide_tape, ide_floppy, ide_scsi} ide_media_t;

typedef union {
	unsigned all			: 8;	/* all of the bits together */
	struct {
		unsigned set_geometry	: 1;	/* respecify drive geometry */
		unsigned recalibrate	: 1;	/* seek to cyl 0      */
		unsigned set_multmode	: 1;	/* set multmode count */
		unsigned set_tune	: 1;	/* tune interface for drive */
		unsigned mc		: 1;	/* acknowledge media change */
		unsigned reserved	: 3;	/* unused */
		} b;
	} special_t;

typedef union {
	unsigned all			: 8;	/* all of the bits together */
	struct {
		unsigned head		: 4;	/* always zeros here */
		unsigned unit		: 1;	/* drive select number, 0 or 1 */
		unsigned bit5		: 1;	/* always 1 */
		unsigned lba		: 1;	/* using LBA instead of CHS */
		unsigned bit7		: 1;	/* always 1 */
	} b;
	} select_t;

typedef struct ide_drive_s {
	special_t	special;	/* special action flags */
	unsigned present	: 1;	/* drive is physically present */
	unsigned noprobe 	: 1;	/* from:  hdx=noprobe */
	unsigned keep_settings  : 1;	/* restore settings after drive reset */
	unsigned busy		: 1;	/* currently doing revalidate_disk() */
	unsigned removable	: 1;	/* 1 if need to do check_media_change */
	unsigned using_dma	: 1;	/* disk is using dma for read/write */
	unsigned forced_geom	: 1;	/* 1 if hdx=c,h,s was given at boot */
	unsigned unmask		: 1;	/* flag: okay to unmask other irqs */
	unsigned no_unmask	: 1;	/* disallow setting unmask bit */
	unsigned no_io_32bit	: 1;	/* disallow enabling 32bit I/O */
	unsigned nobios		: 1;	/* flag: do not probe bios for drive */
	unsigned slow		: 1;	/* flag: slow data port */
	unsigned autotune	: 2;	/* 1=autotune, 2=noautotune, 0=default */
	unsigned nodma		: 1;	/* disk should not use dma for read/write */
#if FAKE_FDISK_FOR_EZDRIVE
	unsigned remap_0_to_1	: 1;	/* flag: partitioned with ezdrive */
#endif /* FAKE_FDISK_FOR_EZDRIVE */
	unsigned no_geom	: 1;	/* flag: do not set geometry */
	ide_media_t	media;		/* disk, cdrom, tape, floppy */
	select_t	select;		/* basic drive/head select reg value */
	byte		ctl;		/* "normal" value for IDE_CONTROL_REG */
	byte		ready_stat;	/* min status value for drive ready */
	byte		mult_count;	/* current multiple sector setting */
	byte 		mult_req;	/* requested multiple sector setting */
	byte 		tune_req;	/* requested drive tuning setting */
	byte		io_32bit;	/* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
	byte		bad_wstat;	/* used for ignoring WRERR_STAT */
	byte		sect0;		/* offset of first sector for DM6:DDO */
	byte 		usage;		/* current "open()" count for drive */
	byte 		head;		/* "real" number of heads */
	byte		sect;		/* "real" sectors per track */
	byte		bios_head;	/* BIOS/fdisk/LILO number of heads */
	byte		bios_sect;	/* BIOS/fdisk/LILO sectors per track */
	unsigned short	bios_cyl;	/* BIOS/fdisk/LILO number of cyls */
	unsigned short	cyl;		/* "real" number of cyls */
	void		  *hwif;	/* actually (ide_hwif_t *) */
	struct wait_queue *wqueue;	/* used to wait for drive in open() */
	struct hd_driveid *id;		/* drive model identification info */
	struct hd_struct  *part;	/* drive partition table */
	char		name[4];	/* drive name, such as "hda" */
#ifdef CONFIG_BLK_DEV_IDECD
	struct cdrom_info cdrom_info;	/* for ide-cd.c */
#endif /* CONFIG_BLK_DEV_IDECD */
#ifdef CONFIG_BLK_DEV_IDETAPE
	idetape_tape_t	tape;		/* for ide-tape.c */
#endif /* CONFIG_BLK_DEV_IDETAPE */
#ifdef CONFIG_BLK_DEV_IDEFLOPPY
	void *floppy;			/* for ide-floppy.c */
#endif /* CONFIG_BLK_DEV_IDEFLOPPY */
#ifdef CONFIG_BLK_DEV_IDESCSI
	void *scsi;			/* for ide-scsi.c */
#endif /* CONFIG_BLK_DEV_IDESCSI */
	byte		ide_scsi;	/* use ide-scsi driver */
	} ide_drive_t;

/*
 * An ide_dmaproc_t() initiates/aborts DMA read/write operations on a drive.
 *
 * The caller is assumed to have selected the drive and programmed the drive's
 * sector address using CHS or LBA.  All that remains is to prepare for DMA
 * and then issue the actual read/write DMA/PIO command to the drive.
 *
 * Returns 0 if all went well.
 * Returns 1 if DMA read/write could not be started, in which case the caller
 * should either try again later, or revert to PIO for the current request.
 */
typedef enum {	ide_dma_read = 0,	ide_dma_write = 1,
		ide_dma_abort = 2,	ide_dma_check = 3,
		ide_dma_status_bad = 4,	ide_dma_transferred = 5,
		ide_dma_begin = 6 }
	ide_dma_action_t;

typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);


/*
 * An ide_tuneproc_t() is used to set the speed of an IDE interface
 * to a particular PIO mode.  The "byte" parameter is used
 * to select the PIO mode by number (0,1,2,3,4,5), and a value of 255
 * indicates that the interface driver should "auto-tune" the PIO mode
 * according to the drive capabilities in drive->id;
 *
 * Not all interface types support tuning, and not all of those
 * support all possible PIO settings.  They may silently ignore
 * or round values as they see fit.
 */
typedef void (ide_tuneproc_t)(ide_drive_t *, byte);

/*
 * This is used to provide HT6560B & PROMISE interface support.
 */
typedef void (ide_selectproc_t) (ide_drive_t *);

/*
 * hwif_chipset_t is used to keep track of the specific hardware
 * chipset used by each IDE interface, if known.
 */
typedef enum {	ide_unknown,	ide_generic,	ide_triton,
		ide_cmd640,	ide_dtc2278,	ide_ali14xx,
		ide_qd6580,	ide_umc8672,	ide_ht6560b,
		ide_promise,	ide_hpt343,	ide_udma,
		ide_ultra66 }
	hwif_chipset_t;

typedef struct hwif_s {
	struct hwif_s	*next;		/* for linked-list in ide_hwgroup_t */
	void		*hwgroup;	/* actually (ide_hwgroup_t *) */
	unsigned short	io_base;	/* base io port addr */
	unsigned short	ctl_port;	/* usually io_base+0x206 */
	ide_drive_t	drives[MAX_DRIVES];	/* drive info */
	struct gendisk	*gd;		/* gendisk structure */
	ide_tuneproc_t	*tuneproc;	/* routine to tune PIO mode for drives */
#if defined(CONFIG_BLK_DEV_HT6560B) || defined(CONFIG_BLK_DEV_PROMISE)
	ide_selectproc_t *selectproc;	/* tweaks hardware to select drive */
#endif
	ide_dmaproc_t	*dmaproc;	/* dma read/write/abort routine */
	unsigned long	*dmatable;	/* dma physical region descriptor table */
	unsigned short	dma_base;	/* base addr for dma ports (triton) */
	byte		irq;		/* our irq number */
	byte		major;		/* our major number */
	char 		name[5];	/* name of interface, eg. "ide0" */
	byte		index;		/* 0 for ide0; 1 for ide1; ... */
	hwif_chipset_t	chipset;	/* sub-module for tuning.. */
	unsigned	noprobe    : 1;	/* don't probe for this interface */
	unsigned	present    : 1;	/* this interface exists */
	unsigned	serialized : 1;	/* serialized operation with mate hwif */
	unsigned	sharing_irq: 1;	/* 1 = sharing irq with another hwif */
#ifdef CONFIG_BLK_DEV_PROMISE
	unsigned	is_promise2: 1;	/* 2nd i/f on promise DC4030 */
#endif /* CONFIG_BLK_DEV_PROMISE */
#if (DISK_RECOVERY_TIME > 0)
	unsigned long	last_time;	/* time when previous rq was done */
#endif
#ifdef CONFIG_BLK_DEV_IDECD
	struct request request_sense_request;	/* from ide-cd.c */
	struct packet_command request_sense_pc;	/* from ide-cd.c */
#endif /* CONFIG_BLK_DEV_IDECD */
#ifdef CONFIG_BLK_DEV_IDETAPE
	ide_drive_t	*tape_drive;	/* Pointer to the tape on this interface */
#endif /* CONFIG_BLK_DEV_IDETAPE */
	} ide_hwif_t;

/*
 *  internal ide interrupt handler type
 */
typedef void (ide_handler_t)(ide_drive_t *);

typedef struct hwgroup_s {
	ide_handler_t		*handler;/* irq handler, if active */
	ide_drive_t		*drive;	/* current drive */
	ide_hwif_t		*hwif;	/* ptr to current hwif in linked-list */
	ide_hwif_t		*next_hwif; /* next selected hwif (for tape) */
	struct request		*rq;	/* current request */
	struct timer_list	timer;	/* failsafe timer */
	struct request		wrq;	/* local copy of current write rq */
	unsigned long		poll_timeout;	/* timeout value during long polls */
	int			active; /* set when servicing requests */
	} ide_hwgroup_t;

/*
 * ide_hwifs[] is the master data structure used to keep track
 * of just about everything in ide.c.  Whenever possible, routines
 * should be using pointers to a drive (ide_drive_t *) or 
 * pointers to a hwif (ide_hwif_t *), rather than indexing this
 * structure directly (the allocation/layout may change!).
 *
 */
#ifndef _IDE_C
extern	ide_hwif_t	ide_hwifs[];		/* master data repository */
#endif

/*
 * One final include file, which references some of the data/defns from above
 */
#define IDE_DRIVER	/* "parameter" for blk.h */
#include <linux/blk.h>

#if (DISK_RECOVERY_TIME > 0)
void ide_set_recovery_timer (ide_hwif_t *);
#define SET_RECOVERY_TIMER(drive) ide_set_recovery_timer (drive)
#else
#define SET_RECOVERY_TIMER(drive)
#endif

/*
 * This is used for (nearly) all data transfers from the IDE interface
 */
void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);

/*
 * This is used for (nearly) all data transfers to the IDE interface
 */
void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);

/*
 * This is used for (nearly) all ATAPI data transfers from/to the IDE interface
 */
void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);

/*
 * This is used on exit from the driver, to designate the next irq handler
 * and also to start the safety timer.
 */
void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout);

/*
 * Error reporting, in human readable form (luxurious, but a memory hog).
 */
byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat);

/*
 * ide_error() takes action based on the error returned by the controller.
 * The calling function must return afterwards, to restart the request.
 */
void ide_error (ide_drive_t *drive, const char *msg, byte stat);

/*
 * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
 * removing leading/trailing blanks and compressing internal blanks.
 * It is primarily used to tidy up the model name/number fields as
 * returned by the WIN_[P]IDENTIFY commands.
 */
void ide_fixstring (byte *s, const int bytecount, const int byteswap);

/*
 * This routine busy-waits for the drive status to be not "busy".
 * It then checks the status for all of the "good" bits and none
 * of the "bad" bits, and if all is okay it returns 0.  All other
 * cases return 1 after invoking ide_error() -- caller should return.
 *
 */
int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout);

/*
 * This routine is called from the partition-table code in genhd.c
 * to "convert" a drive to a logical geometry with fewer than 1024 cyls.
 *
 * The second parameter, "xparm", determines exactly how the translation
 * will be handled:
 *		 0 = convert to CHS with fewer than 1024 cyls
 *			using the same method as Ontrack DiskManager.
 *		 1 = same as "0", plus offset everything by 63 sectors.
 *		-1 = similar to "0", plus redirect sector 0 to sector 1.
 *		>1 = convert to a CHS geometry with "xparm" heads.
 *
 * Returns 0 if the translation was not possible, if the device was not
 * an IDE disk drive, or if a geometry was "forced" on the commandline.
 * Returns 1 if the geometry translation was successful.
 */
int ide_xlate_1024 (kdev_t, int, const char *);

/*
 * Start a reset operation for an IDE interface.
 * The caller should return immediately after invoking this.
 */
void ide_do_reset (ide_drive_t *);

/*
 * This function is intended to be used prior to invoking ide_do_drive_cmd().
 */
void ide_init_drive_cmd (struct request *rq);

/*
 * "action" parameter type for ide_do_drive_cmd() below.
 */
typedef enum
	{ide_wait,	/* insert rq at end of list, and wait for it */
	 ide_next,	/* insert rq immediately after current request */
	 ide_preempt,	/* insert rq in front of current request */
	 ide_end}	/* insert rq at end of list, but don't wait for it */
 ide_action_t;

/*
 * This function issues a special IDE device request
 * onto the request queue.
 *
 * If action is ide_wait, then the rq is queued at the end of the
 * request queue, and the function sleeps until it has been processed.
 * This is for use when invoked from an ioctl handler.
 *
 * If action is ide_preempt, then the rq is queued at the head of
 * the request queue, displacing the currently-being-processed
 * request and this function returns immediately without waiting
 * for the new rq to be completed.  This is VERY DANGEROUS, and is
 * intended for careful use by the ATAPI tape/cdrom driver code.
 *
 * If action is ide_next, then the rq is queued immediately after
 * the currently-being-processed-request (if any), and the function
 * returns without waiting for the new rq to be completed.  As above,
 * This is VERY DANGEROUS, and is intended for careful use by the 
 * ATAPI tape/cdrom driver code.
 *
 * If action is ide_end, then the rq is queued at the end of the
 * request queue, and the function returns immediately without waiting
 * for the new rq to be completed. This is again intended for careful
 * use by the ATAPI tape/cdrom driver code. (Currently used by ide-tape.c,
 * when operating in the pipelined operation mode).
 */
int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action);
 
/*
 * Clean up after success/failure of an explicit drive cmd.
 * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
 */
void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err);

/*
 * ide_system_bus_speed() returns what we think is the system VESA/PCI
 * bus speed (in Mhz).  This is used for calculating interface PIO timings.
 * The default is 40 for known PCI systems, 50 otherwise.
 * The "idebus=xx" parameter can be used to override this value.
 */
int ide_system_bus_speed (void);

/*
 * ide_multwrite() transfers a block of up to mcount sectors of data
 * to a drive as part of a disk multwrite operation.
 */
void ide_multwrite (ide_drive_t *drive, unsigned int mcount);

#ifdef CONFIG_BLK_DEV_IDECD
/*
 * These are routines in ide-cd.c invoked from ide.c
 */
void ide_do_rw_cdrom (ide_drive_t *, unsigned long);
int ide_cdrom_ioctl (ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
int ide_cdrom_check_media_change (ide_drive_t *);
int ide_cdrom_open (struct inode *, struct file *, ide_drive_t *);
void ide_cdrom_release (struct inode *, struct file *, ide_drive_t *);
void ide_cdrom_setup (ide_drive_t *);
#endif /* CONFIG_BLK_DEV_IDECD */

#ifdef CONFIG_BLK_DEV_IDETAPE

/*
 *	Functions in ide-tape.c which are invoked from ide.c:
 */

/*
 *	idetape_identify_device is called during device probing stage to
 *	probe for an ide atapi tape drive and to initialize global variables
 *	in ide-tape.c which provide the link between the character device
 *	and the corresponding block device.
 *
 *	Returns 1 if an ide tape was detected and is supported.
 *	Returns 0 otherwise.
 */
 
int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id);

/*
 *	idetape_setup is called a bit later than idetape_identify_device,
 *	during the search for disk partitions, to initialize various tape
 *	state variables in ide_drive_t *drive.
 */
 
void idetape_setup (ide_drive_t *drive);

/*
 *	idetape_do_request is our request function. It is called by ide.c
 *	to process a new request.
 */

void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block);

/*
 *	idetape_end_request is used to finish servicing a request, and to
 *	insert a pending pipeline request into the main device queue.
 */
 
void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup);

/*
 *	Block device interface functions.
 */
  
int idetape_blkdev_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file,
			unsigned int cmd, unsigned long arg);
int idetape_blkdev_open (struct inode *inode, struct file *filp, ide_drive_t *drive);
void idetape_blkdev_release (struct inode *inode, struct file *filp, ide_drive_t *drive);

/*
 *	idetape_register_chrdev initializes the character device interface to
 *	the ide tape drive.
 */
 
void idetape_register_chrdev (void);

#endif /* CONFIG_BLK_DEV_IDETAPE */

#ifdef CONFIG_BLK_DEV_IDEFLOPPY
int idefloppy_identify_device (ide_drive_t *drive,struct hd_driveid *id);
void idefloppy_setup (ide_drive_t *drive);
void idefloppy_do_request (ide_drive_t *drive, struct request *rq, unsigned long block);
void idefloppy_end_request (byte uptodate, ide_hwgroup_t *hwgroup);
int idefloppy_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file,
			unsigned int cmd, unsigned long arg);
int idefloppy_open (struct inode *inode, struct file *filp, ide_drive_t *drive);
void idefloppy_release (struct inode *inode, struct file *filp, ide_drive_t *drive);
int idefloppy_media_change (ide_drive_t *drive);
unsigned long idefloppy_capacity (ide_drive_t *drive);
#endif /* CONFIG_BLK_DEV_IDEFLOPPY */

#ifdef CONFIG_BLK_DEV_IDESCSI
void idescsi_setup (ide_drive_t *drive);
void idescsi_do_request (ide_drive_t *drive, struct request *rq, unsigned long block);
void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup);
int idescsi_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
int idescsi_open (struct inode *inode, struct file *filp, ide_drive_t *drive);
void idescsi_ide_release (struct inode *inode, struct file *filp, ide_drive_t *drive);
#endif /* CONFIG_BLK_DEV_IDESCSI */

#ifdef CONFIG_BLK_DEV_TRITON
void ide_init_triton (byte, byte);
void ide_init_promise (byte bus, byte fn, ide_hwif_t *hwif0, ide_hwif_t *hwif1, unsigned short dma);
#endif /* CONFIG_BLK_DEV_TRITON */