patch-2.1.78 linux/drivers/block/xd.c
Next file: linux/drivers/block/xd.h
Previous file: linux/drivers/block/ide-cd.c
Back to the patch index
Back to the overall index
- Lines: 230
- Date:
Sun Jan 4 10:40:15 1998
- Orig file:
v2.1.77/linux/drivers/block/xd.c
- Orig date:
Sat Nov 29 11:25:09 1997
diff -u --recursive --new-file v2.1.77/linux/drivers/block/xd.c linux/drivers/block/xd.c
@@ -20,13 +20,14 @@
*
* Modularized: 04/10/96 by Todd Fries, tfries@umr.edu
*
- * Revised: 13/09/97 by Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl
+ * Revised: 13/12/97 by Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl
* Fixed some problems with disk initialization and module initiation.
* Added support for manual geometry setting (except Seagate controllers)
* in form:
* xd_geo=<cyl_xda>,<head_xda>,<sec_xda>[,<cyl_xdb>,<head_xdb>,<sec_xdb>]
- * Recovered DMA access. Abridged messages. Added support for DTC5051CX &
- * WD1002-27X controllers. Added alternate jumper geometry setting.
+ * Recovered DMA access. Abridged messages. Added support for DTC5051CX,
+ * WD1002-27X & XEBEC controllers. Driver uses now some jumper settings.
+ * Extended ioctl() support.
*/
#include <linux/module.h>
@@ -38,6 +39,7 @@
#include <linux/timer.h>
#include <linux/genhd.h>
#include <linux/hdreg.h>
+#include <linux/ioport.h>
#include <linux/init.h>
#include <asm/system.h>
@@ -114,12 +116,15 @@
{ 0x0010,"ST11R BIOS",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Risto Kankkunen, risto.kankkunen@cs.helsinki.fi */
{ 0x0010,"ST11 BIOS v1.7",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11R" }, /* Alan Hourihane, alanh@fairlite.demon.co.uk */
{ 0x1000,"(c)Copyright 1987 SMS",xd_omti_init_controller,xd_omti_init_drive,"n OMTI 5520" }, /* Dirk Melchers, dirk@merlin.nbg.sub.org */
+ { 0x0006,"COPYRIGHT XEBEC (C) 1984",xd_xebec_init_controller,xd_xebec_init_drive," XEBEC" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */
};
static unsigned int xd_bases[] __initdata =
{
0xC8000, 0xCA000, 0xCC000,
- 0xCE000, 0xD0000, 0xD8000,
+ 0xCE000, 0xD0000, 0xD2000,
+ 0xD4000, 0xD6000, 0xD8000,
+ 0xDA000, 0xDC000, 0xDE000,
0xE0000
};
@@ -219,6 +224,11 @@
if (xd_detect(&controller,&address)) {
printk("Detected a%s controller (type %d) at address %06x\n",xd_sigs[controller].name,controller,address);
+ if (check_region(xd_iobase,4)) {
+ printk("xd: Ports at 0x%x are not available\n",xd_iobase);
+ return;
+ }
+ request_region(xd_iobase,4,"xd");
if (controller)
xd_sigs[controller].init_controller(address);
xd_drives = xd_initdrives(xd_sigs[controller].init_drive);
@@ -331,6 +341,8 @@
if(arg > 0xff) return -EINVAL;
read_ahead[MAJOR(inode->i_rdev)] = arg;
return 0;
+ case BLKRAGET:
+ return put_user(read_ahead[MAJOR(inode->i_rdev)], (long*) arg);
case BLKGETSIZE:
if (!arg) return -EINVAL;
return put_user(xd_struct[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
@@ -339,6 +351,19 @@
fsync_dev(inode->i_rdev);
invalidate_buffers(inode->i_rdev);
return 0;
+ case HDIO_SET_DMA:
+ if (!suser()) return -EACCES;
+ if (xdc_busy) return -EBUSY;
+ nodma = !arg;
+ if (nodma && xd_dma_buffer) {
+ xd_dma_mem_free((unsigned long)xd_dma_buffer, xd_maxsectors * 0x200);
+ xd_dma_buffer = 0;
+ }
+ return 0;
+ case HDIO_GET_DMA:
+ return put_user(!nodma, (long *) arg);
+ case HDIO_GET_MULTCOUNT:
+ return put_user(xd_maxsectors, (long *) arg);
case BLKRRPART:
return xd_reread_partitions(inode->i_rdev);
RO_IOCTLS(inode->i_rdev,arg);
@@ -929,6 +954,81 @@
xd_info[drive].control = 2;
}
+/* Xebec support (AK) */
+__initfunc(static void xd_xebec_init_controller (unsigned int address))
+{
+/* iobase may be set manually in range 0x300 - 0x33C
+ irq may be set manually to 2(9),3,4,5,6,7
+ dma may be set manually to 1,2,3
+ (How to detect them ???)
+BIOS address may be set manually in range 0x0 - 0xF8000
+If you need non-standard settings use the xd=... command */
+
+ switch (address) {
+ case 0x00000:
+ case 0xC8000: /* initially: xd_iobase==0x320 */
+ case 0xD0000:
+ case 0xD2000:
+ case 0xD4000:
+ case 0xD6000:
+ case 0xD8000:
+ case 0xDA000:
+ case 0xDC000:
+ case 0xDE000:
+ case 0xE0000: break;
+ default: printk("xd_xebec_init_controller: unsupported BIOS address %06x\n",address);
+ break;
+ }
+
+ xd_maxsectors = 0x01;
+ outb(0,XD_RESET); /* reset the controller */
+
+ xd_timer.expires = jiffies + XD_INIT_DISK_DELAY;
+ add_timer(&xd_timer);
+ sleep_on(&xdc_wait);
+}
+
+__initfunc(static void xd_xebec_init_drive (u_char drive))
+{
+ /* values from controller's BIOS - BIOS chip may be removed */
+ static u_short geometry_table[][5] = {
+ {0x132,4,0x080,0x080,0x7},
+ {0x132,4,0x080,0x080,0x17},
+ {0x264,2,0x100,0x100,0x7},
+ {0x264,2,0x100,0x100,0x17},
+ {0x132,8,0x080,0x080,0x7},
+ {0x132,8,0x080,0x080,0x17},
+ {0x264,4,0x100,0x100,0x6},
+ {0x264,4,0x100,0x100,0x17},
+ {0x2BC,5,0x2BC,0x12C,0x6},
+ {0x3A5,4,0x3A5,0x3A5,0x7},
+ {0x26C,6,0x26C,0x26C,0x7},
+ {0x200,8,0x200,0x100,0x17},
+ {0x400,5,0x400,0x400,0x7},
+ {0x400,6,0x400,0x400,0x7},
+ {0x264,8,0x264,0x200,0x17},
+ {0x33E,7,0x33E,0x200,0x7}};
+ u_char n;
+
+ n = inb(XD_JUMPER) & 0x0F; /* BIOS's drive number: same geometry
+ is assumed for BOTH drives */
+ if (xd_geo[3*drive])
+ xd_manual_geo_set(drive);
+ else {
+ xd_info[drive].heads = (u_char)(geometry_table[n][1]); /* heads */
+ xd_info[drive].cylinders = geometry_table[n][0]; /* cylinders */
+ xd_info[drive].sectors = 17; /* sectors */
+#if 0
+ xd_info[drive].rwrite = geometry_table[n][2]; /* reduced write */
+ xd_info[drive].precomp = geometry_table[n][3] /* write precomp */
+ xd_info[drive].ecc = 0x0B; /* ecc length */
+#endif /* 0 */
+ }
+ xd_info[drive].control = geometry_table[n][4]; /* control byte */
+ xd_setparam(CMD_XBSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B);
+ xd_recalibrate(drive);
+}
+
/* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
__initfunc(static void xd_override_init_drive (u_char drive))
@@ -1008,7 +1108,9 @@
cmdblk[12] = (u_char) (wprecomp & 0xFF);
cmdblk[13] = ecc;
- if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
+ /* Some controllers require geometry info as data, not command */
+
+ if (xd_command(cmdblk,PIO_MODE,0,&cmdblk[6],0,XD_TIMEOUT * 2))
printk("xd: error setting characteristics for xd%c\n", 'a'+drive);
}
@@ -1020,6 +1122,23 @@
MODULE_PARM(xd_geo, "3-6i");
MODULE_PARM(nodma, "i");
+static void xd_done (void)
+{
+ struct gendisk ** gdp;
+
+ blksize_size[MAJOR_NR] = NULL;
+ blk_dev[MAJOR_NR].request_fn = NULL;
+ blk_size[MAJOR_NR] = NULL;
+ hardsect_size[MAJOR_NR] = NULL;
+ read_ahead[MAJOR_NR] = 0;
+ for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
+ if (*gdp == &xd_gendisk)
+ break;
+ if (*gdp)
+ *gdp = (*gdp)->next;
+ release_region(xd_iobase,4);
+}
+
int init_module(void)
{
int i,count = 0;
@@ -1036,6 +1155,7 @@
if (!xd_drives) {
/* no drives detected - unload module */
unregister_blkdev(MAJOR_NR, "xd");
+ xd_done();
return (-1);
}
for (i = 0; i < xd_drives; i++)
@@ -1047,7 +1167,20 @@
void cleanup_module(void)
{
+ int partition,dev,start;
+
unregister_blkdev(MAJOR_NR, "xd");
+ for (dev = 0; dev < xd_drives; dev++) {
+ start = dev << xd_gendisk.minor_shift;
+ for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) {
+ int minor = (start | partition);
+ kdev_t devp = MKDEV(MAJOR_NR, minor);
+ start = dev << xd_gendisk.minor_shift;
+ sync_dev(devp);
+ invalidate_buffers(devp);
+ }
+ }
+ xd_done();
if (xd_drives) {
free_irq(xd_irq, NULL);
free_dma(xd_dma);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov