blob: ce2429219925597edddb597ed88c09ff37c48b75 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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>
Nishanth Aravamudanf6a2f342005-09-10 00:27:14 -070050#include <linux/delay.h>
Matthew Wilcox53d5ed62006-10-11 01:22:01 -070051#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#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 /* Initial value. may be overriden using
65 "nodma" module option */
Nishanth Aravamudanf6a2f342005-09-10 00:27:14 -070066#define XD_INIT_DISK_DELAY (30) /* 30 ms delay during disk initialization */
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
68/* Above may need to be increased if a problem with the 2nd drive detection
69 (ST11M controller) or resetting a controller (WD) appears */
70
71static XD_INFO xd_info[XD_MAXDRIVES];
72
73/* If you try this driver and find that your card is not detected by the driver at bootup, you need to add your BIOS
74 signature and details to the following list of signatures. A BIOS signature is a string embedded into the first
75 few bytes of your controller's on-board ROM BIOS. To find out what yours is, use something like MS-DOS's DEBUG
76 command. Run DEBUG, and then you can examine your BIOS signature with:
77
78 d xxxx:0000
79
80 where xxxx is the segment of your controller (like C800 or D000 or something). On the ASCII dump at the right, you should
81 be able to see a string mentioning the manufacturer's copyright etc. Add this string into the table below. The parameters
82 in the table are, in order:
83
84 offset ; this is the offset (in bytes) from the start of your ROM where the signature starts
85 signature ; this is the actual text of the signature
86 xd_?_init_controller ; this is the controller init routine used by your controller
87 xd_?_init_drive ; this is the drive init routine used by your controller
88
89 The controllers directly supported at the moment are: DTC 5150x, WD 1004A27X, ST11M/R and override. If your controller is
90 made by the same manufacturer as one of these, try using the same init routines as they do. If that doesn't work, your
91 best bet is to use the "override" routines. These routines use a "portable" method of getting the disk's geometry, and
92 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>.
93
94 NOTE: You can now specify your XT controller's parameters from the command line in the form xd=TYPE,IRQ,IO,DMA. The driver
95 should be able to detect your drive's geometry from this info. (eg: xd=0,5,0x320,3 is the "standard"). */
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" }, /* Pat Mackinlay, pat@it.com.au */
104 { 0x0008,"[BXD06 (C) DTC 17-MAY-1985]",xd_dtc_init_controller,xd_dtc5150cx_init_drive," DTC 5150CX" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */
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" }, /* Todd Fries, tfries@umr.edu */
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" }, /* Pat Mackinlay, pat@it.com.au */
107 { 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 */
108 { 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 */
109 { 0x0015,"SEAGATE ST11 BIOS REVISION",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Salvador Abreu, spa@fct.unl.pt */
110 { 0x0010,"ST11R BIOS",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Risto Kankkunen, risto.kankkunen@cs.helsinki.fi */
111 { 0x0010,"ST11 BIOS v1.7",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11R" }, /* Alan Hourihane, alanh@fairlite.demon.co.uk */
112 { 0x1000,"(c)Copyright 1987 SMS",xd_omti_init_controller,xd_omti_init_drive,"n OMTI 5520" }, /* Dirk Melchers, dirk@merlin.nbg.sub.org */
113 { 0x0006,"COPYRIGHT XEBEC (C) 1984",xd_xebec_init_controller,xd_xebec_init_drive," XEBEC" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */
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" }, /* jfree@sovereign.org */
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
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800131static int xd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
132
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133static struct block_device_operations xd_fops = {
134 .owner = THIS_MODULE,
Al Viro961846c2008-03-02 10:23:12 -0500135 .locked_ioctl = xd_ioctl,
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800136 .getgeo = xd_getgeo,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137};
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/* xd_init: register the block device number and set up pointer tables */
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');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 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 /* xd_maxsectors depends on controller - so set after detection */
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/* xd_detect: scan the possible BIOS ROM locations for the signature strings */
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
Tobias Klauser945f3902006-01-08 01:05:11 -0800281 for (i = 0; i < ARRAY_SIZE(xd_bases); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 void __iomem *p = ioremap(xd_bases[i], 0x2000);
283 if (!p)
284 continue;
Tobias Klauser945f3902006-01-08 01:05:11 -0800285 for (j = 1; j < ARRAY_SIZE(xd_sigs); j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 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/* do_xd_request: handle an incoming request */
Jens Axboe165125e2007-07-24 09:28:11 +0200301static void do_xd_request (struct request_queue * q)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302{
303 struct request *req;
304
305 if (xdc_busy)
306 return;
307
Tejun Heo9934c8c2009-05-08 11:54:16 +0900308 req = blk_fetch_request(q);
Tejun Heobab2a802009-05-08 11:54:10 +0900309 while (req) {
Tejun Heo83096eb2009-05-07 22:24:39 +0900310 unsigned block = blk_rq_pos(req);
Tejun Heobab2a802009-05-08 11:54:10 +0900311 unsigned count = blk_rq_cur_sectors(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 XD_INFO *disk = req->rq_disk->private_data;
Tejun Heobab2a802009-05-08 11:54:10 +0900313 int res = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 int retry;
315
Tejun Heobab2a802009-05-08 11:54:10 +0900316 if (!blk_fs_request(req))
317 goto done;
318 if (block + count > get_capacity(req->rq_disk))
319 goto done;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 for (retry = 0; (retry < XD_RETRIES) && !res; retry++)
Tejun Heo5b5c5d12009-04-28 13:06:06 +0900321 res = xd_readwrite(rq_data_dir(req), disk, req->buffer,
322 block, count);
Tejun Heobab2a802009-05-08 11:54:10 +0900323 done:
Tejun Heof06d9a22009-04-23 11:05:19 +0900324 /* wrap up, 0 = success, -errno = fail */
Tejun Heo9934c8c2009-05-08 11:54:16 +0900325 if (!__blk_end_request_cur(req, res))
326 req = blk_fetch_request(q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 }
328}
329
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800330static int xd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
331{
332 XD_INFO *p = bdev->bd_disk->private_data;
333
334 geo->heads = p->heads;
335 geo->sectors = p->sectors;
336 geo->cylinders = p->cylinders;
337 return 0;
338}
339
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340/* xd_ioctl: handle device ioctl's */
Al Viro961846c2008-03-02 10:23:12 -0500341static int xd_ioctl(struct block_device *bdev, fmode_t mode, u_int cmd, u_long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 case HDIO_SET_DMA:
345 if (!capable(CAP_SYS_ADMIN)) return -EACCES;
346 if (xdc_busy) return -EBUSY;
347 nodma = !arg;
348 if (nodma && xd_dma_buffer) {
349 xd_dma_mem_free((unsigned long)xd_dma_buffer,
350 xd_maxsectors * 0x200);
351 xd_dma_buffer = NULL;
352 } else if (!nodma && !xd_dma_buffer) {
353 xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
354 if (!xd_dma_buffer) {
355 nodma = XD_DONT_USE_DMA;
356 return -ENOMEM;
357 }
358 }
359 return 0;
360 case HDIO_GET_DMA:
361 return put_user(!nodma, (long __user *) arg);
362 case HDIO_GET_MULTCOUNT:
363 return put_user(xd_maxsectors, (long __user *) arg);
364 default:
365 return -EINVAL;
366 }
367}
368
369/* xd_readwrite: handle a read/write request */
370static int xd_readwrite (u_char operation,XD_INFO *p,char *buffer,u_int block,u_int count)
371{
372 int drive = p->unit;
373 u_char cmdblk[6],sense[4];
374 u_short track,cylinder;
375 u_char head,sector,control,mode = PIO_MODE,temp;
376 char **real_buffer;
377 register int i;
378
379#ifdef DEBUG_READWRITE
380 printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
381#endif /* DEBUG_READWRITE */
382
383 spin_unlock_irq(&xd_lock);
384
385 control = p->control;
386 if (!xd_dma_buffer)
387 xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
388 while (count) {
389 temp = count < xd_maxsectors ? count : xd_maxsectors;
390
391 track = block / p->sectors;
392 head = track % p->heads;
393 cylinder = track / p->heads;
394 sector = block % p->sectors;
395
396#ifdef DEBUG_READWRITE
397 printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
398#endif /* DEBUG_READWRITE */
399
400 if (xd_dma_buffer) {
401 mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)(xd_dma_buffer),temp * 0x200);
402 real_buffer = &xd_dma_buffer;
403 for (i=0; i < (temp * 0x200); i++)
404 xd_dma_buffer[i] = buffer[i];
405 }
406 else
407 real_buffer = &buffer;
408
409 xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control);
410
411 switch (xd_command(cmdblk,mode,(u_char *)(*real_buffer),(u_char *)(*real_buffer),sense,XD_TIMEOUT)) {
412 case 1:
413 printk("xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write"));
414 xd_recalibrate(drive);
415 spin_lock_irq(&xd_lock);
Tejun Heof06d9a22009-04-23 11:05:19 +0900416 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 case 2:
418 if (sense[0] & 0x30) {
419 printk("xd%c: %s - ",'a'+drive,(operation == READ ? "reading" : "writing"));
420 switch ((sense[0] & 0x30) >> 4) {
421 case 0: printk("drive error, code = 0x%X",sense[0] & 0x0F);
422 break;
423 case 1: printk("controller error, code = 0x%X",sense[0] & 0x0F);
424 break;
425 case 2: printk("command error, code = 0x%X",sense[0] & 0x0F);
426 break;
427 case 3: printk("miscellaneous error, code = 0x%X",sense[0] & 0x0F);
428 break;
429 }
430 }
431 if (sense[0] & 0x80)
432 printk(" - CHS = %d/%d/%d\n",((sense[2] & 0xC0) << 2) | sense[3],sense[1] & 0x1F,sense[2] & 0x3F);
433 /* reported drive number = (sense[1] & 0xE0) >> 5 */
434 else
435 printk(" - no valid disk address\n");
436 spin_lock_irq(&xd_lock);
Tejun Heof06d9a22009-04-23 11:05:19 +0900437 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 }
439 if (xd_dma_buffer)
440 for (i=0; i < (temp * 0x200); i++)
441 buffer[i] = xd_dma_buffer[i];
442
443 count -= temp, buffer += temp * 0x200, block += temp;
444 }
445 spin_lock_irq(&xd_lock);
Tejun Heof06d9a22009-04-23 11:05:19 +0900446 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447}
448
449/* xd_recalibrate: recalibrate a given drive and reset controller if necessary */
450static void xd_recalibrate (u_char drive)
451{
452 u_char cmdblk[6];
453
454 xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0);
455 if (xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 8))
456 printk("xd%c: warning! error recalibrating, controller may be unstable\n", 'a'+drive);
457}
458
459/* xd_interrupt_handler: interrupt service routine */
David Howells7d12e782006-10-05 14:55:46 +0100460static irqreturn_t xd_interrupt_handler(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461{
462 if (inb(XD_STATUS) & STAT_INTERRUPT) { /* check if it was our device */
463#ifdef DEBUG_OTHER
464 printk("xd_interrupt_handler: interrupt detected\n");
465#endif /* DEBUG_OTHER */
466 outb(0,XD_CONTROL); /* acknowledge interrupt */
467 wake_up(&xd_wait_int); /* and wake up sleeping processes */
468 return IRQ_HANDLED;
469 }
470 else
471 printk("xd: unexpected interrupt\n");
472 return IRQ_NONE;
473}
474
475/* xd_setup_dma: set up the DMA controller for a data transfer */
476static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
477{
478 unsigned long f;
479
480 if (nodma)
481 return (PIO_MODE);
482 if (((unsigned long) buffer & 0xFFFF0000) != (((unsigned long) buffer + count) & 0xFFFF0000)) {
483#ifdef DEBUG_OTHER
484 printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
485#endif /* DEBUG_OTHER */
486 return (PIO_MODE);
487 }
488
489 f=claim_dma_lock();
490 disable_dma(xd_dma);
491 clear_dma_ff(xd_dma);
492 set_dma_mode(xd_dma,mode);
493 set_dma_addr(xd_dma, (unsigned long) buffer);
494 set_dma_count(xd_dma,count);
495
496 release_dma_lock(f);
497
498 return (DMA_MODE); /* use DMA and INT */
499}
500
501/* xd_build: put stuff into an array in a format suitable for the controller */
502static 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)
503{
504 cmdblk[0] = command;
505 cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F);
506 cmdblk[2] = ((cylinder & 0x300) >> 2) | (sector & 0x3F);
507 cmdblk[3] = cylinder & 0xFF;
508 cmdblk[4] = count;
509 cmdblk[5] = control;
510
511 return (cmdblk);
512}
513
514static void xd_watchdog (unsigned long unused)
515{
516 xd_error = 1;
517 wake_up(&xd_wait_int);
518}
519
520/* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */
521static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout)
522{
523 u_long expiry = jiffies + timeout;
524 int success;
525
526 xdc_busy = 1;
Nishanth Aravamudan86e84862005-09-10 00:27:28 -0700527 while ((success = ((inb(port) & mask) != flags)) && time_before(jiffies, expiry))
528 schedule_timeout_uninterruptible(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 xdc_busy = 0;
530 return (success);
531}
532
533static inline u_int xd_wait_for_IRQ (void)
534{
535 unsigned long flags;
536 xd_watchdog_int.expires = jiffies + 8 * HZ;
537 add_timer(&xd_watchdog_int);
538
539 flags=claim_dma_lock();
540 enable_dma(xd_dma);
541 release_dma_lock(flags);
542
543 sleep_on(&xd_wait_int);
544 del_timer(&xd_watchdog_int);
545 xdc_busy = 0;
546
547 flags=claim_dma_lock();
548 disable_dma(xd_dma);
549 release_dma_lock(flags);
550
551 if (xd_error) {
552 printk("xd: missed IRQ - command aborted\n");
553 xd_error = 0;
554 return (1);
555 }
556 return (0);
557}
558
559/* xd_command: handle all data transfers necessary for a single command */
560static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout)
561{
562 u_char cmdblk[6],csb,complete = 0;
563
564#ifdef DEBUG_COMMAND
565 printk("xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
566#endif /* DEBUG_COMMAND */
567
568 outb(0,XD_SELECT);
569 outb(mode,XD_CONTROL);
570
571 if (xd_waitport(XD_STATUS,STAT_SELECT,STAT_SELECT,timeout))
572 return (1);
573
574 while (!complete) {
575 if (xd_waitport(XD_STATUS,STAT_READY,STAT_READY,timeout))
576 return (1);
577
578 switch (inb(XD_STATUS) & (STAT_COMMAND | STAT_INPUT)) {
579 case 0:
580 if (mode == DMA_MODE) {
581 if (xd_wait_for_IRQ())
582 return (1);
583 } else
584 outb(outdata ? *outdata++ : 0,XD_DATA);
585 break;
586 case STAT_INPUT:
587 if (mode == DMA_MODE) {
588 if (xd_wait_for_IRQ())
589 return (1);
590 } else
591 if (indata)
592 *indata++ = inb(XD_DATA);
593 else
594 inb(XD_DATA);
595 break;
596 case STAT_COMMAND:
597 outb(command ? *command++ : 0,XD_DATA);
598 break;
599 case STAT_COMMAND | STAT_INPUT:
600 complete = 1;
601 break;
602 }
603 }
604 csb = inb(XD_DATA);
605
606 if (xd_waitport(XD_STATUS,0,STAT_SELECT,timeout)) /* wait until deselected */
607 return (1);
608
609 if (csb & CSB_ERROR) { /* read sense data if error */
610 xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0);
611 if (xd_command(cmdblk,0,sense,NULL,NULL,XD_TIMEOUT))
612 printk("xd: warning! sense command failed!\n");
613 }
614
615#ifdef DEBUG_COMMAND
616 printk("xd_command: completed with csb = 0x%X\n",csb);
617#endif /* DEBUG_COMMAND */
618
619 return (csb & CSB_ERROR);
620}
621
622static u_char __init xd_initdrives (void (*init_drive)(u_char drive))
623{
624 u_char cmdblk[6],i,count = 0;
625
626 for (i = 0; i < XD_MAXDRIVES; i++) {
627 xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0);
628 if (!xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT*8)) {
Nishanth Aravamudanf6a2f342005-09-10 00:27:14 -0700629 msleep_interruptible(XD_INIT_DISK_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630
631 init_drive(count);
632 count++;
633
Nishanth Aravamudanf6a2f342005-09-10 00:27:14 -0700634 msleep_interruptible(XD_INIT_DISK_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 }
636 }
637 return (count);
638}
639
640static void __init xd_manual_geo_set (u_char drive)
641{
642 xd_info[drive].heads = (u_char)(xd_geo[3 * drive + 1]);
643 xd_info[drive].cylinders = (u_short)(xd_geo[3 * drive]);
644 xd_info[drive].sectors = (u_char)(xd_geo[3 * drive + 2]);
645}
646
647static void __init xd_dtc_init_controller (unsigned int address)
648{
649 switch (address) {
650 case 0x00000:
651 case 0xC8000: break; /*initial: 0x320 */
652 case 0xCA000: xd_iobase = 0x324;
653 case 0xD0000: /*5150CX*/
654 case 0xD8000: break; /*5150CX & 5150XL*/
655 default: printk("xd_dtc_init_controller: unsupported BIOS address %06x\n",address);
656 break;
657 }
658 xd_maxsectors = 0x01; /* my card seems to have trouble doing multi-block transfers? */
659
660 outb(0,XD_RESET); /* reset the controller */
661}
662
663
664static void __init xd_dtc5150cx_init_drive (u_char drive)
665{
666 /* values from controller's BIOS - BIOS chip may be removed */
667 static u_short geometry_table[][4] = {
668 {0x200,8,0x200,0x100},
669 {0x267,2,0x267,0x267},
670 {0x264,4,0x264,0x80},
671 {0x132,4,0x132,0x0},
672 {0x132,2,0x80, 0x132},
673 {0x177,8,0x177,0x0},
674 {0x132,8,0x84, 0x0},
675 {}, /* not used */
676 {0x132,6,0x80, 0x100},
677 {0x200,6,0x100,0x100},
678 {0x264,2,0x264,0x80},
679 {0x280,4,0x280,0x100},
680 {0x2B9,3,0x2B9,0x2B9},
681 {0x2B9,5,0x2B9,0x2B9},
682 {0x280,6,0x280,0x100},
683 {0x132,4,0x132,0x0}};
684 u_char n;
685
686 n = inb(XD_JUMPER);
687 n = (drive ? n : (n >> 2)) & 0x33;
688 n = (n | (n >> 2)) & 0x0F;
689 if (xd_geo[3*drive])
690 xd_manual_geo_set(drive);
691 else
692 if (n != 7) {
693 xd_info[drive].heads = (u_char)(geometry_table[n][1]); /* heads */
694 xd_info[drive].cylinders = geometry_table[n][0]; /* cylinders */
695 xd_info[drive].sectors = 17; /* sectors */
696#if 0
697 xd_info[drive].rwrite = geometry_table[n][2]; /* reduced write */
698 xd_info[drive].precomp = geometry_table[n][3] /* write precomp */
699 xd_info[drive].ecc = 0x0B; /* ecc length */
700#endif /* 0 */
701 }
702 else {
703 printk("xd%c: undetermined drive geometry\n",'a'+drive);
704 return;
705 }
706 xd_info[drive].control = 5; /* control byte */
707 xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B);
708 xd_recalibrate(drive);
709}
710
711static void __init xd_dtc_init_drive (u_char drive)
712{
713 u_char cmdblk[6],buf[64];
714
715 xd_build(cmdblk,CMD_DTCGETGEOM,drive,0,0,0,0,0);
716 if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) {
717 xd_info[drive].heads = buf[0x0A]; /* heads */
718 xd_info[drive].cylinders = ((u_short *) (buf))[0x04]; /* cylinders */
719 xd_info[drive].sectors = 17; /* sectors */
720 if (xd_geo[3*drive])
721 xd_manual_geo_set(drive);
722#if 0
723 xd_info[drive].rwrite = ((u_short *) (buf + 1))[0x05]; /* reduced write */
724 xd_info[drive].precomp = ((u_short *) (buf + 1))[0x06]; /* write precomp */
725 xd_info[drive].ecc = buf[0x0F]; /* ecc length */
726#endif /* 0 */
727 xd_info[drive].control = 0; /* control byte */
728
729 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]);
730 xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7);
731 if (xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 2))
732 printk("xd_dtc_init_drive: error setting step rate for xd%c\n", 'a'+drive);
733 }
734 else
735 printk("xd_dtc_init_drive: error reading geometry for xd%c\n", 'a'+drive);
736}
737
738static void __init xd_wd_init_controller (unsigned int address)
739{
740 switch (address) {
741 case 0x00000:
742 case 0xC8000: break; /*initial: 0x320 */
743 case 0xCA000: xd_iobase = 0x324; break;
744 case 0xCC000: xd_iobase = 0x328; break;
745 case 0xCE000: xd_iobase = 0x32C; break;
746 case 0xD0000: xd_iobase = 0x328; break; /* ? */
747 case 0xD8000: xd_iobase = 0x32C; break; /* ? */
748 default: printk("xd_wd_init_controller: unsupported BIOS address %06x\n",address);
749 break;
750 }
751 xd_maxsectors = 0x01; /* this one doesn't wrap properly either... */
752
753 outb(0,XD_RESET); /* reset the controller */
754
Nishanth Aravamudanf6a2f342005-09-10 00:27:14 -0700755 msleep(XD_INIT_DISK_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756}
757
758static void __init xd_wd_init_drive (u_char drive)
759{
760 /* values from controller's BIOS - BIOS may be disabled */
761 static u_short geometry_table[][4] = {
762 {0x264,4,0x1C2,0x1C2}, /* common part */
763 {0x132,4,0x099,0x0},
764 {0x267,2,0x1C2,0x1C2},
765 {0x267,4,0x1C2,0x1C2},
766
767 {0x334,6,0x335,0x335}, /* 1004 series RLL */
768 {0x30E,4,0x30F,0x3DC},
769 {0x30E,2,0x30F,0x30F},
770 {0x267,4,0x268,0x268},
771
772 {0x3D5,5,0x3D6,0x3D6}, /* 1002 series RLL */
773 {0x3DB,7,0x3DC,0x3DC},
774 {0x264,4,0x265,0x265},
775 {0x267,4,0x268,0x268}};
776
777 u_char cmdblk[6],buf[0x200];
778 u_char n = 0,rll,jumper_state,use_jumper_geo;
779 u_char wd_1002 = (xd_sigs[xd_type].string[7] == '6');
780
781 jumper_state = ~(inb(0x322));
782 if (jumper_state & 0x40)
783 xd_irq = 9;
784 rll = (jumper_state & 0x30) ? (0x04 << wd_1002) : 0;
785 xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0);
786 if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) {
787 xd_info[drive].heads = buf[0x1AF]; /* heads */
788 xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6]; /* cylinders */
789 xd_info[drive].sectors = 17; /* sectors */
790 if (xd_geo[3*drive])
791 xd_manual_geo_set(drive);
792#if 0
793 xd_info[drive].rwrite = ((u_short *) (buf))[0xD8]; /* reduced write */
794 xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA]; /* write precomp */
795 xd_info[drive].ecc = buf[0x1B4]; /* ecc length */
796#endif /* 0 */
797 xd_info[drive].control = buf[0x1B5]; /* control byte */
798 use_jumper_geo = !(xd_info[drive].heads) || !(xd_info[drive].cylinders);
799 if (xd_geo[3*drive]) {
800 xd_manual_geo_set(drive);
801 xd_info[drive].control = rll ? 7 : 5;
802 }
803 else if (use_jumper_geo) {
804 n = (((jumper_state & 0x0F) >> (drive << 1)) & 0x03) | rll;
805 xd_info[drive].cylinders = geometry_table[n][0];
806 xd_info[drive].heads = (u_char)(geometry_table[n][1]);
807 xd_info[drive].control = rll ? 7 : 5;
808#if 0
809 xd_info[drive].rwrite = geometry_table[n][2];
810 xd_info[drive].wprecomp = geometry_table[n][3];
811 xd_info[drive].ecc = 0x0B;
812#endif /* 0 */
813 }
814 if (!wd_1002) {
815 if (use_jumper_geo)
816 xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
817 geometry_table[n][2],geometry_table[n][3],0x0B);
818 else
819 xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
820 ((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
821 }
822 /* 1002 based RLL controller requests converted addressing, but reports physical
823 (physical 26 sec., logical 17 sec.)
824 1004 based ???? */
825 if (rll & wd_1002) {
826 if ((xd_info[drive].cylinders *= 26,
827 xd_info[drive].cylinders /= 17) > 1023)
828 xd_info[drive].cylinders = 1023; /* 1024 ? */
829#if 0
830 xd_info[drive].rwrite *= 26;
831 xd_info[drive].rwrite /= 17;
832 xd_info[drive].wprecomp *= 26
833 xd_info[drive].wprecomp /= 17;
834#endif /* 0 */
835 }
836 }
837 else
838 printk("xd_wd_init_drive: error reading geometry for xd%c\n",'a'+drive);
839
840}
841
842static void __init xd_seagate_init_controller (unsigned int address)
843{
844 switch (address) {
845 case 0x00000:
846 case 0xC8000: break; /*initial: 0x320 */
847 case 0xD0000: xd_iobase = 0x324; break;
848 case 0xD8000: xd_iobase = 0x328; break;
849 case 0xE0000: xd_iobase = 0x32C; break;
850 default: printk("xd_seagate_init_controller: unsupported BIOS address %06x\n",address);
851 break;
852 }
853 xd_maxsectors = 0x40;
854
855 outb(0,XD_RESET); /* reset the controller */
856}
857
858static void __init xd_seagate_init_drive (u_char drive)
859{
860 u_char cmdblk[6],buf[0x200];
861
862 xd_build(cmdblk,CMD_ST11GETGEOM,drive,0,0,0,1,0);
863 if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) {
864 xd_info[drive].heads = buf[0x04]; /* heads */
865 xd_info[drive].cylinders = (buf[0x02] << 8) | buf[0x03]; /* cylinders */
866 xd_info[drive].sectors = buf[0x05]; /* sectors */
867 xd_info[drive].control = 0; /* control byte */
868 }
869 else
870 printk("xd_seagate_init_drive: error reading geometry from xd%c\n", 'a'+drive);
871}
872
873/* Omti support courtesy Dirk Melchers */
874static void __init xd_omti_init_controller (unsigned int address)
875{
876 switch (address) {
877 case 0x00000:
878 case 0xC8000: break; /*initial: 0x320 */
879 case 0xD0000: xd_iobase = 0x324; break;
880 case 0xD8000: xd_iobase = 0x328; break;
881 case 0xE0000: xd_iobase = 0x32C; break;
882 default: printk("xd_omti_init_controller: unsupported BIOS address %06x\n",address);
883 break;
884 }
885
886 xd_maxsectors = 0x40;
887
888 outb(0,XD_RESET); /* reset the controller */
889}
890
891static void __init xd_omti_init_drive (u_char drive)
892{
893 /* gets infos from drive */
894 xd_override_init_drive(drive);
895
896 /* set other parameters, Hardcoded, not that nice :-) */
897 xd_info[drive].control = 2;
898}
899
900/* Xebec support (AK) */
901static void __init xd_xebec_init_controller (unsigned int address)
902{
903/* iobase may be set manually in range 0x300 - 0x33C
904 irq may be set manually to 2(9),3,4,5,6,7
905 dma may be set manually to 1,2,3
906 (How to detect them ???)
907BIOS address may be set manually in range 0x0 - 0xF8000
908If you need non-standard settings use the xd=... command */
909
910 switch (address) {
911 case 0x00000:
912 case 0xC8000: /* initially: xd_iobase==0x320 */
913 case 0xD0000:
914 case 0xD2000:
915 case 0xD4000:
916 case 0xD6000:
917 case 0xD8000:
918 case 0xDA000:
919 case 0xDC000:
920 case 0xDE000:
921 case 0xE0000: break;
922 default: printk("xd_xebec_init_controller: unsupported BIOS address %06x\n",address);
923 break;
924 }
925
926 xd_maxsectors = 0x01;
927 outb(0,XD_RESET); /* reset the controller */
928
Nishanth Aravamudanf6a2f342005-09-10 00:27:14 -0700929 msleep(XD_INIT_DISK_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930}
931
932static void __init xd_xebec_init_drive (u_char drive)
933{
934 /* values from controller's BIOS - BIOS chip may be removed */
935 static u_short geometry_table[][5] = {
936 {0x132,4,0x080,0x080,0x7},
937 {0x132,4,0x080,0x080,0x17},
938 {0x264,2,0x100,0x100,0x7},
939 {0x264,2,0x100,0x100,0x17},
940 {0x132,8,0x080,0x080,0x7},
941 {0x132,8,0x080,0x080,0x17},
942 {0x264,4,0x100,0x100,0x6},
943 {0x264,4,0x100,0x100,0x17},
944 {0x2BC,5,0x2BC,0x12C,0x6},
945 {0x3A5,4,0x3A5,0x3A5,0x7},
946 {0x26C,6,0x26C,0x26C,0x7},
947 {0x200,8,0x200,0x100,0x17},
948 {0x400,5,0x400,0x400,0x7},
949 {0x400,6,0x400,0x400,0x7},
950 {0x264,8,0x264,0x200,0x17},
951 {0x33E,7,0x33E,0x200,0x7}};
952 u_char n;
953
954 n = inb(XD_JUMPER) & 0x0F; /* BIOS's drive number: same geometry
955 is assumed for BOTH drives */
956 if (xd_geo[3*drive])
957 xd_manual_geo_set(drive);
958 else {
959 xd_info[drive].heads = (u_char)(geometry_table[n][1]); /* heads */
960 xd_info[drive].cylinders = geometry_table[n][0]; /* cylinders */
961 xd_info[drive].sectors = 17; /* sectors */
962#if 0
963 xd_info[drive].rwrite = geometry_table[n][2]; /* reduced write */
964 xd_info[drive].precomp = geometry_table[n][3] /* write precomp */
965 xd_info[drive].ecc = 0x0B; /* ecc length */
966#endif /* 0 */
967 }
968 xd_info[drive].control = geometry_table[n][4]; /* control byte */
969 xd_setparam(CMD_XBSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B);
970 xd_recalibrate(drive);
971}
972
973/* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
974 etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
975static void __init xd_override_init_drive (u_char drive)
976{
977 u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
978 u_char cmdblk[6],i;
979
980 if (xd_geo[3*drive])
981 xd_manual_geo_set(drive);
982 else {
983 for (i = 0; i < 3; i++) {
984 while (min[i] != max[i] - 1) {
985 test[i] = (min[i] + max[i]) / 2;
986 xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0);
987 if (!xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 2))
988 min[i] = test[i];
989 else
990 max[i] = test[i];
991 }
992 test[i] = min[i];
993 }
994 xd_info[drive].heads = (u_char) min[0] + 1;
995 xd_info[drive].cylinders = (u_short) min[1] + 1;
996 xd_info[drive].sectors = (u_char) min[2] + 1;
997 }
998 xd_info[drive].control = 0;
999}
1000
1001/* xd_setup: initialise controller from command line parameters */
1002static void __init do_xd_setup (int *integers)
1003{
1004 switch (integers[0]) {
1005 case 4: if (integers[4] < 0)
1006 nodma = 1;
1007 else if (integers[4] < 8)
1008 xd_dma = integers[4];
1009 case 3: if ((integers[3] > 0) && (integers[3] <= 0x3FC))
1010 xd_iobase = integers[3];
1011 case 2: if ((integers[2] > 0) && (integers[2] < 16))
1012 xd_irq = integers[2];
1013 case 1: xd_override = 1;
Tobias Klauser945f3902006-01-08 01:05:11 -08001014 if ((integers[1] >= 0) && (integers[1] < ARRAY_SIZE(xd_sigs)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 xd_type = integers[1];
1016 case 0: break;
1017 default:printk("xd: too many parameters for xd\n");
1018 }
1019 xd_maxsectors = 0x01;
1020}
1021
1022/* xd_setparam: set the drive characteristics */
1023static 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)
1024{
1025 u_char cmdblk[14];
1026
1027 xd_build(cmdblk,command,drive,0,0,0,0,0);
1028 cmdblk[6] = (u_char) (cylinders >> 8) & 0x03;
1029 cmdblk[7] = (u_char) (cylinders & 0xFF);
1030 cmdblk[8] = heads & 0x1F;
1031 cmdblk[9] = (u_char) (rwrite >> 8) & 0x03;
1032 cmdblk[10] = (u_char) (rwrite & 0xFF);
1033 cmdblk[11] = (u_char) (wprecomp >> 8) & 0x03;
1034 cmdblk[12] = (u_char) (wprecomp & 0xFF);
1035 cmdblk[13] = ecc;
1036
1037 /* Some controllers require geometry info as data, not command */
1038
1039 if (xd_command(cmdblk,PIO_MODE,NULL,&cmdblk[6],NULL,XD_TIMEOUT * 2))
1040 printk("xd: error setting characteristics for xd%c\n", 'a'+drive);
1041}
1042
1043
1044#ifdef MODULE
1045
1046module_param_array(xd, int, NULL, 0);
1047module_param_array(xd_geo, int, NULL, 0);
1048module_param(nodma, bool, 0);
1049
1050MODULE_LICENSE("GPL");
1051
1052void cleanup_module(void)
1053{
1054 int i;
1055 unregister_blkdev(XT_DISK_MAJOR, "xd");
1056 for (i = 0; i < xd_drives; i++) {
1057 del_gendisk(xd_gendisk[i]);
1058 put_disk(xd_gendisk[i]);
1059 }
1060 blk_cleanup_queue(xd_queue);
1061 release_region(xd_iobase,4);
1062 if (xd_drives) {
1063 free_irq(xd_irq, NULL);
1064 free_dma(xd_dma);
1065 if (xd_dma_buffer)
1066 xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200);
1067 }
1068}
1069#else
1070
1071static int __init xd_setup (char *str)
1072{
1073 int ints[5];
1074 get_options (str, ARRAY_SIZE (ints), ints);
1075 do_xd_setup (ints);
1076 return 1;
1077}
1078
1079/* xd_manual_geo_init: initialise drive geometry from command line parameters
1080 (used only for WD drives) */
1081static int __init xd_manual_geo_init (char *str)
1082{
1083 int i, integers[1 + 3*XD_MAXDRIVES];
1084
1085 get_options (str, ARRAY_SIZE (integers), integers);
1086 if (integers[0]%3 != 0) {
1087 printk("xd: incorrect number of parameters for xd_geo\n");
1088 return 1;
1089 }
1090 for (i = 0; (i < integers[0]) && (i < 3*XD_MAXDRIVES); i++)
1091 xd_geo[i] = integers[i+1];
1092 return 1;
1093}
1094
1095__setup ("xd=", xd_setup);
1096__setup ("xd_geo=", xd_manual_geo_init);
1097
1098#endif /* MODULE */
1099
1100module_init(xd_init);
1101MODULE_ALIAS_BLOCKDEV_MAJOR(XT_DISK_MAJOR);