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