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