1 /* ps2esdi driver based on assembler code by Arindam Banerji,
2 written by Peter De Schrijver */
3 /* Reassuring note to IBM : This driver was NOT developed by vice-versa
4 engineering the PS/2's BIOS */
5 /* Dedicated to Wannes, Tofke, Ykke, Godot, Killroy and all those
6 other lovely fish out there... */
7 /* This code was written during the long and boring WINA
9 /* Thanks to Arindam Banerij for giving me the source of his driver */
10 /* This code may be freely distributed and modified in any way,
11 as long as these notes remain intact */
13 /* Revised: 05/07/94 by Arindam Banerji (axb@cse.nd.edu) */
14 /* Revised: 09/08/94 by Peter De Schrijver (stud11@cc4.kuleuven.ac.be)
15 Thanks to Arindam Banerij for sending me the docs of the adapter */
17 /* BA Modified for ThinkPad 720 by Boris Ashkinazi */
18 /* (bash@vnet.ibm.com) 08/08/95 */
20 /* Modified further for ThinkPad-720C by Uri Blumenthal */
21 /* (uri@watson.ibm.com) Sep 11, 1995 */
27 + reset after read/write error
30 #include <linux/config.h>
31 #include <linux/major.h>
33 #ifdef CONFIG_BLK_DEV_PS2
35 #define MAJOR_NR PS2ESDI_MAJOR
37 #include <linux/errno.h>
38 #include <linux/sched.h>
41 #include <linux/kernel.h>
42 #include <linux/genhd.h>
43 #include <linux/ps2esdi.h>
44 #include <linux/devfs_fs_kernel.h>
45 #include <linux/blk.h>
46 #include <linux/blkpg.h>
47 #include <linux/mca.h>
48 #include <linux/init.h>
49 #include <linux/ioport.h>
51 #include <asm/system.h>
53 #include <asm/segment.h>
55 #include <asm/uaccess.h>
57 #define PS2ESDI_IRQ 14
60 #define MAX_16BIT 65536
61 #define ESDI_TIMEOUT 0xf000
62 #define ESDI_STAT_TIMEOUT 4
64 #define TYPE_0_CMD_BLK_LENGTH 2
65 #define TYPE_1_CMD_BLK_LENGTH 4
68 static void reset_ctrl(void);
70 int ps2esdi_init(void);
72 static void ps2esdi_geninit(void);
74 static void do_ps2esdi_request(request_queue_t
* q
);
76 static void ps2esdi_readwrite(int cmd
, u_char drive
, u_int block
, u_int count
);
78 static void ps2esdi_fill_cmd_block(u_short
* cmd_blk
, u_short cmd
,
79 u_short cyl
, u_short head
, u_short sector
, u_short length
, u_char drive
);
81 static int ps2esdi_out_cmd_blk(u_short
* cmd_blk
);
83 static void ps2esdi_prep_dma(char *buffer
, u_short length
, u_char dma_xmode
);
85 static void ps2esdi_interrupt_handler(int irq
, void *dev_id
,
86 struct pt_regs
*regs
);
87 static void (*current_int_handler
) (u_int
) = NULL
;
88 static void ps2esdi_normal_interrupt_handler(u_int
);
89 static void ps2esdi_initial_reset_int_handler(u_int
);
90 static void ps2esdi_geometry_int_handler(u_int
);
92 static void ps2esdi_continue_request(void);
94 static int ps2esdi_open(struct inode
*inode
, struct file
*file
);
96 static int ps2esdi_release(struct inode
*inode
, struct file
*file
);
98 static int ps2esdi_ioctl(struct inode
*inode
, struct file
*file
,
99 u_int cmd
, u_long arg
);
101 static int ps2esdi_reread_partitions(kdev_t dev
);
103 static int ps2esdi_read_status_words(int num_words
, int max_words
, u_short
* buffer
);
105 static void dump_cmd_complete_status(u_int int_ret_code
);
107 static void ps2esdi_get_device_cfg(void);
109 void ps2esdi_reset_timer(unsigned long unused
);
111 u_int dma_arb_level
; /* DMA arbitration level */
113 static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_int
);
114 static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_wait_open
);
117 static int access_count
[MAX_HD
];
118 static char ps2esdi_valid
[MAX_HD
];
119 static int ps2esdi_sizes
[MAX_HD
<< 6];
120 static int ps2esdi_blocksizes
[MAX_HD
<< 6];
121 static int ps2esdi_drives
;
122 static struct hd_struct ps2esdi
[MAX_HD
<< 6];
123 static u_short io_base
;
124 static struct timer_list esdi_timer
= { function
: ps2esdi_reset_timer
};
125 static int reset_status
;
126 static int ps2esdi_slot
= -1;
127 int tp720esdi
= 0; /* Is it Integrated ESDI of ThinkPad-720? */
128 int intg_esdi
= 0; /* If integrated adapter */
129 struct ps2esdi_i_struct
{
130 unsigned int head
, sect
, cyl
, wpcom
, lzone
, ctl
;
134 #if 0 /* try both - I don't know which one is better... UB */
135 struct ps2esdi_i_struct ps2esdi_info
[] =
137 {4, 48, 1553, 0, 0, 0},
140 struct ps2esdi_i_struct ps2esdi_info
[] =
142 {64, 32, 161, 0, 0, 0},
146 struct ps2esdi_i_struct ps2esdi_info
[] =
151 static struct block_device_operations ps2esdi_fops
=
154 release
: ps2esdi_release
,
155 ioctl
: ps2esdi_ioctl
,
158 static struct gendisk ps2esdi_gendisk
=
160 MAJOR_NR
, /* Major number */
161 "ed", /* Major name */
162 6, /* Bits to shift to get real from partition */
163 1 << 6, /* Number of partitions per real disk */
164 ps2esdi
, /* hd struct */
165 ps2esdi_sizes
, /* block sizes */
167 (void *) ps2esdi_info
, /* internal */
169 &ps2esdi_fops
, /* file operations */
172 /* initialization routine called by ll_rw_blk.c */
173 int __init
ps2esdi_init(void)
176 /* register the device - pass the name, major number and operations
178 if (devfs_register_blkdev(MAJOR_NR
, "ed", &ps2esdi_fops
)) {
179 printk("%s: Unable to get major number %d\n", DEVICE_NAME
, MAJOR_NR
);
182 /* set up some global information - indicating device specific info */
183 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR
), DEVICE_REQUEST
);
184 read_ahead
[MAJOR_NR
] = 8; /* 8 sector (4kB) read ahead */
186 /* some minor housekeeping - setup the global gendisk structure */
187 ps2esdi_gendisk
.next
= gendisk_head
;
188 gendisk_head
= &ps2esdi_gendisk
;
195 int cyl
[2] = {-1,-1};
196 int head
[2] = {-1, -1};
197 int sect
[2] = {-1, -1};
199 MODULE_PARM(tp720esdi
, "i");
200 MODULE_PARM(cyl
, "i");
201 MODULE_PARM(head
, "i");
202 MODULE_PARM(track
, "i");
204 int init_module(void) {
207 for(drive
= 0; drive
<= 1; drive
++) {
208 struct ps2_esdi_i_struct
*info
= &ps2esdi_info
[drive
];
210 if (cyl
[drive
] != -1) {
211 info
->cyl
= info
->lzone
= cyl
[drive
];
214 if (head
[drive
] != -1) {
215 info
->head
= head
[drive
];
216 info
->ctl
= (head
[drive
] > 8 ? 8 : 0);
218 if (sect
[drive
] != -1) info
->sect
= sect
[drive
];
220 return ps2esdi_init();
228 mca_mark_as_unused(ps2esdi_slot
);
229 mca_set_adapter_procfn(ps2esdi_slot
, NULL
, NULL
);
231 release_region(io_base
, 4);
232 free_dma(dma_arb_level
);
233 free_irq(PS2ESDI_IRQ
, NULL
)
234 devfs_unregister_blkdev(MAJOR_NR
, "ed");
235 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR
));
239 /* handles boot time command line parameters */
240 void __init
tp720_setup(char *str
, int *ints
)
242 /* no params, just sets the tp720esdi flag if it exists */
244 printk("%s: TP 720 ESDI flag set\n", DEVICE_NAME
);
248 void __init
ed_setup(char *str
, int *ints
)
252 /* handles 3 parameters only - corresponding to
253 1. Number of cylinders
261 /* print out the information - seen at boot time */
262 printk("%s: ints[0]=%d ints[1]=%d ints[2]=%d ints[3]=%d\n",
263 DEVICE_NAME
, ints
[0], ints
[1], ints
[2], ints
[3]);
265 /* set the index into device specific information table */
266 if (ps2esdi_info
[0].head
!= 0)
269 /* set up all the device information */
270 ps2esdi_info
[hdind
].head
= ints
[2];
271 ps2esdi_info
[hdind
].sect
= ints
[3];
272 ps2esdi_info
[hdind
].cyl
= ints
[1];
273 ps2esdi_info
[hdind
].wpcom
= 0;
274 ps2esdi_info
[hdind
].lzone
= ints
[1];
275 ps2esdi_info
[hdind
].ctl
= (ints
[2] > 8 ? 8 : 0);
276 #if 0 /* this may be needed for PS2/Mod.80, but it hurts ThinkPad! */
277 ps2esdi_drives
= hdind
+ 1; /* increment index for the next time */
281 static int ps2esdi_getinfo(char *buf
, int slot
, void *d
)
285 len
+= sprintf(buf
+ len
, "DMA Arbitration Level: %d\n",
287 len
+= sprintf(buf
+ len
, "IO Port: %x\n", io_base
);
288 len
+= sprintf(buf
+ len
, "IRQ: 14\n");
289 len
+= sprintf(buf
+ len
, "Drives: %d\n", ps2esdi_drives
);
294 /* ps2 esdi specific initialization - called thru the gendisk chain */
295 static void __init
ps2esdi_geninit(void)
298 The first part contains the initialization code
299 for the ESDI disk subsystem. All we really do
300 is search for the POS registers of the controller
301 to do some simple setup operations. First, we
302 must ensure that the controller is installed,
303 enabled, and configured as PRIMARY. Then we must
304 determine the DMA arbitration level being used by
305 the controller so we can handle data transfer
306 operations properly. If all of this works, then
307 we will set the INIT_FLAG to a non-zero value.
310 int slot
= 0, i
, reset_start
, reset_end
;
312 unsigned short adapterID
;
314 if ((slot
= mca_find_adapter(INTG_ESDI_ID
, 0)) != MCA_NOTFOUND
) {
315 adapterID
= INTG_ESDI_ID
;
316 printk("%s: integrated ESDI adapter found in slot %d\n",
317 DEVICE_NAME
, slot
+1);
319 mca_set_adapter_name(slot
, "PS/2 Integrated ESDI");
321 } else if ((slot
= mca_find_adapter(NRML_ESDI_ID
, 0)) != -1) {
322 adapterID
= NRML_ESDI_ID
;
323 printk("%s: normal ESDI adapter found in slot %d\n",
324 DEVICE_NAME
, slot
+1);
325 mca_set_adapter_name(slot
, "PS/2 ESDI");
331 mca_mark_as_used(slot
);
332 mca_set_adapter_procfn(slot
, (MCA_ProcFn
) ps2esdi_getinfo
, NULL
);
334 /* Found the slot - read the POS register 2 to get the necessary
335 configuration and status information. POS register 2 has the
336 following information :
341 1 - fairness disabled, linear priority assignment
342 5-2 arbitration level
345 0 - use addresses 0x3510 - 0x3517
349 status
= mca_read_stored_pos(slot
, 2);
350 /* is it enabled ? */
351 if (!(status
& STATUS_ENABLED
)) {
352 printk("%s: ESDI adapter disabled\n", DEVICE_NAME
);
355 /* try to grab IRQ, and try to grab a slow IRQ if it fails, so we can
356 share with the SCSI driver */
357 if (request_irq(PS2ESDI_IRQ
, ps2esdi_interrupt_handler
,
358 SA_INTERRUPT
| SA_SHIRQ
, "PS/2 ESDI", &ps2esdi_gendisk
)
359 && request_irq(PS2ESDI_IRQ
, ps2esdi_interrupt_handler
,
360 SA_SHIRQ
, "PS/2 ESDI", &ps2esdi_gendisk
)
362 printk("%s: Unable to get IRQ %d\n", DEVICE_NAME
, PS2ESDI_IRQ
);
365 if (status
& STATUS_ALTERNATE
)
366 io_base
= ALT_IO_BASE
;
368 io_base
= PRIMARY_IO_BASE
;
370 /* get the dma arbitration level */
371 dma_arb_level
= (status
>> 2) & 0xf;
374 printk("%s: DMA arbitration level : %d\n",
375 DEVICE_NAME
, dma_arb_level
);
378 current_int_handler
= ps2esdi_initial_reset_int_handler
;
381 reset_start
= jiffies
;
382 while (!reset_status
) {
383 init_timer(&esdi_timer
);
384 esdi_timer
.expires
= jiffies
+ HZ
;
386 add_timer(&esdi_timer
);
387 sleep_on(&ps2esdi_int
);
391 printk("%s: reset interrupt after %d jiffies, %u.%02u secs\n",
392 DEVICE_NAME
, reset_end
- reset_start
, (reset_end
- reset_start
) / HZ
,
393 (reset_end
- reset_start
) % HZ
);
396 /* Integrated ESDI Disk and Controller has only one drive! */
397 if (adapterID
== INTG_ESDI_ID
) {/* if not "normal" PS2 ESDI adapter */
398 ps2esdi_drives
= 1; /* then we have only one physical disk! */ intg_esdi
= 1;
403 /* finally this part sets up some global data structures etc. */
405 ps2esdi_get_device_cfg();
407 /* some annoyance in the above routine returns TWO drives?
408 Is something else happining in the background?
409 Regaurdless we fix the # of drives again. AJK */
410 /* Integrated ESDI Disk and Controller has only one drive! */
411 if (adapterID
== INTG_ESDI_ID
) /* if not "normal" PS2 ESDI adapter */
412 ps2esdi_drives
= 1; /* Not three or two, ONE DAMNIT! */
414 current_int_handler
= ps2esdi_normal_interrupt_handler
;
416 ps2esdi_gendisk
.nr_real
= ps2esdi_drives
;
418 for (i
= 0; i
< (MAX_HD
<< 6); i
++)
419 ps2esdi_blocksizes
[i
] = 1024;
421 request_dma(dma_arb_level
, "ed");
422 request_region(io_base
, 4, "ed");
423 blksize_size
[MAJOR_NR
] = ps2esdi_blocksizes
;
425 for (i
= 0; i
< ps2esdi_drives
; i
++) {
426 register_disk(&ps2esdi_gendisk
,MKDEV(MAJOR_NR
,i
<<6),1<<6,
428 ps2esdi_info
[i
].head
* ps2esdi_info
[i
].sect
*
429 ps2esdi_info
[i
].cyl
);
430 ps2esdi_valid
[i
] = 1;
434 static void __init
ps2esdi_get_device_cfg(void)
436 u_short cmd_blk
[TYPE_0_CMD_BLK_LENGTH
];
438 /*BA */ printk("%s: Drive 0\n", DEVICE_NAME
);
439 current_int_handler
= ps2esdi_geometry_int_handler
;
440 cmd_blk
[0] = CMD_GET_DEV_CONFIG
| 0x600;
443 ps2esdi_out_cmd_blk(cmd_blk
);
445 sleep_on(&ps2esdi_int
);
447 if (ps2esdi_drives
> 1) {
448 printk("%s: Drive 1\n", DEVICE_NAME
); /*BA */
449 cmd_blk
[0] = CMD_GET_DEV_CONFIG
| (1 << 5) | 0x600;
452 ps2esdi_out_cmd_blk(cmd_blk
);
454 sleep_on(&ps2esdi_int
);
455 } /* if second physical drive is present */
459 /* strategy routine that handles most of the IO requests */
460 static void do_ps2esdi_request(request_queue_t
* q
)
463 /* since, this routine is called with interrupts cleared - they
464 must be before it finishes */
468 printk("%s:got request. device : %d minor : %d command : %d sector : %ld count : %ld, buffer: %p\n",
470 CURRENT_DEV
, MINOR(CURRENT
->rq_dev
),
471 CURRENT
->cmd
, CURRENT
->sector
,
472 CURRENT
->nr_sectors
, CURRENT
->buffer
);
475 /* standard macro that ensures that requests are really on the
476 list + sanity checks. */
479 if (virt_to_bus(CURRENT
->buffer
+ CURRENT
->nr_sectors
* 512) > 16 * MB
) {
480 printk("%s: DMA above 16MB not supported\n", DEVICE_NAME
);
483 do_ps2esdi_request(q
);
485 } /* check for above 16Mb dmas */
486 if ((CURRENT_DEV
< ps2esdi_drives
) &&
487 (CURRENT
->sector
+ CURRENT
->nr_sectors
<=
488 ps2esdi
[MINOR(CURRENT
->rq_dev
)].nr_sects
)) {
490 printk("%s:got request. device : %d minor : %d command : %d sector : %ld count : %ld\n",
492 CURRENT_DEV
, MINOR(CURRENT
->dev
),
493 CURRENT
->cmd
, CURRENT
->sector
,
494 CURRENT
->nr_sectors
);
498 block
= CURRENT
->sector
+ ps2esdi
[MINOR(CURRENT
->rq_dev
)].start_sect
;
501 printk("%s: blocknumber : %d\n", DEVICE_NAME
, block
);
503 count
= CURRENT
->nr_sectors
;
504 switch (CURRENT
->cmd
) {
506 ps2esdi_readwrite(READ
, CURRENT_DEV
, block
, count
);
510 ps2esdi_readwrite(WRITE
, CURRENT_DEV
, block
, count
);
514 printk("%s: Unknown command\n", DEVICE_NAME
);
517 do_ps2esdi_request(q
);
519 } /* handle different commands */
521 /* is request is valid */
523 printk("Grrr. error. ps2esdi_drives: %d, %lu %lu\n", ps2esdi_drives
,
524 CURRENT
->sector
, ps2esdi
[MINOR(CURRENT
->rq_dev
)].nr_sects
);
527 do_ps2esdi_request(q
);
530 } /* main strategy routine */
532 /* resets the ESDI adapter */
533 static void reset_ctrl(void)
539 /* enable interrupts on the controller */
540 status
= inb(ESDI_INTRPT
);
541 outb((status
& 0xe0) | ATT_EOI
, ESDI_ATTN
); /* to be sure we don't have
542 any interrupt pending... */
543 outb_p(CTRL_ENABLE_INTR
, ESDI_CONTROL
);
545 /* read the ESDI status port - if the controller is not busy,
546 simply do a soft reset (fast) - otherwise we'll have to do a
547 hard (slow) reset. */
548 if (!(inb_p(ESDI_STATUS
) & STATUS_BUSY
)) {
549 /*BA */ printk("%s: soft reset...\n", DEVICE_NAME
);
550 outb_p(CTRL_SOFT_RESET
, ESDI_ATTN
);
555 printk("%s: hard reset...\n", DEVICE_NAME
);
556 outb_p(CTRL_HARD_RESET
, ESDI_CONTROL
);
557 expire
= jiffies
+ 2*HZ
;
558 while (time_before(jiffies
, expire
));
559 outb_p(1, ESDI_CONTROL
);
563 } /* reset the controller */
565 /* called by the strategy routine to handle read and write requests */
566 static void ps2esdi_readwrite(int cmd
, u_char drive
, u_int block
, u_int count
)
569 u_short track
, head
, cylinder
, sector
;
570 u_short cmd_blk
[TYPE_1_CMD_BLK_LENGTH
];
572 /* do some relevant arithmatic */
573 CURRENT
->current_nr_sectors
=
574 (count
< (2 * MAX_16BIT
/ SECT_SIZE
)) ? count
: (2 * MAX_16BIT
/ SECT_SIZE
);
575 track
= block
/ ps2esdi_info
[drive
].sect
;
576 head
= track
% ps2esdi_info
[drive
].head
;
577 cylinder
= track
/ ps2esdi_info
[drive
].head
;
578 sector
= block
% ps2esdi_info
[drive
].sect
;
581 printk("%s: cyl=%d head=%d sect=%d\n", DEVICE_NAME
, cylinder
, head
, sector
);
583 /* call the routine that actually fills out a command block */
584 ps2esdi_fill_cmd_block
586 (cmd
== READ
) ? CMD_READ
: CMD_WRITE
,
587 cylinder
, head
, sector
,
588 CURRENT
->current_nr_sectors
, drive
);
590 /* send the command block to the controller */
591 if (ps2esdi_out_cmd_blk(cmd_blk
)) {
592 printk("%s: Controller failed\n", DEVICE_NAME
);
593 if ((++CURRENT
->errors
) < MAX_RETRIES
)
594 return do_ps2esdi_request(NULL
);
598 do_ps2esdi_request(NULL
);
601 /* check for failure to put out the command block */
604 printk("%s: waiting for xfer\n", DEVICE_NAME
);
606 /* turn disk lights on */
610 } /* ps2esdi_readwrite */
612 /* fill out the command block */
613 static void ps2esdi_fill_cmd_block(u_short
* cmd_blk
, u_short cmd
,
614 u_short cyl
, u_short head
, u_short sector
, u_short length
, u_char drive
)
617 cmd_blk
[0] = (drive
<< 5) | cmd
;
619 cmd_blk
[2] = ((cyl
& 0x1f) << 11) | (head
<< 5) | sector
;
620 cmd_blk
[3] = (cyl
& 0x3E0) >> 5;
622 } /* fill out the command block */
624 /* write a command block to the controller */
625 static int ps2esdi_out_cmd_blk(u_short
* cmd_blk
)
631 /* enable interrupts */
632 outb(CTRL_ENABLE_INTR
, ESDI_CONTROL
);
634 /* do not write to the controller, if it is busy */
635 for (i
= jiffies
+ ESDI_STAT_TIMEOUT
; time_after(i
, jiffies
) && (inb(ESDI_STATUS
) &
639 printk("%s: i(1)=%d\n", DEVICE_NAME
, i
);
642 /* if device is still busy - then just time out */
643 if (inb(ESDI_STATUS
) & STATUS_BUSY
) {
644 printk("%s: ps2esdi_out_cmd timed out (1)\n", DEVICE_NAME
);
647 /* Set up the attention register in the controller */
648 outb(((*cmd_blk
) & 0xE0) | 1, ESDI_ATTN
);
651 printk("%s: sending %d words to controller\n", DEVICE_NAME
, (((*cmd_blk
) >> 14) + 1) << 1);
654 /* one by one send each word out */
655 for (i
= (((*cmd_blk
) >> 14) + 1) << 1; i
; i
--) {
656 status
= inb(ESDI_STATUS
);
657 for (j
= jiffies
+ ESDI_STAT_TIMEOUT
;
658 time_after(j
, jiffies
) && (status
& STATUS_BUSY
) &&
659 (status
& STATUS_CMD_INF
); status
= inb(ESDI_STATUS
));
660 if ((status
& (STATUS_BUSY
| STATUS_CMD_INF
)) == STATUS_BUSY
) {
662 printk("%s: sending %04X\n", DEVICE_NAME
, *cmd_blk
);
664 outw(*cmd_blk
++, ESDI_CMD_INT
);
666 printk("%s: ps2esdi_out_cmd timed out while sending command (status=%02X)\n",
667 DEVICE_NAME
, status
);
670 } /* send all words out */
672 } /* send out the commands */
675 /* prepare for dma - do all the necessary setup */
676 static void ps2esdi_prep_dma(char *buffer
, u_short length
, u_char dma_xmode
)
680 buffer
=(char *)virt_to_bus(buffer
);
683 printk("ps2esdi: b_wait: %p\n", CURRENT
->bh
->b_wait
);
687 outb(dma_arb_level
| DMA_MASK_CHAN
, PORT_DMA_FN
);
689 outb(dma_arb_level
| DMA_WRITE_ADDR
, PORT_DMA_FN
);
690 outb((u_int
) buffer
& (u_int
) 0xff, PORT_DMA_EX
);
691 outb(((u_int
) buffer
>> 8) & (u_int
) 0xff, PORT_DMA_EX
);
692 outb(((u_int
) buffer
>> 16) & (u_int
) 0xff, PORT_DMA_EX
);
694 outb(dma_arb_level
| DMA_WRITE_TC
, PORT_DMA_FN
);
695 tc
= (length
* SECT_SIZE
/ 2) - 1;
696 outb(tc
& 0xff, PORT_DMA_EX
);
697 outb((tc
>> 8) & 0xff, PORT_DMA_EX
);
699 outb(dma_arb_level
| DMA_WRITE_MODE
, PORT_DMA_FN
);
700 outb(dma_xmode
, PORT_DMA_EX
);
702 outb(dma_arb_level
| DMA_UNMASK_CHAN
, PORT_DMA_FN
);
706 } /* prepare for dma */
710 static void ps2esdi_interrupt_handler(int irq
, void *dev_id
,
711 struct pt_regs
*regs
)
715 if (inb(ESDI_STATUS
) & STATUS_INTR
) {
716 int_ret_code
= inb(ESDI_INTRPT
);
717 if (current_int_handler
) {
718 /* Disable adapter interrupts till processing is finished */
719 outb(CTRL_DISABLE_INTR
, ESDI_CONTROL
);
720 current_int_handler(int_ret_code
);
722 printk("%s: help ! No interrupt handler.\n", DEVICE_NAME
);
728 static void ps2esdi_initial_reset_int_handler(u_int int_ret_code
)
731 switch (int_ret_code
& 0xf) {
734 printk("%s: initial reset completed.\n", DEVICE_NAME
);
735 outb((int_ret_code
& 0xe0) | ATT_EOI
, ESDI_ATTN
);
736 wake_up(&ps2esdi_int
);
739 printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME
,
741 printk("%s: status: %02x\n", DEVICE_NAME
, inb(ESDI_STATUS
));
744 printk("%s: initial reset handler received interrupt: %02X\n",
745 DEVICE_NAME
, int_ret_code
);
746 outb((int_ret_code
& 0xe0) | ATT_EOI
, ESDI_ATTN
);
749 outb(CTRL_ENABLE_INTR
, ESDI_CONTROL
);
753 static void ps2esdi_geometry_int_handler(u_int int_ret_code
)
755 u_int status
, drive_num
;
759 drive_num
= int_ret_code
>> 5;
760 switch (int_ret_code
& 0xf) {
761 case INT_CMD_COMPLETE
:
762 for (i
= ESDI_TIMEOUT
; i
& !(inb(ESDI_STATUS
) & STATUS_STAT_AVAIL
); i
--);
763 if (!(inb(ESDI_STATUS
) & STATUS_STAT_AVAIL
)) {
764 printk("%s: timeout reading status word\n", DEVICE_NAME
);
765 outb((int_ret_code
& 0xe0) | ATT_EOI
, ESDI_ATTN
);
768 status
= inw(ESDI_STT_INT
);
769 if ((status
& 0x1F) == CMD_GET_DEV_CONFIG
) {
770 #define REPLY_WORDS 5 /* we already read word 0 */
771 u_short reply
[REPLY_WORDS
];
773 if (ps2esdi_read_status_words((status
>> 8) - 1, REPLY_WORDS
, reply
)) {
775 printk("%s: Device Configuration Status for drive %u\n",
776 DEVICE_NAME
, drive_num
);
778 printk("%s: Spares/cyls: %u", DEVICE_NAME
, reply
[0] >> 8);
781 ("Config bits: %s%s%s%s%s\n",
782 (reply
[0] & CONFIG_IS
) ? "Invalid Secondary, " : "",
783 ((reply
[0] & CONFIG_ZD
) && !(reply
[0] & CONFIG_IS
))
784 ? "Zero Defect, " : "Defects Present, ",
785 (reply
[0] & CONFIG_SF
) ? "Skewed Format, " : "",
786 (reply
[0] & CONFIG_FR
) ? "Removable, " : "Non-Removable, ",
787 (reply
[0] & CONFIG_RT
) ? "No Retries" : "Retries");
789 rba
= reply
[1] | ((unsigned long) reply
[2] << 16);
790 printk("%s: Number of RBA's: %lu\n", DEVICE_NAME
, rba
);
792 printk("%s: Physical number of cylinders: %u, Sectors/Track: %u, Heads: %u\n",
793 DEVICE_NAME
, reply
[3], reply
[4] >> 8, reply
[4] & 0xff);
795 if (!ps2esdi_info
[drive_num
].head
) {
796 ps2esdi_info
[drive_num
].head
= 64;
797 ps2esdi_info
[drive_num
].sect
= 32;
798 ps2esdi_info
[drive_num
].cyl
= rba
/ (64 * 32);
799 ps2esdi_info
[drive_num
].wpcom
= 0;
800 ps2esdi_info
[drive_num
].lzone
= ps2esdi_info
[drive_num
].cyl
;
801 ps2esdi_info
[drive_num
].ctl
= 8;
802 if (tp720esdi
) { /* store the retrieved parameters */
803 ps2esdi_info
[0].head
= reply
[4] & 0Xff;
804 ps2esdi_info
[0].sect
= reply
[4] >> 8;
805 ps2esdi_info
[0].cyl
= reply
[3];
806 ps2esdi_info
[0].wpcom
= 0;
807 ps2esdi_info
[0].lzone
= reply
[3];
814 if (!ps2esdi_info
[drive_num
].head
) {
815 ps2esdi_info
[drive_num
].head
= reply
[4] & 0Xff;
816 ps2esdi_info
[drive_num
].sect
= reply
[4] >> 8;
817 ps2esdi_info
[drive_num
].cyl
= reply
[3];
818 ps2esdi_info
[drive_num
].wpcom
= 0;
819 ps2esdi_info
[drive_num
].lzone
= reply
[3];
820 if (tp720esdi
) { /* store the retrieved parameters */
821 ps2esdi_info
[0].head
= reply
[4] & 0Xff;
822 ps2esdi_info
[0].sect
= reply
[4] >> 8;
823 ps2esdi_info
[0].cyl
= reply
[3];
824 ps2esdi_info
[0].wpcom
= 0;
825 ps2esdi_info
[0].lzone
= reply
[3];
833 printk("%s: failed while getting device config\n", DEVICE_NAME
);
836 printk("%s: command %02X unknown by geometry handler\n",
837 DEVICE_NAME
, status
& 0x1f);
839 outb((int_ret_code
& 0xe0) | ATT_EOI
, ESDI_ATTN
);
843 printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME
,
845 printk("%s: Device not available\n", DEVICE_NAME
);
849 case INT_CMD_ECC_RETRY
:
850 case INT_CMD_WARNING
:
854 case INT_CMD_BLK_ERR
:
855 /*BA */ printk("%s: Whaa. Error occurred...\n", DEVICE_NAME
);
856 dump_cmd_complete_status(int_ret_code
);
857 outb((int_ret_code
& 0xe0) | ATT_EOI
, ESDI_ATTN
);
860 printk("%s: Unknown interrupt reason: %02X\n",
861 DEVICE_NAME
, int_ret_code
& 0xf);
862 outb((int_ret_code
& 0xe0) | ATT_EOI
, ESDI_ATTN
);
866 wake_up(&ps2esdi_int
);
868 outb(CTRL_ENABLE_INTR
, ESDI_CONTROL
);
872 static void ps2esdi_normal_interrupt_handler(u_int int_ret_code
)
877 switch (int_ret_code
& 0x0f) {
878 case INT_TRANSFER_REQ
:
879 ps2esdi_prep_dma(CURRENT
->buffer
, CURRENT
->current_nr_sectors
,
880 (CURRENT
->cmd
== READ
) ? DMA_READ_16
: DMA_WRITE_16
);
881 outb(CTRL_ENABLE_DMA
| CTRL_ENABLE_INTR
, ESDI_CONTROL
);
885 printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME
,
887 outb(CTRL_ENABLE_INTR
, ESDI_CONTROL
);
890 case INT_CMD_COMPLETE
:
891 for (i
= ESDI_TIMEOUT
; i
& !(inb(ESDI_STATUS
) & STATUS_STAT_AVAIL
); i
--);
892 if (!(inb(ESDI_STATUS
) & STATUS_STAT_AVAIL
)) {
893 printk("%s: timeout reading status word\n", DEVICE_NAME
);
894 outb((int_ret_code
& 0xe0) | ATT_EOI
, ESDI_ATTN
);
895 outb(CTRL_ENABLE_INTR
, ESDI_CONTROL
);
896 if ((++CURRENT
->errors
) < MAX_RETRIES
)
897 do_ps2esdi_request(NULL
);
901 do_ps2esdi_request(NULL
);
905 status
= inw(ESDI_STT_INT
);
906 switch (status
& 0x1F) {
907 case (CMD_READ
& 0xff):
908 case (CMD_WRITE
& 0xff):
910 outb((int_ret_code
& 0xe0) | ATT_EOI
, ESDI_ATTN
);
911 outb(CTRL_ENABLE_INTR
, ESDI_CONTROL
);
913 printk("ps2esdi: cmd_complete b_wait: %p\n", CURRENT
->bh
->b_wait
);
915 ps2esdi_continue_request();
918 printk("%s: interrupt for unknown command %02X\n",
919 DEVICE_NAME
, status
& 0x1f);
920 outb((int_ret_code
& 0xe0) | ATT_EOI
, ESDI_ATTN
);
921 outb(CTRL_ENABLE_INTR
, ESDI_CONTROL
);
927 case INT_CMD_ECC_RETRY
:
929 dump_cmd_complete_status(int_ret_code
);
930 outb((int_ret_code
& 0xe0) | ATT_EOI
, ESDI_ATTN
);
931 outb(CTRL_ENABLE_INTR
, ESDI_CONTROL
);
932 ps2esdi_continue_request();
934 case INT_CMD_WARNING
:
939 dump_cmd_complete_status(int_ret_code
);
940 outb((int_ret_code
& 0xe0) | ATT_EOI
, ESDI_ATTN
);
941 outb(CTRL_ENABLE_INTR
, ESDI_CONTROL
);
942 if ((++CURRENT
->errors
) < MAX_RETRIES
)
943 do_ps2esdi_request(NULL
);
947 do_ps2esdi_request(NULL
);
951 case INT_CMD_BLK_ERR
:
952 dump_cmd_complete_status(int_ret_code
);
953 outb((int_ret_code
& 0xe0) | ATT_EOI
, ESDI_ATTN
);
954 outb(CTRL_ENABLE_INTR
, ESDI_CONTROL
);
957 do_ps2esdi_request(NULL
);
961 printk("%s: huh ? Who issued this format command ?\n"
963 outb((int_ret_code
& 0xe0) | ATT_EOI
, ESDI_ATTN
);
964 outb(CTRL_ENABLE_INTR
, ESDI_CONTROL
);
968 /* BA printk("%s: reset completed.\n", DEVICE_NAME) */ ;
969 outb((int_ret_code
& 0xe0) | ATT_EOI
, ESDI_ATTN
);
970 outb(CTRL_ENABLE_INTR
, ESDI_CONTROL
);
974 printk("%s: Unknown interrupt reason: %02X\n",
975 DEVICE_NAME
, int_ret_code
& 0xf);
976 outb((int_ret_code
& 0xe0) | ATT_EOI
, ESDI_ATTN
);
977 outb(CTRL_ENABLE_INTR
, ESDI_CONTROL
);
981 } /* handle interrupts */
984 static void ps2esdi_continue_request(void)
986 if (CURRENT
->nr_sectors
-= CURRENT
->current_nr_sectors
) {
987 CURRENT
->buffer
+= CURRENT
->current_nr_sectors
* SECT_SIZE
;
988 CURRENT
->sector
+= CURRENT
->current_nr_sectors
;
989 do_ps2esdi_request(NULL
);
993 do_ps2esdi_request(NULL
);
999 static int ps2esdi_read_status_words(int num_words
,
1005 for (; max_words
&& num_words
; max_words
--, num_words
--, buffer
++) {
1006 for (i
= ESDI_TIMEOUT
; i
&& !(inb(ESDI_STATUS
) & STATUS_STAT_AVAIL
); i
--);
1007 if (!(inb(ESDI_STATUS
) & STATUS_STAT_AVAIL
)) {
1008 printk("%s: timeout reading status word\n", DEVICE_NAME
);
1011 *buffer
= inw(ESDI_STT_INT
);
1019 static void dump_cmd_complete_status(u_int int_ret_code
)
1021 #define WAIT_FOR_STATUS \
1022 for(i=ESDI_TIMEOUT;i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL);i--); \
1023 if(!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) { \
1024 printk("%s: timeout reading status word\n",DEVICE_NAME); \
1032 printk("%s: Device: %u, interrupt ID: %02X\n",
1033 DEVICE_NAME
, int_ret_code
>> 5,
1034 int_ret_code
& 0xf);
1037 stat_word
= inw(ESDI_STT_INT
);
1038 word_count
= (stat_word
>> 8) - 1;
1039 printk("%s: %u status words, command: %02X\n", DEVICE_NAME
, word_count
,
1044 stat_word
= inw(ESDI_STT_INT
);
1045 printk("%s: command status code: %02X, command error code: %02X\n",
1046 DEVICE_NAME
, stat_word
>> 8, stat_word
& 0xff);
1050 stat_word
= inw(ESDI_STT_INT
);
1051 printk("%s: device error code: %s%s%s%s%s,%02X\n", DEVICE_NAME
,
1052 (stat_word
& 0x1000) ? "Ready, " : "Not Ready, ",
1053 (stat_word
& 0x0800) ? "Selected, " : "Not Selected, ",
1054 (stat_word
& 0x0400) ? "Write Fault, " : "",
1055 (stat_word
& 0x0200) ? "Track 0, " : "",
1056 (stat_word
& 0x0100) ? "Seek or command complete, " : "",
1061 stat_word
= inw(ESDI_STT_INT
);
1062 printk("%s: Blocks to do: %u", DEVICE_NAME
, stat_word
);
1064 if (word_count
-= 2) {
1066 rba
= inw(ESDI_STT_INT
);
1068 rba
|= inw(ESDI_STT_INT
) << 16;
1069 printk(", Last Cyl: %u Head: %u Sector: %u\n",
1070 (u_short
) ((rba
& 0x1ff80000) >> 11),
1071 (u_short
) ((rba
& 0x7E0) >> 5), (u_short
) (rba
& 0x1f));
1077 stat_word
= inw(ESDI_STT_INT
);
1078 printk("%s: Blocks required ECC: %u", DEVICE_NAME
, stat_word
);
1082 #undef WAIT_FOR_STATUS
1087 static int ps2esdi_open(struct inode
*inode
, struct file
*file
)
1089 int dev
= DEVICE_NR(inode
->i_rdev
);
1091 if (dev
< ps2esdi_drives
) {
1092 while (!ps2esdi_valid
[dev
])
1093 sleep_on(&ps2esdi_wait_open
);
1095 access_count
[dev
]++;
1104 static int ps2esdi_release(struct inode
*inode
, struct file
*file
)
1106 int dev
= DEVICE_NR(inode
->i_rdev
);
1108 if (dev
< ps2esdi_drives
) {
1109 access_count
[dev
]--;
1116 static int ps2esdi_ioctl(struct inode
*inode
,
1117 struct file
*file
, u_int cmd
, u_long arg
)
1120 struct ps2esdi_geometry
*geometry
= (struct ps2esdi_geometry
*) arg
;
1121 int dev
= DEVICE_NR(inode
->i_rdev
), err
;
1123 if (inode
&& (dev
< ps2esdi_drives
))
1127 if ((err
= verify_area(VERIFY_WRITE
, geometry
, sizeof(*geometry
))))
1129 put_user(ps2esdi_info
[dev
].head
, (char *) &geometry
->heads
);
1130 put_user(ps2esdi_info
[dev
].sect
, (char *) &geometry
->sectors
);
1131 put_user(ps2esdi_info
[dev
].cyl
, (short *) &geometry
->cylinders
);
1132 put_user(ps2esdi
[MINOR(inode
->i_rdev
)].start_sect
,
1133 (long *) &geometry
->start
);
1141 if ((err
= verify_area(VERIFY_WRITE
, (long *) arg
, sizeof(long))))
1143 put_user(ps2esdi
[MINOR(inode
->i_rdev
)].nr_sects
, (long *) arg
);
1150 if (!capable(CAP_SYS_ADMIN
))
1152 return (ps2esdi_reread_partitions(inode
->i_rdev
));
1160 return blk_ioctl(inode
->i_rdev
, cmd
, arg
);
1167 static int ps2esdi_reread_partitions(kdev_t dev
)
1169 int target
= DEVICE_NR(dev
);
1170 int start
= target
<< ps2esdi_gendisk
.minor_shift
;
1174 ps2esdi_valid
[target
] = (access_count
[target
] != 1);
1176 if (ps2esdi_valid
[target
])
1179 for (partition
= ps2esdi_gendisk
.max_p
- 1;
1180 partition
>= 0; partition
--) {
1181 int minor
= (start
| partition
);
1182 kdev_t devp
= MKDEV(MAJOR_NR
, minor
);
1183 struct super_block
* sb
= get_super(devp
);
1187 invalidate_inodes(sb
);
1188 invalidate_buffers(devp
);
1189 ps2esdi_gendisk
.part
[start
+ partition
].start_sect
= 0;
1190 ps2esdi_gendisk
.part
[start
+ partition
].nr_sects
= 0;
1193 grok_partitions(&ps2esdi_gendisk
, target
, 1<<6,
1194 ps2esdi_info
[target
].head
* ps2esdi_info
[target
].cyl
* ps2esdi_info
[target
].sect
);
1196 ps2esdi_valid
[target
] = 1;
1197 wake_up(&ps2esdi_wait_open
);
1202 void ps2esdi_reset_timer(unsigned long unused
)
1207 status
= inb(ESDI_INTRPT
);
1208 if ((status
& 0xf) == INT_RESET
) {
1209 outb((status
& 0xe0) | ATT_EOI
, ESDI_ATTN
);
1210 outb(CTRL_ENABLE_INTR
, ESDI_CONTROL
);
1213 wake_up(&ps2esdi_int
);