blob: cbce7c5e9445638474640e59738db7b7cec3b74b [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52#include <asm/system.h>
53#include <asm/io.h>
54#include <asm/uaccess.h>
55#include <asm/dma.h>
56
57#include "xd.h"
58
59static void __init do_xd_setup (int *integers);
60#ifdef MODULE
61static int xd[5] = { -1,-1,-1,-1, };
62#endif
63
64#define XD_DONT_USE_DMA 0 /* 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,
135 .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');
218 sprintf(disk->devfs_name, "xd/target%d", i);
219 disk->fops = &xd_fops;
220 disk->private_data = p;
221 disk->queue = xd_queue;
222 set_capacity(disk, p->heads * p->cylinders * p->sectors);
223 printk(" %s: CHS=%d/%d/%d\n", disk->disk_name,
224 p->cylinders, p->heads, p->sectors);
225 xd_gendisk[i] = disk;
226 }
227
228 err = -EBUSY;
229 if (request_irq(xd_irq,xd_interrupt_handler, 0, "XT hard disk", NULL)) {
230 printk("xd: unable to get IRQ%d\n",xd_irq);
231 goto out4;
232 }
233
234 if (request_dma(xd_dma,"xd")) {
235 printk("xd: unable to get DMA%d\n",xd_dma);
236 goto out5;
237 }
238
239 /* xd_maxsectors depends on controller - so set after detection */
240 blk_queue_max_sectors(xd_queue, xd_maxsectors);
241
242 for (i = 0; i < xd_drives; i++)
243 add_disk(xd_gendisk[i]);
244
245 return 0;
246
247out5:
248 free_irq(xd_irq, NULL);
249out4:
250 for (i = 0; i < xd_drives; i++)
251 put_disk(xd_gendisk[i]);
252out3:
253 release_region(xd_iobase,4);
254out2:
255 blk_cleanup_queue(xd_queue);
256out1a:
257 unregister_blkdev(XT_DISK_MAJOR, "xd");
258out1:
259 if (xd_dma_buffer)
260 xd_dma_mem_free((unsigned long)xd_dma_buffer,
261 xd_maxsectors * 0x200);
262 return err;
263Enomem:
264 err = -ENOMEM;
265 while (i--)
266 put_disk(xd_gendisk[i]);
267 goto out3;
268}
269
270/* xd_detect: scan the possible BIOS ROM locations for the signature strings */
271static u_char __init xd_detect (u_char *controller, unsigned int *address)
272{
273 int i, j;
274
275 if (xd_override)
276 {
277 *controller = xd_type;
278 *address = 0;
279 return(1);
280 }
281
Tobias Klauser945f3902006-01-08 01:05:11 -0800282 for (i = 0; i < ARRAY_SIZE(xd_bases); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 void __iomem *p = ioremap(xd_bases[i], 0x2000);
284 if (!p)
285 continue;
Tobias Klauser945f3902006-01-08 01:05:11 -0800286 for (j = 1; j < ARRAY_SIZE(xd_sigs); j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 const char *s = xd_sigs[j].string;
288 if (check_signature(p + xd_sigs[j].offset, s, strlen(s))) {
289 *controller = j;
290 xd_type = j;
291 *address = xd_bases[i];
292 iounmap(p);
293 return 1;
294 }
295 }
296 iounmap(p);
297 }
298 return 0;
299}
300
301/* do_xd_request: handle an incoming request */
302static void do_xd_request (request_queue_t * q)
303{
304 struct request *req;
305
306 if (xdc_busy)
307 return;
308
309 while ((req = elv_next_request(q)) != NULL) {
310 unsigned block = req->sector;
311 unsigned count = req->nr_sectors;
312 int rw = rq_data_dir(req);
313 XD_INFO *disk = req->rq_disk->private_data;
314 int res = 0;
315 int retry;
316
317 if (!(req->flags & REQ_CMD)) {
318 end_request(req, 0);
319 continue;
320 }
321 if (block + count > get_capacity(req->rq_disk)) {
322 end_request(req, 0);
323 continue;
324 }
325 if (rw != READ && rw != WRITE) {
326 printk("do_xd_request: unknown request\n");
327 end_request(req, 0);
328 continue;
329 }
330 for (retry = 0; (retry < XD_RETRIES) && !res; retry++)
331 res = xd_readwrite(rw, disk, req->buffer, block, count);
332 end_request(req, res); /* wrap up, 0 = fail, 1 = success */
333 }
334}
335
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800336static int xd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
337{
338 XD_INFO *p = bdev->bd_disk->private_data;
339
340 geo->heads = p->heads;
341 geo->sectors = p->sectors;
342 geo->cylinders = p->cylinders;
343 return 0;
344}
345
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346/* xd_ioctl: handle device ioctl's */
347static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
348{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 case HDIO_SET_DMA:
351 if (!capable(CAP_SYS_ADMIN)) return -EACCES;
352 if (xdc_busy) return -EBUSY;
353 nodma = !arg;
354 if (nodma && xd_dma_buffer) {
355 xd_dma_mem_free((unsigned long)xd_dma_buffer,
356 xd_maxsectors * 0x200);
357 xd_dma_buffer = NULL;
358 } else if (!nodma && !xd_dma_buffer) {
359 xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
360 if (!xd_dma_buffer) {
361 nodma = XD_DONT_USE_DMA;
362 return -ENOMEM;
363 }
364 }
365 return 0;
366 case HDIO_GET_DMA:
367 return put_user(!nodma, (long __user *) arg);
368 case HDIO_GET_MULTCOUNT:
369 return put_user(xd_maxsectors, (long __user *) arg);
370 default:
371 return -EINVAL;
372 }
373}
374
375/* xd_readwrite: handle a read/write request */
376static int xd_readwrite (u_char operation,XD_INFO *p,char *buffer,u_int block,u_int count)
377{
378 int drive = p->unit;
379 u_char cmdblk[6],sense[4];
380 u_short track,cylinder;
381 u_char head,sector,control,mode = PIO_MODE,temp;
382 char **real_buffer;
383 register int i;
384
385#ifdef DEBUG_READWRITE
386 printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
387#endif /* DEBUG_READWRITE */
388
389 spin_unlock_irq(&xd_lock);
390
391 control = p->control;
392 if (!xd_dma_buffer)
393 xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
394 while (count) {
395 temp = count < xd_maxsectors ? count : xd_maxsectors;
396
397 track = block / p->sectors;
398 head = track % p->heads;
399 cylinder = track / p->heads;
400 sector = block % p->sectors;
401
402#ifdef DEBUG_READWRITE
403 printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
404#endif /* DEBUG_READWRITE */
405
406 if (xd_dma_buffer) {
407 mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)(xd_dma_buffer),temp * 0x200);
408 real_buffer = &xd_dma_buffer;
409 for (i=0; i < (temp * 0x200); i++)
410 xd_dma_buffer[i] = buffer[i];
411 }
412 else
413 real_buffer = &buffer;
414
415 xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control);
416
417 switch (xd_command(cmdblk,mode,(u_char *)(*real_buffer),(u_char *)(*real_buffer),sense,XD_TIMEOUT)) {
418 case 1:
419 printk("xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write"));
420 xd_recalibrate(drive);
421 spin_lock_irq(&xd_lock);
422 return (0);
423 case 2:
424 if (sense[0] & 0x30) {
425 printk("xd%c: %s - ",'a'+drive,(operation == READ ? "reading" : "writing"));
426 switch ((sense[0] & 0x30) >> 4) {
427 case 0: printk("drive error, code = 0x%X",sense[0] & 0x0F);
428 break;
429 case 1: printk("controller error, code = 0x%X",sense[0] & 0x0F);
430 break;
431 case 2: printk("command error, code = 0x%X",sense[0] & 0x0F);
432 break;
433 case 3: printk("miscellaneous error, code = 0x%X",sense[0] & 0x0F);
434 break;
435 }
436 }
437 if (sense[0] & 0x80)
438 printk(" - CHS = %d/%d/%d\n",((sense[2] & 0xC0) << 2) | sense[3],sense[1] & 0x1F,sense[2] & 0x3F);
439 /* reported drive number = (sense[1] & 0xE0) >> 5 */
440 else
441 printk(" - no valid disk address\n");
442 spin_lock_irq(&xd_lock);
443 return (0);
444 }
445 if (xd_dma_buffer)
446 for (i=0; i < (temp * 0x200); i++)
447 buffer[i] = xd_dma_buffer[i];
448
449 count -= temp, buffer += temp * 0x200, block += temp;
450 }
451 spin_lock_irq(&xd_lock);
452 return (1);
453}
454
455/* xd_recalibrate: recalibrate a given drive and reset controller if necessary */
456static void xd_recalibrate (u_char drive)
457{
458 u_char cmdblk[6];
459
460 xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0);
461 if (xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 8))
462 printk("xd%c: warning! error recalibrating, controller may be unstable\n", 'a'+drive);
463}
464
465/* xd_interrupt_handler: interrupt service routine */
466static irqreturn_t xd_interrupt_handler(int irq, void *dev_id,
467 struct pt_regs *regs)
468{
469 if (inb(XD_STATUS) & STAT_INTERRUPT) { /* check if it was our device */
470#ifdef DEBUG_OTHER
471 printk("xd_interrupt_handler: interrupt detected\n");
472#endif /* DEBUG_OTHER */
473 outb(0,XD_CONTROL); /* acknowledge interrupt */
474 wake_up(&xd_wait_int); /* and wake up sleeping processes */
475 return IRQ_HANDLED;
476 }
477 else
478 printk("xd: unexpected interrupt\n");
479 return IRQ_NONE;
480}
481
482/* xd_setup_dma: set up the DMA controller for a data transfer */
483static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
484{
485 unsigned long f;
486
487 if (nodma)
488 return (PIO_MODE);
489 if (((unsigned long) buffer & 0xFFFF0000) != (((unsigned long) buffer + count) & 0xFFFF0000)) {
490#ifdef DEBUG_OTHER
491 printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
492#endif /* DEBUG_OTHER */
493 return (PIO_MODE);
494 }
495
496 f=claim_dma_lock();
497 disable_dma(xd_dma);
498 clear_dma_ff(xd_dma);
499 set_dma_mode(xd_dma,mode);
500 set_dma_addr(xd_dma, (unsigned long) buffer);
501 set_dma_count(xd_dma,count);
502
503 release_dma_lock(f);
504
505 return (DMA_MODE); /* use DMA and INT */
506}
507
508/* xd_build: put stuff into an array in a format suitable for the controller */
509static 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)
510{
511 cmdblk[0] = command;
512 cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F);
513 cmdblk[2] = ((cylinder & 0x300) >> 2) | (sector & 0x3F);
514 cmdblk[3] = cylinder & 0xFF;
515 cmdblk[4] = count;
516 cmdblk[5] = control;
517
518 return (cmdblk);
519}
520
521static void xd_watchdog (unsigned long unused)
522{
523 xd_error = 1;
524 wake_up(&xd_wait_int);
525}
526
527/* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */
528static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout)
529{
530 u_long expiry = jiffies + timeout;
531 int success;
532
533 xdc_busy = 1;
Nishanth Aravamudan86e84862005-09-10 00:27:28 -0700534 while ((success = ((inb(port) & mask) != flags)) && time_before(jiffies, expiry))
535 schedule_timeout_uninterruptible(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 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)) {
Nishanth Aravamudanf6a2f342005-09-10 00:27:14 -0700636 msleep_interruptible(XD_INIT_DISK_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
638 init_drive(count);
639 count++;
640
Nishanth Aravamudanf6a2f342005-09-10 00:27:14 -0700641 msleep_interruptible(XD_INIT_DISK_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 }
643 }
644 return (count);
645}
646
647static void __init xd_manual_geo_set (u_char drive)
648{
649 xd_info[drive].heads = (u_char)(xd_geo[3 * drive + 1]);
650 xd_info[drive].cylinders = (u_short)(xd_geo[3 * drive]);
651 xd_info[drive].sectors = (u_char)(xd_geo[3 * drive + 2]);
652}
653
654static void __init xd_dtc_init_controller (unsigned int address)
655{
656 switch (address) {
657 case 0x00000:
658 case 0xC8000: break; /*initial: 0x320 */
659 case 0xCA000: xd_iobase = 0x324;
660 case 0xD0000: /*5150CX*/
661 case 0xD8000: break; /*5150CX & 5150XL*/
662 default: printk("xd_dtc_init_controller: unsupported BIOS address %06x\n",address);
663 break;
664 }
665 xd_maxsectors = 0x01; /* my card seems to have trouble doing multi-block transfers? */
666
667 outb(0,XD_RESET); /* reset the controller */
668}
669
670
671static void __init xd_dtc5150cx_init_drive (u_char drive)
672{
673 /* values from controller's BIOS - BIOS chip may be removed */
674 static u_short geometry_table[][4] = {
675 {0x200,8,0x200,0x100},
676 {0x267,2,0x267,0x267},
677 {0x264,4,0x264,0x80},
678 {0x132,4,0x132,0x0},
679 {0x132,2,0x80, 0x132},
680 {0x177,8,0x177,0x0},
681 {0x132,8,0x84, 0x0},
682 {}, /* not used */
683 {0x132,6,0x80, 0x100},
684 {0x200,6,0x100,0x100},
685 {0x264,2,0x264,0x80},
686 {0x280,4,0x280,0x100},
687 {0x2B9,3,0x2B9,0x2B9},
688 {0x2B9,5,0x2B9,0x2B9},
689 {0x280,6,0x280,0x100},
690 {0x132,4,0x132,0x0}};
691 u_char n;
692
693 n = inb(XD_JUMPER);
694 n = (drive ? n : (n >> 2)) & 0x33;
695 n = (n | (n >> 2)) & 0x0F;
696 if (xd_geo[3*drive])
697 xd_manual_geo_set(drive);
698 else
699 if (n != 7) {
700 xd_info[drive].heads = (u_char)(geometry_table[n][1]); /* heads */
701 xd_info[drive].cylinders = geometry_table[n][0]; /* cylinders */
702 xd_info[drive].sectors = 17; /* sectors */
703#if 0
704 xd_info[drive].rwrite = geometry_table[n][2]; /* reduced write */
705 xd_info[drive].precomp = geometry_table[n][3] /* write precomp */
706 xd_info[drive].ecc = 0x0B; /* ecc length */
707#endif /* 0 */
708 }
709 else {
710 printk("xd%c: undetermined drive geometry\n",'a'+drive);
711 return;
712 }
713 xd_info[drive].control = 5; /* control byte */
714 xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B);
715 xd_recalibrate(drive);
716}
717
718static void __init xd_dtc_init_drive (u_char drive)
719{
720 u_char cmdblk[6],buf[64];
721
722 xd_build(cmdblk,CMD_DTCGETGEOM,drive,0,0,0,0,0);
723 if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) {
724 xd_info[drive].heads = buf[0x0A]; /* heads */
725 xd_info[drive].cylinders = ((u_short *) (buf))[0x04]; /* cylinders */
726 xd_info[drive].sectors = 17; /* sectors */
727 if (xd_geo[3*drive])
728 xd_manual_geo_set(drive);
729#if 0
730 xd_info[drive].rwrite = ((u_short *) (buf + 1))[0x05]; /* reduced write */
731 xd_info[drive].precomp = ((u_short *) (buf + 1))[0x06]; /* write precomp */
732 xd_info[drive].ecc = buf[0x0F]; /* ecc length */
733#endif /* 0 */
734 xd_info[drive].control = 0; /* control byte */
735
736 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]);
737 xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7);
738 if (xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 2))
739 printk("xd_dtc_init_drive: error setting step rate for xd%c\n", 'a'+drive);
740 }
741 else
742 printk("xd_dtc_init_drive: error reading geometry for xd%c\n", 'a'+drive);
743}
744
745static void __init xd_wd_init_controller (unsigned int address)
746{
747 switch (address) {
748 case 0x00000:
749 case 0xC8000: break; /*initial: 0x320 */
750 case 0xCA000: xd_iobase = 0x324; break;
751 case 0xCC000: xd_iobase = 0x328; break;
752 case 0xCE000: xd_iobase = 0x32C; break;
753 case 0xD0000: xd_iobase = 0x328; break; /* ? */
754 case 0xD8000: xd_iobase = 0x32C; break; /* ? */
755 default: printk("xd_wd_init_controller: unsupported BIOS address %06x\n",address);
756 break;
757 }
758 xd_maxsectors = 0x01; /* this one doesn't wrap properly either... */
759
760 outb(0,XD_RESET); /* reset the controller */
761
Nishanth Aravamudanf6a2f342005-09-10 00:27:14 -0700762 msleep(XD_INIT_DISK_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763}
764
765static void __init xd_wd_init_drive (u_char drive)
766{
767 /* values from controller's BIOS - BIOS may be disabled */
768 static u_short geometry_table[][4] = {
769 {0x264,4,0x1C2,0x1C2}, /* common part */
770 {0x132,4,0x099,0x0},
771 {0x267,2,0x1C2,0x1C2},
772 {0x267,4,0x1C2,0x1C2},
773
774 {0x334,6,0x335,0x335}, /* 1004 series RLL */
775 {0x30E,4,0x30F,0x3DC},
776 {0x30E,2,0x30F,0x30F},
777 {0x267,4,0x268,0x268},
778
779 {0x3D5,5,0x3D6,0x3D6}, /* 1002 series RLL */
780 {0x3DB,7,0x3DC,0x3DC},
781 {0x264,4,0x265,0x265},
782 {0x267,4,0x268,0x268}};
783
784 u_char cmdblk[6],buf[0x200];
785 u_char n = 0,rll,jumper_state,use_jumper_geo;
786 u_char wd_1002 = (xd_sigs[xd_type].string[7] == '6');
787
788 jumper_state = ~(inb(0x322));
789 if (jumper_state & 0x40)
790 xd_irq = 9;
791 rll = (jumper_state & 0x30) ? (0x04 << wd_1002) : 0;
792 xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0);
793 if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) {
794 xd_info[drive].heads = buf[0x1AF]; /* heads */
795 xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6]; /* cylinders */
796 xd_info[drive].sectors = 17; /* sectors */
797 if (xd_geo[3*drive])
798 xd_manual_geo_set(drive);
799#if 0
800 xd_info[drive].rwrite = ((u_short *) (buf))[0xD8]; /* reduced write */
801 xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA]; /* write precomp */
802 xd_info[drive].ecc = buf[0x1B4]; /* ecc length */
803#endif /* 0 */
804 xd_info[drive].control = buf[0x1B5]; /* control byte */
805 use_jumper_geo = !(xd_info[drive].heads) || !(xd_info[drive].cylinders);
806 if (xd_geo[3*drive]) {
807 xd_manual_geo_set(drive);
808 xd_info[drive].control = rll ? 7 : 5;
809 }
810 else if (use_jumper_geo) {
811 n = (((jumper_state & 0x0F) >> (drive << 1)) & 0x03) | rll;
812 xd_info[drive].cylinders = geometry_table[n][0];
813 xd_info[drive].heads = (u_char)(geometry_table[n][1]);
814 xd_info[drive].control = rll ? 7 : 5;
815#if 0
816 xd_info[drive].rwrite = geometry_table[n][2];
817 xd_info[drive].wprecomp = geometry_table[n][3];
818 xd_info[drive].ecc = 0x0B;
819#endif /* 0 */
820 }
821 if (!wd_1002) {
822 if (use_jumper_geo)
823 xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
824 geometry_table[n][2],geometry_table[n][3],0x0B);
825 else
826 xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
827 ((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
828 }
829 /* 1002 based RLL controller requests converted addressing, but reports physical
830 (physical 26 sec., logical 17 sec.)
831 1004 based ???? */
832 if (rll & wd_1002) {
833 if ((xd_info[drive].cylinders *= 26,
834 xd_info[drive].cylinders /= 17) > 1023)
835 xd_info[drive].cylinders = 1023; /* 1024 ? */
836#if 0
837 xd_info[drive].rwrite *= 26;
838 xd_info[drive].rwrite /= 17;
839 xd_info[drive].wprecomp *= 26
840 xd_info[drive].wprecomp /= 17;
841#endif /* 0 */
842 }
843 }
844 else
845 printk("xd_wd_init_drive: error reading geometry for xd%c\n",'a'+drive);
846
847}
848
849static void __init xd_seagate_init_controller (unsigned int address)
850{
851 switch (address) {
852 case 0x00000:
853 case 0xC8000: break; /*initial: 0x320 */
854 case 0xD0000: xd_iobase = 0x324; break;
855 case 0xD8000: xd_iobase = 0x328; break;
856 case 0xE0000: xd_iobase = 0x32C; break;
857 default: printk("xd_seagate_init_controller: unsupported BIOS address %06x\n",address);
858 break;
859 }
860 xd_maxsectors = 0x40;
861
862 outb(0,XD_RESET); /* reset the controller */
863}
864
865static void __init xd_seagate_init_drive (u_char drive)
866{
867 u_char cmdblk[6],buf[0x200];
868
869 xd_build(cmdblk,CMD_ST11GETGEOM,drive,0,0,0,1,0);
870 if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) {
871 xd_info[drive].heads = buf[0x04]; /* heads */
872 xd_info[drive].cylinders = (buf[0x02] << 8) | buf[0x03]; /* cylinders */
873 xd_info[drive].sectors = buf[0x05]; /* sectors */
874 xd_info[drive].control = 0; /* control byte */
875 }
876 else
877 printk("xd_seagate_init_drive: error reading geometry from xd%c\n", 'a'+drive);
878}
879
880/* Omti support courtesy Dirk Melchers */
881static void __init xd_omti_init_controller (unsigned int address)
882{
883 switch (address) {
884 case 0x00000:
885 case 0xC8000: break; /*initial: 0x320 */
886 case 0xD0000: xd_iobase = 0x324; break;
887 case 0xD8000: xd_iobase = 0x328; break;
888 case 0xE0000: xd_iobase = 0x32C; break;
889 default: printk("xd_omti_init_controller: unsupported BIOS address %06x\n",address);
890 break;
891 }
892
893 xd_maxsectors = 0x40;
894
895 outb(0,XD_RESET); /* reset the controller */
896}
897
898static void __init xd_omti_init_drive (u_char drive)
899{
900 /* gets infos from drive */
901 xd_override_init_drive(drive);
902
903 /* set other parameters, Hardcoded, not that nice :-) */
904 xd_info[drive].control = 2;
905}
906
907/* Xebec support (AK) */
908static void __init xd_xebec_init_controller (unsigned int address)
909{
910/* iobase may be set manually in range 0x300 - 0x33C
911 irq may be set manually to 2(9),3,4,5,6,7
912 dma may be set manually to 1,2,3
913 (How to detect them ???)
914BIOS address may be set manually in range 0x0 - 0xF8000
915If you need non-standard settings use the xd=... command */
916
917 switch (address) {
918 case 0x00000:
919 case 0xC8000: /* initially: xd_iobase==0x320 */
920 case 0xD0000:
921 case 0xD2000:
922 case 0xD4000:
923 case 0xD6000:
924 case 0xD8000:
925 case 0xDA000:
926 case 0xDC000:
927 case 0xDE000:
928 case 0xE0000: break;
929 default: printk("xd_xebec_init_controller: unsupported BIOS address %06x\n",address);
930 break;
931 }
932
933 xd_maxsectors = 0x01;
934 outb(0,XD_RESET); /* reset the controller */
935
Nishanth Aravamudanf6a2f342005-09-10 00:27:14 -0700936 msleep(XD_INIT_DISK_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937}
938
939static void __init xd_xebec_init_drive (u_char drive)
940{
941 /* values from controller's BIOS - BIOS chip may be removed */
942 static u_short geometry_table[][5] = {
943 {0x132,4,0x080,0x080,0x7},
944 {0x132,4,0x080,0x080,0x17},
945 {0x264,2,0x100,0x100,0x7},
946 {0x264,2,0x100,0x100,0x17},
947 {0x132,8,0x080,0x080,0x7},
948 {0x132,8,0x080,0x080,0x17},
949 {0x264,4,0x100,0x100,0x6},
950 {0x264,4,0x100,0x100,0x17},
951 {0x2BC,5,0x2BC,0x12C,0x6},
952 {0x3A5,4,0x3A5,0x3A5,0x7},
953 {0x26C,6,0x26C,0x26C,0x7},
954 {0x200,8,0x200,0x100,0x17},
955 {0x400,5,0x400,0x400,0x7},
956 {0x400,6,0x400,0x400,0x7},
957 {0x264,8,0x264,0x200,0x17},
958 {0x33E,7,0x33E,0x200,0x7}};
959 u_char n;
960
961 n = inb(XD_JUMPER) & 0x0F; /* BIOS's drive number: same geometry
962 is assumed for BOTH drives */
963 if (xd_geo[3*drive])
964 xd_manual_geo_set(drive);
965 else {
966 xd_info[drive].heads = (u_char)(geometry_table[n][1]); /* heads */
967 xd_info[drive].cylinders = geometry_table[n][0]; /* cylinders */
968 xd_info[drive].sectors = 17; /* sectors */
969#if 0
970 xd_info[drive].rwrite = geometry_table[n][2]; /* reduced write */
971 xd_info[drive].precomp = geometry_table[n][3] /* write precomp */
972 xd_info[drive].ecc = 0x0B; /* ecc length */
973#endif /* 0 */
974 }
975 xd_info[drive].control = geometry_table[n][4]; /* control byte */
976 xd_setparam(CMD_XBSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B);
977 xd_recalibrate(drive);
978}
979
980/* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
981 etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
982static void __init xd_override_init_drive (u_char drive)
983{
984 u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
985 u_char cmdblk[6],i;
986
987 if (xd_geo[3*drive])
988 xd_manual_geo_set(drive);
989 else {
990 for (i = 0; i < 3; i++) {
991 while (min[i] != max[i] - 1) {
992 test[i] = (min[i] + max[i]) / 2;
993 xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0);
994 if (!xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 2))
995 min[i] = test[i];
996 else
997 max[i] = test[i];
998 }
999 test[i] = min[i];
1000 }
1001 xd_info[drive].heads = (u_char) min[0] + 1;
1002 xd_info[drive].cylinders = (u_short) min[1] + 1;
1003 xd_info[drive].sectors = (u_char) min[2] + 1;
1004 }
1005 xd_info[drive].control = 0;
1006}
1007
1008/* xd_setup: initialise controller from command line parameters */
1009static void __init do_xd_setup (int *integers)
1010{
1011 switch (integers[0]) {
1012 case 4: if (integers[4] < 0)
1013 nodma = 1;
1014 else if (integers[4] < 8)
1015 xd_dma = integers[4];
1016 case 3: if ((integers[3] > 0) && (integers[3] <= 0x3FC))
1017 xd_iobase = integers[3];
1018 case 2: if ((integers[2] > 0) && (integers[2] < 16))
1019 xd_irq = integers[2];
1020 case 1: xd_override = 1;
Tobias Klauser945f3902006-01-08 01:05:11 -08001021 if ((integers[1] >= 0) && (integers[1] < ARRAY_SIZE(xd_sigs)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 xd_type = integers[1];
1023 case 0: break;
1024 default:printk("xd: too many parameters for xd\n");
1025 }
1026 xd_maxsectors = 0x01;
1027}
1028
1029/* xd_setparam: set the drive characteristics */
1030static 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)
1031{
1032 u_char cmdblk[14];
1033
1034 xd_build(cmdblk,command,drive,0,0,0,0,0);
1035 cmdblk[6] = (u_char) (cylinders >> 8) & 0x03;
1036 cmdblk[7] = (u_char) (cylinders & 0xFF);
1037 cmdblk[8] = heads & 0x1F;
1038 cmdblk[9] = (u_char) (rwrite >> 8) & 0x03;
1039 cmdblk[10] = (u_char) (rwrite & 0xFF);
1040 cmdblk[11] = (u_char) (wprecomp >> 8) & 0x03;
1041 cmdblk[12] = (u_char) (wprecomp & 0xFF);
1042 cmdblk[13] = ecc;
1043
1044 /* Some controllers require geometry info as data, not command */
1045
1046 if (xd_command(cmdblk,PIO_MODE,NULL,&cmdblk[6],NULL,XD_TIMEOUT * 2))
1047 printk("xd: error setting characteristics for xd%c\n", 'a'+drive);
1048}
1049
1050
1051#ifdef MODULE
1052
1053module_param_array(xd, int, NULL, 0);
1054module_param_array(xd_geo, int, NULL, 0);
1055module_param(nodma, bool, 0);
1056
1057MODULE_LICENSE("GPL");
1058
1059void cleanup_module(void)
1060{
1061 int i;
1062 unregister_blkdev(XT_DISK_MAJOR, "xd");
1063 for (i = 0; i < xd_drives; i++) {
1064 del_gendisk(xd_gendisk[i]);
1065 put_disk(xd_gendisk[i]);
1066 }
1067 blk_cleanup_queue(xd_queue);
1068 release_region(xd_iobase,4);
1069 if (xd_drives) {
1070 free_irq(xd_irq, NULL);
1071 free_dma(xd_dma);
1072 if (xd_dma_buffer)
1073 xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200);
1074 }
1075}
1076#else
1077
1078static int __init xd_setup (char *str)
1079{
1080 int ints[5];
1081 get_options (str, ARRAY_SIZE (ints), ints);
1082 do_xd_setup (ints);
1083 return 1;
1084}
1085
1086/* xd_manual_geo_init: initialise drive geometry from command line parameters
1087 (used only for WD drives) */
1088static int __init xd_manual_geo_init (char *str)
1089{
1090 int i, integers[1 + 3*XD_MAXDRIVES];
1091
1092 get_options (str, ARRAY_SIZE (integers), integers);
1093 if (integers[0]%3 != 0) {
1094 printk("xd: incorrect number of parameters for xd_geo\n");
1095 return 1;
1096 }
1097 for (i = 0; (i < integers[0]) && (i < 3*XD_MAXDRIVES); i++)
1098 xd_geo[i] = integers[i+1];
1099 return 1;
1100}
1101
1102__setup ("xd=", xd_setup);
1103__setup ("xd_geo=", xd_manual_geo_init);
1104
1105#endif /* MODULE */
1106
1107module_init(xd_init);
1108MODULE_ALIAS_BLOCKDEV_MAJOR(XT_DISK_MAJOR);