blob: 1a325fb05c9282745013d53e541e13b7b748d1a8 [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
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -0700133static const struct block_device_operations xd_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 .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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 err = -EBUSY;
173 if (register_blkdev(XT_DISK_MAJOR, "xd"))
174 goto out1;
175
176 err = -ENOMEM;
177 xd_queue = blk_init_queue(do_xd_request, &xd_lock);
178 if (!xd_queue)
179 goto out1a;
180
181 if (xd_detect(&controller,&address)) {
182
183 printk("Detected a%s controller (type %d) at address %06x\n",
184 xd_sigs[controller].name,controller,address);
185 if (!request_region(xd_iobase,4,"xd")) {
186 printk("xd: Ports at 0x%x are not available\n",
187 xd_iobase);
188 goto out2;
189 }
190 if (controller)
191 xd_sigs[controller].init_controller(address);
192 xd_drives = xd_initdrives(xd_sigs[controller].init_drive);
193
194 printk("Detected %d hard drive%s (using IRQ%d & DMA%d)\n",
195 xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma);
196 }
197
Mel Gormana3b8d922009-12-07 22:10:46 +0100198 /*
199 * With the drive detected, xd_maxsectors should now be known.
200 * If xd_maxsectors is 0, nothing was detected and we fall through
201 * to return -ENODEV
202 */
203 if (!xd_dma_buffer && xd_maxsectors) {
204 xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
205 if (!xd_dma_buffer) {
206 printk(KERN_ERR "xd: Out of memory.\n");
207 goto out3;
208 }
209 }
210
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 err = -ENODEV;
212 if (!xd_drives)
213 goto out3;
214
215 for (i = 0; i < xd_drives; i++) {
216 XD_INFO *p = &xd_info[i];
217 struct gendisk *disk = alloc_disk(64);
218 if (!disk)
219 goto Enomem;
220 p->unit = i;
221 disk->major = XT_DISK_MAJOR;
222 disk->first_minor = i<<6;
223 sprintf(disk->disk_name, "xd%c", i+'a');
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 disk->fops = &xd_fops;
225 disk->private_data = p;
226 disk->queue = xd_queue;
227 set_capacity(disk, p->heads * p->cylinders * p->sectors);
228 printk(" %s: CHS=%d/%d/%d\n", disk->disk_name,
229 p->cylinders, p->heads, p->sectors);
230 xd_gendisk[i] = disk;
231 }
232
233 err = -EBUSY;
234 if (request_irq(xd_irq,xd_interrupt_handler, 0, "XT hard disk", NULL)) {
235 printk("xd: unable to get IRQ%d\n",xd_irq);
236 goto out4;
237 }
238
239 if (request_dma(xd_dma,"xd")) {
240 printk("xd: unable to get DMA%d\n",xd_dma);
241 goto out5;
242 }
243
244 /* xd_maxsectors depends on controller - so set after detection */
Martin K. Petersen086fa5f2010-02-26 00:20:38 -0500245 blk_queue_max_hw_sectors(xd_queue, xd_maxsectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
247 for (i = 0; i < xd_drives; i++)
248 add_disk(xd_gendisk[i]);
249
250 return 0;
251
252out5:
253 free_irq(xd_irq, NULL);
254out4:
255 for (i = 0; i < xd_drives; i++)
256 put_disk(xd_gendisk[i]);
257out3:
Mel Gormana3b8d922009-12-07 22:10:46 +0100258 if (xd_maxsectors)
259 release_region(xd_iobase,4);
260
261 if (xd_dma_buffer)
262 xd_dma_mem_free((unsigned long)xd_dma_buffer,
263 xd_maxsectors * 0x200);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264out2:
265 blk_cleanup_queue(xd_queue);
266out1a:
267 unregister_blkdev(XT_DISK_MAJOR, "xd");
268out1:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 return err;
270Enomem:
271 err = -ENOMEM;
272 while (i--)
273 put_disk(xd_gendisk[i]);
274 goto out3;
275}
276
277/* xd_detect: scan the possible BIOS ROM locations for the signature strings */
278static u_char __init xd_detect (u_char *controller, unsigned int *address)
279{
280 int i, j;
281
282 if (xd_override)
283 {
284 *controller = xd_type;
285 *address = 0;
286 return(1);
287 }
288
Tobias Klauser945f3902006-01-08 01:05:11 -0800289 for (i = 0; i < ARRAY_SIZE(xd_bases); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 void __iomem *p = ioremap(xd_bases[i], 0x2000);
291 if (!p)
292 continue;
Tobias Klauser945f3902006-01-08 01:05:11 -0800293 for (j = 1; j < ARRAY_SIZE(xd_sigs); j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 const char *s = xd_sigs[j].string;
295 if (check_signature(p + xd_sigs[j].offset, s, strlen(s))) {
296 *controller = j;
297 xd_type = j;
298 *address = xd_bases[i];
299 iounmap(p);
300 return 1;
301 }
302 }
303 iounmap(p);
304 }
305 return 0;
306}
307
308/* do_xd_request: handle an incoming request */
Jens Axboe165125e2007-07-24 09:28:11 +0200309static void do_xd_request (struct request_queue * q)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310{
311 struct request *req;
312
313 if (xdc_busy)
314 return;
315
Tejun Heo9934c8c2009-05-08 11:54:16 +0900316 req = blk_fetch_request(q);
Tejun Heobab2a802009-05-08 11:54:10 +0900317 while (req) {
Tejun Heo83096eb2009-05-07 22:24:39 +0900318 unsigned block = blk_rq_pos(req);
Tejun Heobab2a802009-05-08 11:54:10 +0900319 unsigned count = blk_rq_cur_sectors(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 XD_INFO *disk = req->rq_disk->private_data;
Tejun Heobab2a802009-05-08 11:54:10 +0900321 int res = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 int retry;
323
Tejun Heobab2a802009-05-08 11:54:10 +0900324 if (!blk_fs_request(req))
325 goto done;
326 if (block + count > get_capacity(req->rq_disk))
327 goto done;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 for (retry = 0; (retry < XD_RETRIES) && !res; retry++)
Tejun Heo5b5c5d12009-04-28 13:06:06 +0900329 res = xd_readwrite(rq_data_dir(req), disk, req->buffer,
330 block, count);
Tejun Heobab2a802009-05-08 11:54:10 +0900331 done:
Tejun Heof06d9a22009-04-23 11:05:19 +0900332 /* wrap up, 0 = success, -errno = fail */
Tejun Heo9934c8c2009-05-08 11:54:16 +0900333 if (!__blk_end_request_cur(req, res))
334 req = blk_fetch_request(q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 }
336}
337
Christoph Hellwiga885c8c2006-01-08 01:02:50 -0800338static int xd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
339{
340 XD_INFO *p = bdev->bd_disk->private_data;
341
342 geo->heads = p->heads;
343 geo->sectors = p->sectors;
344 geo->cylinders = p->cylinders;
345 return 0;
346}
347
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348/* xd_ioctl: handle device ioctl's */
Al Viro961846c2008-03-02 10:23:12 -0500349static int xd_ioctl(struct block_device *bdev, fmode_t mode, u_int cmd, u_long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 case HDIO_SET_DMA:
353 if (!capable(CAP_SYS_ADMIN)) return -EACCES;
354 if (xdc_busy) return -EBUSY;
355 nodma = !arg;
356 if (nodma && xd_dma_buffer) {
357 xd_dma_mem_free((unsigned long)xd_dma_buffer,
358 xd_maxsectors * 0x200);
359 xd_dma_buffer = NULL;
360 } else if (!nodma && !xd_dma_buffer) {
361 xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
362 if (!xd_dma_buffer) {
363 nodma = XD_DONT_USE_DMA;
364 return -ENOMEM;
365 }
366 }
367 return 0;
368 case HDIO_GET_DMA:
369 return put_user(!nodma, (long __user *) arg);
370 case HDIO_GET_MULTCOUNT:
371 return put_user(xd_maxsectors, (long __user *) arg);
372 default:
373 return -EINVAL;
374 }
375}
376
377/* xd_readwrite: handle a read/write request */
378static int xd_readwrite (u_char operation,XD_INFO *p,char *buffer,u_int block,u_int count)
379{
380 int drive = p->unit;
381 u_char cmdblk[6],sense[4];
382 u_short track,cylinder;
383 u_char head,sector,control,mode = PIO_MODE,temp;
384 char **real_buffer;
385 register int i;
386
387#ifdef DEBUG_READWRITE
388 printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
389#endif /* DEBUG_READWRITE */
390
391 spin_unlock_irq(&xd_lock);
392
393 control = p->control;
394 if (!xd_dma_buffer)
395 xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200);
396 while (count) {
397 temp = count < xd_maxsectors ? count : xd_maxsectors;
398
399 track = block / p->sectors;
400 head = track % p->heads;
401 cylinder = track / p->heads;
402 sector = block % p->sectors;
403
404#ifdef DEBUG_READWRITE
405 printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
406#endif /* DEBUG_READWRITE */
407
408 if (xd_dma_buffer) {
409 mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)(xd_dma_buffer),temp * 0x200);
410 real_buffer = &xd_dma_buffer;
411 for (i=0; i < (temp * 0x200); i++)
412 xd_dma_buffer[i] = buffer[i];
413 }
414 else
415 real_buffer = &buffer;
416
417 xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control);
418
419 switch (xd_command(cmdblk,mode,(u_char *)(*real_buffer),(u_char *)(*real_buffer),sense,XD_TIMEOUT)) {
420 case 1:
421 printk("xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write"));
422 xd_recalibrate(drive);
423 spin_lock_irq(&xd_lock);
Tejun Heof06d9a22009-04-23 11:05:19 +0900424 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 case 2:
426 if (sense[0] & 0x30) {
427 printk("xd%c: %s - ",'a'+drive,(operation == READ ? "reading" : "writing"));
428 switch ((sense[0] & 0x30) >> 4) {
429 case 0: printk("drive error, code = 0x%X",sense[0] & 0x0F);
430 break;
431 case 1: printk("controller error, code = 0x%X",sense[0] & 0x0F);
432 break;
433 case 2: printk("command error, code = 0x%X",sense[0] & 0x0F);
434 break;
435 case 3: printk("miscellaneous error, code = 0x%X",sense[0] & 0x0F);
436 break;
437 }
438 }
439 if (sense[0] & 0x80)
440 printk(" - CHS = %d/%d/%d\n",((sense[2] & 0xC0) << 2) | sense[3],sense[1] & 0x1F,sense[2] & 0x3F);
441 /* reported drive number = (sense[1] & 0xE0) >> 5 */
442 else
443 printk(" - no valid disk address\n");
444 spin_lock_irq(&xd_lock);
Tejun Heof06d9a22009-04-23 11:05:19 +0900445 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 }
447 if (xd_dma_buffer)
448 for (i=0; i < (temp * 0x200); i++)
449 buffer[i] = xd_dma_buffer[i];
450
451 count -= temp, buffer += temp * 0x200, block += temp;
452 }
453 spin_lock_irq(&xd_lock);
Tejun Heof06d9a22009-04-23 11:05:19 +0900454 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455}
456
457/* xd_recalibrate: recalibrate a given drive and reset controller if necessary */
458static void xd_recalibrate (u_char drive)
459{
460 u_char cmdblk[6];
461
462 xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0);
463 if (xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 8))
464 printk("xd%c: warning! error recalibrating, controller may be unstable\n", 'a'+drive);
465}
466
467/* xd_interrupt_handler: interrupt service routine */
David Howells7d12e782006-10-05 14:55:46 +0100468static irqreturn_t xd_interrupt_handler(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469{
470 if (inb(XD_STATUS) & STAT_INTERRUPT) { /* check if it was our device */
471#ifdef DEBUG_OTHER
472 printk("xd_interrupt_handler: interrupt detected\n");
473#endif /* DEBUG_OTHER */
474 outb(0,XD_CONTROL); /* acknowledge interrupt */
475 wake_up(&xd_wait_int); /* and wake up sleeping processes */
476 return IRQ_HANDLED;
477 }
478 else
479 printk("xd: unexpected interrupt\n");
480 return IRQ_NONE;
481}
482
483/* xd_setup_dma: set up the DMA controller for a data transfer */
484static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
485{
486 unsigned long f;
487
488 if (nodma)
489 return (PIO_MODE);
490 if (((unsigned long) buffer & 0xFFFF0000) != (((unsigned long) buffer + count) & 0xFFFF0000)) {
491#ifdef DEBUG_OTHER
492 printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
493#endif /* DEBUG_OTHER */
494 return (PIO_MODE);
495 }
496
497 f=claim_dma_lock();
498 disable_dma(xd_dma);
499 clear_dma_ff(xd_dma);
500 set_dma_mode(xd_dma,mode);
501 set_dma_addr(xd_dma, (unsigned long) buffer);
502 set_dma_count(xd_dma,count);
503
504 release_dma_lock(f);
505
506 return (DMA_MODE); /* use DMA and INT */
507}
508
509/* xd_build: put stuff into an array in a format suitable for the controller */
510static 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)
511{
512 cmdblk[0] = command;
513 cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F);
514 cmdblk[2] = ((cylinder & 0x300) >> 2) | (sector & 0x3F);
515 cmdblk[3] = cylinder & 0xFF;
516 cmdblk[4] = count;
517 cmdblk[5] = control;
518
519 return (cmdblk);
520}
521
522static void xd_watchdog (unsigned long unused)
523{
524 xd_error = 1;
525 wake_up(&xd_wait_int);
526}
527
528/* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */
529static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout)
530{
531 u_long expiry = jiffies + timeout;
532 int success;
533
534 xdc_busy = 1;
Nishanth Aravamudan86e84862005-09-10 00:27:28 -0700535 while ((success = ((inb(port) & mask) != flags)) && time_before(jiffies, expiry))
536 schedule_timeout_uninterruptible(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 xdc_busy = 0;
538 return (success);
539}
540
541static inline u_int xd_wait_for_IRQ (void)
542{
543 unsigned long flags;
544 xd_watchdog_int.expires = jiffies + 8 * HZ;
545 add_timer(&xd_watchdog_int);
546
547 flags=claim_dma_lock();
548 enable_dma(xd_dma);
549 release_dma_lock(flags);
550
551 sleep_on(&xd_wait_int);
552 del_timer(&xd_watchdog_int);
553 xdc_busy = 0;
554
555 flags=claim_dma_lock();
556 disable_dma(xd_dma);
557 release_dma_lock(flags);
558
559 if (xd_error) {
560 printk("xd: missed IRQ - command aborted\n");
561 xd_error = 0;
562 return (1);
563 }
564 return (0);
565}
566
567/* xd_command: handle all data transfers necessary for a single command */
568static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout)
569{
570 u_char cmdblk[6],csb,complete = 0;
571
572#ifdef DEBUG_COMMAND
573 printk("xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
574#endif /* DEBUG_COMMAND */
575
576 outb(0,XD_SELECT);
577 outb(mode,XD_CONTROL);
578
579 if (xd_waitport(XD_STATUS,STAT_SELECT,STAT_SELECT,timeout))
580 return (1);
581
582 while (!complete) {
583 if (xd_waitport(XD_STATUS,STAT_READY,STAT_READY,timeout))
584 return (1);
585
586 switch (inb(XD_STATUS) & (STAT_COMMAND | STAT_INPUT)) {
587 case 0:
588 if (mode == DMA_MODE) {
589 if (xd_wait_for_IRQ())
590 return (1);
591 } else
592 outb(outdata ? *outdata++ : 0,XD_DATA);
593 break;
594 case STAT_INPUT:
595 if (mode == DMA_MODE) {
596 if (xd_wait_for_IRQ())
597 return (1);
598 } else
599 if (indata)
600 *indata++ = inb(XD_DATA);
601 else
602 inb(XD_DATA);
603 break;
604 case STAT_COMMAND:
605 outb(command ? *command++ : 0,XD_DATA);
606 break;
607 case STAT_COMMAND | STAT_INPUT:
608 complete = 1;
609 break;
610 }
611 }
612 csb = inb(XD_DATA);
613
614 if (xd_waitport(XD_STATUS,0,STAT_SELECT,timeout)) /* wait until deselected */
615 return (1);
616
617 if (csb & CSB_ERROR) { /* read sense data if error */
618 xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0);
619 if (xd_command(cmdblk,0,sense,NULL,NULL,XD_TIMEOUT))
620 printk("xd: warning! sense command failed!\n");
621 }
622
623#ifdef DEBUG_COMMAND
624 printk("xd_command: completed with csb = 0x%X\n",csb);
625#endif /* DEBUG_COMMAND */
626
627 return (csb & CSB_ERROR);
628}
629
630static u_char __init xd_initdrives (void (*init_drive)(u_char drive))
631{
632 u_char cmdblk[6],i,count = 0;
633
634 for (i = 0; i < XD_MAXDRIVES; i++) {
635 xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0);
636 if (!xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT*8)) {
Nishanth Aravamudanf6a2f342005-09-10 00:27:14 -0700637 msleep_interruptible(XD_INIT_DISK_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
639 init_drive(count);
640 count++;
641
Nishanth Aravamudanf6a2f342005-09-10 00:27:14 -0700642 msleep_interruptible(XD_INIT_DISK_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 }
644 }
645 return (count);
646}
647
648static void __init xd_manual_geo_set (u_char drive)
649{
650 xd_info[drive].heads = (u_char)(xd_geo[3 * drive + 1]);
651 xd_info[drive].cylinders = (u_short)(xd_geo[3 * drive]);
652 xd_info[drive].sectors = (u_char)(xd_geo[3 * drive + 2]);
653}
654
655static void __init xd_dtc_init_controller (unsigned int address)
656{
657 switch (address) {
658 case 0x00000:
659 case 0xC8000: break; /*initial: 0x320 */
660 case 0xCA000: xd_iobase = 0x324;
661 case 0xD0000: /*5150CX*/
662 case 0xD8000: break; /*5150CX & 5150XL*/
663 default: printk("xd_dtc_init_controller: unsupported BIOS address %06x\n",address);
664 break;
665 }
666 xd_maxsectors = 0x01; /* my card seems to have trouble doing multi-block transfers? */
667
668 outb(0,XD_RESET); /* reset the controller */
669}
670
671
672static void __init xd_dtc5150cx_init_drive (u_char drive)
673{
674 /* values from controller's BIOS - BIOS chip may be removed */
675 static u_short geometry_table[][4] = {
676 {0x200,8,0x200,0x100},
677 {0x267,2,0x267,0x267},
678 {0x264,4,0x264,0x80},
679 {0x132,4,0x132,0x0},
680 {0x132,2,0x80, 0x132},
681 {0x177,8,0x177,0x0},
682 {0x132,8,0x84, 0x0},
683 {}, /* not used */
684 {0x132,6,0x80, 0x100},
685 {0x200,6,0x100,0x100},
686 {0x264,2,0x264,0x80},
687 {0x280,4,0x280,0x100},
688 {0x2B9,3,0x2B9,0x2B9},
689 {0x2B9,5,0x2B9,0x2B9},
690 {0x280,6,0x280,0x100},
691 {0x132,4,0x132,0x0}};
692 u_char n;
693
694 n = inb(XD_JUMPER);
695 n = (drive ? n : (n >> 2)) & 0x33;
696 n = (n | (n >> 2)) & 0x0F;
697 if (xd_geo[3*drive])
698 xd_manual_geo_set(drive);
699 else
700 if (n != 7) {
701 xd_info[drive].heads = (u_char)(geometry_table[n][1]); /* heads */
702 xd_info[drive].cylinders = geometry_table[n][0]; /* cylinders */
703 xd_info[drive].sectors = 17; /* sectors */
704#if 0
705 xd_info[drive].rwrite = geometry_table[n][2]; /* reduced write */
706 xd_info[drive].precomp = geometry_table[n][3] /* write precomp */
707 xd_info[drive].ecc = 0x0B; /* ecc length */
708#endif /* 0 */
709 }
710 else {
711 printk("xd%c: undetermined drive geometry\n",'a'+drive);
712 return;
713 }
714 xd_info[drive].control = 5; /* control byte */
715 xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B);
716 xd_recalibrate(drive);
717}
718
719static void __init xd_dtc_init_drive (u_char drive)
720{
721 u_char cmdblk[6],buf[64];
722
723 xd_build(cmdblk,CMD_DTCGETGEOM,drive,0,0,0,0,0);
724 if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) {
725 xd_info[drive].heads = buf[0x0A]; /* heads */
726 xd_info[drive].cylinders = ((u_short *) (buf))[0x04]; /* cylinders */
727 xd_info[drive].sectors = 17; /* sectors */
728 if (xd_geo[3*drive])
729 xd_manual_geo_set(drive);
730#if 0
731 xd_info[drive].rwrite = ((u_short *) (buf + 1))[0x05]; /* reduced write */
732 xd_info[drive].precomp = ((u_short *) (buf + 1))[0x06]; /* write precomp */
733 xd_info[drive].ecc = buf[0x0F]; /* ecc length */
734#endif /* 0 */
735 xd_info[drive].control = 0; /* control byte */
736
737 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]);
738 xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7);
739 if (xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 2))
740 printk("xd_dtc_init_drive: error setting step rate for xd%c\n", 'a'+drive);
741 }
742 else
743 printk("xd_dtc_init_drive: error reading geometry for xd%c\n", 'a'+drive);
744}
745
746static void __init xd_wd_init_controller (unsigned int address)
747{
748 switch (address) {
749 case 0x00000:
750 case 0xC8000: break; /*initial: 0x320 */
751 case 0xCA000: xd_iobase = 0x324; break;
752 case 0xCC000: xd_iobase = 0x328; break;
753 case 0xCE000: xd_iobase = 0x32C; break;
754 case 0xD0000: xd_iobase = 0x328; break; /* ? */
755 case 0xD8000: xd_iobase = 0x32C; break; /* ? */
756 default: printk("xd_wd_init_controller: unsupported BIOS address %06x\n",address);
757 break;
758 }
759 xd_maxsectors = 0x01; /* this one doesn't wrap properly either... */
760
761 outb(0,XD_RESET); /* reset the controller */
762
Nishanth Aravamudanf6a2f342005-09-10 00:27:14 -0700763 msleep(XD_INIT_DISK_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764}
765
766static void __init xd_wd_init_drive (u_char drive)
767{
768 /* values from controller's BIOS - BIOS may be disabled */
769 static u_short geometry_table[][4] = {
770 {0x264,4,0x1C2,0x1C2}, /* common part */
771 {0x132,4,0x099,0x0},
772 {0x267,2,0x1C2,0x1C2},
773 {0x267,4,0x1C2,0x1C2},
774
775 {0x334,6,0x335,0x335}, /* 1004 series RLL */
776 {0x30E,4,0x30F,0x3DC},
777 {0x30E,2,0x30F,0x30F},
778 {0x267,4,0x268,0x268},
779
780 {0x3D5,5,0x3D6,0x3D6}, /* 1002 series RLL */
781 {0x3DB,7,0x3DC,0x3DC},
782 {0x264,4,0x265,0x265},
783 {0x267,4,0x268,0x268}};
784
785 u_char cmdblk[6],buf[0x200];
786 u_char n = 0,rll,jumper_state,use_jumper_geo;
787 u_char wd_1002 = (xd_sigs[xd_type].string[7] == '6');
788
789 jumper_state = ~(inb(0x322));
790 if (jumper_state & 0x40)
791 xd_irq = 9;
792 rll = (jumper_state & 0x30) ? (0x04 << wd_1002) : 0;
793 xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0);
794 if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) {
795 xd_info[drive].heads = buf[0x1AF]; /* heads */
796 xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6]; /* cylinders */
797 xd_info[drive].sectors = 17; /* sectors */
798 if (xd_geo[3*drive])
799 xd_manual_geo_set(drive);
800#if 0
801 xd_info[drive].rwrite = ((u_short *) (buf))[0xD8]; /* reduced write */
802 xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA]; /* write precomp */
803 xd_info[drive].ecc = buf[0x1B4]; /* ecc length */
804#endif /* 0 */
805 xd_info[drive].control = buf[0x1B5]; /* control byte */
806 use_jumper_geo = !(xd_info[drive].heads) || !(xd_info[drive].cylinders);
807 if (xd_geo[3*drive]) {
808 xd_manual_geo_set(drive);
809 xd_info[drive].control = rll ? 7 : 5;
810 }
811 else if (use_jumper_geo) {
812 n = (((jumper_state & 0x0F) >> (drive << 1)) & 0x03) | rll;
813 xd_info[drive].cylinders = geometry_table[n][0];
814 xd_info[drive].heads = (u_char)(geometry_table[n][1]);
815 xd_info[drive].control = rll ? 7 : 5;
816#if 0
817 xd_info[drive].rwrite = geometry_table[n][2];
818 xd_info[drive].wprecomp = geometry_table[n][3];
819 xd_info[drive].ecc = 0x0B;
820#endif /* 0 */
821 }
822 if (!wd_1002) {
823 if (use_jumper_geo)
824 xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
825 geometry_table[n][2],geometry_table[n][3],0x0B);
826 else
827 xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,
828 ((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
829 }
830 /* 1002 based RLL controller requests converted addressing, but reports physical
831 (physical 26 sec., logical 17 sec.)
832 1004 based ???? */
833 if (rll & wd_1002) {
834 if ((xd_info[drive].cylinders *= 26,
835 xd_info[drive].cylinders /= 17) > 1023)
836 xd_info[drive].cylinders = 1023; /* 1024 ? */
837#if 0
838 xd_info[drive].rwrite *= 26;
839 xd_info[drive].rwrite /= 17;
840 xd_info[drive].wprecomp *= 26
841 xd_info[drive].wprecomp /= 17;
842#endif /* 0 */
843 }
844 }
845 else
846 printk("xd_wd_init_drive: error reading geometry for xd%c\n",'a'+drive);
847
848}
849
850static void __init xd_seagate_init_controller (unsigned int address)
851{
852 switch (address) {
853 case 0x00000:
854 case 0xC8000: break; /*initial: 0x320 */
855 case 0xD0000: xd_iobase = 0x324; break;
856 case 0xD8000: xd_iobase = 0x328; break;
857 case 0xE0000: xd_iobase = 0x32C; break;
858 default: printk("xd_seagate_init_controller: unsupported BIOS address %06x\n",address);
859 break;
860 }
861 xd_maxsectors = 0x40;
862
863 outb(0,XD_RESET); /* reset the controller */
864}
865
866static void __init xd_seagate_init_drive (u_char drive)
867{
868 u_char cmdblk[6],buf[0x200];
869
870 xd_build(cmdblk,CMD_ST11GETGEOM,drive,0,0,0,1,0);
871 if (!xd_command(cmdblk,PIO_MODE,buf,NULL,NULL,XD_TIMEOUT * 2)) {
872 xd_info[drive].heads = buf[0x04]; /* heads */
873 xd_info[drive].cylinders = (buf[0x02] << 8) | buf[0x03]; /* cylinders */
874 xd_info[drive].sectors = buf[0x05]; /* sectors */
875 xd_info[drive].control = 0; /* control byte */
876 }
877 else
878 printk("xd_seagate_init_drive: error reading geometry from xd%c\n", 'a'+drive);
879}
880
881/* Omti support courtesy Dirk Melchers */
882static void __init xd_omti_init_controller (unsigned int address)
883{
884 switch (address) {
885 case 0x00000:
886 case 0xC8000: break; /*initial: 0x320 */
887 case 0xD0000: xd_iobase = 0x324; break;
888 case 0xD8000: xd_iobase = 0x328; break;
889 case 0xE0000: xd_iobase = 0x32C; break;
890 default: printk("xd_omti_init_controller: unsupported BIOS address %06x\n",address);
891 break;
892 }
893
894 xd_maxsectors = 0x40;
895
896 outb(0,XD_RESET); /* reset the controller */
897}
898
899static void __init xd_omti_init_drive (u_char drive)
900{
901 /* gets infos from drive */
902 xd_override_init_drive(drive);
903
904 /* set other parameters, Hardcoded, not that nice :-) */
905 xd_info[drive].control = 2;
906}
907
908/* Xebec support (AK) */
909static void __init xd_xebec_init_controller (unsigned int address)
910{
911/* iobase may be set manually in range 0x300 - 0x33C
912 irq may be set manually to 2(9),3,4,5,6,7
913 dma may be set manually to 1,2,3
914 (How to detect them ???)
915BIOS address may be set manually in range 0x0 - 0xF8000
916If you need non-standard settings use the xd=... command */
917
918 switch (address) {
919 case 0x00000:
920 case 0xC8000: /* initially: xd_iobase==0x320 */
921 case 0xD0000:
922 case 0xD2000:
923 case 0xD4000:
924 case 0xD6000:
925 case 0xD8000:
926 case 0xDA000:
927 case 0xDC000:
928 case 0xDE000:
929 case 0xE0000: break;
930 default: printk("xd_xebec_init_controller: unsupported BIOS address %06x\n",address);
931 break;
932 }
933
934 xd_maxsectors = 0x01;
935 outb(0,XD_RESET); /* reset the controller */
936
Nishanth Aravamudanf6a2f342005-09-10 00:27:14 -0700937 msleep(XD_INIT_DISK_DELAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938}
939
940static void __init xd_xebec_init_drive (u_char drive)
941{
942 /* values from controller's BIOS - BIOS chip may be removed */
943 static u_short geometry_table[][5] = {
944 {0x132,4,0x080,0x080,0x7},
945 {0x132,4,0x080,0x080,0x17},
946 {0x264,2,0x100,0x100,0x7},
947 {0x264,2,0x100,0x100,0x17},
948 {0x132,8,0x080,0x080,0x7},
949 {0x132,8,0x080,0x080,0x17},
950 {0x264,4,0x100,0x100,0x6},
951 {0x264,4,0x100,0x100,0x17},
952 {0x2BC,5,0x2BC,0x12C,0x6},
953 {0x3A5,4,0x3A5,0x3A5,0x7},
954 {0x26C,6,0x26C,0x26C,0x7},
955 {0x200,8,0x200,0x100,0x17},
956 {0x400,5,0x400,0x400,0x7},
957 {0x400,6,0x400,0x400,0x7},
958 {0x264,8,0x264,0x200,0x17},
959 {0x33E,7,0x33E,0x200,0x7}};
960 u_char n;
961
962 n = inb(XD_JUMPER) & 0x0F; /* BIOS's drive number: same geometry
963 is assumed for BOTH drives */
964 if (xd_geo[3*drive])
965 xd_manual_geo_set(drive);
966 else {
967 xd_info[drive].heads = (u_char)(geometry_table[n][1]); /* heads */
968 xd_info[drive].cylinders = geometry_table[n][0]; /* cylinders */
969 xd_info[drive].sectors = 17; /* sectors */
970#if 0
971 xd_info[drive].rwrite = geometry_table[n][2]; /* reduced write */
972 xd_info[drive].precomp = geometry_table[n][3] /* write precomp */
973 xd_info[drive].ecc = 0x0B; /* ecc length */
974#endif /* 0 */
975 }
976 xd_info[drive].control = geometry_table[n][4]; /* control byte */
977 xd_setparam(CMD_XBSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B);
978 xd_recalibrate(drive);
979}
980
981/* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
982 etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
983static void __init xd_override_init_drive (u_char drive)
984{
985 u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
986 u_char cmdblk[6],i;
987
988 if (xd_geo[3*drive])
989 xd_manual_geo_set(drive);
990 else {
991 for (i = 0; i < 3; i++) {
992 while (min[i] != max[i] - 1) {
993 test[i] = (min[i] + max[i]) / 2;
994 xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0);
995 if (!xd_command(cmdblk,PIO_MODE,NULL,NULL,NULL,XD_TIMEOUT * 2))
996 min[i] = test[i];
997 else
998 max[i] = test[i];
999 }
1000 test[i] = min[i];
1001 }
1002 xd_info[drive].heads = (u_char) min[0] + 1;
1003 xd_info[drive].cylinders = (u_short) min[1] + 1;
1004 xd_info[drive].sectors = (u_char) min[2] + 1;
1005 }
1006 xd_info[drive].control = 0;
1007}
1008
1009/* xd_setup: initialise controller from command line parameters */
1010static void __init do_xd_setup (int *integers)
1011{
1012 switch (integers[0]) {
1013 case 4: if (integers[4] < 0)
1014 nodma = 1;
1015 else if (integers[4] < 8)
1016 xd_dma = integers[4];
1017 case 3: if ((integers[3] > 0) && (integers[3] <= 0x3FC))
1018 xd_iobase = integers[3];
1019 case 2: if ((integers[2] > 0) && (integers[2] < 16))
1020 xd_irq = integers[2];
1021 case 1: xd_override = 1;
Tobias Klauser945f3902006-01-08 01:05:11 -08001022 if ((integers[1] >= 0) && (integers[1] < ARRAY_SIZE(xd_sigs)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 xd_type = integers[1];
1024 case 0: break;
1025 default:printk("xd: too many parameters for xd\n");
1026 }
1027 xd_maxsectors = 0x01;
1028}
1029
1030/* xd_setparam: set the drive characteristics */
1031static 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)
1032{
1033 u_char cmdblk[14];
1034
1035 xd_build(cmdblk,command,drive,0,0,0,0,0);
1036 cmdblk[6] = (u_char) (cylinders >> 8) & 0x03;
1037 cmdblk[7] = (u_char) (cylinders & 0xFF);
1038 cmdblk[8] = heads & 0x1F;
1039 cmdblk[9] = (u_char) (rwrite >> 8) & 0x03;
1040 cmdblk[10] = (u_char) (rwrite & 0xFF);
1041 cmdblk[11] = (u_char) (wprecomp >> 8) & 0x03;
1042 cmdblk[12] = (u_char) (wprecomp & 0xFF);
1043 cmdblk[13] = ecc;
1044
1045 /* Some controllers require geometry info as data, not command */
1046
1047 if (xd_command(cmdblk,PIO_MODE,NULL,&cmdblk[6],NULL,XD_TIMEOUT * 2))
1048 printk("xd: error setting characteristics for xd%c\n", 'a'+drive);
1049}
1050
1051
1052#ifdef MODULE
1053
1054module_param_array(xd, int, NULL, 0);
1055module_param_array(xd_geo, int, NULL, 0);
1056module_param(nodma, bool, 0);
1057
1058MODULE_LICENSE("GPL");
1059
1060void cleanup_module(void)
1061{
1062 int i;
1063 unregister_blkdev(XT_DISK_MAJOR, "xd");
1064 for (i = 0; i < xd_drives; i++) {
1065 del_gendisk(xd_gendisk[i]);
1066 put_disk(xd_gendisk[i]);
1067 }
1068 blk_cleanup_queue(xd_queue);
1069 release_region(xd_iobase,4);
1070 if (xd_drives) {
1071 free_irq(xd_irq, NULL);
1072 free_dma(xd_dma);
1073 if (xd_dma_buffer)
1074 xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200);
1075 }
1076}
1077#else
1078
1079static int __init xd_setup (char *str)
1080{
1081 int ints[5];
1082 get_options (str, ARRAY_SIZE (ints), ints);
1083 do_xd_setup (ints);
1084 return 1;
1085}
1086
1087/* xd_manual_geo_init: initialise drive geometry from command line parameters
1088 (used only for WD drives) */
1089static int __init xd_manual_geo_init (char *str)
1090{
1091 int i, integers[1 + 3*XD_MAXDRIVES];
1092
1093 get_options (str, ARRAY_SIZE (integers), integers);
1094 if (integers[0]%3 != 0) {
1095 printk("xd: incorrect number of parameters for xd_geo\n");
1096 return 1;
1097 }
1098 for (i = 0; (i < integers[0]) && (i < 3*XD_MAXDRIVES); i++)
1099 xd_geo[i] = integers[i+1];
1100 return 1;
1101}
1102
1103__setup ("xd=", xd_setup);
1104__setup ("xd_geo=", xd_manual_geo_init);
1105
1106#endif /* MODULE */
1107
1108module_init(xd_init);
1109MODULE_ALIAS_BLOCKDEV_MAJOR(XT_DISK_MAJOR);