1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36#include <linux/module.h>
37#include <linux/errno.h>
38#include <linux/interrupt.h>
39#include <linux/mm.h>
40#include <linux/fs.h>
41#include <linux/kernel.h>
42#include <linux/timer.h>
43#include <linux/genhd.h>
44#include <linux/hdreg.h>
45#include <linux/ioport.h>
46#include <linux/init.h>
47#include <linux/wait.h>
48#include <linux/blkdev.h>
49#include <linux/blkpg.h>
50#include <linux/delay.h>
51#include <linux/io.h>
52
53#include <asm/system.h>
54#include <asm/uaccess.h>
55#include <asm/dma.h>
56
57#include "xd.h"
58
59static void __init do_xd_setup (int *integers);
60#ifdef MODULE
61static int xd[5] = { -1,-1,-1,-1, };
62#endif
63
64#define XD_DONT_USE_DMA 0
65
66#define XD_INIT_DISK_DELAY (30)
67
68
69
70
71static XD_INFO xd_info[XD_MAXDRIVES];
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97#include <asm/page.h>
98#define xd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,get_order(size))
99#define xd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
100static char *xd_dma_buffer;
101
102static XD_SIGNATURE xd_sigs[] __initdata = {
103 { 0x0000,"Override geometry handler",NULL,xd_override_init_drive,"n unknown" },
104 { 0x0008,"[BXD06 (C) DTC 17-MAY-1985]",xd_dtc_init_controller,xd_dtc5150cx_init_drive," DTC 5150CX" },
105 { 0x000B,"CRD18A Not an IBM rom. (C) Copyright Data Technology Corp. 05/31/88",xd_dtc_init_controller,xd_dtc_init_drive," DTC 5150X" },
106 { 0x000B,"CXD23A Not an IBM ROM (C)Copyright Data Technology Corp 12/03/88",xd_dtc_init_controller,xd_dtc_init_drive," DTC 5150X" },
107 { 0x0008,"07/15/86(C) Copyright 1986 Western Digital Corp.",xd_wd_init_controller,xd_wd_init_drive," Western Dig. 1002-27X" },
108 { 0x0008,"06/24/88(C) Copyright 1988 Western Digital Corp.",xd_wd_init_controller,xd_wd_init_drive," Western Dig. WDXT-GEN2" },
109 { 0x0015,"SEAGATE ST11 BIOS REVISION",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" },
110 { 0x0010,"ST11R BIOS",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" },
111 { 0x0010,"ST11 BIOS v1.7",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11R" },
112 { 0x1000,"(c)Copyright 1987 SMS",xd_omti_init_controller,xd_omti_init_drive,"n OMTI 5520" },
113 { 0x0006,"COPYRIGHT XEBEC (C) 1984",xd_xebec_init_controller,xd_xebec_init_drive," XEBEC" },
114 { 0x0008,"(C) Copyright 1984 Western Digital Corp", xd_wd_init_controller, xd_wd_init_drive," Western Dig. 1002s-wx2" },
115 { 0x0008,"(C) Copyright 1986 Western Digital Corporation", xd_wd_init_controller, xd_wd_init_drive," 1986 Western Digital" },
116};
117
118static unsigned int xd_bases[] __initdata =
119{
120 0xC8000, 0xCA000, 0xCC000,
121 0xCE000, 0xD0000, 0xD2000,
122 0xD4000, 0xD6000, 0xD8000,
123 0xDA000, 0xDC000, 0xDE000,
124 0xE0000
125};
126
127static DEFINE_SPINLOCK(xd_lock);
128
129static struct gendisk *xd_gendisk[2];
130
131static int xd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
132
133static struct block_device_operations xd_fops = {
134 .owner = THIS_MODULE,
135 .ioctl = xd_ioctl,
136 .getgeo = xd_getgeo,
137};
138static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int);
139static u_char xd_drives, xd_irq = 5, xd_dma = 3, xd_maxsectors;
140static u_char xd_override __initdata = 0, xd_type __initdata = 0;
141static u_short xd_iobase = 0x320;
142static int xd_geo[XD_MAXDRIVES*3] __initdata = { 0, };
143
144static volatile int xdc_busy;
145static struct timer_list xd_watchdog_int;
146
147static volatile u_char xd_error;
148static int nodma = XD_DONT_USE_DMA;
149
150static struct request_queue *xd_queue;
151
152
153static int __init xd_init(void)
154{
155 u_char i,controller;
156 unsigned int address;
157 int err;
158
159#ifdef MODULE
160 {
161 u_char count = 0;
162 for (i = 4; i > 0; i--)
163 if (((xd[i] = xd[i-1]) >= 0) && !count)
164 count = i;
165 if ((xd[0] = count))
166 do_xd_setup(xd);
167 }
168#endif
169
170 init_timer (&xd_watchdog_int); xd_watchdog_int.function = xd_watchdog;
171
172 if (!xd_dma_buffer)
173 xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
174 if (!xd_dma_buffer) {
175 printk(KERN_ERR "xd: Out of memory.\n");
176 return -ENOMEM;
177 }
178
179 err = -EBUSY;
180 if (register_blkdev(XT_DISK_MAJOR, "xd"))
181 goto out1;
182
183 err = -ENOMEM;
184 xd_queue = blk_init_queue(do_xd_request, &xd_lock);
185 if (!xd_queue)
186 goto out1a;
187
188 if (xd_detect(&controller,&address)) {
189
190 printk("Detected a%s controller (type %d) at address %06x\n",
191 xd_sigs[controller].name,controller,address);
192 if (!request_region(xd_iobase,4,"xd")) {
193 printk("xd: Ports at 0x%x are not available\n",
194 xd_iobase);
195 goto out2;
196 }
197 if (controller)
198 xd_sigs[controller].init_controller(address);
199 xd_drives = xd_initdrives(xd_sigs[controller].init_drive);
200
201 printk("Detected %d hard drive%s (using IRQ%d & DMA%d)\n",
202 xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma);
203 }
204
205 err = -ENODEV;
206 if (!xd_drives)
207 goto out3;
208
209 for (i = 0; i < xd_drives; i++) {
210 XD_INFO *p = &xd_info[i];
211 struct gendisk *disk = alloc_disk(64);
212 if (!disk)
213 goto Enomem;
214 p->unit = i;
215 disk->major = XT_DISK_MAJOR;
216 disk->first_minor = i<<6;
217 sprintf(disk->disk_name, "xd%c", i+'a');
218 disk->fops = &xd_fops;
219 disk->private_data = p;
220 disk->queue = xd_queue;
221 set_capacity(disk, p->heads * p->cylinders * p->sectors);
222 printk(" %s: CHS=%d/%d/%d\n", disk->disk_name,
223 p->cylinders, p->heads, p->sectors);
224 xd_gendisk[i] = disk;
225 }
226
227 err = -EBUSY;
228 if (request_irq(xd_irq,xd_interrupt_handler, 0, "XT hard disk", NULL)) {
229 printk("xd: unable to get IRQ%d\n",xd_irq);
230 goto out4;
231 }
232
233 if (request_dma(xd_dma,"xd")) {
234 printk("xd: unable to get DMA%d\n",xd_dma);
235 goto out5;
236 }
237
238
239 blk_queue_max_sectors(xd_queue, xd_maxsectors);
240
241 for (i = 0; i < xd_drives; i++)
242 add_disk(xd_gendisk[i]);
243
244 return 0;
245
246out5:
247 free_irq(xd_irq, NULL);
248out4:
249 for (i = 0; i < xd_drives; i++)
250 put_disk(xd_gendisk[i]);
251out3:
252 release_region(xd_iobase,4);
253out2:
254 blk_cleanup_queue(xd_queue);
255out1a:
256 unregister_blkdev(XT_DISK_MAJOR, "xd");
257out1:
258 if (xd_dma_buffer)
259 xd_dma_mem_free((unsigned long)xd_dma_buffer,
260 xd_maxsectors * 0x200);
261 return err;
262Enomem:
263 err = -ENOMEM;
264 while (i--)
265 put_disk(xd_gendisk[i]);
266 goto out3;
267}
268
269
270static u_char __init xd_detect (u_char *controller, unsigned int *address)
271{
272 int i, j;
273
274 if (xd_override)
275 {
276 *controller = xd_type;
277 *address = 0;
278 return(1);
279 }
280
281 for (i = 0; i < ARRAY_SIZE(xd_bases); i++) {
282 void __iomem *p = ioremap(xd_bases[i], 0x2000);
283 if (!p)
284 continue;
285 for (j = 1; j < ARRAY_SIZE(xd_sigs); j++) {
286 const char *s = xd_sigs[j].string;
287 if (check_signature(p + xd_sigs[j].offset, s, strlen(s))) {
288 *controller = j;
289 xd_type = j;
290 *address = xd_bases[i];
291 iounmap(p);
292 return 1;
293 }
294 }
295 iounmap(p);
296 }
297 return 0;
298}
299
300
301static void do_xd_request (struct request_queue * q)
302{
303 struct request *req;
304
305 if (xdc_busy)
306 return;
307
308 while ((req = elv_next_request(q)) != NULL) {
309 unsigned block = req->sector;
310 unsigned count = req->nr_sectors;
311 int rw = rq_data_dir(req);
312 XD_INFO *disk = req->rq_disk->private_data;
313 int res = 0;
314 int retry;
315
316 if (!blk_fs_request(req)) {
317 end_request(req, 0);
318 continue;
319 }
320 if (block + count > get_capacity(req->rq_disk)) {
321 end_request(req, 0);
322 continue;
323 }
324 if (rw != READ && rw != WRITE) {
325 printk("do_xd_request: unknown request\n");
326 end_request(req, 0);
327 continue;
328 }
329 for (retry = 0; (retry < XD_RETRIES) && !res; retry++)
330 res = xd_readwrite(rw, disk, req->buffer, block, count);
331 end_request(req, res);
332 }
333}
334
335static int xd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
336{
337 XD_INFO *p = bdev->bd_disk->private_data;
338
339 geo->heads = p->heads;
340 geo->sectors = p->sectors;
341 geo->cylinders = p->cylinders;
342 return 0;
343}
344
345
346static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
347{
348 switch (cmd) {
349 case HDIO_SET_DMA:
350 if (!capable(CAP_SYS_ADMIN)) return -EACCES;
351 if (xdc_busy) return -EBUSY;
352 nodma = !arg;
353 if (nodma && xd_dma_buffer) {
354 xd_dma_mem_free((unsigned long)xd_dma_buffer,
355 xd_maxsectors * 0x200);
356 xd_dma_buffer = NULL;
357 } else if (!nodma && !xd_dma_buffer) {
358 xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
359 if (!xd_dma_buffer) {
360 nodma = XD_DONT_USE_DMA;
361 return -ENOMEM;
362 }
363 }
364 return 0;
365 case HDIO_GET_DMA:
366 return put_user(!nodma, (long __user *) arg);
367 case HDIO_GET_MULTCOUNT:
368 return put_user(xd_maxsectors, (long __user *) arg);
369 default:
370 return -EINVAL;
371 }
372}
373
374
375static int xd_readwrite (u_char operation,XD_INFO *p,char *buffer,u_int block,u_int count)
376{
377 int drive = p->unit;
378 u_char cmdblk[6],sense[4];
379 u_short track,cylinder;
380 u_char head,sector,control,mode = PIO_MODE,temp;
381 char **real_buffer;
382 register int i;
383
384#ifdef DEBUG_READWRITE
385 printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
386#endif
387
388 spin_unlock_irq(&xd_lock);
389
390 control = p->control;
391 if (!xd_dma_buffer)
392 xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
393 while (count) {
394 temp = count < xd_maxsectors ? count : xd_maxsectors;
395
396 track = block / p->sectors;
397 head = track % p->heads;
398 cylinder = track / p->heads;
399 sector = block % p->sectors;
400
401#ifdef DEBUG_READWRITE
402 printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
403#endif
404
405 if (xd_dma_buffer) {
406 mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)(xd_dma_buffer),temp * 0x200);
407 real_buffer = &xd_dma_buffer;
408 for (i=0; i < (temp * 0x200); i++)
409 xd_dma_buffer[i] = buffer[i];
410 }
411 else
412 real_buffer = &buffer;
413
414 xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control);
415
416 switch (xd_command(cmdblk,mode,(u_char *)(*real_buffer),(u_char *)(*real_buffer),sense,XD_TIMEOUT)) {
417 case 1:
418 printk("xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write"));
419 xd_recalibrate(drive);
420 spin_lock_irq(&xd_lock);
421 return (0);
422 case 2:
423 if (sense[0] & 0x30) {
424 printk("xd%c: %s - ",'a'+drive,(operation == READ ? "reading" : "writing"));
425 switch ((sense[0] & 0x30) >> 4) {
426 case 0: printk("drive error, code = 0x%X",sense[0] & 0x0F);
427 break;
428 case 1: printk("controller error, code = 0x%X",sense[0] & 0x0F);
429 break;
430 case 2: printk("command error, code = 0x%X",sense[0] & 0x0F);
431 break;
432 case 3: printk("miscellaneous error, code = 0x%X",sense[0] & 0x0F);
433 break;
434 }
435 }
436 if (sense[0] & 0x80)
437 printk(" - CHS = %d/%d/%d\n",((sense[2] & 0xC0) << 2) | sense[3],sense[1] & 0x1F,sense[2] & 0x3F);
438
439 else
440 printk(" - no valid disk address\n");
441 spin_lock_irq(&xd_lock);
442 return (0);
443 }
444 if (xd_dma_buffer)
445 for (i=0; i < (temp * 0x200); i++)
446 buffer[i] = xd_dma_buffer[i];
447
448 count -= temp, buffer += temp * 0x200, block += temp;
449 }
450 spin_lock_irq(&xd_lock);
451 return (1);
452}
453
454
455static void xd_recalibrate (u_char drive)
456{
457 u_char cmdblk[6];
458
459 xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0);
460 if (xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 8))
461 printk("xd%c: warning! error recalibrating, controller may be unstable\n", 'a'+drive);
462}
463
464
465static irqreturn_t xd_interrupt_handler(int irq, void *dev_id)
466{
467 if (inb(XD_STATUS) & STAT_INTERRUPT) {
468#ifdef DEBUG_OTHER
469 printk("xd_interrupt_handler: interrupt detected\n");
470#endif
471 outb(0,XD_CONTROL);
472 wake_up(&xd_wait_int);
473 return IRQ_HANDLED;
474 }
475 else
476 printk("xd: unexpected interrupt\n");
477 return IRQ_NONE;
478}
479
480
481static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
482{
483 unsigned long f;
484
485 if (nodma)
486 return (PIO_MODE);
487 if (((unsigned long) buffer & 0xFFFF0000) != (((unsigned long) buffer + count) & 0xFFFF0000)) {
488#ifdef DEBUG_OTHER
489 printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
490#endif
491 return (PIO_MODE);
492 }
493
494 f=claim_dma_lock();
495 disable_dma(xd_dma);
496 clear_dma_ff(xd_dma);
497 set_dma_mode(xd_dma,mode);
498 set_dma_addr(xd_dma, (unsigned long) buffer);
499 set_dma_count(xd_dma,count);
500
501 release_dma_lock(f);
502
503 return (DMA_MODE);
504}
505
506
507static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control)
508{
509 cmdblk[0] = command;
510 cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F);
511 cmdblk[2] = ((cylinder & 0x300) >> 2) | (sector & 0x3F);
512 cmdblk[3] = cylinder & 0xFF;
513 cmdblk[4] = count;
514 cmdblk[5] = control;
515
516 return (cmdblk);
517}
518
519static void xd_watchdog (unsigned long unused)
520{
521 xd_error = 1;
522 wake_up(&xd_wait_int);
523}
524
525
526static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout)
527{
528 u_long expiry = jiffies + timeout;
529 int success;
530
531 xdc_busy = 1;
532 while ((success = ((inb(port) & mask) != flags)) && time_before(jiffies, expiry))
533 schedule_timeout_uninterruptible(1);
534 xdc_busy = 0;
535 return (success);
536}
537
538static inline u_int xd_wait_for_IRQ (void)
539{
540 unsigned long flags;
541 xd_watchdog_int.expires = jiffies + 8 * HZ;
542 add_timer(&xd_watchdog_int);
543
544 flags=claim_dma_lock();
545 enable_dma(xd_dma);
546 release_dma_lock(flags);
547
548 sleep_on(&xd_wait_int);
549 del_timer(&xd_watchdog_int);
550 xdc_busy = 0;
551
552 flags=claim_dma_lock();
553 disable_dma(xd_dma);
554 release_dma_lock(flags);
555
556 if (xd_error) {
557 printk("xd: missed IRQ - command aborted\n");
558 xd_error = 0;
559 return (1);
560 }
561 return (0);
562}
563
564
565static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout)
566{
567 u_char cmdblk[6],csb,complete = 0;
568
569#ifdef DEBUG_COMMAND
570 printk("xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
571#endif
572
573 outb(0,XD_SELECT);
574 outb(mode,XD_CONTROL);
575
576 if (xd_waitport(XD_STATUS,STAT_SELECT,STAT_SELECT,timeout))
577 return (1);
578
579 while (!complete) {
580 if (xd_waitport(XD_STATUS,STAT_READY,STAT_READY,timeout))
581 return (1);
582
583 switch (inb(XD_STATUS) & (STAT_COMMAND | STAT_INPUT)) {
584 case 0:
585 if (mode == DMA_MODE) {
586 if (xd_wait_for_IRQ())
587 return (1);
588 } else
589 outb(outdata ? *outdata++ : 0,XD_DATA);
590 break;
591 case STAT_INPUT:
592 if (mode == DMA_MODE) {
593 if (xd_wait_for_IRQ())
594 return (1);
595 } else
596 if (indata)
597 *indata++ = inb(XD_DATA);
598 else
599 inb(XD_DATA);
600 break;
601 case STAT_COMMAND:
602 outb(command ? *command++ : 0,XD_DATA);
603 break;
604 case STAT_COMMAND | STAT_INPUT:
605 complete = 1;
606 break;
607 }
608 }
609 csb = inb(XD_DATA);
610
611 if (xd_waitport(XD_STATUS,0,STAT_SELECT,timeout))
612 return (1);
613
614 if (csb & CSB_ERROR) {
615 xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0);
616 if (xd_command(cmdblk,0,sense,NULL,NULL,XD_TIMEOUT))
617 printk("xd: warning! sense command failed!\n");
618 }
619
620#ifdef DEBUG_COMMAND
621 printk("xd_command: completed with csb = 0x%X\n",csb);
622#endif
623
624 return (csb & CSB_ERROR);
625}
626
627static u_char __init xd_initdrives (void (*init_drive)(u_char drive))
628{
629 u_char cmdblk[6],i,count = 0;
630
631 for (i = 0; i < XD_MAXDRIVES; i++) {
632 xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0);
633 if (!xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT*8)) {
634 msleep_interruptible(XD_INIT_DISK_DELAY);
635
636 init_drive(count);
637 count++;
638
639 msleep_interruptible(XD_INIT_DISK_DELAY);
640 }
641 }
642 return (count);
643}
644
645static void __init xd_manual_geo_set (u_char drive)
646{
647 xd_info[drive].heads = (u_char)(xd_geo[3 * drive + 1]);
648 xd_info[drive].cylinders = (u_short)(xd_geo[3 * drive]);
649 xd_info[drive].sectors = (u_char)(xd_geo[3 * drive + 2]);
650}
651
652static void __init xd_dtc_init_controller (unsigned int address)
653{
654 switch (address) {
655 case 0x00000:
656 case 0xC8000: break;
657 case 0xCA000: xd_iobase = 0x324;
658 case 0xD0000:
659 case 0xD8000: break;
660 default: printk("xd_dtc_init_controller: unsupported BIOS address %06x\n",address);
661 break;
662 }
663 xd_maxsectors = 0x01;
664
665 outb(0,XD_RESET);
666}
667
668
669static void __init xd_dtc5150cx_init_drive (u_char drive)
670{
671
672 static u_short geometry_table[][4] = {
673 {0x200,8,0x200,0x100},
674 {0x267,2,0x267,0x267},
675 {0x264,4,0x264,0x80},
676 {0x132,4,0x132,0x0},
677 {0x132,2,0x80, 0x132},
678 {0x177,8,0x177,0x0},
679 {0x132,8,0x84, 0x0},
680 {},
681 {0x132,6,0x80, 0x100},
682 {0x200,6,0x100,0x100},
683 {0x264,2,0x264,0x80},
684 {0x280,4,0x280,0x100},
685 {0x2B9,3,0x2B9,0x2B9},
686 {0x2B9,5,0x2B9,0x2B9},
687 {0x280,6,0x280,0x100},
688 {0x132,4,0x132,0x0}};
689 u_char n;
690
691 n = inb(XD_JUMPER);
692 n = (drive ? n : (n >> 2)) & 0x33;
693 n = (n | (n >> 2)) & 0x0F;
694 if (xd_geo[3*drive])
695 xd_manual_geo_set(drive);
696 else
697 if (n != 7) {
698 xd_info[drive].heads = (u_char)(geometry_table[n][1]);
699 xd_info[drive].cylinders = geometry_table[n][0];
700 xd_info[drive].sectors = 17;
701#if 0
702 xd_info[drive].rwrite = geometry_table[n][2];
703 xd_info[drive].precomp = geometry_table[n][3]
704 xd_info[drive].ecc = 0x0B;
705#endif
706 }
707 else {
708 printk("xd%c: undetermined drive geometry\n",'a'+drive);
709 return;
710 }
711 xd_info[drive].control = 5;
712 xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B);
713 xd_recalibrate(drive);
714}
715
716static void __init xd_dtc_init_drive (u_char drive)
717{
718 u_char cmdblk[6],buf[64];
719
720 xd_build(cmdblk,CMD_DTCGETGEOM,drive,0,0,0,0,0);
721 if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) {
722 xd_info[drive].heads = buf[0x0A];
723 xd_info[drive].cylinders = ((u_short *) (buf))[0x04];
724 xd_info[drive].sectors = 17;
725 if (xd_geo[3*drive])
726 xd_manual_geo_set(drive);
727#if 0
728 xd_info[drive].rwrite = ((u_short *) (buf + 1))[0x05];
729 xd_info[drive].precomp = ((u_short *) (buf + 1))[0x06];
730 xd_info[drive].ecc = buf[0x0F];
731#endif
732 xd_info[drive].control = 0;
733
734 xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf + 1))[0x05],((u_short *) (buf + 1))[0x06],buf[0x0F]);
735 xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7);
736 if (xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 2))
737 printk("xd_dtc_init_drive: error setting step rate for xd%c\n", 'a'+drive);
738 }
739 else
740 printk("xd_dtc_init_drive: error reading geometry for xd%c\n", 'a'+drive);
741}
742
743static void __init xd_wd_init_controller (unsigned int address)
744{
745 switch (address) {
746 case 0x00000:
747 case 0xC8000: break;
748 case 0xCA000: xd_iobase = 0x324; break;
749 case 0xCC000: xd_iobase = 0x328; break;
750 case 0xCE000: xd_iobase = 0x32C; break;
751 case 0xD0000: xd_iobase = 0x328; break;
752 case 0xD8000: xd_iobase = 0x32C; break;
753 default: printk("xd_wd_init_controller: unsupported BIOS address %06x\n",address);
754 break;
755 }
756 xd_maxsectors = 0x01;
757
758 outb(0,XD_RESET);
759
760 msleep(XD_INIT_DISK_DELAY);
761}
762
763static void __init xd_wd_init_drive (u_char drive)
764{
765
766 static u_short geometry_table[][4] = {
767 {0x264,4,0x1C2,0x1C2},
768 {0x132,4,0x099,0x0},
769 {0x267,2,0x1C2,0x1C2},
770 {0x267,4,0x1C2,0x1C2},
771
772 {0x334,6,0x335,0x335},
773 {0x30E,4,0x30F,0x3DC},
774 {0x30E,2,0x30F,0x30F},
775 {0x267,4,0x268,0x268},
776
777 {0x3D5,5,0x3D6,0x3D6},
778 {0x3DB,7,0x3DC,0x3DC},
779 {0x264,4,0x265,0x265},
780 {0x267,4,0x268,0x268}};
781
782 u_char cmdblk[6],buf[0x200];
783 u_char n = 0,rll,jumper_state,use_jumper_geo;
784 u_char wd_1002 = (xd_sigs[xd_type].string[7] == '6');
785
786 jumper_state = ~(inb(0x322));
787 if (jumper_state & 0x40)
788 xd_irq = 9;
789 rll = (jumper_state & 0x30) ? (0x04 << wd_1002) : 0;
790 xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0);
791 if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) {
792 xd_info[drive].heads = buf[0x1AF];
793 xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6];
794 xd_info[drive].sectors = 17;
795 if (xd_geo[3*drive])
796 xd_manual_geo_set(drive);
797#if 0
798 xd_info[drive].rwrite = ((u_short *) (buf))[0xD8];
799 xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA];
800 xd_info[drive].ecc = buf[0x1B4];
801#endif
802 xd_info[drive].control = buf[0x1B5];
803 use_jumper_geo = !(xd_info[drive].heads) || !(xd_info[drive].cylinders);
804 if (xd_geo[3*drive]) {
805 xd_manual_geo_set(drive);
806 xd_info[drive].control = rll ? 7 : 5;
807 }
808 else if (use_jumper_geo) {
809 n = (((jumper_state & 0x0F) >> (drive << 1)) & 0x03) | rll;
810 xd_info[drive].cylinders = geometry_table[n][0];
811 xd_info[drive].heads = (u_char)(geometry_table[n][1]);
812 xd_info[drive].control = rll ? 7 : 5;
813#if 0
814 xd_info[drive].rwrite = geometry_table[n][2];
815 xd_info[drive].wprecomp = geometry_table[n][3];
816 xd_info[drive].ecc = 0x0B;
817#endif
818 }
819 if (!wd_1002) {
820 if (use_jumper_geo)
821 xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
822 geometry_table[n][2],geometry_table[n][3],0x0B);
823 else
824 xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
825 ((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
826 }
827
828
829
830 if (rll & wd_1002) {
831 if ((xd_info[drive].cylinders *= 26,
832 xd_info[drive].cylinders /= 17) > 1023)
833 xd_info[drive].cylinders = 1023;
834#if 0
835 xd_info[drive].rwrite *= 26;
836 xd_info[drive].rwrite /= 17;
837 xd_info[drive].wprecomp *= 26
838 xd_info[drive].wprecomp /= 17;
839#endif
840 }
841 }
842 else
843 printk("xd_wd_init_drive: error reading geometry for xd%c\n",'a'+drive);
844
845}
846
847static void __init xd_seagate_init_controller (unsigned int address)
848{
849 switch (address) {
850 case 0x00000:
851 case 0xC8000: break;
852 case 0xD0000: xd_iobase = 0x324; break;
853 case 0xD8000: xd_iobase = 0x328; break;
854 case 0xE0000: xd_iobase = 0x32C; break;
855 default: printk("xd_seagate_init_controller: unsupported BIOS address %06x\n",address);
856 break;
857 }
858 xd_maxsectors = 0x40;
859
860 outb(0,XD_RESET);
861}
862
863static void __init xd_seagate_init_drive (u_char drive)
864{
865 u_char cmdblk[6],buf[0x200];
866
867 xd_build(cmdblk,CMD_ST11GETGEOM,drive,0,0,0,1,0);
868 if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) {
869 xd_info[drive].heads = buf[0x04];
870 xd_info[drive].cylinders = (buf[0x02] << 8) | buf[0x03];
871 xd_info[drive].sectors = buf[0x05];
872 xd_info[drive].control = 0;
873 }
874 else
875 printk("xd_seagate_init_drive: error reading geometry from xd%c\n", 'a'+drive);
876}
877
878
879static void __init xd_omti_init_controller (unsigned int address)
880{
881 switch (address) {
882 case 0x00000:
883 case 0xC8000: break;
884 case 0xD0000: xd_iobase = 0x324; break;
885 case 0xD8000: xd_iobase = 0x328; break;
886 case 0xE0000: xd_iobase = 0x32C; break;
887 default: printk("xd_omti_init_controller: unsupported BIOS address %06x\n",address);
888 break;
889 }
890
891 xd_maxsectors = 0x40;
892
893 outb(0,XD_RESET);
894}
895
896static void __init xd_omti_init_drive (u_char drive)
897{
898
899 xd_override_init_drive(drive);
900
901
902 xd_info[drive].control = 2;
903}
904
905
906static void __init xd_xebec_init_controller (unsigned int address)
907{
908
909
910
911
912
913
914
915 switch (address) {
916 case 0x00000:
917 case 0xC8000:
918 case 0xD0000:
919 case 0xD2000:
920 case 0xD4000:
921 case 0xD6000:
922 case 0xD8000:
923 case 0xDA000:
924 case 0xDC000:
925 case 0xDE000:
926 case 0xE0000: break;
927 default: printk("xd_xebec_init_controller: unsupported BIOS address %06x\n",address);
928 break;
929 }
930
931 xd_maxsectors = 0x01;
932 outb(0,XD_RESET);
933
934 msleep(XD_INIT_DISK_DELAY);
935}
936
937static void __init xd_xebec_init_drive (u_char drive)
938{
939
940 static u_short geometry_table[][5] = {
941 {0x132,4,0x080,0x080,0x7},
942 {0x132,4,0x080,0x080,0x17},
943 {0x264,2,0x100,0x100,0x7},
944 {0x264,2,0x100,0x100,0x17},
945 {0x132,8,0x080,0x080,0x7},
946 {0x132,8,0x080,0x080,0x17},
947 {0x264,4,0x100,0x100,0x6},
948 {0x264,4,0x100,0x100,0x17},
949 {0x2BC,5,0x2BC,0x12C,0x6},
950 {0x3A5,4,0x3A5,0x3A5,0x7},
951 {0x26C,6,0x26C,0x26C,0x7},
952 {0x200,8,0x200,0x100,0x17},
953 {0x400,5,0x400,0x400,0x7},
954 {0x400,6,0x400,0x400,0x7},
955 {0x264,8,0x264,0x200,0x17},
956 {0x33E,7,0x33E,0x200,0x7}};
957 u_char n;
958
959 n = inb(XD_JUMPER) & 0x0F;
960
961 if (xd_geo[3*drive])
962 xd_manual_geo_set(drive);
963 else {
964 xd_info[drive].heads = (u_char)(geometry_table[n][1]);
965 xd_info[drive].cylinders = geometry_table[n][0];
966 xd_info[drive].sectors = 17;
967#if 0
968 xd_info[drive].rwrite = geometry_table[n][2];
969 xd_info[drive].precomp = geometry_table[n][3]
970 xd_info[drive].ecc = 0x0B;
971#endif
972 }
973 xd_info[drive].control = geometry_table[n][4];
974 xd_setparam(CMD_XBSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B);
975 xd_recalibrate(drive);
976}
977
978
979
980static void __init xd_override_init_drive (u_char drive)
981{
982 u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
983 u_char cmdblk[6],i;
984
985 if (xd_geo[3*drive])
986 xd_manual_geo_set(drive);
987 else {
988 for (i = 0; i < 3; i++) {
989 while (min[i] != max[i] - 1) {
990 test[i] = (min[i] + max[i]) / 2;
991 xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0);
992 if (!xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 2))
993 min[i] = test[i];
994 else
995 max[i] = test[i];
996 }
997 test[i] = min[i];
998 }
999 xd_info[drive].heads = (u_char) min[0] + 1;
1000 xd_info[drive].cylinders = (u_short) min[1] + 1;
1001 xd_info[drive].sectors = (u_char) min[2] + 1;
1002 }
1003 xd_info[drive].control = 0;
1004}
1005
1006
1007static void __init do_xd_setup (int *integers)
1008{
1009 switch (integers[0]) {
1010 case 4: if (integers[4] < 0)
1011 nodma = 1;
1012 else if (integers[4] < 8)
1013 xd_dma = integers[4];
1014 case 3: if ((integers[3] > 0) && (integers[3] <= 0x3FC))
1015 xd_iobase = integers[3];
1016 case 2: if ((integers[2] > 0) && (integers[2] < 16))
1017 xd_irq = integers[2];
1018 case 1: xd_override = 1;
1019 if ((integers[1] >= 0) && (integers[1] < ARRAY_SIZE(xd_sigs)))
1020 xd_type = integers[1];
1021 case 0: break;
1022 default:printk("xd: too many parameters for xd\n");
1023 }
1024 xd_maxsectors = 0x01;
1025}
1026
1027
1028static void __init xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)
1029{
1030 u_char cmdblk[14];
1031
1032 xd_build(cmdblk,command,drive,0,0,0,0,0);
1033 cmdblk[6] = (u_char) (cylinders >> 8) & 0x03;
1034 cmdblk[7] = (u_char) (cylinders & 0xFF);
1035 cmdblk[8] = heads & 0x1F;
1036 cmdblk[9] = (u_char) (rwrite >> 8) & 0x03;
1037 cmdblk[10] = (u_char) (rwrite & 0xFF);
1038 cmdblk[11] = (u_char) (wprecomp >> 8) & 0x03;
1039 cmdblk[12] = (u_char) (wprecomp & 0xFF);
1040 cmdblk[13] = ecc;
1041
1042
1043
1044 if (xd_command(cmdblk,PIO_MODE,NULL,&cmdblk[6],NULL,XD_TIMEOUT * 2))
1045 printk("xd: error setting characteristics for xd%c\n", 'a'+drive);
1046}
1047
1048
1049#ifdef MODULE
1050
1051module_param_array(xd, int, NULL, 0);
1052module_param_array(xd_geo, int, NULL, 0);
1053module_param(nodma, bool, 0);
1054
1055MODULE_LICENSE("GPL");
1056
1057void cleanup_module(void)
1058{
1059 int i;
1060 unregister_blkdev(XT_DISK_MAJOR, "xd");
1061 for (i = 0; i < xd_drives; i++) {
1062 del_gendisk(xd_gendisk[i]);
1063 put_disk(xd_gendisk[i]);
1064 }
1065 blk_cleanup_queue(xd_queue);
1066 release_region(xd_iobase,4);
1067 if (xd_drives) {
1068 free_irq(xd_irq, NULL);
1069 free_dma(xd_dma);
1070 if (xd_dma_buffer)
1071 xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200);
1072 }
1073}
1074#else
1075
1076static int __init xd_setup (char *str)
1077{
1078 int ints[5];
1079 get_options (str, ARRAY_SIZE (ints), ints);
1080 do_xd_setup (ints);
1081 return 1;
1082}
1083
1084
1085
1086static int __init xd_manual_geo_init (char *str)
1087{
1088 int i, integers[1 + 3*XD_MAXDRIVES];
1089
1090 get_options (str, ARRAY_SIZE (integers), integers);
1091 if (integers[0]%3 != 0) {
1092 printk("xd: incorrect number of parameters for xd_geo\n");
1093 return 1;
1094 }
1095 for (i = 0; (i < integers[0]) && (i < 3*XD_MAXDRIVES); i++)
1096 xd_geo[i] = integers[i+1];
1097 return 1;
1098}
1099
1100__setup ("xd=", xd_setup);
1101__setup ("xd_geo=", xd_manual_geo_init);
1102
1103#endif
1104
1105module_init(xd_init);
1106MODULE_ALIAS_BLOCKDEV_MAJOR(XT_DISK_MAJOR);
1107