blob: 14be4c1ed1aaf53b57c7f62f4010e9b888f116a7 [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
308 while ((req = elv_next_request(q)) != NULL) {
309 unsigned block = req->sector;
310 unsigned count = req->nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 XD_INFO *disk = req->rq_disk->private_data;
312 int res = 0;
313 int retry;
314
Jens Axboe4aff5e22006-08-10 08:44:47 +0200315 if (!blk_fs_request(req)) {
Tejun Heof06d9a22009-04-23 11:05:19 +0900316 __blk_end_request_cur(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 continue;
318 }
319 if (block + count > get_capacity(req->rq_disk)) {
Tejun Heof06d9a22009-04-23 11:05:19 +0900320 __blk_end_request_cur(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 continue;
322 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 for (retry = 0; (retry < XD_RETRIES) && !res; retry++)
Tejun Heo5b5c5d12009-04-28 13:06:06 +0900324 res = xd_readwrite(rq_data_dir(req), disk, req->buffer,
325 block, count);
Tejun Heof06d9a22009-04-23 11:05:19 +0900326 /* wrap up, 0 = success, -errno = fail */
327 __blk_end_request_cur(req, res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 }
329}
330
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800331static int xd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
332{
333 XD_INFO *p = bdev->bd_disk->private_data;
334
335 geo->heads = p->heads;
336 geo->sectors = p->sectors;
337 geo->cylinders = p->cylinders;
338 return 0;
339}
340
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341/* xd_ioctl: handle device ioctl's */
Al Viro961846c2008-03-02 10:23:12 -0500342static int xd_ioctl(struct block_device *bdev, fmode_t mode, u_int cmd, u_long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 case HDIO_SET_DMA:
346 if (!capable(CAP_SYS_ADMIN)) return -EACCES;
347 if (xdc_busy) return -EBUSY;
348 nodma = !arg;
349 if (nodma && xd_dma_buffer) {
350 xd_dma_mem_free((unsigned long)xd_dma_buffer,
351 xd_maxsectors * 0x200);
352 xd_dma_buffer = NULL;
353 } else if (!nodma && !xd_dma_buffer) {
354 xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
355 if (!xd_dma_buffer) {
356 nodma = XD_DONT_USE_DMA;
357 return -ENOMEM;
358 }
359 }
360 return 0;
361 case HDIO_GET_DMA:
362 return put_user(!nodma, (long __user *) arg);
363 case HDIO_GET_MULTCOUNT:
364 return put_user(xd_maxsectors, (long __user *) arg);
365 default:
366 return -EINVAL;
367 }
368}
369
370/* xd_readwrite: handle a read/write request */
371static int xd_readwrite (u_char operation,XD_INFO *p,char *buffer,u_int block,u_int count)
372{
373 int drive = p->unit;
374 u_char cmdblk[6],sense[4];
375 u_short track,cylinder;
376 u_char head,sector,control,mode = PIO_MODE,temp;
377 char **real_buffer;
378 register int i;
379
380#ifdef DEBUG_READWRITE
381 printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
382#endif /* DEBUG_READWRITE */
383
384 spin_unlock_irq(&xd_lock);
385
386 control = p->control;
387 if (!xd_dma_buffer)
388 xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
389 while (count) {
390 temp = count < xd_maxsectors ? count : xd_maxsectors;
391
392 track = block / p->sectors;
393 head = track % p->heads;
394 cylinder = track / p->heads;
395 sector = block % p->sectors;
396
397#ifdef DEBUG_READWRITE
398 printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
399#endif /* DEBUG_READWRITE */
400
401 if (xd_dma_buffer) {
402 mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)(xd_dma_buffer),temp * 0x200);
403 real_buffer = &xd_dma_buffer;
404 for (i=0; i < (temp * 0x200); i++)
405 xd_dma_buffer[i] = buffer[i];
406 }
407 else
408 real_buffer = &buffer;
409
410 xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control);
411
412 switch (xd_command(cmdblk,mode,(u_char *)(*real_buffer),(u_char *)(*real_buffer),sense,XD_TIMEOUT)) {
413 case 1:
414 printk("xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write"));
415 xd_recalibrate(drive);
416 spin_lock_irq(&xd_lock);
Tejun Heof06d9a22009-04-23 11:05:19 +0900417 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 case 2:
419 if (sense[0] & 0x30) {
420 printk("xd%c: %s - ",'a'+drive,(operation == READ ? "reading" : "writing"));
421 switch ((sense[0] & 0x30) >> 4) {
422 case 0: printk("drive error, code = 0x%X",sense[0] & 0x0F);
423 break;
424 case 1: printk("controller error, code = 0x%X",sense[0] & 0x0F);
425 break;
426 case 2: printk("command error, code = 0x%X",sense[0] & 0x0F);
427 break;
428 case 3: printk("miscellaneous error, code = 0x%X",sense[0] & 0x0F);
429 break;
430 }
431 }
432 if (sense[0] & 0x80)
433 printk(" - CHS = %d/%d/%d\n",((sense[2] & 0xC0) << 2) | sense[3],sense[1] & 0x1F,sense[2] & 0x3F);
434 /* reported drive number = (sense[1] & 0xE0) >> 5 */
435 else
436 printk(" - no valid disk address\n");
437 spin_lock_irq(&xd_lock);
Tejun Heof06d9a22009-04-23 11:05:19 +0900438 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 }
440 if (xd_dma_buffer)
441 for (i=0; i < (temp * 0x200); i++)
442 buffer[i] = xd_dma_buffer[i];
443
444 count -= temp, buffer += temp * 0x200, block += temp;
445 }
446 spin_lock_irq(&xd_lock);
Tejun Heof06d9a22009-04-23 11:05:19 +0900447 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448}
449
450/* xd_recalibrate: recalibrate a given drive and reset controller if necessary */
451static void xd_recalibrate (u_char drive)
452{
453 u_char cmdblk[6];
454
455 xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0);
456 if (xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 8))
457 printk("xd%c: warning! error recalibrating, controller may be unstable\n", 'a'+drive);
458}
459
460/* xd_interrupt_handler: interrupt service routine */
David Howells7d12e782006-10-05 14:55:46 +0100461static irqreturn_t xd_interrupt_handler(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462{
463 if (inb(XD_STATUS) & STAT_INTERRUPT) { /* check if it was our device */
464#ifdef DEBUG_OTHER
465 printk("xd_interrupt_handler: interrupt detected\n");
466#endif /* DEBUG_OTHER */
467 outb(0,XD_CONTROL); /* acknowledge interrupt */
468 wake_up(&xd_wait_int); /* and wake up sleeping processes */
469 return IRQ_HANDLED;
470 }
471 else
472 printk("xd: unexpected interrupt\n");
473 return IRQ_NONE;
474}
475
476/* xd_setup_dma: set up the DMA controller for a data transfer */
477static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
478{
479 unsigned long f;
480
481 if (nodma)
482 return (PIO_MODE);
483 if (((unsigned long) buffer & 0xFFFF0000) != (((unsigned long) buffer + count) & 0xFFFF0000)) {
484#ifdef DEBUG_OTHER
485 printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
486#endif /* DEBUG_OTHER */
487 return (PIO_MODE);
488 }
489
490 f=claim_dma_lock();
491 disable_dma(xd_dma);
492 clear_dma_ff(xd_dma);
493 set_dma_mode(xd_dma,mode);
494 set_dma_addr(xd_dma, (unsigned long) buffer);
495 set_dma_count(xd_dma,count);
496
497 release_dma_lock(f);
498
499 return (DMA_MODE); /* use DMA and INT */
500}
501
502/* xd_build: put stuff into an array in a format suitable for the controller */
503static 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)
504{
505 cmdblk[0] = command;
506 cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F);
507 cmdblk[2] = ((cylinder & 0x300) >> 2) | (sector & 0x3F);
508 cmdblk[3] = cylinder & 0xFF;
509 cmdblk[4] = count;
510 cmdblk[5] = control;
511
512 return (cmdblk);
513}
514
515static void xd_watchdog (unsigned long unused)
516{
517 xd_error = 1;
518 wake_up(&xd_wait_int);
519}
520
521/* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */
522static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout)
523{
524 u_long expiry = jiffies + timeout;
525 int success;
526
527 xdc_busy = 1;
Nishanth Aravamudan86e84862005-09-10 00:27:28 -0700528 while ((success = ((inb(port) & mask) != flags)) && time_before(jiffies, expiry))
529 schedule_timeout_uninterruptible(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 xdc_busy = 0;
531 return (success);
532}
533
534static inline u_int xd_wait_for_IRQ (void)
535{
536 unsigned long flags;
537 xd_watchdog_int.expires = jiffies + 8 * HZ;
538 add_timer(&xd_watchdog_int);
539
540 flags=claim_dma_lock();
541 enable_dma(xd_dma);
542 release_dma_lock(flags);
543
544 sleep_on(&xd_wait_int);
545 del_timer(&xd_watchdog_int);
546 xdc_busy = 0;
547
548 flags=claim_dma_lock();
549 disable_dma(xd_dma);
550 release_dma_lock(flags);
551
552 if (xd_error) {
553 printk("xd: missed IRQ - command aborted\n");
554 xd_error = 0;
555 return (1);
556 }
557 return (0);
558}
559
560/* xd_command: handle all data transfers necessary for a single command */
561static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout)
562{
563 u_char cmdblk[6],csb,complete = 0;
564
565#ifdef DEBUG_COMMAND
566 printk("xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
567#endif /* DEBUG_COMMAND */
568
569 outb(0,XD_SELECT);
570 outb(mode,XD_CONTROL);
571
572 if (xd_waitport(XD_STATUS,STAT_SELECT,STAT_SELECT,timeout))
573 return (1);
574
575 while (!complete) {
576 if (xd_waitport(XD_STATUS,STAT_READY,STAT_READY,timeout))
577 return (1);
578
579 switch (inb(XD_STATUS) & (STAT_COMMAND | STAT_INPUT)) {
580 case 0:
581 if (mode == DMA_MODE) {
582 if (xd_wait_for_IRQ())
583 return (1);
584 } else
585 outb(outdata ? *outdata++ : 0,XD_DATA);
586 break;
587 case STAT_INPUT:
588 if (mode == DMA_MODE) {
589 if (xd_wait_for_IRQ())
590 return (1);
591 } else
592 if (indata)
593 *indata++ = inb(XD_DATA);
594 else
595 inb(XD_DATA);
596 break;
597 case STAT_COMMAND:
598 outb(command ? *command++ : 0,XD_DATA);
599 break;
600 case STAT_COMMAND | STAT_INPUT:
601 complete = 1;
602 break;
603 }
604 }
605 csb = inb(XD_DATA);
606
607 if (xd_waitport(XD_STATUS,0,STAT_SELECT,timeout)) /* wait until deselected */
608 return (1);
609
610 if (csb & CSB_ERROR) { /* read sense data if error */
611 xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0);
612 if (xd_command(cmdblk,0,sense,NULL,NULL,XD_TIMEOUT))
613 printk("xd: warning! sense command failed!\n");
614 }
615
616#ifdef DEBUG_COMMAND
617 printk("xd_command: completed with csb = 0x%X\n",csb);
618#endif /* DEBUG_COMMAND */
619
620 return (csb & CSB_ERROR);
621}
622
623static u_char __init xd_initdrives (void (*init_drive)(u_char drive))
624{
625 u_char cmdblk[6],i,count = 0;
626
627 for (i = 0; i < XD_MAXDRIVES; i++) {
628 xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0);
629 if (!xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT*8)) {
Nishanth Aravamudanf6a2f342005-09-10 00:27:14 -0700630 msleep_interruptible(XD_INIT_DISK_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
632 init_drive(count);
633 count++;
634
Nishanth Aravamudanf6a2f342005-09-10 00:27:14 -0700635 msleep_interruptible(XD_INIT_DISK_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 }
637 }
638 return (count);
639}
640
641static void __init xd_manual_geo_set (u_char drive)
642{
643 xd_info[drive].heads = (u_char)(xd_geo[3 * drive + 1]);
644 xd_info[drive].cylinders = (u_short)(xd_geo[3 * drive]);
645 xd_info[drive].sectors = (u_char)(xd_geo[3 * drive + 2]);
646}
647
648static void __init xd_dtc_init_controller (unsigned int address)
649{
650 switch (address) {
651 case 0x00000:
652 case 0xC8000: break; /*initial: 0x320 */
653 case 0xCA000: xd_iobase = 0x324;
654 case 0xD0000: /*5150CX*/
655 case 0xD8000: break; /*5150CX & 5150XL*/
656 default: printk("xd_dtc_init_controller: unsupported BIOS address %06x\n",address);
657 break;
658 }
659 xd_maxsectors = 0x01; /* my card seems to have trouble doing multi-block transfers? */
660
661 outb(0,XD_RESET); /* reset the controller */
662}
663
664
665static void __init xd_dtc5150cx_init_drive (u_char drive)
666{
667 /* values from controller's BIOS - BIOS chip may be removed */
668 static u_short geometry_table[][4] = {
669 {0x200,8,0x200,0x100},
670 {0x267,2,0x267,0x267},
671 {0x264,4,0x264,0x80},
672 {0x132,4,0x132,0x0},
673 {0x132,2,0x80, 0x132},
674 {0x177,8,0x177,0x0},
675 {0x132,8,0x84, 0x0},
676 {}, /* not used */
677 {0x132,6,0x80, 0x100},
678 {0x200,6,0x100,0x100},
679 {0x264,2,0x264,0x80},
680 {0x280,4,0x280,0x100},
681 {0x2B9,3,0x2B9,0x2B9},
682 {0x2B9,5,0x2B9,0x2B9},
683 {0x280,6,0x280,0x100},
684 {0x132,4,0x132,0x0}};
685 u_char n;
686
687 n = inb(XD_JUMPER);
688 n = (drive ? n : (n >> 2)) & 0x33;
689 n = (n | (n >> 2)) & 0x0F;
690 if (xd_geo[3*drive])
691 xd_manual_geo_set(drive);
692 else
693 if (n != 7) {
694 xd_info[drive].heads = (u_char)(geometry_table[n][1]); /* heads */
695 xd_info[drive].cylinders = geometry_table[n][0]; /* cylinders */
696 xd_info[drive].sectors = 17; /* sectors */
697#if 0
698 xd_info[drive].rwrite = geometry_table[n][2]; /* reduced write */
699 xd_info[drive].precomp = geometry_table[n][3] /* write precomp */
700 xd_info[drive].ecc = 0x0B; /* ecc length */
701#endif /* 0 */
702 }
703 else {
704 printk("xd%c: undetermined drive geometry\n",'a'+drive);
705 return;
706 }
707 xd_info[drive].control = 5; /* control byte */
708 xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B);
709 xd_recalibrate(drive);
710}
711
712static void __init xd_dtc_init_drive (u_char drive)
713{
714 u_char cmdblk[6],buf[64];
715
716 xd_build(cmdblk,CMD_DTCGETGEOM,drive,0,0,0,0,0);
717 if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) {
718 xd_info[drive].heads = buf[0x0A]; /* heads */
719 xd_info[drive].cylinders = ((u_short *) (buf))[0x04]; /* cylinders */
720 xd_info[drive].sectors = 17; /* sectors */
721 if (xd_geo[3*drive])
722 xd_manual_geo_set(drive);
723#if 0
724 xd_info[drive].rwrite = ((u_short *) (buf + 1))[0x05]; /* reduced write */
725 xd_info[drive].precomp = ((u_short *) (buf + 1))[0x06]; /* write precomp */
726 xd_info[drive].ecc = buf[0x0F]; /* ecc length */
727#endif /* 0 */
728 xd_info[drive].control = 0; /* control byte */
729
730 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]);
731 xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7);
732 if (xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 2))
733 printk("xd_dtc_init_drive: error setting step rate for xd%c\n", 'a'+drive);
734 }
735 else
736 printk("xd_dtc_init_drive: error reading geometry for xd%c\n", 'a'+drive);
737}
738
739static void __init xd_wd_init_controller (unsigned int address)
740{
741 switch (address) {
742 case 0x00000:
743 case 0xC8000: break; /*initial: 0x320 */
744 case 0xCA000: xd_iobase = 0x324; break;
745 case 0xCC000: xd_iobase = 0x328; break;
746 case 0xCE000: xd_iobase = 0x32C; break;
747 case 0xD0000: xd_iobase = 0x328; break; /* ? */
748 case 0xD8000: xd_iobase = 0x32C; break; /* ? */
749 default: printk("xd_wd_init_controller: unsupported BIOS address %06x\n",address);
750 break;
751 }
752 xd_maxsectors = 0x01; /* this one doesn't wrap properly either... */
753
754 outb(0,XD_RESET); /* reset the controller */
755
Nishanth Aravamudanf6a2f342005-09-10 00:27:14 -0700756 msleep(XD_INIT_DISK_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757}
758
759static void __init xd_wd_init_drive (u_char drive)
760{
761 /* values from controller's BIOS - BIOS may be disabled */
762 static u_short geometry_table[][4] = {
763 {0x264,4,0x1C2,0x1C2}, /* common part */
764 {0x132,4,0x099,0x0},
765 {0x267,2,0x1C2,0x1C2},
766 {0x267,4,0x1C2,0x1C2},
767
768 {0x334,6,0x335,0x335}, /* 1004 series RLL */
769 {0x30E,4,0x30F,0x3DC},
770 {0x30E,2,0x30F,0x30F},
771 {0x267,4,0x268,0x268},
772
773 {0x3D5,5,0x3D6,0x3D6}, /* 1002 series RLL */
774 {0x3DB,7,0x3DC,0x3DC},
775 {0x264,4,0x265,0x265},
776 {0x267,4,0x268,0x268}};
777
778 u_char cmdblk[6],buf[0x200];
779 u_char n = 0,rll,jumper_state,use_jumper_geo;
780 u_char wd_1002 = (xd_sigs[xd_type].string[7] == '6');
781
782 jumper_state = ~(inb(0x322));
783 if (jumper_state & 0x40)
784 xd_irq = 9;
785 rll = (jumper_state & 0x30) ? (0x04 << wd_1002) : 0;
786 xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0);
787 if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) {
788 xd_info[drive].heads = buf[0x1AF]; /* heads */
789 xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6]; /* cylinders */
790 xd_info[drive].sectors = 17; /* sectors */
791 if (xd_geo[3*drive])
792 xd_manual_geo_set(drive);
793#if 0
794 xd_info[drive].rwrite = ((u_short *) (buf))[0xD8]; /* reduced write */
795 xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA]; /* write precomp */
796 xd_info[drive].ecc = buf[0x1B4]; /* ecc length */
797#endif /* 0 */
798 xd_info[drive].control = buf[0x1B5]; /* control byte */
799 use_jumper_geo = !(xd_info[drive].heads) || !(xd_info[drive].cylinders);
800 if (xd_geo[3*drive]) {
801 xd_manual_geo_set(drive);
802 xd_info[drive].control = rll ? 7 : 5;
803 }
804 else if (use_jumper_geo) {
805 n = (((jumper_state & 0x0F) >> (drive << 1)) & 0x03) | rll;
806 xd_info[drive].cylinders = geometry_table[n][0];
807 xd_info[drive].heads = (u_char)(geometry_table[n][1]);
808 xd_info[drive].control = rll ? 7 : 5;
809#if 0
810 xd_info[drive].rwrite = geometry_table[n][2];
811 xd_info[drive].wprecomp = geometry_table[n][3];
812 xd_info[drive].ecc = 0x0B;
813#endif /* 0 */
814 }
815 if (!wd_1002) {
816 if (use_jumper_geo)
817 xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
818 geometry_table[n][2],geometry_table[n][3],0x0B);
819 else
820 xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
821 ((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
822 }
823 /* 1002 based RLL controller requests converted addressing, but reports physical
824 (physical 26 sec., logical 17 sec.)
825 1004 based ???? */
826 if (rll & wd_1002) {
827 if ((xd_info[drive].cylinders *= 26,
828 xd_info[drive].cylinders /= 17) > 1023)
829 xd_info[drive].cylinders = 1023; /* 1024 ? */
830#if 0
831 xd_info[drive].rwrite *= 26;
832 xd_info[drive].rwrite /= 17;
833 xd_info[drive].wprecomp *= 26
834 xd_info[drive].wprecomp /= 17;
835#endif /* 0 */
836 }
837 }
838 else
839 printk("xd_wd_init_drive: error reading geometry for xd%c\n",'a'+drive);
840
841}
842
843static void __init xd_seagate_init_controller (unsigned int address)
844{
845 switch (address) {
846 case 0x00000:
847 case 0xC8000: break; /*initial: 0x320 */
848 case 0xD0000: xd_iobase = 0x324; break;
849 case 0xD8000: xd_iobase = 0x328; break;
850 case 0xE0000: xd_iobase = 0x32C; break;
851 default: printk("xd_seagate_init_controller: unsupported BIOS address %06x\n",address);
852 break;
853 }
854 xd_maxsectors = 0x40;
855
856 outb(0,XD_RESET); /* reset the controller */
857}
858
859static void __init xd_seagate_init_drive (u_char drive)
860{
861 u_char cmdblk[6],buf[0x200];
862
863 xd_build(cmdblk,CMD_ST11GETGEOM,drive,0,0,0,1,0);
864 if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) {
865 xd_info[drive].heads = buf[0x04]; /* heads */
866 xd_info[drive].cylinders = (buf[0x02] << 8) | buf[0x03]; /* cylinders */
867 xd_info[drive].sectors = buf[0x05]; /* sectors */
868 xd_info[drive].control = 0; /* control byte */
869 }
870 else
871 printk("xd_seagate_init_drive: error reading geometry from xd%c\n", 'a'+drive);
872}
873
874/* Omti support courtesy Dirk Melchers */
875static void __init xd_omti_init_controller (unsigned int address)
876{
877 switch (address) {
878 case 0x00000:
879 case 0xC8000: break; /*initial: 0x320 */
880 case 0xD0000: xd_iobase = 0x324; break;
881 case 0xD8000: xd_iobase = 0x328; break;
882 case 0xE0000: xd_iobase = 0x32C; break;
883 default: printk("xd_omti_init_controller: unsupported BIOS address %06x\n",address);
884 break;
885 }
886
887 xd_maxsectors = 0x40;
888
889 outb(0,XD_RESET); /* reset the controller */
890}
891
892static void __init xd_omti_init_drive (u_char drive)
893{
894 /* gets infos from drive */
895 xd_override_init_drive(drive);
896
897 /* set other parameters, Hardcoded, not that nice :-) */
898 xd_info[drive].control = 2;
899}
900
901/* Xebec support (AK) */
902static void __init xd_xebec_init_controller (unsigned int address)
903{
904/* iobase may be set manually in range 0x300 - 0x33C
905 irq may be set manually to 2(9),3,4,5,6,7
906 dma may be set manually to 1,2,3
907 (How to detect them ???)
908BIOS address may be set manually in range 0x0 - 0xF8000
909If you need non-standard settings use the xd=... command */
910
911 switch (address) {
912 case 0x00000:
913 case 0xC8000: /* initially: xd_iobase==0x320 */
914 case 0xD0000:
915 case 0xD2000:
916 case 0xD4000:
917 case 0xD6000:
918 case 0xD8000:
919 case 0xDA000:
920 case 0xDC000:
921 case 0xDE000:
922 case 0xE0000: break;
923 default: printk("xd_xebec_init_controller: unsupported BIOS address %06x\n",address);
924 break;
925 }
926
927 xd_maxsectors = 0x01;
928 outb(0,XD_RESET); /* reset the controller */
929
Nishanth Aravamudanf6a2f342005-09-10 00:27:14 -0700930 msleep(XD_INIT_DISK_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931}
932
933static void __init xd_xebec_init_drive (u_char drive)
934{
935 /* values from controller's BIOS - BIOS chip may be removed */
936 static u_short geometry_table[][5] = {
937 {0x132,4,0x080,0x080,0x7},
938 {0x132,4,0x080,0x080,0x17},
939 {0x264,2,0x100,0x100,0x7},
940 {0x264,2,0x100,0x100,0x17},
941 {0x132,8,0x080,0x080,0x7},
942 {0x132,8,0x080,0x080,0x17},
943 {0x264,4,0x100,0x100,0x6},
944 {0x264,4,0x100,0x100,0x17},
945 {0x2BC,5,0x2BC,0x12C,0x6},
946 {0x3A5,4,0x3A5,0x3A5,0x7},
947 {0x26C,6,0x26C,0x26C,0x7},
948 {0x200,8,0x200,0x100,0x17},
949 {0x400,5,0x400,0x400,0x7},
950 {0x400,6,0x400,0x400,0x7},
951 {0x264,8,0x264,0x200,0x17},
952 {0x33E,7,0x33E,0x200,0x7}};
953 u_char n;
954
955 n = inb(XD_JUMPER) & 0x0F; /* BIOS's drive number: same geometry
956 is assumed for BOTH drives */
957 if (xd_geo[3*drive])
958 xd_manual_geo_set(drive);
959 else {
960 xd_info[drive].heads = (u_char)(geometry_table[n][1]); /* heads */
961 xd_info[drive].cylinders = geometry_table[n][0]; /* cylinders */
962 xd_info[drive].sectors = 17; /* sectors */
963#if 0
964 xd_info[drive].rwrite = geometry_table[n][2]; /* reduced write */
965 xd_info[drive].precomp = geometry_table[n][3] /* write precomp */
966 xd_info[drive].ecc = 0x0B; /* ecc length */
967#endif /* 0 */
968 }
969 xd_info[drive].control = geometry_table[n][4]; /* control byte */
970 xd_setparam(CMD_XBSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B);
971 xd_recalibrate(drive);
972}
973
974/* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
975 etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
976static void __init xd_override_init_drive (u_char drive)
977{
978 u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
979 u_char cmdblk[6],i;
980
981 if (xd_geo[3*drive])
982 xd_manual_geo_set(drive);
983 else {
984 for (i = 0; i < 3; i++) {
985 while (min[i] != max[i] - 1) {
986 test[i] = (min[i] + max[i]) / 2;
987 xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0);
988 if (!xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 2))
989 min[i] = test[i];
990 else
991 max[i] = test[i];
992 }
993 test[i] = min[i];
994 }
995 xd_info[drive].heads = (u_char) min[0] + 1;
996 xd_info[drive].cylinders = (u_short) min[1] + 1;
997 xd_info[drive].sectors = (u_char) min[2] + 1;
998 }
999 xd_info[drive].control = 0;
1000}
1001
1002/* xd_setup: initialise controller from command line parameters */
1003static void __init do_xd_setup (int *integers)
1004{
1005 switch (integers[0]) {
1006 case 4: if (integers[4] < 0)
1007 nodma = 1;
1008 else if (integers[4] < 8)
1009 xd_dma = integers[4];
1010 case 3: if ((integers[3] > 0) && (integers[3] <= 0x3FC))
1011 xd_iobase = integers[3];
1012 case 2: if ((integers[2] > 0) && (integers[2] < 16))
1013 xd_irq = integers[2];
1014 case 1: xd_override = 1;
Tobias Klauser945f3902006-01-08 01:05:11 -08001015 if ((integers[1] >= 0) && (integers[1] < ARRAY_SIZE(xd_sigs)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 xd_type = integers[1];
1017 case 0: break;
1018 default:printk("xd: too many parameters for xd\n");
1019 }
1020 xd_maxsectors = 0x01;
1021}
1022
1023/* xd_setparam: set the drive characteristics */
1024static 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)
1025{
1026 u_char cmdblk[14];
1027
1028 xd_build(cmdblk,command,drive,0,0,0,0,0);
1029 cmdblk[6] = (u_char) (cylinders >> 8) & 0x03;
1030 cmdblk[7] = (u_char) (cylinders & 0xFF);
1031 cmdblk[8] = heads & 0x1F;
1032 cmdblk[9] = (u_char) (rwrite >> 8) & 0x03;
1033 cmdblk[10] = (u_char) (rwrite & 0xFF);
1034 cmdblk[11] = (u_char) (wprecomp >> 8) & 0x03;
1035 cmdblk[12] = (u_char) (wprecomp & 0xFF);
1036 cmdblk[13] = ecc;
1037
1038 /* Some controllers require geometry info as data, not command */
1039
1040 if (xd_command(cmdblk,PIO_MODE,NULL,&cmdblk[6],NULL,XD_TIMEOUT * 2))
1041 printk("xd: error setting characteristics for xd%c\n", 'a'+drive);
1042}
1043
1044
1045#ifdef MODULE
1046
1047module_param_array(xd, int, NULL, 0);
1048module_param_array(xd_geo, int, NULL, 0);
1049module_param(nodma, bool, 0);
1050
1051MODULE_LICENSE("GPL");
1052
1053void cleanup_module(void)
1054{
1055 int i;
1056 unregister_blkdev(XT_DISK_MAJOR, "xd");
1057 for (i = 0; i < xd_drives; i++) {
1058 del_gendisk(xd_gendisk[i]);
1059 put_disk(xd_gendisk[i]);
1060 }
1061 blk_cleanup_queue(xd_queue);
1062 release_region(xd_iobase,4);
1063 if (xd_drives) {
1064 free_irq(xd_irq, NULL);
1065 free_dma(xd_dma);
1066 if (xd_dma_buffer)
1067 xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200);
1068 }
1069}
1070#else
1071
1072static int __init xd_setup (char *str)
1073{
1074 int ints[5];
1075 get_options (str, ARRAY_SIZE (ints), ints);
1076 do_xd_setup (ints);
1077 return 1;
1078}
1079
1080/* xd_manual_geo_init: initialise drive geometry from command line parameters
1081 (used only for WD drives) */
1082static int __init xd_manual_geo_init (char *str)
1083{
1084 int i, integers[1 + 3*XD_MAXDRIVES];
1085
1086 get_options (str, ARRAY_SIZE (integers), integers);
1087 if (integers[0]%3 != 0) {
1088 printk("xd: incorrect number of parameters for xd_geo\n");
1089 return 1;
1090 }
1091 for (i = 0; (i < integers[0]) && (i < 3*XD_MAXDRIVES); i++)
1092 xd_geo[i] = integers[i+1];
1093 return 1;
1094}
1095
1096__setup ("xd=", xd_setup);
1097__setup ("xd_geo=", xd_manual_geo_init);
1098
1099#endif /* MODULE */
1100
1101module_init(xd_init);
1102MODULE_ALIAS_BLOCKDEV_MAJOR(XT_DISK_MAJOR);