[PATCH] Add block_device_operations.getgeo block device method
[deliverable/linux.git] / drivers / block / ps2esdi.c
1 /* ps2esdi driver based on assembler code by Arindam Banerji,
2 written by Peter De Schrijver */
3 /* Reassuring note to IBM : This driver was NOT developed by vice-versa
4 engineering the PS/2's BIOS */
5 /* Dedicated to Wannes, Tofke, Ykke, Godot, Killroy and all those
6 other lovely fish out there... */
7 /* This code was written during the long and boring WINA
8 elections 1994 */
9 /* Thanks to Arindam Banerij for giving me the source of his driver */
10 /* This code may be freely distributed and modified in any way,
11 as long as these notes remain intact */
12
13 /* Revised: 05/07/94 by Arindam Banerji (axb@cse.nd.edu) */
14 /* Revised: 09/08/94 by Peter De Schrijver (stud11@cc4.kuleuven.ac.be)
15 Thanks to Arindam Banerij for sending me the docs of the adapter */
16
17 /* BA Modified for ThinkPad 720 by Boris Ashkinazi */
18 /* (bash@vnet.ibm.com) 08/08/95 */
19
20 /* Modified further for ThinkPad-720C by Uri Blumenthal */
21 /* (uri@watson.ibm.com) Sep 11, 1995 */
22
23 /* TODO :
24 + Timeouts
25 + Get disk parameters
26 + DMA above 16MB
27 + reset after read/write error
28 */
29
30 #define DEVICE_NAME "PS/2 ESDI"
31
32 #include <linux/config.h>
33 #include <linux/major.h>
34 #include <linux/errno.h>
35 #include <linux/wait.h>
36 #include <linux/interrupt.h>
37 #include <linux/fs.h>
38 #include <linux/kernel.h>
39 #include <linux/genhd.h>
40 #include <linux/ps2esdi.h>
41 #include <linux/blkdev.h>
42 #include <linux/mca-legacy.h>
43 #include <linux/init.h>
44 #include <linux/ioport.h>
45 #include <linux/module.h>
46
47 #include <asm/system.h>
48 #include <asm/io.h>
49 #include <asm/dma.h>
50 #include <asm/mca_dma.h>
51 #include <asm/uaccess.h>
52
53 #define PS2ESDI_IRQ 14
54 #define MAX_HD 2
55 #define MAX_RETRIES 5
56 #define MAX_16BIT 65536
57 #define ESDI_TIMEOUT 0xf000
58 #define ESDI_STAT_TIMEOUT 4
59
60 #define TYPE_0_CMD_BLK_LENGTH 2
61 #define TYPE_1_CMD_BLK_LENGTH 4
62
63 static void reset_ctrl(void);
64
65 static int ps2esdi_geninit(void);
66
67 static void do_ps2esdi_request(request_queue_t * q);
68
69 static void ps2esdi_readwrite(int cmd, struct request *req);
70
71 static void ps2esdi_fill_cmd_block(u_short * cmd_blk, u_short cmd,
72 u_short cyl, u_short head, u_short sector, u_short length, u_char drive);
73
74 static int ps2esdi_out_cmd_blk(u_short * cmd_blk);
75
76 static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode);
77
78 static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id,
79 struct pt_regs *regs);
80 static void (*current_int_handler) (u_int) = NULL;
81 static void ps2esdi_normal_interrupt_handler(u_int);
82 static void ps2esdi_initial_reset_int_handler(u_int);
83 static void ps2esdi_geometry_int_handler(u_int);
84 static int ps2esdi_getgeo(struct block_device *bdev, struct hd_geometry *geo);
85
86 static int ps2esdi_read_status_words(int num_words, int max_words, u_short * buffer);
87
88 static void dump_cmd_complete_status(u_int int_ret_code);
89
90 static void ps2esdi_get_device_cfg(void);
91
92 static void ps2esdi_reset_timer(unsigned long unused);
93
94 static u_int dma_arb_level; /* DMA arbitration level */
95
96 static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_int);
97
98 static int no_int_yet;
99 static int ps2esdi_drives;
100 static u_short io_base;
101 static DEFINE_TIMER(esdi_timer, ps2esdi_reset_timer, 0, 0);
102 static int reset_status;
103 static int ps2esdi_slot = -1;
104 static int tp720esdi = 0; /* Is it Integrated ESDI of ThinkPad-720? */
105 static int intg_esdi = 0; /* If integrated adapter */
106 struct ps2esdi_i_struct {
107 unsigned int head, sect, cyl, wpcom, lzone, ctl;
108 };
109 static DEFINE_SPINLOCK(ps2esdi_lock);
110 static struct request_queue *ps2esdi_queue;
111 static struct request *current_req;
112
113 #if 0
114 #if 0 /* try both - I don't know which one is better... UB */
115 static 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
120 static 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
126 static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] =
127 {
128 {0, 0, 0, 0, 0, 0},
129 {0, 0, 0, 0, 0, 0}};
130
131 static struct block_device_operations ps2esdi_fops =
132 {
133 .owner = THIS_MODULE,
134 .getgeo = ps2esdi_getgeo,
135 };
136
137 static struct gendisk *ps2esdi_gendisk[2];
138
139 /* initialization routine called by ll_rw_blk.c */
140 static 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
170 module_init(ps2esdi_init);
171
172 #else
173
174 static int cyl[MAX_HD] = {-1,-1};
175 static int head[MAX_HD] = {-1, -1};
176 static int sect[MAX_HD] = {-1, -1};
177
178 module_param(tp720esdi, bool, 0);
179 module_param_array(cyl, int, NULL, 0);
180 module_param_array(head, int, NULL, 0);
181 module_param_array(sect, int, NULL, 0);
182 MODULE_LICENSE("GPL");
183
184 int 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
203 void
204 cleanup_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 */
223 void __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
231 void __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
264 static 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 */
278 static 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,
343 SA_INTERRUPT | SA_SHIRQ, "PS/2 ESDI", &ps2esdi_gendisk)
344 && request_irq(PS2ESDI_IRQ, ps2esdi_interrupt_handler,
345 SA_SHIRQ, "PS/2 ESDI", &ps2esdi_gendisk)
346 ) {
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);
423 sprintf(disk->devfs_name, "ed/target%d", i);
424 disk->fops = &ps2esdi_fops;
425 ps2esdi_gendisk[i] = disk;
426 }
427
428 for (i = 0; i < ps2esdi_drives; i++) {
429 struct gendisk *disk = ps2esdi_gendisk[i];
430 set_capacity(disk, ps2esdi_info[i].head * ps2esdi_info[i].sect *
431 ps2esdi_info[i].cyl);
432 disk->queue = ps2esdi_queue;
433 disk->private_data = &ps2esdi_info[i];
434 add_disk(disk);
435 }
436 return 0;
437 err_out4:
438 while (i--)
439 put_disk(ps2esdi_gendisk[i]);
440 err_out3:
441 release_region(io_base, 4);
442 err_out2:
443 free_irq(PS2ESDI_IRQ, &ps2esdi_gendisk);
444 err_out1:
445 if(ps2esdi_slot) {
446 mca_mark_as_unused(ps2esdi_slot);
447 mca_set_adapter_procfn(ps2esdi_slot, NULL, NULL);
448 }
449 return error;
450 }
451
452 static void __init ps2esdi_get_device_cfg(void)
453 {
454 u_short cmd_blk[TYPE_0_CMD_BLK_LENGTH];
455
456 /*BA */ printk("%s: Drive 0\n", DEVICE_NAME);
457 current_int_handler = ps2esdi_geometry_int_handler;
458 cmd_blk[0] = CMD_GET_DEV_CONFIG | 0x600;
459 cmd_blk[1] = 0;
460 no_int_yet = TRUE;
461 ps2esdi_out_cmd_blk(cmd_blk);
462 if (no_int_yet)
463 sleep_on(&ps2esdi_int);
464
465 if (ps2esdi_drives > 1) {
466 printk("%s: Drive 1\n", DEVICE_NAME); /*BA */
467 cmd_blk[0] = CMD_GET_DEV_CONFIG | (1 << 5) | 0x600;
468 cmd_blk[1] = 0;
469 no_int_yet = TRUE;
470 ps2esdi_out_cmd_blk(cmd_blk);
471 if (no_int_yet)
472 sleep_on(&ps2esdi_int);
473 } /* if second physical drive is present */
474 return;
475 }
476
477 /* strategy routine that handles most of the IO requests */
478 static void do_ps2esdi_request(request_queue_t * q)
479 {
480 struct request *req;
481 /* since, this routine is called with interrupts cleared - they
482 must be before it finishes */
483
484 req = elv_next_request(q);
485 if (!req)
486 return;
487
488 #if 0
489 printk("%s:got request. device : %s command : %d sector : %ld count : %ld, buffer: %p\n",
490 DEVICE_NAME,
491 req->rq_disk->disk_name,
492 req->cmd, req->sector,
493 req->current_nr_sectors, req->buffer);
494 #endif
495
496 /* check for above 16Mb dmas */
497 if (isa_virt_to_bus(req->buffer + req->current_nr_sectors * 512) > 16 * MB) {
498 printk("%s: DMA above 16MB not supported\n", DEVICE_NAME);
499 end_request(req, FAIL);
500 return;
501 }
502
503 if (req->sector+req->current_nr_sectors > get_capacity(req->rq_disk)) {
504 printk("Grrr. error. ps2esdi_drives: %d, %llu %llu\n",
505 ps2esdi_drives, req->sector,
506 (unsigned long long)get_capacity(req->rq_disk));
507 end_request(req, FAIL);
508 return;
509 }
510
511 switch (rq_data_dir(req)) {
512 case READ:
513 ps2esdi_readwrite(READ, req);
514 break;
515 case WRITE:
516 ps2esdi_readwrite(WRITE, req);
517 break;
518 default:
519 printk("%s: Unknown command\n", req->rq_disk->disk_name);
520 end_request(req, FAIL);
521 break;
522 } /* handle different commands */
523 } /* main strategy routine */
524
525 /* resets the ESDI adapter */
526 static void reset_ctrl(void)
527 {
528
529 u_long expire;
530 u_short status;
531
532 /* enable interrupts on the controller */
533 status = inb(ESDI_INTRPT);
534 outb((status & 0xe0) | ATT_EOI, ESDI_ATTN); /* to be sure we don't have
535 any interrupt pending... */
536 outb_p(CTRL_ENABLE_INTR, ESDI_CONTROL);
537
538 /* read the ESDI status port - if the controller is not busy,
539 simply do a soft reset (fast) - otherwise we'll have to do a
540 hard (slow) reset. */
541 if (!(inb_p(ESDI_STATUS) & STATUS_BUSY)) {
542 /*BA */ printk("%s: soft reset...\n", DEVICE_NAME);
543 outb_p(CTRL_SOFT_RESET, ESDI_ATTN);
544 }
545 /* soft reset */
546 else {
547 /*BA */
548 printk("%s: hard reset...\n", DEVICE_NAME);
549 outb_p(CTRL_HARD_RESET, ESDI_CONTROL);
550 expire = jiffies + 2*HZ;
551 while (time_before(jiffies, expire));
552 outb_p(1, ESDI_CONTROL);
553 } /* hard reset */
554
555
556 } /* reset the controller */
557
558 /* called by the strategy routine to handle read and write requests */
559 static void ps2esdi_readwrite(int cmd, struct request *req)
560 {
561 struct ps2esdi_i_struct *p = req->rq_disk->private_data;
562 unsigned block = req->sector;
563 unsigned count = req->current_nr_sectors;
564 int drive = p - ps2esdi_info;
565 u_short track, head, cylinder, sector;
566 u_short cmd_blk[TYPE_1_CMD_BLK_LENGTH];
567
568 /* do some relevant arithmatic */
569 track = block / p->sect;
570 head = track % p->head;
571 cylinder = track / p->head;
572 sector = block % p->sect;
573
574 #if 0
575 printk("%s: cyl=%d head=%d sect=%d\n", DEVICE_NAME, cylinder, head, sector);
576 #endif
577 /* call the routine that actually fills out a command block */
578 ps2esdi_fill_cmd_block
579 (cmd_blk,
580 (cmd == READ) ? CMD_READ : CMD_WRITE,
581 cylinder, head, sector, count, drive);
582
583 /* send the command block to the controller */
584 current_req = req;
585 spin_unlock_irq(&ps2esdi_lock);
586 if (ps2esdi_out_cmd_blk(cmd_blk)) {
587 spin_lock_irq(&ps2esdi_lock);
588 printk("%s: Controller failed\n", DEVICE_NAME);
589 if ((++req->errors) >= MAX_RETRIES)
590 end_request(req, FAIL);
591 }
592 /* check for failure to put out the command block */
593 else {
594 spin_lock_irq(&ps2esdi_lock);
595 #if 0
596 printk("%s: waiting for xfer\n", DEVICE_NAME);
597 #endif
598 /* turn disk lights on */
599 LITE_ON;
600 }
601
602 } /* ps2esdi_readwrite */
603
604 /* fill out the command block */
605 static void ps2esdi_fill_cmd_block(u_short * cmd_blk, u_short cmd,
606 u_short cyl, u_short head, u_short sector, u_short length, u_char drive)
607 {
608
609 cmd_blk[0] = (drive << 5) | cmd;
610 cmd_blk[1] = length;
611 cmd_blk[2] = ((cyl & 0x1f) << 11) | (head << 5) | sector;
612 cmd_blk[3] = (cyl & 0x3E0) >> 5;
613
614 } /* fill out the command block */
615
616 /* write a command block to the controller */
617 static int ps2esdi_out_cmd_blk(u_short * cmd_blk)
618 {
619
620 int i;
621 unsigned long jif;
622 u_char status;
623
624 /* enable interrupts */
625 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
626
627 /* do not write to the controller, if it is busy */
628 for (jif = jiffies + ESDI_STAT_TIMEOUT;
629 time_after(jif, jiffies) &&
630 (inb(ESDI_STATUS) & STATUS_BUSY); )
631 ;
632
633 #if 0
634 printk("%s: i(1)=%ld\n", DEVICE_NAME, jif);
635 #endif
636
637 /* if device is still busy - then just time out */
638 if (inb(ESDI_STATUS) & STATUS_BUSY) {
639 printk("%s: ps2esdi_out_cmd timed out (1)\n", DEVICE_NAME);
640 return ERROR;
641 } /* timeout ??? */
642 /* Set up the attention register in the controller */
643 outb(((*cmd_blk) & 0xE0) | 1, ESDI_ATTN);
644
645 #if 0
646 printk("%s: sending %d words to controller\n", DEVICE_NAME, (((*cmd_blk) >> 14) + 1) << 1);
647 #endif
648
649 /* one by one send each word out */
650 for (i = (((*cmd_blk) >> 14) + 1) << 1; i; i--) {
651 status = inb(ESDI_STATUS);
652 for (jif = jiffies + ESDI_STAT_TIMEOUT;
653 time_after(jif, jiffies) && (status & STATUS_BUSY) &&
654 (status & STATUS_CMD_INF); status = inb(ESDI_STATUS));
655 if ((status & (STATUS_BUSY | STATUS_CMD_INF)) == STATUS_BUSY) {
656 #if 0
657 printk("%s: sending %04X\n", DEVICE_NAME, *cmd_blk);
658 #endif
659 outw(*cmd_blk++, ESDI_CMD_INT);
660 } else {
661 printk("%s: ps2esdi_out_cmd timed out while sending command (status=%02X)\n",
662 DEVICE_NAME, status);
663 return ERROR;
664 }
665 } /* send all words out */
666 return OK;
667 } /* send out the commands */
668
669
670 /* prepare for dma - do all the necessary setup */
671 static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode)
672 {
673 unsigned long flags = claim_dma_lock();
674
675 mca_disable_dma(dma_arb_level);
676
677 mca_set_dma_addr(dma_arb_level, isa_virt_to_bus(buffer));
678
679 mca_set_dma_count(dma_arb_level, length * 512 / 2);
680
681 mca_set_dma_mode(dma_arb_level, dma_xmode);
682
683 mca_enable_dma(dma_arb_level);
684
685 release_dma_lock(flags);
686
687 } /* prepare for dma */
688
689
690
691 static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id,
692 struct pt_regs *regs)
693 {
694 u_int int_ret_code;
695
696 if (inb(ESDI_STATUS) & STATUS_INTR) {
697 int_ret_code = inb(ESDI_INTRPT);
698 if (current_int_handler) {
699 /* Disable adapter interrupts till processing is finished */
700 outb(CTRL_DISABLE_INTR, ESDI_CONTROL);
701 current_int_handler(int_ret_code);
702 } else
703 printk("%s: help ! No interrupt handler.\n", DEVICE_NAME);
704 } else {
705 return IRQ_NONE;
706 }
707 return IRQ_HANDLED;
708 }
709
710 static void ps2esdi_initial_reset_int_handler(u_int int_ret_code)
711 {
712
713 switch (int_ret_code & 0xf) {
714 case INT_RESET:
715 /*BA */
716 printk("%s: initial reset completed.\n", DEVICE_NAME);
717 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
718 wake_up(&ps2esdi_int);
719 break;
720 case INT_ATTN_ERROR:
721 printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME,
722 int_ret_code);
723 printk("%s: status: %02x\n", DEVICE_NAME, inb(ESDI_STATUS));
724 break;
725 default:
726 printk("%s: initial reset handler received interrupt: %02X\n",
727 DEVICE_NAME, int_ret_code);
728 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
729 break;
730 }
731 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
732 }
733
734
735 static void ps2esdi_geometry_int_handler(u_int int_ret_code)
736 {
737 u_int status, drive_num;
738 unsigned long rba;
739 int i;
740
741 drive_num = int_ret_code >> 5;
742 switch (int_ret_code & 0xf) {
743 case INT_CMD_COMPLETE:
744 for (i = ESDI_TIMEOUT; i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--);
745 if (!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) {
746 printk("%s: timeout reading status word\n", DEVICE_NAME);
747 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
748 break;
749 }
750 status = inw(ESDI_STT_INT);
751 if ((status & 0x1F) == CMD_GET_DEV_CONFIG) {
752 #define REPLY_WORDS 5 /* we already read word 0 */
753 u_short reply[REPLY_WORDS];
754
755 if (ps2esdi_read_status_words((status >> 8) - 1, REPLY_WORDS, reply)) {
756 /*BA */
757 printk("%s: Device Configuration Status for drive %u\n",
758 DEVICE_NAME, drive_num);
759
760 printk("%s: Spares/cyls: %u", DEVICE_NAME, reply[0] >> 8);
761
762 printk
763 ("Config bits: %s%s%s%s%s\n",
764 (reply[0] & CONFIG_IS) ? "Invalid Secondary, " : "",
765 ((reply[0] & CONFIG_ZD) && !(reply[0] & CONFIG_IS))
766 ? "Zero Defect, " : "Defects Present, ",
767 (reply[0] & CONFIG_SF) ? "Skewed Format, " : "",
768 (reply[0] & CONFIG_FR) ? "Removable, " : "Non-Removable, ",
769 (reply[0] & CONFIG_RT) ? "No Retries" : "Retries");
770
771 rba = reply[1] | ((unsigned long) reply[2] << 16);
772 printk("%s: Number of RBA's: %lu\n", DEVICE_NAME, rba);
773
774 printk("%s: Physical number of cylinders: %u, Sectors/Track: %u, Heads: %u\n",
775 DEVICE_NAME, reply[3], reply[4] >> 8, reply[4] & 0xff);
776
777 if (!ps2esdi_info[drive_num].head) {
778 ps2esdi_info[drive_num].head = 64;
779 ps2esdi_info[drive_num].sect = 32;
780 ps2esdi_info[drive_num].cyl = rba / (64 * 32);
781 ps2esdi_info[drive_num].wpcom = 0;
782 ps2esdi_info[drive_num].lzone = ps2esdi_info[drive_num].cyl;
783 ps2esdi_info[drive_num].ctl = 8;
784 if (tp720esdi) { /* store the retrieved parameters */
785 ps2esdi_info[0].head = reply[4] & 0Xff;
786 ps2esdi_info[0].sect = reply[4] >> 8;
787 ps2esdi_info[0].cyl = reply[3];
788 ps2esdi_info[0].wpcom = 0;
789 ps2esdi_info[0].lzone = reply[3];
790 } else {
791 if (!intg_esdi)
792 ps2esdi_drives++;
793 }
794 }
795 #ifdef OBSOLETE
796 if (!ps2esdi_info[drive_num].head) {
797 ps2esdi_info[drive_num].head = reply[4] & 0Xff;
798 ps2esdi_info[drive_num].sect = reply[4] >> 8;
799 ps2esdi_info[drive_num].cyl = reply[3];
800 ps2esdi_info[drive_num].wpcom = 0;
801 ps2esdi_info[drive_num].lzone = reply[3];
802 if (tp720esdi) { /* store the retrieved parameters */
803 ps2esdi_info[0].head = reply[4] & 0Xff;
804 ps2esdi_info[0].sect = reply[4] >> 8;
805 ps2esdi_info[0].cyl = reply[3];
806 ps2esdi_info[0].wpcom = 0;
807 ps2esdi_info[0].lzone = reply[3];
808 } else {
809 ps2esdi_drives++;
810 }
811 }
812 #endif
813
814 } else
815 printk("%s: failed while getting device config\n", DEVICE_NAME);
816 #undef REPLY_WORDS
817 } else
818 printk("%s: command %02X unknown by geometry handler\n",
819 DEVICE_NAME, status & 0x1f);
820
821 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
822 break;
823
824 case INT_ATTN_ERROR:
825 printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME,
826 int_ret_code);
827 printk("%s: Device not available\n", DEVICE_NAME);
828 break;
829 case INT_CMD_ECC:
830 case INT_CMD_RETRY:
831 case INT_CMD_ECC_RETRY:
832 case INT_CMD_WARNING:
833 case INT_CMD_ABORT:
834 case INT_CMD_FAILED:
835 case INT_DMA_ERR:
836 case INT_CMD_BLK_ERR:
837 /*BA */ printk("%s: Whaa. Error occurred...\n", DEVICE_NAME);
838 dump_cmd_complete_status(int_ret_code);
839 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
840 break;
841 default:
842 printk("%s: Unknown interrupt reason: %02X\n",
843 DEVICE_NAME, int_ret_code & 0xf);
844 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
845 break;
846 }
847
848 wake_up(&ps2esdi_int);
849 no_int_yet = FALSE;
850 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
851
852 }
853
854 static void ps2esdi_normal_interrupt_handler(u_int int_ret_code)
855 {
856 unsigned long flags;
857 u_int status;
858 u_int ending;
859 int i;
860
861 switch (int_ret_code & 0x0f) {
862 case INT_TRANSFER_REQ:
863 ps2esdi_prep_dma(current_req->buffer,
864 current_req->current_nr_sectors,
865 (rq_data_dir(current_req) == READ)
866 ? MCA_DMA_MODE_16 | MCA_DMA_MODE_WRITE | MCA_DMA_MODE_XFER
867 : MCA_DMA_MODE_16 | MCA_DMA_MODE_READ);
868 outb(CTRL_ENABLE_DMA | CTRL_ENABLE_INTR, ESDI_CONTROL);
869 ending = -1;
870 break;
871
872 case INT_ATTN_ERROR:
873 printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME,
874 int_ret_code);
875 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
876 ending = FAIL;
877 break;
878
879 case INT_CMD_COMPLETE:
880 for (i = ESDI_TIMEOUT; i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--);
881 if (!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) {
882 printk("%s: timeout reading status word\n", DEVICE_NAME);
883 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
884 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
885 if ((++current_req->errors) >= MAX_RETRIES)
886 ending = FAIL;
887 else
888 ending = -1;
889 break;
890 }
891 status = inw(ESDI_STT_INT);
892 switch (status & 0x1F) {
893 case (CMD_READ & 0xff):
894 case (CMD_WRITE & 0xff):
895 LITE_OFF;
896 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
897 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
898 ending = SUCCES;
899 break;
900 default:
901 printk("%s: interrupt for unknown command %02X\n",
902 DEVICE_NAME, status & 0x1f);
903 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
904 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
905 ending = -1;
906 break;
907 }
908 break;
909 case INT_CMD_ECC:
910 case INT_CMD_RETRY:
911 case INT_CMD_ECC_RETRY:
912 LITE_OFF;
913 dump_cmd_complete_status(int_ret_code);
914 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
915 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
916 ending = SUCCES;
917 break;
918 case INT_CMD_WARNING:
919 case INT_CMD_ABORT:
920 case INT_CMD_FAILED:
921 case INT_DMA_ERR:
922 LITE_OFF;
923 dump_cmd_complete_status(int_ret_code);
924 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
925 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
926 if ((++current_req->errors) >= MAX_RETRIES)
927 ending = FAIL;
928 else
929 ending = -1;
930 break;
931
932 case INT_CMD_BLK_ERR:
933 dump_cmd_complete_status(int_ret_code);
934 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
935 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
936 ending = FAIL;
937 break;
938
939 case INT_CMD_FORMAT:
940 printk("%s: huh ? Who issued this format command ?\n"
941 ,DEVICE_NAME);
942 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
943 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
944 ending = -1;
945 break;
946
947 case INT_RESET:
948 /* BA printk("%s: reset completed.\n", DEVICE_NAME) */ ;
949 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
950 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
951 ending = -1;
952 break;
953
954 default:
955 printk("%s: Unknown interrupt reason: %02X\n",
956 DEVICE_NAME, int_ret_code & 0xf);
957 outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);
958 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
959 ending = -1;
960 break;
961 }
962 if(ending != -1) {
963 spin_lock_irqsave(&ps2esdi_lock, flags);
964 end_request(current_req, ending);
965 current_req = NULL;
966 do_ps2esdi_request(ps2esdi_queue);
967 spin_unlock_irqrestore(&ps2esdi_lock, flags);
968 }
969 } /* handle interrupts */
970
971
972
973 static int ps2esdi_read_status_words(int num_words,
974 int max_words,
975 u_short * buffer)
976 {
977 int i;
978
979 for (; max_words && num_words; max_words--, num_words--, buffer++) {
980 for (i = ESDI_TIMEOUT; i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--);
981 if (!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) {
982 printk("%s: timeout reading status word\n", DEVICE_NAME);
983 return FAIL;
984 }
985 *buffer = inw(ESDI_STT_INT);
986 }
987 return SUCCES;
988 }
989
990
991
992
993 static void dump_cmd_complete_status(u_int int_ret_code)
994 {
995 #define WAIT_FOR_STATUS \
996 for(i=ESDI_TIMEOUT;i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL);i--); \
997 if(!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) { \
998 printk("%s: timeout reading status word\n",DEVICE_NAME); \
999 return; \
1000 }
1001
1002 int i, word_count;
1003 u_short stat_word;
1004 u_long rba;
1005
1006 printk("%s: Device: %u, interrupt ID: %02X\n",
1007 DEVICE_NAME, int_ret_code >> 5,
1008 int_ret_code & 0xf);
1009
1010 WAIT_FOR_STATUS;
1011 stat_word = inw(ESDI_STT_INT);
1012 word_count = (stat_word >> 8) - 1;
1013 printk("%s: %u status words, command: %02X\n", DEVICE_NAME, word_count,
1014 stat_word & 0xff);
1015
1016 if (word_count--) {
1017 WAIT_FOR_STATUS;
1018 stat_word = inw(ESDI_STT_INT);
1019 printk("%s: command status code: %02X, command error code: %02X\n",
1020 DEVICE_NAME, stat_word >> 8, stat_word & 0xff);
1021 }
1022 if (word_count--) {
1023 WAIT_FOR_STATUS;
1024 stat_word = inw(ESDI_STT_INT);
1025 printk("%s: device error code: %s%s%s%s%s,%02X\n", DEVICE_NAME,
1026 (stat_word & 0x1000) ? "Ready, " : "Not Ready, ",
1027 (stat_word & 0x0800) ? "Selected, " : "Not Selected, ",
1028 (stat_word & 0x0400) ? "Write Fault, " : "",
1029 (stat_word & 0x0200) ? "Track 0, " : "",
1030 (stat_word & 0x0100) ? "Seek or command complete, " : "",
1031 stat_word >> 8);
1032 }
1033 if (word_count--) {
1034 WAIT_FOR_STATUS;
1035 stat_word = inw(ESDI_STT_INT);
1036 printk("%s: Blocks to do: %u", DEVICE_NAME, stat_word);
1037 }
1038 if (word_count -= 2) {
1039 WAIT_FOR_STATUS;
1040 rba = inw(ESDI_STT_INT);
1041 WAIT_FOR_STATUS;
1042 rba |= inw(ESDI_STT_INT) << 16;
1043 printk(", Last Cyl: %u Head: %u Sector: %u\n",
1044 (u_short) ((rba & 0x1ff80000) >> 11),
1045 (u_short) ((rba & 0x7E0) >> 5), (u_short) (rba & 0x1f));
1046 } else
1047 printk("\n");
1048
1049 if (word_count--) {
1050 WAIT_FOR_STATUS;
1051 stat_word = inw(ESDI_STT_INT);
1052 printk("%s: Blocks required ECC: %u", DEVICE_NAME, stat_word);
1053 }
1054 printk("\n");
1055
1056 #undef WAIT_FOR_STATUS
1057
1058 }
1059
1060 static int ps2esdi_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1061 {
1062 struct ps2esdi_i_struct *p = bdev->bd_disk->private_data;
1063
1064 geo->heads = p->head;
1065 geo->sectors = p->sect;
1066 geo->cylinders = p->cyl;
1067 return 0;
1068 }
1069
1070 static void ps2esdi_reset_timer(unsigned long unused)
1071 {
1072
1073 int status;
1074
1075 status = inb(ESDI_INTRPT);
1076 if ((status & 0xf) == INT_RESET) {
1077 outb((status & 0xe0) | ATT_EOI, ESDI_ATTN);
1078 outb(CTRL_ENABLE_INTR, ESDI_CONTROL);
1079 reset_status = 1;
1080 }
1081 wake_up(&ps2esdi_int);
1082 }
This page took 0.067839 seconds and 5 git commands to generate.