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