aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/xd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/block/xd.c')
-rw-r--r--drivers/block/xd.c1112
1 files changed, 1112 insertions, 0 deletions
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
new file mode 100644
index 000000000000..1676033da6c6
--- /dev/null
+++ b/drivers/block/xd.c
@@ -0,0 +1,1112 @@
1/*
2 * This file contains the driver for an XT hard disk controller
3 * (at least the DTC 5150X) for Linux.
4 *
5 * Author: Pat Mackinlay, pat@it.com.au
6 * Date: 29/09/92
7 *
8 * Revised: 01/01/93, ...
9 *
10 * Ref: DTC 5150X Controller Specification (thanks to Kevin Fowler,
11 * kevinf@agora.rain.com)
12 * Also thanks to: Salvador Abreu, Dave Thaler, Risto Kankkunen and
13 * Wim Van Dorst.
14 *
15 * Revised: 04/04/94 by Risto Kankkunen
16 * Moved the detection code from xd_init() to xd_geninit() as it needed
17 * interrupts enabled and Linus didn't want to enable them in that first
18 * phase. xd_geninit() is the place to do these kinds of things anyway,
19 * he says.
20 *
21 * Modularized: 04/10/96 by Todd Fries, tfries@umr.edu
22 *
23 * Revised: 13/12/97 by Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl
24 * Fixed some problems with disk initialization and module initiation.
25 * Added support for manual geometry setting (except Seagate controllers)
26 * in form:
27 * xd_geo=<cyl_xda>,<head_xda>,<sec_xda>[,<cyl_xdb>,<head_xdb>,<sec_xdb>]
28 * Recovered DMA access. Abridged messages. Added support for DTC5051CX,
29 * WD1002-27X & XEBEC controllers. Driver uses now some jumper settings.
30 * Extended ioctl() support.
31 *
32 * Bugfix: 15/02/01, Paul G. - inform queue layer of tiny xd_maxsect.
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
51#include <asm/system.h>
52#include <asm/io.h>
53#include <asm/uaccess.h>
54#include <asm/dma.h>
55
56#include "xd.h"
57
58static void __init do_xd_setup (int *integers);
59#ifdef MODULE
60static int xd[5] = { -1,-1,-1,-1, };
61#endif
62
63#define XD_DONT_USE_DMA 0 /* Initial value. may be overriden using
64 "nodma" module option */
65#define XD_INIT_DISK_DELAY (30*HZ/1000) /* 30 ms delay during disk initialization */
66
67/* Above may need to be increased if a problem with the 2nd drive detection
68 (ST11M controller) or resetting a controller (WD) appears */
69
70static XD_INFO xd_info[XD_MAXDRIVES];
71
72/* If you try this driver and find that your card is not detected by the driver at bootup, you need to add your BIOS
73 signature and details to the following list of signatures. A BIOS signature is a string embedded into the first
74 few bytes of your controller's on-board ROM BIOS. To find out what yours is, use something like MS-DOS's DEBUG
75 command. Run DEBUG, and then you can examine your BIOS signature with:
76
77 d xxxx:0000
78
79 where xxxx is the segment of your controller (like C800 or D000 or something). On the ASCII dump at the right, you should
80 be able to see a string mentioning the manufacturer's copyright etc. Add this string into the table below. The parameters
81 in the table are, in order:
82
83 offset ; this is the offset (in bytes) from the start of your ROM where the signature starts
84 signature ; this is the actual text of the signature
85 xd_?_init_controller ; this is the controller init routine used by your controller
86 xd_?_init_drive ; this is the drive init routine used by your controller
87
88 The controllers directly supported at the moment are: DTC 5150x, WD 1004A27X, ST11M/R and override. If your controller is
89 made by the same manufacturer as one of these, try using the same init routines as they do. If that doesn't work, your
90 best bet is to use the "override" routines. These routines use a "portable" method of getting the disk's geometry, and
91 may work with your card. If none of these seem to work, try sending me some email and I'll see what I can do <grin>.
92
93 NOTE: You can now specify your XT controller's parameters from the command line in the form xd=TYPE,IRQ,IO,DMA. The driver
94 should be able to detect your drive's geometry from this info. (eg: xd=0,5,0x320,3 is the "standard"). */
95
96#include <asm/page.h>
97#define xd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,get_order(size))
98#define xd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
99static char *xd_dma_buffer;
100
101static XD_SIGNATURE xd_sigs[] __initdata = {
102 { 0x0000,"Override geometry handler",NULL,xd_override_init_drive,"n unknown" }, /* Pat Mackinlay, pat@it.com.au */
103 { 0x0008,"[BXD06 (C) DTC 17-MAY-1985]",xd_dtc_init_controller,xd_dtc5150cx_init_drive," DTC 5150CX" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */
104 { 0x000B,"CRD18A Not an IBM rom. (C) Copyright Data Technology Corp. 05/31/88",xd_dtc_init_controller,xd_dtc_init_drive," DTC 5150X" }, /* Todd Fries, tfries@umr.edu */
105 { 0x000B,"CXD23A Not an IBM ROM (C)Copyright Data Technology Corp 12/03/88",xd_dtc_init_controller,xd_dtc_init_drive," DTC 5150X" }, /* Pat Mackinlay, pat@it.com.au */
106 { 0x0008,"07/15/86(C) Copyright 1986 Western Digital Corp.",xd_wd_init_controller,xd_wd_init_drive," Western Dig. 1002-27X" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */
107 { 0x0008,"06/24/88(C) Copyright 1988 Western Digital Corp.",xd_wd_init_controller,xd_wd_init_drive," Western Dig. WDXT-GEN2" }, /* Dan Newcombe, newcombe@aa.csc.peachnet.edu */
108 { 0x0015,"SEAGATE ST11 BIOS REVISION",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Salvador Abreu, spa@fct.unl.pt */
109 { 0x0010,"ST11R BIOS",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Risto Kankkunen, risto.kankkunen@cs.helsinki.fi */
110 { 0x0010,"ST11 BIOS v1.7",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11R" }, /* Alan Hourihane, alanh@fairlite.demon.co.uk */
111 { 0x1000,"(c)Copyright 1987 SMS",xd_omti_init_controller,xd_omti_init_drive,"n OMTI 5520" }, /* Dirk Melchers, dirk@merlin.nbg.sub.org */
112 { 0x0006,"COPYRIGHT XEBEC (C) 1984",xd_xebec_init_controller,xd_xebec_init_drive," XEBEC" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */
113 { 0x0008,"(C) Copyright 1984 Western Digital Corp", xd_wd_init_controller, xd_wd_init_drive," Western Dig. 1002s-wx2" },
114 { 0x0008,"(C) Copyright 1986 Western Digital Corporation", xd_wd_init_controller, xd_wd_init_drive," 1986 Western Digital" }, /* jfree@sovereign.org */
115};
116
117static unsigned int xd_bases[] __initdata =
118{
119 0xC8000, 0xCA000, 0xCC000,
120 0xCE000, 0xD0000, 0xD2000,
121 0xD4000, 0xD6000, 0xD8000,
122 0xDA000, 0xDC000, 0xDE000,
123 0xE0000
124};
125
126static DEFINE_SPINLOCK(xd_lock);
127
128static struct gendisk *xd_gendisk[2];
129
130static struct block_device_operations xd_fops = {
131 .owner = THIS_MODULE,
132 .ioctl = xd_ioctl,
133};
134static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int);
135static u_char xd_drives, xd_irq = 5, xd_dma = 3, xd_maxsectors;
136static u_char xd_override __initdata = 0, xd_type __initdata = 0;
137static u_short xd_iobase = 0x320;
138static int xd_geo[XD_MAXDRIVES*3] __initdata = { 0, };
139
140static volatile int xdc_busy;
141static struct timer_list xd_watchdog_int;
142
143static volatile u_char xd_error;
144static int nodma = XD_DONT_USE_DMA;
145
146static struct request_queue *xd_queue;
147
148/* xd_init: register the block device number and set up pointer tables */
149static int __init xd_init(void)
150{
151 u_char i,controller;
152 unsigned int address;
153 int err;
154
155#ifdef MODULE
156 {
157 u_char count = 0;
158 for (i = 4; i > 0; i--)
159 if (((xd[i] = xd[i-1]) >= 0) && !count)
160 count = i;
161 if ((xd[0] = count))
162 do_xd_setup(xd);
163 }
164#endif
165
166 init_timer (&xd_watchdog_int); xd_watchdog_int.function = xd_watchdog;
167
168 if (!xd_dma_buffer)
169 xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
170 if (!xd_dma_buffer) {
171 printk(KERN_ERR "xd: Out of memory.\n");
172 return -ENOMEM;
173 }
174
175 err = -EBUSY;
176 if (register_blkdev(XT_DISK_MAJOR, "xd"))
177 goto out1;
178
179 err = -ENOMEM;
180 xd_queue = blk_init_queue(do_xd_request, &xd_lock);
181 if (!xd_queue)
182 goto out1a;
183
184 if (xd_detect(&controller,&address)) {
185
186 printk("Detected a%s controller (type %d) at address %06x\n",
187 xd_sigs[controller].name,controller,address);
188 if (!request_region(xd_iobase,4,"xd")) {
189 printk("xd: Ports at 0x%x are not available\n",
190 xd_iobase);
191 goto out2;
192 }
193 if (controller)
194 xd_sigs[controller].init_controller(address);
195 xd_drives = xd_initdrives(xd_sigs[controller].init_drive);
196
197 printk("Detected %d hard drive%s (using IRQ%d & DMA%d)\n",
198 xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma);
199 }
200
201 err = -ENODEV;
202 if (!xd_drives)
203 goto out3;
204
205 for (i = 0; i < xd_drives; i++) {
206 XD_INFO *p = &xd_info[i];
207 struct gendisk *disk = alloc_disk(64);
208 if (!disk)
209 goto Enomem;
210 p->unit = i;
211 disk->major = XT_DISK_MAJOR;
212 disk->first_minor = i<<6;
213 sprintf(disk->disk_name, "xd%c", i+'a');
214 sprintf(disk->devfs_name, "xd/target%d", i);
215 disk->fops = &xd_fops;
216 disk->private_data = p;
217 disk->queue = xd_queue;
218 set_capacity(disk, p->heads * p->cylinders * p->sectors);
219 printk(" %s: CHS=%d/%d/%d\n", disk->disk_name,
220 p->cylinders, p->heads, p->sectors);
221 xd_gendisk[i] = disk;
222 }
223
224 err = -EBUSY;
225 if (request_irq(xd_irq,xd_interrupt_handler, 0, "XT hard disk", NULL)) {
226 printk("xd: unable to get IRQ%d\n",xd_irq);
227 goto out4;
228 }
229
230 if (request_dma(xd_dma,"xd")) {
231 printk("xd: unable to get DMA%d\n",xd_dma);
232 goto out5;
233 }
234
235 /* xd_maxsectors depends on controller - so set after detection */
236 blk_queue_max_sectors(xd_queue, xd_maxsectors);
237
238 for (i = 0; i < xd_drives; i++)
239 add_disk(xd_gendisk[i]);
240
241 return 0;
242
243out5:
244 free_irq(xd_irq, NULL);
245out4:
246 for (i = 0; i < xd_drives; i++)
247 put_disk(xd_gendisk[i]);
248out3:
249 release_region(xd_iobase,4);
250out2:
251 blk_cleanup_queue(xd_queue);
252out1a:
253 unregister_blkdev(XT_DISK_MAJOR, "xd");
254out1:
255 if (xd_dma_buffer)
256 xd_dma_mem_free((unsigned long)xd_dma_buffer,
257 xd_maxsectors * 0x200);
258 return err;
259Enomem:
260 err = -ENOMEM;
261 while (i--)
262 put_disk(xd_gendisk[i]);
263 goto out3;
264}
265
266/* xd_detect: scan the possible BIOS ROM locations for the signature strings */
267static u_char __init xd_detect (u_char *controller, unsigned int *address)
268{
269 int i, j;
270
271 if (xd_override)
272 {
273 *controller = xd_type;
274 *address = 0;
275 return(1);
276 }
277
278 for (i = 0; i < (sizeof(xd_bases) / sizeof(xd_bases[0])); i++) {
279 void __iomem *p = ioremap(xd_bases[i], 0x2000);
280 if (!p)
281 continue;
282 for (j = 1; j < (sizeof(xd_sigs) / sizeof(xd_sigs[0])); j++) {
283 const char *s = xd_sigs[j].string;
284 if (check_signature(p + xd_sigs[j].offset, s, strlen(s))) {
285 *controller = j;
286 xd_type = j;
287 *address = xd_bases[i];
288 iounmap(p);
289 return 1;
290 }
291 }
292 iounmap(p);
293 }
294 return 0;
295}
296
297/* do_xd_request: handle an incoming request */
298static void do_xd_request (request_queue_t * q)
299{
300 struct request *req;
301
302 if (xdc_busy)
303 return;
304
305 while ((req = elv_next_request(q)) != NULL) {
306 unsigned block = req->sector;
307 unsigned count = req->nr_sectors;
308 int rw = rq_data_dir(req);
309 XD_INFO *disk = req->rq_disk->private_data;
310 int res = 0;
311 int retry;
312
313 if (!(req->flags & REQ_CMD)) {
314 end_request(req, 0);
315 continue;
316 }
317 if (block + count > get_capacity(req->rq_disk)) {
318 end_request(req, 0);
319 continue;
320 }
321 if (rw != READ && rw != WRITE) {
322 printk("do_xd_request: unknown request\n");
323 end_request(req, 0);
324 continue;
325 }
326 for (retry = 0; (retry < XD_RETRIES) && !res; retry++)
327 res = xd_readwrite(rw, disk, req->buffer, block, count);
328 end_request(req, res); /* wrap up, 0 = fail, 1 = success */
329 }
330}
331
332/* xd_ioctl: handle device ioctl's */
333static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
334{
335 XD_INFO *p = inode->i_bdev->bd_disk->private_data;
336
337 switch (cmd) {
338 case HDIO_GETGEO:
339 {
340 struct hd_geometry g;
341 struct hd_geometry __user *geom= (void __user *)arg;
342 g.heads = p->heads;
343 g.sectors = p->sectors;
344 g.cylinders = p->cylinders;
345 g.start = get_start_sect(inode->i_bdev);
346 return copy_to_user(geom, &g, sizeof(g)) ? -EFAULT : 0;
347 }
348 case HDIO_SET_DMA:
349 if (!capable(CAP_SYS_ADMIN)) return -EACCES;
350 if (xdc_busy) return -EBUSY;
351 nodma = !arg;
352 if (nodma && xd_dma_buffer) {
353 xd_dma_mem_free((unsigned long)xd_dma_buffer,
354 xd_maxsectors * 0x200);
355 xd_dma_buffer = NULL;
356 } else if (!nodma && !xd_dma_buffer) {
357 xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
358 if (!xd_dma_buffer) {
359 nodma = XD_DONT_USE_DMA;
360 return -ENOMEM;
361 }
362 }
363 return 0;
364 case HDIO_GET_DMA:
365 return put_user(!nodma, (long __user *) arg);
366 case HDIO_GET_MULTCOUNT:
367 return put_user(xd_maxsectors, (long __user *) arg);
368 default:
369 return -EINVAL;
370 }
371}
372
373/* xd_readwrite: handle a read/write request */
374static int xd_readwrite (u_char operation,XD_INFO *p,char *buffer,u_int block,u_int count)
375{
376 int drive = p->unit;
377 u_char cmdblk[6],sense[4];
378 u_short track,cylinder;
379 u_char head,sector,control,mode = PIO_MODE,temp;
380 char **real_buffer;
381 register int i;
382
383#ifdef DEBUG_READWRITE
384 printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
385#endif /* DEBUG_READWRITE */
386
387 spin_unlock_irq(&xd_lock);
388
389 control = p->control;
390 if (!xd_dma_buffer)
391 xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
392 while (count) {
393 temp = count < xd_maxsectors ? count : xd_maxsectors;
394
395 track = block / p->sectors;
396 head = track % p->heads;
397 cylinder = track / p->heads;
398 sector = block % p->sectors;
399
400#ifdef DEBUG_READWRITE
401 printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
402#endif /* DEBUG_READWRITE */
403
404 if (xd_dma_buffer) {
405 mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)(xd_dma_buffer),temp * 0x200);
406 real_buffer = &xd_dma_buffer;
407 for (i=0; i < (temp * 0x200); i++)
408 xd_dma_buffer[i] = buffer[i];
409 }
410 else
411 real_buffer = &buffer;
412
413 xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control);
414
415 switch (xd_command(cmdblk,mode,(u_char *)(*real_buffer),(u_char *)(*real_buffer),sense,XD_TIMEOUT)) {
416 case 1:
417 printk("xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write"));
418 xd_recalibrate(drive);
419 spin_lock_irq(&xd_lock);
420 return (0);
421 case 2:
422 if (sense[0] & 0x30) {
423 printk("xd%c: %s - ",'a'+drive,(operation == READ ? "reading" : "writing"));
424 switch ((sense[0] & 0x30) >> 4) {
425 case 0: printk("drive error, code = 0x%X",sense[0] & 0x0F);
426 break;
427 case 1: printk("controller error, code = 0x%X",sense[0] & 0x0F);
428 break;
429 case 2: printk("command error, code = 0x%X",sense[0] & 0x0F);
430 break;
431 case 3: printk("miscellaneous error, code = 0x%X",sense[0] & 0x0F);
432 break;
433 }
434 }
435 if (sense[0] & 0x80)
436 printk(" - CHS = %d/%d/%d\n",((sense[2] & 0xC0) << 2) | sense[3],sense[1] & 0x1F,sense[2] & 0x3F);
437 /* reported drive number = (sense[1] & 0xE0) >> 5 */
438 else
439 printk(" - no valid disk address\n");
440 spin_lock_irq(&xd_lock);
441 return (0);
442 }
443 if (xd_dma_buffer)
444 for (i=0; i < (temp * 0x200); i++)
445 buffer[i] = xd_dma_buffer[i];
446
447 count -= temp, buffer += temp * 0x200, block += temp;
448 }
449 spin_lock_irq(&xd_lock);
450 return (1);
451}
452
453/* xd_recalibrate: recalibrate a given drive and reset controller if necessary */
454static void xd_recalibrate (u_char drive)
455{
456 u_char cmdblk[6];
457
458 xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0);
459 if (xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 8))
460 printk("xd%c: warning! error recalibrating, controller may be unstable\n", 'a'+drive);
461}
462
463/* xd_interrupt_handler: interrupt service routine */
464static irqreturn_t xd_interrupt_handler(int irq, void *dev_id,
465 struct pt_regs *regs)
466{
467 if (inb(XD_STATUS) & STAT_INTERRUPT) { /* check if it was our device */
468#ifdef DEBUG_OTHER
469 printk("xd_interrupt_handler: interrupt detected\n");
470#endif /* DEBUG_OTHER */
471 outb(0,XD_CONTROL); /* acknowledge interrupt */
472 wake_up(&xd_wait_int); /* and wake up sleeping processes */
473 return IRQ_HANDLED;
474 }
475 else
476 printk("xd: unexpected interrupt\n");
477 return IRQ_NONE;
478}
479
480/* xd_setup_dma: set up the DMA controller for a data transfer */
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 /* DEBUG_OTHER */
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); /* use DMA and INT */
504}
505
506/* xd_build: put stuff into an array in a format suitable for the controller */
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/* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */
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 set_current_state(TASK_UNINTERRUPTIBLE);
534 schedule_timeout(1);
535 }
536 xdc_busy = 0;
537 return (success);
538}
539
540static inline u_int xd_wait_for_IRQ (void)
541{
542 unsigned long flags;
543 xd_watchdog_int.expires = jiffies + 8 * HZ;
544 add_timer(&xd_watchdog_int);
545
546 flags=claim_dma_lock();
547 enable_dma(xd_dma);
548 release_dma_lock(flags);
549
550 sleep_on(&xd_wait_int);
551 del_timer(&xd_watchdog_int);
552 xdc_busy = 0;
553
554 flags=claim_dma_lock();
555 disable_dma(xd_dma);
556 release_dma_lock(flags);
557
558 if (xd_error) {
559 printk("xd: missed IRQ - command aborted\n");
560 xd_error = 0;
561 return (1);
562 }
563 return (0);
564}
565
566/* xd_command: handle all data transfers necessary for a single command */
567static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout)
568{
569 u_char cmdblk[6],csb,complete = 0;
570
571#ifdef DEBUG_COMMAND
572 printk("xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
573#endif /* DEBUG_COMMAND */
574
575 outb(0,XD_SELECT);
576 outb(mode,XD_CONTROL);
577
578 if (xd_waitport(XD_STATUS,STAT_SELECT,STAT_SELECT,timeout))
579 return (1);
580
581 while (!complete) {
582 if (xd_waitport(XD_STATUS,STAT_READY,STAT_READY,timeout))
583 return (1);
584
585 switch (inb(XD_STATUS) & (STAT_COMMAND | STAT_INPUT)) {
586 case 0:
587 if (mode == DMA_MODE) {
588 if (xd_wait_for_IRQ())
589 return (1);
590 } else
591 outb(outdata ? *outdata++ : 0,XD_DATA);
592 break;
593 case STAT_INPUT:
594 if (mode == DMA_MODE) {
595 if (xd_wait_for_IRQ())
596 return (1);
597 } else
598 if (indata)
599 *indata++ = inb(XD_DATA);
600 else
601 inb(XD_DATA);
602 break;
603 case STAT_COMMAND:
604 outb(command ? *command++ : 0,XD_DATA);
605 break;
606 case STAT_COMMAND | STAT_INPUT:
607 complete = 1;
608 break;
609 }
610 }
611 csb = inb(XD_DATA);
612
613 if (xd_waitport(XD_STATUS,0,STAT_SELECT,timeout)) /* wait until deselected */
614 return (1);
615
616 if (csb & CSB_ERROR) { /* read sense data if error */
617 xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0);
618 if (xd_command(cmdblk,0,sense,NULL,NULL,XD_TIMEOUT))
619 printk("xd: warning! sense command failed!\n");
620 }
621
622#ifdef DEBUG_COMMAND
623 printk("xd_command: completed with csb = 0x%X\n",csb);
624#endif /* DEBUG_COMMAND */
625
626 return (csb & CSB_ERROR);
627}
628
629static u_char __init xd_initdrives (void (*init_drive)(u_char drive))
630{
631 u_char cmdblk[6],i,count = 0;
632
633 for (i = 0; i < XD_MAXDRIVES; i++) {
634 xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0);
635 if (!xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT*8)) {
636 set_current_state(TASK_INTERRUPTIBLE);
637 schedule_timeout(XD_INIT_DISK_DELAY);
638
639 init_drive(count);
640 count++;
641
642 set_current_state(TASK_INTERRUPTIBLE);
643 schedule_timeout(XD_INIT_DISK_DELAY);
644 }
645 }
646 return (count);
647}
648
649static void __init xd_manual_geo_set (u_char drive)
650{
651 xd_info[drive].heads = (u_char)(xd_geo[3 * drive + 1]);
652 xd_info[drive].cylinders = (u_short)(xd_geo[3 * drive]);
653 xd_info[drive].sectors = (u_char)(xd_geo[3 * drive + 2]);
654}
655
656static void __init xd_dtc_init_controller (unsigned int address)
657{
658 switch (address) {
659 case 0x00000:
660 case 0xC8000: break; /*initial: 0x320 */
661 case 0xCA000: xd_iobase = 0x324;
662 case 0xD0000: /*5150CX*/
663 case 0xD8000: break; /*5150CX & 5150XL*/
664 default: printk("xd_dtc_init_controller: unsupported BIOS address %06x\n",address);
665 break;
666 }
667 xd_maxsectors = 0x01; /* my card seems to have trouble doing multi-block transfers? */
668
669 outb(0,XD_RESET); /* reset the controller */
670}
671
672
673static void __init xd_dtc5150cx_init_drive (u_char drive)
674{
675 /* values from controller's BIOS - BIOS chip may be removed */
676 static u_short geometry_table[][4] = {
677 {0x200,8,0x200,0x100},
678 {0x267,2,0x267,0x267},
679 {0x264,4,0x264,0x80},
680 {0x132,4,0x132,0x0},
681 {0x132,2,0x80, 0x132},
682 {0x177,8,0x177,0x0},
683 {0x132,8,0x84, 0x0},
684 {}, /* not used */
685 {0x132,6,0x80, 0x100},
686 {0x200,6,0x100,0x100},
687 {0x264,2,0x264,0x80},
688 {0x280,4,0x280,0x100},
689 {0x2B9,3,0x2B9,0x2B9},
690 {0x2B9,5,0x2B9,0x2B9},
691 {0x280,6,0x280,0x100},
692 {0x132,4,0x132,0x0}};
693 u_char n;
694
695 n = inb(XD_JUMPER);
696 n = (drive ? n : (n >> 2)) & 0x33;
697 n = (n | (n >> 2)) & 0x0F;
698 if (xd_geo[3*drive])
699 xd_manual_geo_set(drive);
700 else
701 if (n != 7) {
702 xd_info[drive].heads = (u_char)(geometry_table[n][1]); /* heads */
703 xd_info[drive].cylinders = geometry_table[n][0]; /* cylinders */
704 xd_info[drive].sectors = 17; /* sectors */
705#if 0
706 xd_info[drive].rwrite = geometry_table[n][2]; /* reduced write */
707 xd_info[drive].precomp = geometry_table[n][3] /* write precomp */
708 xd_info[drive].ecc = 0x0B; /* ecc length */
709#endif /* 0 */
710 }
711 else {
712 printk("xd%c: undetermined drive geometry\n",'a'+drive);
713 return;
714 }
715 xd_info[drive].control = 5; /* control byte */
716 xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B);
717 xd_recalibrate(drive);
718}
719
720static void __init xd_dtc_init_drive (u_char drive)
721{
722 u_char cmdblk[6],buf[64];
723
724 xd_build(cmdblk,CMD_DTCGETGEOM,drive,0,0,0,0,0);
725 if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) {
726 xd_info[drive].heads = buf[0x0A]; /* heads */
727 xd_info[drive].cylinders = ((u_short *) (buf))[0x04]; /* cylinders */
728 xd_info[drive].sectors = 17; /* sectors */
729 if (xd_geo[3*drive])
730 xd_manual_geo_set(drive);
731#if 0
732 xd_info[drive].rwrite = ((u_short *) (buf + 1))[0x05]; /* reduced write */
733 xd_info[drive].precomp = ((u_short *) (buf + 1))[0x06]; /* write precomp */
734 xd_info[drive].ecc = buf[0x0F]; /* ecc length */
735#endif /* 0 */
736 xd_info[drive].control = 0; /* control byte */
737
738 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]);
739 xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7);
740 if (xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 2))
741 printk("xd_dtc_init_drive: error setting step rate for xd%c\n", 'a'+drive);
742 }
743 else
744 printk("xd_dtc_init_drive: error reading geometry for xd%c\n", 'a'+drive);
745}
746
747static void __init xd_wd_init_controller (unsigned int address)
748{
749 switch (address) {
750 case 0x00000:
751 case 0xC8000: break; /*initial: 0x320 */
752 case 0xCA000: xd_iobase = 0x324; break;
753 case 0xCC000: xd_iobase = 0x328; break;
754 case 0xCE000: xd_iobase = 0x32C; break;
755 case 0xD0000: xd_iobase = 0x328; break; /* ? */
756 case 0xD8000: xd_iobase = 0x32C; break; /* ? */
757 default: printk("xd_wd_init_controller: unsupported BIOS address %06x\n",address);
758 break;
759 }
760 xd_maxsectors = 0x01; /* this one doesn't wrap properly either... */
761
762 outb(0,XD_RESET); /* reset the controller */
763
764 set_current_state(TASK_UNINTERRUPTIBLE);
765 schedule_timeout(XD_INIT_DISK_DELAY);
766}
767
768static void __init xd_wd_init_drive (u_char drive)
769{
770 /* values from controller's BIOS - BIOS may be disabled */
771 static u_short geometry_table[][4] = {
772 {0x264,4,0x1C2,0x1C2}, /* common part */
773 {0x132,4,0x099,0x0},
774 {0x267,2,0x1C2,0x1C2},
775 {0x267,4,0x1C2,0x1C2},
776
777 {0x334,6,0x335,0x335}, /* 1004 series RLL */
778 {0x30E,4,0x30F,0x3DC},
779 {0x30E,2,0x30F,0x30F},
780 {0x267,4,0x268,0x268},
781
782 {0x3D5,5,0x3D6,0x3D6}, /* 1002 series RLL */
783 {0x3DB,7,0x3DC,0x3DC},
784 {0x264,4,0x265,0x265},
785 {0x267,4,0x268,0x268}};
786
787 u_char cmdblk[6],buf[0x200];
788 u_char n = 0,rll,jumper_state,use_jumper_geo;
789 u_char wd_1002 = (xd_sigs[xd_type].string[7] == '6');
790
791 jumper_state = ~(inb(0x322));
792 if (jumper_state & 0x40)
793 xd_irq = 9;
794 rll = (jumper_state & 0x30) ? (0x04 << wd_1002) : 0;
795 xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0);
796 if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) {
797 xd_info[drive].heads = buf[0x1AF]; /* heads */
798 xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6]; /* cylinders */
799 xd_info[drive].sectors = 17; /* sectors */
800 if (xd_geo[3*drive])
801 xd_manual_geo_set(drive);
802#if 0
803 xd_info[drive].rwrite = ((u_short *) (buf))[0xD8]; /* reduced write */
804 xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA]; /* write precomp */
805 xd_info[drive].ecc = buf[0x1B4]; /* ecc length */
806#endif /* 0 */
807 xd_info[drive].control = buf[0x1B5]; /* control byte */
808 use_jumper_geo = !(xd_info[drive].heads) || !(xd_info[drive].cylinders);
809 if (xd_geo[3*drive]) {
810 xd_manual_geo_set(drive);
811 xd_info[drive].control = rll ? 7 : 5;
812 }
813 else if (use_jumper_geo) {
814 n = (((jumper_state & 0x0F) >> (drive << 1)) & 0x03) | rll;
815 xd_info[drive].cylinders = geometry_table[n][0];
816 xd_info[drive].heads = (u_char)(geometry_table[n][1]);
817 xd_info[drive].control = rll ? 7 : 5;
818#if 0
819 xd_info[drive].rwrite = geometry_table[n][2];
820 xd_info[drive].wprecomp = geometry_table[n][3];
821 xd_info[drive].ecc = 0x0B;
822#endif /* 0 */
823 }
824 if (!wd_1002) {
825 if (use_jumper_geo)
826 xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
827 geometry_table[n][2],geometry_table[n][3],0x0B);
828 else
829 xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
830 ((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
831 }
832 /* 1002 based RLL controller requests converted addressing, but reports physical
833 (physical 26 sec., logical 17 sec.)
834 1004 based ???? */
835 if (rll & wd_1002) {
836 if ((xd_info[drive].cylinders *= 26,
837 xd_info[drive].cylinders /= 17) > 1023)
838 xd_info[drive].cylinders = 1023; /* 1024 ? */
839#if 0
840 xd_info[drive].rwrite *= 26;
841 xd_info[drive].rwrite /= 17;
842 xd_info[drive].wprecomp *= 26
843 xd_info[drive].wprecomp /= 17;
844#endif /* 0 */
845 }
846 }
847 else
848 printk("xd_wd_init_drive: error reading geometry for xd%c\n",'a'+drive);
849
850}
851
852static void __init xd_seagate_init_controller (unsigned int address)
853{
854 switch (address) {
855 case 0x00000:
856 case 0xC8000: break; /*initial: 0x320 */
857 case 0xD0000: xd_iobase = 0x324; break;
858 case 0xD8000: xd_iobase = 0x328; break;
859 case 0xE0000: xd_iobase = 0x32C; break;
860 default: printk("xd_seagate_init_controller: unsupported BIOS address %06x\n",address);
861 break;
862 }
863 xd_maxsectors = 0x40;
864
865 outb(0,XD_RESET); /* reset the controller */
866}
867
868static void __init xd_seagate_init_drive (u_char drive)
869{
870 u_char cmdblk[6],buf[0x200];
871
872 xd_build(cmdblk,CMD_ST11GETGEOM,drive,0,0,0,1,0);
873 if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) {
874 xd_info[drive].heads = buf[0x04]; /* heads */
875 xd_info[drive].cylinders = (buf[0x02] << 8) | buf[0x03]; /* cylinders */
876 xd_info[drive].sectors = buf[0x05]; /* sectors */
877 xd_info[drive].control = 0; /* control byte */
878 }
879 else
880 printk("xd_seagate_init_drive: error reading geometry from xd%c\n", 'a'+drive);
881}
882
883/* Omti support courtesy Dirk Melchers */
884static void __init xd_omti_init_controller (unsigned int address)
885{
886 switch (address) {
887 case 0x00000:
888 case 0xC8000: break; /*initial: 0x320 */
889 case 0xD0000: xd_iobase = 0x324; break;
890 case 0xD8000: xd_iobase = 0x328; break;
891 case 0xE0000: xd_iobase = 0x32C; break;
892 default: printk("xd_omti_init_controller: unsupported BIOS address %06x\n",address);
893 break;
894 }
895
896 xd_maxsectors = 0x40;
897
898 outb(0,XD_RESET); /* reset the controller */
899}
900
901static void __init xd_omti_init_drive (u_char drive)
902{
903 /* gets infos from drive */
904 xd_override_init_drive(drive);
905
906 /* set other parameters, Hardcoded, not that nice :-) */
907 xd_info[drive].control = 2;
908}
909
910/* Xebec support (AK) */
911static void __init xd_xebec_init_controller (unsigned int address)
912{
913/* iobase may be set manually in range 0x300 - 0x33C
914 irq may be set manually to 2(9),3,4,5,6,7
915 dma may be set manually to 1,2,3
916 (How to detect them ???)
917BIOS address may be set manually in range 0x0 - 0xF8000
918If you need non-standard settings use the xd=... command */
919
920 switch (address) {
921 case 0x00000:
922 case 0xC8000: /* initially: xd_iobase==0x320 */
923 case 0xD0000:
924 case 0xD2000:
925 case 0xD4000:
926 case 0xD6000:
927 case 0xD8000:
928 case 0xDA000:
929 case 0xDC000:
930 case 0xDE000:
931 case 0xE0000: break;
932 default: printk("xd_xebec_init_controller: unsupported BIOS address %06x\n",address);
933 break;
934 }
935
936 xd_maxsectors = 0x01;
937 outb(0,XD_RESET); /* reset the controller */
938
939 set_current_state(TASK_UNINTERRUPTIBLE);
940 schedule_timeout(XD_INIT_DISK_DELAY);
941}
942
943static void __init xd_xebec_init_drive (u_char drive)
944{
945 /* values from controller's BIOS - BIOS chip may be removed */
946 static u_short geometry_table[][5] = {
947 {0x132,4,0x080,0x080,0x7},
948 {0x132,4,0x080,0x080,0x17},
949 {0x264,2,0x100,0x100,0x7},
950 {0x264,2,0x100,0x100,0x17},
951 {0x132,8,0x080,0x080,0x7},
952 {0x132,8,0x080,0x080,0x17},
953 {0x264,4,0x100,0x100,0x6},
954 {0x264,4,0x100,0x100,0x17},
955 {0x2BC,5,0x2BC,0x12C,0x6},
956 {0x3A5,4,0x3A5,0x3A5,0x7},
957 {0x26C,6,0x26C,0x26C,0x7},
958 {0x200,8,0x200,0x100,0x17},
959 {0x400,5,0x400,0x400,0x7},
960 {0x400,6,0x400,0x400,0x7},
961 {0x264,8,0x264,0x200,0x17},
962 {0x33E,7,0x33E,0x200,0x7}};
963 u_char n;
964
965 n = inb(XD_JUMPER) & 0x0F; /* BIOS's drive number: same geometry
966 is assumed for BOTH drives */
967 if (xd_geo[3*drive])
968 xd_manual_geo_set(drive);
969 else {
970 xd_info[drive].heads = (u_char)(geometry_table[n][1]); /* heads */
971 xd_info[drive].cylinders = geometry_table[n][0]; /* cylinders */
972 xd_info[drive].sectors = 17; /* sectors */
973#if 0
974 xd_info[drive].rwrite = geometry_table[n][2]; /* reduced write */
975 xd_info[drive].precomp = geometry_table[n][3] /* write precomp */
976 xd_info[drive].ecc = 0x0B; /* ecc length */
977#endif /* 0 */
978 }
979 xd_info[drive].control = geometry_table[n][4]; /* control byte */
980 xd_setparam(CMD_XBSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B);
981 xd_recalibrate(drive);
982}
983
984/* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
985 etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
986static void __init xd_override_init_drive (u_char drive)
987{
988 u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
989 u_char cmdblk[6],i;
990
991 if (xd_geo[3*drive])
992 xd_manual_geo_set(drive);
993 else {
994 for (i = 0; i < 3; i++) {
995 while (min[i] != max[i] - 1) {
996 test[i] = (min[i] + max[i]) / 2;
997 xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0);
998 if (!xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 2))
999 min[i] = test[i];
1000 else
1001 max[i] = test[i];
1002 }
1003 test[i] = min[i];
1004 }
1005 xd_info[drive].heads = (u_char) min[0] + 1;
1006 xd_info[drive].cylinders = (u_short) min[1] + 1;
1007 xd_info[drive].sectors = (u_char) min[2] + 1;
1008 }
1009 xd_info[drive].control = 0;
1010}
1011
1012/* xd_setup: initialise controller from command line parameters */
1013static void __init do_xd_setup (int *integers)
1014{
1015 switch (integers[0]) {
1016 case 4: if (integers[4] < 0)
1017 nodma = 1;
1018 else if (integers[4] < 8)
1019 xd_dma = integers[4];
1020 case 3: if ((integers[3] > 0) && (integers[3] <= 0x3FC))
1021 xd_iobase = integers[3];
1022 case 2: if ((integers[2] > 0) && (integers[2] < 16))
1023 xd_irq = integers[2];
1024 case 1: xd_override = 1;
1025 if ((integers[1] >= 0) && (integers[1] < (sizeof(xd_sigs) / sizeof(xd_sigs[0]))))
1026 xd_type = integers[1];
1027 case 0: break;
1028 default:printk("xd: too many parameters for xd\n");
1029 }
1030 xd_maxsectors = 0x01;
1031}
1032
1033/* xd_setparam: set the drive characteristics */
1034static 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)
1035{
1036 u_char cmdblk[14];
1037
1038 xd_build(cmdblk,command,drive,0,0,0,0,0);
1039 cmdblk[6] = (u_char) (cylinders >> 8) & 0x03;
1040 cmdblk[7] = (u_char) (cylinders & 0xFF);
1041 cmdblk[8] = heads & 0x1F;
1042 cmdblk[9] = (u_char) (rwrite >> 8) & 0x03;
1043 cmdblk[10] = (u_char) (rwrite & 0xFF);
1044 cmdblk[11] = (u_char) (wprecomp >> 8) & 0x03;
1045 cmdblk[12] = (u_char) (wprecomp & 0xFF);
1046 cmdblk[13] = ecc;
1047
1048 /* Some controllers require geometry info as data, not command */
1049
1050 if (xd_command(cmdblk,PIO_MODE,NULL,&cmdblk[6],NULL,XD_TIMEOUT * 2))
1051 printk("xd: error setting characteristics for xd%c\n", 'a'+drive);
1052}
1053
1054
1055#ifdef MODULE
1056
1057module_param_array(xd, int, NULL, 0);
1058module_param_array(xd_geo, int, NULL, 0);
1059module_param(nodma, bool, 0);
1060
1061MODULE_LICENSE("GPL");
1062
1063void cleanup_module(void)
1064{
1065 int i;
1066 unregister_blkdev(XT_DISK_MAJOR, "xd");
1067 for (i = 0; i < xd_drives; i++) {
1068 del_gendisk(xd_gendisk[i]);
1069 put_disk(xd_gendisk[i]);
1070 }
1071 blk_cleanup_queue(xd_queue);
1072 release_region(xd_iobase,4);
1073 if (xd_drives) {
1074 free_irq(xd_irq, NULL);
1075 free_dma(xd_dma);
1076 if (xd_dma_buffer)
1077 xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200);
1078 }
1079}
1080#else
1081
1082static int __init xd_setup (char *str)
1083{
1084 int ints[5];
1085 get_options (str, ARRAY_SIZE (ints), ints);
1086 do_xd_setup (ints);
1087 return 1;
1088}
1089
1090/* xd_manual_geo_init: initialise drive geometry from command line parameters
1091 (used only for WD drives) */
1092static int __init xd_manual_geo_init (char *str)
1093{
1094 int i, integers[1 + 3*XD_MAXDRIVES];
1095
1096 get_options (str, ARRAY_SIZE (integers), integers);
1097 if (integers[0]%3 != 0) {
1098 printk("xd: incorrect number of parameters for xd_geo\n");
1099 return 1;
1100 }
1101 for (i = 0; (i < integers[0]) && (i < 3*XD_MAXDRIVES); i++)
1102 xd_geo[i] = integers[i+1];
1103 return 1;
1104}
1105
1106__setup ("xd=", xd_setup);
1107__setup ("xd_geo=", xd_manual_geo_init);
1108
1109#endif /* MODULE */
1110
1111module_init(xd_init);
1112MODULE_ALIAS_BLOCKDEV_MAJOR(XT_DISK_MAJOR);