aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/ps2esdi.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/block/ps2esdi.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/block/ps2esdi.c')
-rw-r--r--drivers/block/ps2esdi.c1092
1 files changed, 1092 insertions, 0 deletions
diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
new file mode 100644
index 000000000000..29548784cb7b
--- /dev/null
+++ b/drivers/block/ps2esdi.c
@@ -0,0 +1,1092 @@
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
8 elections 1994 */
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 */
12
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 */
16
17/* BA Modified for ThinkPad 720 by Boris Ashkinazi */
18/* (bash@vnet.ibm.com) 08/08/95 */
19
20/* Modified further for ThinkPad-720C by Uri Blumenthal */
21/* (uri@watson.ibm.com) Sep 11, 1995 */
22
23/* TODO :
24 + Timeouts
25 + Get disk parameters
26 + DMA above 16MB
27 + reset after read/write error
28 */
29
30#define DEVICE_NAME "PS/2 ESDI"
31
32#include <linux/config.h>
33#include <linux/major.h>
34#include <linux/errno.h>
35#include <linux/wait.h>
36#include <linux/interrupt.h>
37#include <linux/fs.h>
38#include <linux/kernel.h>
39#include <linux/genhd.h>
40#include <linux/ps2esdi.h>
41#include <linux/blkdev.h>
42#include <linux/mca-legacy.h>
43#include <linux/init.h>
44#include <linux/ioport.h>
45#include <linux/module.h>
46
47#include <asm/system.h>
48#include <asm/io.h>
49#include <asm/dma.h>
50#include <asm/mca_dma.h>
51#include <asm/uaccess.h>
52
53#define PS2ESDI_IRQ 14
54#define MAX_HD 2
55#define MAX_RETRIES 5
56#define MAX_16BIT 65536
57#define ESDI_TIMEOUT 0xf000
58#define ESDI_STAT_TIMEOUT 4
59
60#define TYPE_0_CMD_BLK_LENGTH 2
61#define TYPE_1_CMD_BLK_LENGTH 4
62
63static void reset_ctrl(void);
64
65static int ps2esdi_geninit(void);
66
67static void do_ps2esdi_request(request_queue_t * q);
68
69static void ps2esdi_readwrite(int cmd, struct request *req);
70
71static void ps2esdi_fill_cmd_block(u_short * cmd_blk, u_short cmd,
72u_short cyl, u_short head, u_short sector, u_short length, u_char drive);
73
74static int ps2esdi_out_cmd_blk(u_short * cmd_blk);
75
76static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode);
77
78static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id,
79 struct pt_regs *regs);
80static void (*current_int_handler) (u_int) = NULL;
81static void ps2esdi_normal_interrupt_handler(u_int);
82static void ps2esdi_initial_reset_int_handler(u_int);
83static void ps2esdi_geometry_int_handler(u_int);
84static int ps2esdi_ioctl(struct inode *inode, struct file *file,
85 u_int cmd, u_long arg);
86
87static int ps2esdi_read_status_words(int num_words, int max_words, u_short * buffer);
88
89static void dump_cmd_complete_status(u_int int_ret_code);
90
91static void ps2esdi_get_device_cfg(void);
92
93static void ps2esdi_reset_timer(unsigned long unused);
94
95static u_int dma_arb_level; /* DMA arbitration level */
96
97static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_int);
98
99static int no_int_yet;
100static int ps2esdi_drives;
101static u_short io_base;
102static struct timer_list esdi_timer =
103 TIMER_INITIALIZER(ps2esdi_reset_timer, 0, 0);
104static int reset_status;
105static int ps2esdi_slot = -1;
106static int tp720esdi = 0; /* Is it Integrated ESDI of ThinkPad-720? */
107static int intg_esdi = 0; /* If integrated adapter */
108struct ps2esdi_i_struct {
109 unsigned int head, sect, cyl, wpcom, lzone, ctl;
110};
111static DEFINE_SPINLOCK(ps2esdi_lock);
112static struct request_queue *ps2esdi_queue;
113static struct request *current_req;
114
115#if 0
116#if 0 /* try both - I don't know which one is better... UB */
117static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] =
118{
119 {4, 48, 1553, 0, 0, 0},
120 {0, 0, 0, 0, 0, 0}};
121#else
122static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] =
123{
124 {64, 32, 161, 0, 0, 0},
125 {0, 0, 0, 0, 0, 0}};
126#endif
127#endif
128static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] =
129{
130 {0, 0, 0, 0, 0, 0},
131 {0, 0, 0, 0, 0, 0}};
132
133static struct block_device_operations ps2esdi_fops =
134{
135 .owner = THIS_MODULE,
136 .ioctl = ps2esdi_ioctl,
137};
138
139static struct gendisk *ps2esdi_gendisk[2];
140
141/* initialization routine called by ll_rw_blk.c */
142static int __init ps2esdi_init(void)
143{
144
145 int error = 0;
146
147 /* register the device - pass the name and major number */
148 if (register_blkdev(PS2ESDI_MAJOR, "ed"))
149 return -EBUSY;
150
151 /* set up some global information - indicating device specific info */
152 ps2esdi_queue = blk_init_queue(do_ps2esdi_request, &ps2esdi_lock);
153 if (!ps2esdi_queue) {
154 unregister_blkdev(PS2ESDI_MAJOR, "ed");
155 return -ENOMEM;
156 }
157
158 /* some minor housekeeping - setup the global gendisk structure */
159 error = ps2esdi_geninit();
160 if (error) {
161 printk(KERN_WARNING "PS2ESDI: error initialising"
162 " device, releasing resources\n");
163 unregister_blkdev(PS2ESDI_MAJOR, "ed");
164 blk_cleanup_queue(ps2esdi_queue);
165 return error;
166 }
167 return 0;
168} /* ps2esdi_init */
169
170#ifndef MODULE
171
172module_init(ps2esdi_init);
173
174#else
175
176static int cyl[MAX_HD] = {-1,-1};
177static int head[MAX_HD] = {-1, -1};
178static int sect[MAX_HD] = {-1, -1};
179
180module_param(tp720esdi, bool, 0);
181module_param_array(cyl, int, NULL, 0);
182module_param_array(head, int, NULL, 0);
183module_param_array(sect, int, NULL, 0);
184MODULE_LICENSE("GPL");
185
186int init_module(void) {
187 int drive;
188
189 for(drive = 0; drive < MAX_HD; drive++) {
190 struct ps2esdi_i_struct *info = &ps2esdi_info[drive];
191
192 if (cyl[drive] != -1) {
193 info->cyl = info->lzone = cyl[drive];
194 info->wpcom = 0;
195 }
196 if (head[drive] != -1) {
197 info->head = head[drive];
198 info->ctl = (head[drive] > 8 ? 8 : 0);
199 }
200 if (sect[drive] != -1) info->sect = sect[drive];
201 }
202 return ps2esdi_init();
203}
204
205void
206cleanup_module(void) {
207 int i;
208 if(ps2esdi_slot) {
209 mca_mark_as_unused(ps2esdi_slot);
210 mca_set_adapter_procfn(ps2esdi_slot, NULL, NULL);
211 }
212 release_region(io_base, 4);
213 free_dma(dma_arb_level);
214 free_irq(PS2ESDI_IRQ, &ps2esdi_gendisk);
215 unregister_blkdev(PS2ESDI_MAJOR, "ed");
216 blk_cleanup_queue(ps2esdi_queue);
217 for (i = 0; i < ps2esdi_drives; i++) {
218 del_gendisk(ps2esdi_gendisk[i]);
219 put_disk(ps2esdi_gendisk[i]);
220 }
221}
222#endif /* MODULE */
223
224/* handles boot time command line parameters */
225void __init tp720_setup(char *str, int *ints)
226{
227 /* no params, just sets the tp720esdi flag if it exists */
228
229 printk("%s: TP 720 ESDI flag set\n", DEVICE_NAME);
230 tp720esdi = 1;
231}
232
233void __init ed_setup(char *str, int *ints)
234{
235 int hdind = 0;
236
237 /* handles 3 parameters only - corresponding to
238 1. Number of cylinders
239 2. Number of heads
240 3. Sectors/track
241 */
242
243 if (ints[0] != 3)
244 return;
245
246 /* print out the information - seen at boot time */
247 printk("%s: ints[0]=%d ints[1]=%d ints[2]=%d ints[3]=%d\n",
248 DEVICE_NAME, ints[0], ints[1], ints[2], ints[3]);
249
250 /* set the index into device specific information table */
251 if (ps2esdi_info[0].head != 0)
252 hdind = 1;
253
254 /* set up all the device information */
255 ps2esdi_info[hdind].head = ints[2];
256 ps2esdi_info[hdind].sect = ints[3];
257 ps2esdi_info[hdind].cyl = ints[1];
258 ps2esdi_info[hdind].wpcom = 0;
259 ps2esdi_info[hdind].lzone = ints[1];
260 ps2esdi_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
261#if 0 /* this may be needed for PS2/Mod.80, but it hurts ThinkPad! */
262 ps2esdi_drives = hdind + 1; /* increment index for the next time */
263#endif
264} /* ed_setup */
265
266static int ps2esdi_getinfo(char *buf, int slot, void *d)
267{
268 int len = 0;
269
270 len += sprintf(buf + len, "DMA Arbitration Level: %d\n",
271 dma_arb_level);
272 len += sprintf(buf + len, "IO Port: %x\n", io_base);
273 len += sprintf(buf + len, "IRQ: 14\n");
274 len += sprintf(buf + len, "Drives: %d\n", ps2esdi_drives);
275
276 return len;
277}
278
279/* ps2 esdi specific initialization - called thru the gendisk chain */
280static int __init ps2esdi_geninit(void)
281{
282 /*
283 The first part contains the initialization code
284 for the ESDI disk subsystem. All we really do
285 is search for the POS registers of the controller
286 to do some simple setup operations. First, we
287 must ensure that the controller is installed,
288 enabled, and configured as PRIMARY. Then we must
289 determine the DMA arbitration level being used by
290 the controller so we can handle data transfer
291 operations properly. If all of this works, then
292 we will set the INIT_FLAG to a non-zero value.
293 */
294
295 int slot = 0, i, reset_start, reset_end;
296 u_char status;
297 unsigned short adapterID;
298 int error = 0;
299
300 if ((slot = mca_find_adapter(INTG_ESDI_ID, 0)) != MCA_NOTFOUND) {
301 adapterID = INTG_ESDI_ID;
302 printk("%s: integrated ESDI adapter found in slot %d\n",
303 DEVICE_NAME, slot+1);
304#ifndef MODULE
305 mca_set_adapter_name(slot, "PS/2 Integrated ESDI");
306#endif
307 } else if ((slot = mca_find_adapter(NRML_ESDI_ID, 0)) != -1) {
308 adapterID = NRML_ESDI_ID;
309 printk("%s: normal ESDI adapter found in slot %d\n",
310 DEVICE_NAME, slot+1);
311 mca_set_adapter_name(slot, "PS/2 ESDI");
312 } else {
313 return -ENODEV;
314 }
315
316 ps2esdi_slot = slot;
317 mca_mark_as_used(slot);
318 mca_set_adapter_procfn(slot, (MCA_ProcFn) ps2esdi_getinfo, NULL);
319
320 /* Found the slot - read the POS register 2 to get the necessary
321 configuration and status information. POS register 2 has the
322 following information :
323 Bit Function
324 7 reserved = 0
325 6 arbitration method
326 0 - fairness enabled
327 1 - fairness disabled, linear priority assignment
328 5-2 arbitration level
329 1 alternate address
330 1 alternate address
331 0 - use addresses 0x3510 - 0x3517
332 0 adapter enable
333 */
334
335 status = mca_read_stored_pos(slot, 2);
336 /* is it enabled ? */
337 if (!(status & STATUS_ENABLED)) {
338 printk("%s: ESDI adapter disabled\n", DEVICE_NAME);
339 error = -ENODEV;
340 goto err_out1;
341 }
342 /* try to grab IRQ, and try to grab a slow IRQ if it fails, so we can
343 share with the SCSI driver */
344 if (request_irq(PS2ESDI_IRQ, ps2esdi_interrupt_handler,
345 SA_INTERRUPT | SA_SHIRQ, "PS/2 ESDI", &ps2esdi_gendisk)
346 && request_irq(PS2ESDI_IRQ, ps2esdi_interrupt_handler,
347 SA_SHIRQ, "PS/2 ESDI", &ps2esdi_gendisk)
348 ) {
349 printk("%s: Unable to get IRQ %d\n", DEVICE_NAME, PS2ESDI_IRQ);
350 error = -EBUSY;
351 goto err_out1;
352 }
353 if (status & STATUS_ALTERNATE)
354 io_base = ALT_IO_BASE;
355 else
356 io_base = PRIMARY_IO_BASE;
357
358 if (!request_region(io_base, 4, "ed")) {
359 printk(KERN_WARNING"Unable to request region 0x%x\n", io_base);
360 error = -EBUSY;
361 goto err_out2;
362 }
363 /* get the dma arbitration level */
364 dma_arb_level = (status >> 2) & 0xf;
365
366 /* BA */
367 printk("%s: DMA arbitration level : %d\n",
368 DEVICE_NAME, dma_arb_level);
369
370 LITE_ON;
371 current_int_handler = ps2esdi_initial_reset_int_handler;
372 reset_ctrl();
373 reset_status = 0;
374 reset_start = jiffies;
375 while (!reset_status) {
376 init_timer(&esdi_timer);
377 esdi_timer.expires = jiffies + HZ;
378 esdi_timer.data = 0;
379 add_timer(&esdi_timer);
380 sleep_on(&ps2esdi_int);
381 }
382 reset_end = jiffies;
383 LITE_OFF;
384 printk("%s: reset interrupt after %d jiffies, %u.%02u secs\n",
385 DEVICE_NAME, reset_end - reset_start, (reset_end - reset_start) / HZ,
386 (reset_end - reset_start) % HZ);
387
388
389 /* Integrated ESDI Disk and Controller has only one drive! */
390 if (adapterID == INTG_ESDI_ID) {/* if not "normal" PS2 ESDI adapter */
391 ps2esdi_drives = 1; /* then we have only one physical disk! */ intg_esdi = 1;
392 }
393
394
395
396 /* finally this part sets up some global data structures etc. */
397
398 ps2esdi_get_device_cfg();
399
400 /* some annoyance in the above routine returns TWO drives?
401 Is something else happining in the background?
402 Regaurdless we fix the # of drives again. AJK */
403 /* Integrated ESDI Disk and Controller has only one drive! */
404 if (adapterID == INTG_ESDI_ID) /* if not "normal" PS2 ESDI adapter */
405 ps2esdi_drives = 1; /* Not three or two, ONE DAMNIT! */
406
407 current_int_handler = ps2esdi_normal_interrupt_handler;
408
409 if (request_dma(dma_arb_level, "ed") !=0) {
410 printk(KERN_WARNING "PS2ESDI: Can't request dma-channel %d\n"
411 ,(int) dma_arb_level);
412 error = -EBUSY;
413 goto err_out3;
414 }
415 blk_queue_max_sectors(ps2esdi_queue, 128);
416
417 error = -ENOMEM;
418 for (i = 0; i < ps2esdi_drives; i++) {
419 struct gendisk *disk = alloc_disk(64);
420 if (!disk)
421 goto err_out4;
422 disk->major = PS2ESDI_MAJOR;
423 disk->first_minor = i<<6;
424 sprintf(disk->disk_name, "ed%c", 'a'+i);
425 sprintf(disk->devfs_name, "ed/target%d", i);
426 disk->fops = &ps2esdi_fops;
427 ps2esdi_gendisk[i] = disk;
428 }
429
430 for (i = 0; i < ps2esdi_drives; i++) {
431 struct gendisk *disk = ps2esdi_gendisk[i];
432 set_capacity(disk, ps2esdi_info[i].head * ps2esdi_info[i].sect *
433 ps2esdi_info[i].cyl);
434 disk->queue = ps2esdi_queue;
435 disk->private_data = &ps2esdi_info[i];
436 add_disk(disk);
437 }
438 return 0;
439err_out4:
440 while (i--)
441 put_disk(ps2esdi_gendisk[i]);
442err_out3:
443 release_region(io_base, 4);
444err_out2:
445 free_irq(PS2ESDI_IRQ, &ps2esdi_gendisk);
446err_out1:
447 if(ps2esdi_slot) {
448 mca_mark_as_unused(ps2esdi_slot);
449 mca_set_adapter_procfn(ps2esdi_slot, NULL, NULL);
450 }
451 return error;
452}
453
454static void __init ps2esdi_get_device_cfg(void)
455{
456 u_short cmd_blk[TYPE_0_CMD_BLK_LENGTH];
457
458 /*BA */ printk("%s: Drive 0\n", DEVICE_NAME);
459 current_int_handler = ps2esdi_geometry_int_handler;
460 cmd_blk[0] = CMD_GET_DEV_CONFIG | 0x600;
461 cmd_blk[1] = 0;
462 no_int_yet = TRUE;
463 ps2esdi_out_cmd_blk(cmd_blk);
464 if (no_int_yet)
465 sleep_on(&ps2esdi_int);
466
467 if (ps2esdi_drives > 1) {
468 printk("%s: Drive 1\n", DEVICE_NAME); /*BA */
469 cmd_blk[0] = CMD_GET_DEV_CONFIG | (1 << 5) | 0x600;
470 cmd_blk[1] = 0;
471 no_int_yet = TRUE;
472 ps2esdi_out_cmd_blk(cmd_blk);
473 if (no_int_yet)
474 sleep_on(&ps2esdi_int);
475 } /* if second physical drive is present */
476 return;
477}
478
479/* strategy routine that handles most of the IO requests */
480static void do_ps2esdi_request(request_queue_t * q)
481{
482 struct request *req;
483 /* since, this routine is called with interrupts cleared - they
484 must be before it finishes */
485
486 req = elv_next_request(q);
487 if (!req)
488 return;
489
490#if 0
491 printk("%s:got request. device : %s command : %d sector : %ld count : %ld, buffer: %p\n",
492 DEVICE_NAME,
493 req->rq_disk->disk_name,
494 req->cmd, req->sector,
495 req->current_nr_sectors, req->buffer);
496#endif
497
498 /* check for above 16Mb dmas */
499 if (isa_virt_to_bus(req->buffer + req->current_nr_sectors * 512) > 16 * MB) {
500 printk("%s: DMA above 16MB not supported\n", DEVICE_NAME);
501 end_request(req, FAIL);
502 return;
503 }
504
505 if (req->sector+req->current_nr_sectors > get_capacity(req->rq_disk)) {
506 printk("Grrr. error. ps2esdi_drives: %d, %llu %llu\n",
507 ps2esdi_drives, req->sector,
508 (unsigned long long)get_capacity(req->rq_disk));
509 end_request(req, FAIL);
510 return;
511 }
512
513 switch (rq_data_dir(req)) {
514 case READ:
515 ps2esdi_readwrite(READ, req);
516 break;
517 case WRITE:
518 ps2esdi_readwrite(WRITE, req);
519 break;
520 default:
521 printk("%s: Unknown command\n", req->rq_disk->disk_name);
522 end_request(req, FAIL);
523 break;
524 } /* handle different commands */
525} /* main strategy routine */
526
527/* resets the ESDI adapter */
528static void reset_ctrl(void)
529{
530
531 u_long expire;
532 u_short status;
533
534 /* enable interrupts on the controller */
535 status = inb(ESDI_INTRPT);
536 outb((status & 0xe0) | ATT_EOI, ESDI_ATTN); /* to be sure we don't have
537 any interrupt pending... */
538 outb_p(CTRL_ENABLE_INTR, ESDI_CONTROL);
539
540 /* read the ESDI status port - if the controller is not busy,
541 simply do a soft reset (fast) - otherwise we'll have to do a
542 hard (slow) reset. */
543 if (!(inb_p(ESDI_STATUS) & STATUS_BUSY)) {
544 /*BA */ printk("%s: soft reset...\n", DEVICE_NAME);
545 outb_p(CTRL_SOFT_RESET, ESDI_ATTN);
546 }
547 /* soft reset */
548 else {
549 /*BA */
550 printk("%s: hard reset...\n", DEVICE_NAME);
551 outb_p(CTRL_HARD_RESET, ESDI_CONTROL);
552 expire = jiffies + 2*HZ;
553 while (time_before(jiffies, expire));
554 outb_p(1, ESDI_CONTROL);
555 } /* hard reset */
556
557
558} /* reset the controller */
559
560/* called by the strategy routine to handle read and write requests */
561static void ps2esdi_readwrite(int cmd, struct request *req)
562{
563 struct ps2esdi_i_struct *p = req->rq_disk->private_data;
564 unsigned block = req->sector;
565 unsigned count = req->current_nr_sectors;
566 int drive = p - ps2esdi_info;
567 u_short track, head, cylinder, sector;
568 u_short cmd_blk[TYPE_1_CMD_BLK_LENGTH];
569
570 /* do some relevant arithmatic */
571 track = block / p->sect;
572 head = track % p->head;
573 cylinder = track / p->head;
574 sector = block % p->sect;
575
576#if 0
577 printk("%s: cyl=%d head=%d sect=%d\n", DEVICE_NAME, cylinder, head, sector);
578#endif
579 /* call the routine that actually fills out a command block */
580 ps2esdi_fill_cmd_block
581 (cmd_blk,
582 (cmd == READ) ? CMD_READ : CMD_WRITE,
583 cylinder, head, sector, count, drive);
584
585 /* send the command block to the controller */
586 current_req = req;
587 spin_unlock_irq(&ps2esdi_lock);
588 if (ps2esdi_out_cmd_blk(cmd_blk)) {
589 spin_lock_irq(&ps2esdi_lock);
590 printk("%s: Controller failed\n", DEVICE_NAME);
591 if ((++req->errors) >= MAX_RETRIES)
592 end_request(req, FAIL);
593 }
594 /* check for failure to put out the command block */
595 else {
596 spin_lock_irq(&ps2esdi_lock);
597#if 0
598 printk("%s: waiting for xfer\n", DEVICE_NAME);
599#endif
600 /* turn disk lights on */
601 LITE_ON;
602 }
603
604} /* ps2esdi_readwrite */
605
606/* fill out the command block */
607static void ps2esdi_fill_cmd_block(u_short * cmd_blk, u_short cmd,
608 u_short cyl, u_short head, u_short sector, u_short length, u_char drive)
609{
610
611 cmd_blk[0] = (drive << 5) | cmd;
612 cmd_blk[1] = length;
613 cmd_blk[2] = ((cyl & 0x1f) << 11) | (head << 5) | sector;
614 cmd_blk[3] = (cyl & 0x3E0) >> 5;
615
616} /* fill out the command block */
617
618/* write a command block to the controller */
619static int ps2esdi_out_cmd_blk(u_short * cmd_blk)
620{
621
622 int i;
623 unsigned long jif;
624 u_char status;
625
626 /* enable interrupts */
627 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
628
629 /* do not write to the controller, if it is busy */
630 for (jif = jiffies + ESDI_STAT_TIMEOUT;
631 time_after(jif, jiffies) &&
632 (inb(ESDI_STATUS) & STATUS_BUSY); )
633 ;
634
635#if 0
636 printk("%s: i(1)=%ld\n", DEVICE_NAME, jif);
637#endif
638
639 /* if device is still busy - then just time out */
640 if (inb(ESDI_STATUS) & STATUS_BUSY) {
641 printk("%s: ps2esdi_out_cmd timed out (1)\n", DEVICE_NAME);
642 return ERROR;
643 } /* timeout ??? */
644 /* Set up the attention register in the controller */
645 outb(((*cmd_blk) & 0xE0) | 1, ESDI_ATTN);
646
647#if 0
648 printk("%s: sending %d words to controller\n", DEVICE_NAME, (((*cmd_blk) >> 14) + 1) << 1);
649#endif
650
651 /* one by one send each word out */
652 for (i = (((*cmd_blk) >> 14) + 1) << 1; i; i--) {
653 status = inb(ESDI_STATUS);
654 for (jif = jiffies + ESDI_STAT_TIMEOUT;
655 time_after(jif, jiffies) && (status & STATUS_BUSY) &&
656 (status & STATUS_CMD_INF); status = inb(ESDI_STATUS));
657 if ((status & (STATUS_BUSY | STATUS_CMD_INF)) == STATUS_BUSY) {
658#if 0
659 printk("%s: sending %04X\n", DEVICE_NAME, *cmd_blk);
660#endif
661 outw(*cmd_blk++, ESDI_CMD_INT);
662 } else {
663 printk("%s: ps2esdi_out_cmd timed out while sending command (status=%02X)\n",
664 DEVICE_NAME, status);
665 return ERROR;
666 }
667 } /* send all words out */
668 return OK;
669} /* send out the commands */
670
671
672/* prepare for dma - do all the necessary setup */
673static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode)
674{
675 unsigned long flags = claim_dma_lock();
676
677 mca_disable_dma(dma_arb_level);
678
679 mca_set_dma_addr(dma_arb_level, isa_virt_to_bus(buffer));
680
681 mca_set_dma_count(dma_arb_level, length * 512 / 2);
682
683 mca_set_dma_mode(dma_arb_level, dma_xmode);
684
685 mca_enable_dma(dma_arb_level);
686
687 release_dma_lock(flags);
688
689} /* prepare for dma */
690
691
692
693static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id,
694 struct pt_regs *regs)
695{
696 u_int int_ret_code;
697
698 if (inb(ESDI_STATUS) & STATUS_INTR) {
699 int_ret_code = inb(ESDI_INTRPT);
700 if (current_int_handler) {
701 /* Disable adapter interrupts till processing is finished */
702 outb(CTRL_DISABLE_INTR, ESDI_CONTROL);
703 current_int_handler(int_ret_code);
704 } else
705 printk("%s: help ! No interrupt handler.\n", DEVICE_NAME);
706 } else {
707 return IRQ_NONE;
708 }
709 return IRQ_HANDLED;
710}
711
712static void ps2esdi_initial_reset_int_handler(u_int int_ret_code)
713{
714
715 switch (int_ret_code & 0xf) {
716 case INT_RESET:
717 /*BA */
718 printk("%s: initial reset completed.\n", DEVICE_NAME);
719 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
720 wake_up(&ps2esdi_int);
721 break;
722 case INT_ATTN_ERROR:
723 printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME,
724 int_ret_code);
725 printk("%s: status: %02x\n", DEVICE_NAME, inb(ESDI_STATUS));
726 break;
727 default:
728 printk("%s: initial reset handler received interrupt: %02X\n",
729 DEVICE_NAME, int_ret_code);
730 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
731 break;
732 }
733 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
734}
735
736
737static void ps2esdi_geometry_int_handler(u_int int_ret_code)
738{
739 u_int status, drive_num;
740 unsigned long rba;
741 int i;
742
743 drive_num = int_ret_code >> 5;
744 switch (int_ret_code & 0xf) {
745 case INT_CMD_COMPLETE:
746 for (i = ESDI_TIMEOUT; i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--);
747 if (!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) {
748 printk("%s: timeout reading status word\n", DEVICE_NAME);
749 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
750 break;
751 }
752 status = inw(ESDI_STT_INT);
753 if ((status & 0x1F) == CMD_GET_DEV_CONFIG) {
754#define REPLY_WORDS 5 /* we already read word 0 */
755 u_short reply[REPLY_WORDS];
756
757 if (ps2esdi_read_status_words((status >> 8) - 1, REPLY_WORDS, reply)) {
758 /*BA */
759 printk("%s: Device Configuration Status for drive %u\n",
760 DEVICE_NAME, drive_num);
761
762 printk("%s: Spares/cyls: %u", DEVICE_NAME, reply[0] >> 8);
763
764 printk
765 ("Config bits: %s%s%s%s%s\n",
766 (reply[0] & CONFIG_IS) ? "Invalid Secondary, " : "",
767 ((reply[0] & CONFIG_ZD) && !(reply[0] & CONFIG_IS))
768 ? "Zero Defect, " : "Defects Present, ",
769 (reply[0] & CONFIG_SF) ? "Skewed Format, " : "",
770 (reply[0] & CONFIG_FR) ? "Removable, " : "Non-Removable, ",
771 (reply[0] & CONFIG_RT) ? "No Retries" : "Retries");
772
773 rba = reply[1] | ((unsigned long) reply[2] << 16);
774 printk("%s: Number of RBA's: %lu\n", DEVICE_NAME, rba);
775
776 printk("%s: Physical number of cylinders: %u, Sectors/Track: %u, Heads: %u\n",
777 DEVICE_NAME, reply[3], reply[4] >> 8, reply[4] & 0xff);
778
779 if (!ps2esdi_info[drive_num].head) {
780 ps2esdi_info[drive_num].head = 64;
781 ps2esdi_info[drive_num].sect = 32;
782 ps2esdi_info[drive_num].cyl = rba / (64 * 32);
783 ps2esdi_info[drive_num].wpcom = 0;
784 ps2esdi_info[drive_num].lzone = ps2esdi_info[drive_num].cyl;
785 ps2esdi_info[drive_num].ctl = 8;
786 if (tp720esdi) { /* store the retrieved parameters */
787 ps2esdi_info[0].head = reply[4] & 0Xff;
788 ps2esdi_info[0].sect = reply[4] >> 8;
789 ps2esdi_info[0].cyl = reply[3];
790 ps2esdi_info[0].wpcom = 0;
791 ps2esdi_info[0].lzone = reply[3];
792 } else {
793 if (!intg_esdi)
794 ps2esdi_drives++;
795 }
796 }
797#ifdef OBSOLETE
798 if (!ps2esdi_info[drive_num].head) {
799 ps2esdi_info[drive_num].head = reply[4] & 0Xff;
800 ps2esdi_info[drive_num].sect = reply[4] >> 8;
801 ps2esdi_info[drive_num].cyl = reply[3];
802 ps2esdi_info[drive_num].wpcom = 0;
803 ps2esdi_info[drive_num].lzone = reply[3];
804 if (tp720esdi) { /* store the retrieved parameters */
805 ps2esdi_info[0].head = reply[4] & 0Xff;
806 ps2esdi_info[0].sect = reply[4] >> 8;
807 ps2esdi_info[0].cyl = reply[3];
808 ps2esdi_info[0].wpcom = 0;
809 ps2esdi_info[0].lzone = reply[3];
810 } else {
811 ps2esdi_drives++;
812 }
813 }
814#endif
815
816 } else
817 printk("%s: failed while getting device config\n", DEVICE_NAME);
818#undef REPLY_WORDS
819 } else
820 printk("%s: command %02X unknown by geometry handler\n",
821 DEVICE_NAME, status & 0x1f);
822
823 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
824 break;
825
826 case INT_ATTN_ERROR:
827 printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME,
828 int_ret_code);
829 printk("%s: Device not available\n", DEVICE_NAME);
830 break;
831 case INT_CMD_ECC:
832 case INT_CMD_RETRY:
833 case INT_CMD_ECC_RETRY:
834 case INT_CMD_WARNING:
835 case INT_CMD_ABORT:
836 case INT_CMD_FAILED:
837 case INT_DMA_ERR:
838 case INT_CMD_BLK_ERR:
839 /*BA */ printk("%s: Whaa. Error occurred...\n", DEVICE_NAME);
840 dump_cmd_complete_status(int_ret_code);
841 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
842 break;
843 default:
844 printk("%s: Unknown interrupt reason: %02X\n",
845 DEVICE_NAME, int_ret_code & 0xf);
846 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
847 break;
848 }
849
850 wake_up(&ps2esdi_int);
851 no_int_yet = FALSE;
852 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
853
854}
855
856static void ps2esdi_normal_interrupt_handler(u_int int_ret_code)
857{
858 unsigned long flags;
859 u_int status;
860 u_int ending;
861 int i;
862
863 switch (int_ret_code & 0x0f) {
864 case INT_TRANSFER_REQ:
865 ps2esdi_prep_dma(current_req->buffer,
866 current_req->current_nr_sectors,
867 (rq_data_dir(current_req) == READ)
868 ? MCA_DMA_MODE_16 | MCA_DMA_MODE_WRITE | MCA_DMA_MODE_XFER
869 : MCA_DMA_MODE_16 | MCA_DMA_MODE_READ);
870 outb(CTRL_ENABLE_DMA | CTRL_ENABLE_INTR, ESDI_CONTROL);
871 ending = -1;
872 break;
873
874 case INT_ATTN_ERROR:
875 printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME,
876 int_ret_code);
877 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
878 ending = FAIL;
879 break;
880
881 case INT_CMD_COMPLETE:
882 for (i = ESDI_TIMEOUT; i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--);
883 if (!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) {
884 printk("%s: timeout reading status word\n", DEVICE_NAME);
885 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
886 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
887 if ((++current_req->errors) >= MAX_RETRIES)
888 ending = FAIL;
889 else
890 ending = -1;
891 break;
892 }
893 status = inw(ESDI_STT_INT);
894 switch (status & 0x1F) {
895 case (CMD_READ & 0xff):
896 case (CMD_WRITE & 0xff):
897 LITE_OFF;
898 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
899 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
900 ending = SUCCES;
901 break;
902 default:
903 printk("%s: interrupt for unknown command %02X\n",
904 DEVICE_NAME, status & 0x1f);
905 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
906 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
907 ending = -1;
908 break;
909 }
910 break;
911 case INT_CMD_ECC:
912 case INT_CMD_RETRY:
913 case INT_CMD_ECC_RETRY:
914 LITE_OFF;
915 dump_cmd_complete_status(int_ret_code);
916 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
917 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
918 ending = SUCCES;
919 break;
920 case INT_CMD_WARNING:
921 case INT_CMD_ABORT:
922 case INT_CMD_FAILED:
923 case INT_DMA_ERR:
924 LITE_OFF;
925 dump_cmd_complete_status(int_ret_code);
926 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
927 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
928 if ((++current_req->errors) >= MAX_RETRIES)
929 ending = FAIL;
930 else
931 ending = -1;
932 break;
933
934 case INT_CMD_BLK_ERR:
935 dump_cmd_complete_status(int_ret_code);
936 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
937 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
938 ending = FAIL;
939 break;
940
941 case INT_CMD_FORMAT:
942 printk("%s: huh ? Who issued this format command ?\n"
943 ,DEVICE_NAME);
944 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
945 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
946 ending = -1;
947 break;
948
949 case INT_RESET:
950 /* BA printk("%s: reset completed.\n", DEVICE_NAME) */ ;
951 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
952 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
953 ending = -1;
954 break;
955
956 default:
957 printk("%s: Unknown interrupt reason: %02X\n",
958 DEVICE_NAME, int_ret_code & 0xf);
959 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
960 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
961 ending = -1;
962 break;
963 }
964 if(ending != -1) {
965 spin_lock_irqsave(&ps2esdi_lock, flags);
966 end_request(current_req, ending);
967 current_req = NULL;
968 do_ps2esdi_request(ps2esdi_queue);
969 spin_unlock_irqrestore(&ps2esdi_lock, flags);
970 }
971} /* handle interrupts */
972
973
974
975static int ps2esdi_read_status_words(int num_words,
976 int max_words,
977 u_short * buffer)
978{
979 int i;
980
981 for (; max_words && num_words; max_words--, num_words--, buffer++) {
982 for (i = ESDI_TIMEOUT; i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--);
983 if (!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) {
984 printk("%s: timeout reading status word\n", DEVICE_NAME);
985 return FAIL;
986 }
987 *buffer = inw(ESDI_STT_INT);
988 }
989 return SUCCES;
990}
991
992
993
994
995static void dump_cmd_complete_status(u_int int_ret_code)
996{
997#define WAIT_FOR_STATUS \
998 for(i=ESDI_TIMEOUT;i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL);i--); \
999 if(!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) { \
1000 printk("%s: timeout reading status word\n",DEVICE_NAME); \
1001 return; \
1002 }
1003
1004 int i, word_count;
1005 u_short stat_word;
1006 u_long rba;
1007
1008 printk("%s: Device: %u, interrupt ID: %02X\n",
1009 DEVICE_NAME, int_ret_code >> 5,
1010 int_ret_code & 0xf);
1011
1012 WAIT_FOR_STATUS;
1013 stat_word = inw(ESDI_STT_INT);
1014 word_count = (stat_word >> 8) - 1;
1015 printk("%s: %u status words, command: %02X\n", DEVICE_NAME, word_count,
1016 stat_word & 0xff);
1017
1018 if (word_count--) {
1019 WAIT_FOR_STATUS;
1020 stat_word = inw(ESDI_STT_INT);
1021 printk("%s: command status code: %02X, command error code: %02X\n",
1022 DEVICE_NAME, stat_word >> 8, stat_word & 0xff);
1023 }
1024 if (word_count--) {
1025 WAIT_FOR_STATUS;
1026 stat_word = inw(ESDI_STT_INT);
1027 printk("%s: device error code: %s%s%s%s%s,%02X\n", DEVICE_NAME,
1028 (stat_word & 0x1000) ? "Ready, " : "Not Ready, ",
1029 (stat_word & 0x0800) ? "Selected, " : "Not Selected, ",
1030 (stat_word & 0x0400) ? "Write Fault, " : "",
1031 (stat_word & 0x0200) ? "Track 0, " : "",
1032 (stat_word & 0x0100) ? "Seek or command complete, " : "",
1033 stat_word >> 8);
1034 }
1035 if (word_count--) {
1036 WAIT_FOR_STATUS;
1037 stat_word = inw(ESDI_STT_INT);
1038 printk("%s: Blocks to do: %u", DEVICE_NAME, stat_word);
1039 }
1040 if (word_count -= 2) {
1041 WAIT_FOR_STATUS;
1042 rba = inw(ESDI_STT_INT);
1043 WAIT_FOR_STATUS;
1044 rba |= inw(ESDI_STT_INT) << 16;
1045 printk(", Last Cyl: %u Head: %u Sector: %u\n",
1046 (u_short) ((rba & 0x1ff80000) >> 11),
1047 (u_short) ((rba & 0x7E0) >> 5), (u_short) (rba & 0x1f));
1048 } else
1049 printk("\n");
1050
1051 if (word_count--) {
1052 WAIT_FOR_STATUS;
1053 stat_word = inw(ESDI_STT_INT);
1054 printk("%s: Blocks required ECC: %u", DEVICE_NAME, stat_word);
1055 }
1056 printk("\n");
1057
1058#undef WAIT_FOR_STATUS
1059
1060}
1061
1062static int ps2esdi_ioctl(struct inode *inode,
1063 struct file *file, u_int cmd, u_long arg)
1064{
1065 struct ps2esdi_i_struct *p = inode->i_bdev->bd_disk->private_data;
1066 struct ps2esdi_geometry geom;
1067
1068 if (cmd != HDIO_GETGEO)
1069 return -EINVAL;
1070 memset(&geom, 0, sizeof(geom));
1071 geom.heads = p->head;
1072 geom.sectors = p->sect;
1073 geom.cylinders = p->cyl;
1074 geom.start = get_start_sect(inode->i_bdev);
1075 if (copy_to_user((void __user *)arg, &geom, sizeof(geom)))
1076 return -EFAULT;
1077 return 0;
1078}
1079
1080static void ps2esdi_reset_timer(unsigned long unused)
1081{
1082
1083 int status;
1084
1085 status = inb(ESDI_INTRPT);
1086 if ((status & 0xf) == INT_RESET) {
1087 outb((status & 0xe0) | ATT_EOI, ESDI_ATTN);
1088 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
1089 reset_status = 1;
1090 }
1091 wake_up(&ps2esdi_int);
1092}