new version of xd.c patch (fwd)

=?ISO-8859-2?Q?Tomasz_K=B3oczko?= (kloczek@rudy.mif.pg.gda.pl)
Fri, 15 Aug 1997 15:34:58 +0200 (MET DST)


---------- Forwarded message ----------
Date: Thu, 14 Aug 1997 11:02:48 +0200 (MET DST)
From: "Andrzej M. Krzysztofowicz" <ankry@disneyland.mif.pg.gda.pl>
To: Tomasz Kłoczko <kloczek@disneyland.mif.pg.gda.pl>
Subject: new version of xd.c patch

Hi,
I have prepared new version of patch for XT-disk driver for 2.0 kernels.
Totally my changes include

* removed some problems with using the driver as a module (in the
original form it was unusable as a module):
- partition detection,
- increasing/decreasing usage count,
- driver will not load when no drives detected (removed problem
with freeing not allocated memory while unloading);
* added support for 2 more controllers;
* removed problems with 2nd drive (xdb) detection with Seagate ST11M;
* removed(? - need testing) problem with WD controllers resetting;
* enabled manual drive geometry setting for WD controllers (autodetection
fails sometimes);
* after applying this patch the driver will rely on *ALL* parameters
you enter manually (the original relied only on the first one -
controller type). You can now omit some of them or set to "0" for
standard values

All versions of my patch are available as

ftp://rudy.mif.pg.gda.pl/pub/People/ankry/patch-xd-<date>-2.0.gz

The last version is always available as

ftp://rudy.mif.pg.gda.pl/pub/People/ankry/patch-xd-2.0.gz

With greetings

Andrzej

****************************************************************************
diff -u --recursive v2.0.30p2/include/linux/xd.h linux/include/linux/xd.h
--- v2.0.30p2/include/linux/xd.h Fri Mar 1 06:50:56 1996
+++ linux/include/linux/xd.h Wed Aug 13 10:47:04 1997
@@ -128,6 +128,7 @@
static void xd_dtc_init_drive (u_char drive);
static void xd_wd_init_controller (u_char *address);
static void xd_wd_init_drive (u_char drive);
+static void xd_wd1002_init_drive (u_char drive);
static void xd_seagate_init_controller (u_char *address);
static void xd_seagate_init_drive (u_char drive);
static void xd_omti_init_controller (u_char *address);
diff -u --recursive v2.0.30p2/init/main.c linux/init/main.c
--- v2.0.30p2/init/main.c Wed Aug 13 11:42:54 1997
+++ linux/init/main.c Wed Aug 13 11:44:26 1997
@@ -354,6 +354,7 @@
#endif
#ifdef CONFIG_BLK_DEV_XD
{ "xd=", xd_setup },
+ { "xd_geo=", xd_manual_geo },
#endif
#ifdef CONFIG_BLK_DEV_FD
{ "floppy=", floppy_setup },
diff -u --recursive v2.0.30p2/drivers/block/xd.c linux/drivers/block/xd.c
--- v2.0.30p2/drivers/block/xd.c Sun Sep 8 18:50:20 1996
+++ linux/drivers/block/xd.c Thu Aug 14 00:30:05 1997
@@ -20,6 +20,10 @@
*
* Modularized: 04/10/96 by Todd Fries, tfries@umr.edu
*
+ * Revised: 14/08/97 by Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl
+ * Fixed problems with 2nd disk initialization. Continued modularization.
+ * Added support for manual geometry setting (for WD controllers) in form:
+ * xd_geo=<cyl_xda>,<head_xda>,<sec_xda>[,<cyl_xdb>,<head_xdb>,<sec_xdb>]
*/

#include <linux/module.h>
@@ -39,6 +43,11 @@
#define MAJOR_NR XT_DISK_MAJOR
#include <linux/blk.h>

+#define XD_INIT_DISK_DELAY 3 /* 30 ms delay during disk initialization */
+
+/* Above may need to be increased if a problem with the 2nd drive detection
+ (for ST11M controller) or resetting a controler (WD) appears */
+
XD_INFO xd_info[XD_MAXDRIVES];

/* If you try this driver and find that your card is not detected by the driver at bootup, you need to add your BIOS
@@ -76,6 +85,10 @@
{ 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 */
+ { 0x0008,"[BXD06 (C) DTC 17-MAY-1985]",xd_dtc_init_controller,xd_override_init_drive," DTC 5150CX" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */
+ { 0x0008,"07/15/86(C) Copyright 1986 Western Digital Corp.",xd_wd_init_controller,xd_wd1002_init_drive," Western Digital 1002-27X" }, /* Andrzej Krzysztofowicz, ankry@mif.pg.gda.pl */
+/* Re-sort the table? It'll need changes in HOWTO */
+/* Are pos. 3,4 (WD1002AWX1,WD1004A27X) mistakes? */
};
static u_char *xd_bases[] =
{
@@ -84,7 +97,7 @@
(u_char *) 0xE0000
};

-static struct hd_struct xd[XD_MAXDRIVES << 6];
+static struct hd_struct xd_struct[XD_MAXDRIVES << 6];
static int xd_sizes[XD_MAXDRIVES << 6], xd_access[XD_MAXDRIVES] = { 0, 0 };
static int xd_blocksizes[XD_MAXDRIVES << 6];
static struct gendisk xd_gendisk = {
@@ -98,7 +111,7 @@
#else
xd_geninit, /* init function */
#endif
- xd, /* hd struct */
+ xd_struct, /* hd struct */
xd_sizes, /* block sizes */
0, /* number */
(void *) xd_info, /* internal */
@@ -122,6 +135,11 @@
static u_char xd_override = 0, xd_type = 0;
static u_short xd_iobase = 0;

+#ifndef MODULE
+static
+#endif /* MODULE */
+int xd_geo[XD_MAXDRIVES*3] = { 0,0,0,0,0,0 };
+
/* xd_init: register the block device number and set up pointer tables */
int xd_init (void)
{
@@ -175,7 +193,8 @@
printk("xd_geninit: detected %d hard drive%s (using IRQ%d & DMA%d)\n",xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma);
for (i = 0; i < xd_drives; i++)
printk("xd_geninit: drive %d geometry - heads = %d, cylinders = %d, sectors = %d\n",i,xd_info[i].heads,xd_info[i].cylinders,xd_info[i].sectors);
-
+ }
+ if (xd_drives) {
if (!request_irq(xd_irq,xd_interrupt_handler, 0, "XT harddisk", NULL)) {
if (request_dma(xd_dma,"xd")) {
printk("xd_geninit: unable to get DMA%d\n",xd_dma);
@@ -187,7 +206,7 @@
}

for (i = 0; i < xd_drives; i++) {
- xd[i << 6].nr_sects = xd_info[i].heads * xd_info[i].cylinders * xd_info[i].sectors;
+ xd_struct[i << 6].nr_sects = xd_info[i].heads * xd_info[i].cylinders * xd_info[i].sectors;
xd_valid[i] = 1;
}

@@ -206,6 +225,10 @@
while (!xd_valid[dev])
sleep_on(&xd_wait_open);

+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif /* MODULE */
+
xd_access[dev]++;

return (0);
@@ -226,8 +249,8 @@

if (CURRENT_DEV < xd_drives
&& CURRENT->sector + CURRENT->nr_sectors
- <= xd[MINOR(CURRENT->rq_dev)].nr_sects) {
- block = CURRENT->sector + xd[MINOR(CURRENT->rq_dev)].start_sect;
+ <= xd_struct[MINOR(CURRENT->rq_dev)].nr_sects) {
+ block = CURRENT->sector + xd_struct[MINOR(CURRENT->rq_dev)].start_sect;
count = CURRENT->nr_sectors;

switch (CURRENT->cmd) {
@@ -259,7 +282,7 @@
put_user(xd_info[dev].heads, &geometry->heads);
put_user(xd_info[dev].sectors, &geometry->sectors);
put_user(xd_info[dev].cylinders, &geometry->cylinders);
- put_user(xd[MINOR(inode->i_rdev)].start_sect,&geometry->start);
+ put_user(xd_struct[MINOR(inode->i_rdev)].start_sect,&geometry->start);

return (0);
}
@@ -277,7 +300,7 @@
if (arg) {
if ((err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long))))
return (err);
- put_user(xd[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
+ put_user(xd_struct[MINOR(inode->i_rdev)].nr_sects,(long *) arg);

return (0);
}
@@ -305,6 +328,11 @@
if (dev < xd_drives) {
sync_dev(inode->i_rdev);
xd_access[dev]--;
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif /* MODULE */
+
}
}

@@ -378,7 +406,7 @@
case 3: printk("xd_readwrite: miscellaneous error, code = 0x%X",sense[0] & 0x0F); break;
}
if (sense[0] & 0x80)
- printk(" - drive = %d, head = %d, cylinder = %d, sector = %d\n",sense[1] & 0xE0,sense[1] & 0x1F,((sense[2] & 0xC0) << 2) | sense[3],sense[2] & 0x3F);
+ printk(" - drive = %d, head = %d, cylinder = %d, sector = %d\n",((sense[1] & 0xE0) >> 5),sense[1] & 0x1F,((sense[2] & 0xC0) << 2) | sense[3],sense[2] & 0x3F);
else
printk(" - no valid disk address\n");
return (0);
@@ -527,12 +555,19 @@
static u_char xd_initdrives (void (*init_drive)(u_char drive))
{
u_char cmdblk[6],i,count = 0;
+ u_long end_delay;

for (i = 0; i < XD_MAXDRIVES; i++) {
xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0);
if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8)) {
+ end_delay = jiffies + XD_INIT_DISK_DELAY;
+ while (jiffies < end_delay)
+ ;
init_drive(count);
count++;
+ end_delay = jiffies + XD_INIT_DISK_DELAY;
+ while (jiffies < end_delay)
+ ;
}
}
return (count);
@@ -540,14 +575,19 @@

static void xd_dtc_init_controller (u_char *address)
{
- switch ((u_long) address) {
- case 0xC8000: xd_iobase = 0x320; break;
- case 0xCA000: xd_iobase = 0x324; break;
- default: printk("xd_dtc_init_controller: unsupported BIOS address %p\n",address);
- xd_iobase = 0x320; break;
- }
- xd_irq = 5; /* the IRQ _can_ be changed on this card, but requires a hardware mod */
- xd_dma = 3;
+ if (!xd_iobase) /* if not set manually...*/
+ switch ((u_long) address) {
+ case 0xC8000: xd_iobase = 0x320; break;
+ case 0xCA000: xd_iobase = 0x324; break;
+ case 0xD0000: xd_iobase = 0x320; break;
+ case 0xD8000: xd_iobase = 0x320; break;
+ default: printk("xd_dtc_init_controller: unsupported BIOS address %p\n",address);
+ xd_iobase = 0x320; break;
+ }
+ if (!xd_irq) /* if not set manually...*/
+ xd_irq = 5; /* the IRQ _can_ be changed on this card, but requires a hardware mod */
+ if (!xd_dma) /* if not set manually...*/
+ xd_dma = 3;
xd_maxsectors = 0x01; /* my card seems to have trouble doing multi-block transfers? */

outb(0,XD_RESET); /* reset the controller */
@@ -580,21 +620,30 @@

static void xd_wd_init_controller (u_char *address)
{
- switch ((u_long) address) {
- case 0xC8000: xd_iobase = 0x320; break;
- case 0xCA000: xd_iobase = 0x324; break;
- case 0xCC000: xd_iobase = 0x328; break;
- case 0xCE000: xd_iobase = 0x32C; break;
- case 0xD0000: xd_iobase = 0x328; break;
- case 0xD8000: xd_iobase = 0x32C; break;
- default: printk("xd_wd_init_controller: unsupported BIOS address %p\n",address);
- xd_iobase = 0x320; break;
- }
- xd_irq = 5; /* don't know how to auto-detect this yet */
- xd_dma = 3;
+ u_long end_delay;
+
+ if (!xd_iobase) /* if not set manually...*/
+ switch ((u_long) address) {
+ case 0xC8000: xd_iobase = 0x320; break;
+ case 0xCA000: xd_iobase = 0x324; break;
+ case 0xCC000: xd_iobase = 0x328; break;
+ case 0xCE000: xd_iobase = 0x32C; break;
+ case 0xD0000: xd_iobase = 0x328; break;
+ case 0xD8000: xd_iobase = 0x32C; break;
+ default: printk("xd_wd_init_controller: unsupported BIOS address %p\n",address);
+ xd_iobase = 0x320; break;
+ }
+ if (!xd_irq) /* if not set manually...*/
+ xd_irq = 5; /* don't know how to auto-detect this yet */
+ if (!xd_dma) /* if not set manually...*/
+ xd_dma = 3;
xd_maxsectors = 0x01; /* this one doesn't wrap properly either... */

- /* outb(0,XD_RESET); */ /* reset the controller */
+ outb(0,XD_RESET); /* reset the controller */
+
+ end_delay = jiffies + XD_INIT_DISK_DELAY;
+ while (jiffies < end_delay) /* without this delay controller hangs */
+ ;
}

static void xd_wd_init_drive (u_char drive)
@@ -606,6 +655,11 @@
xd_info[drive].heads = buf[0x1AF]; /* heads */
xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6]; /* cylinders */
xd_info[drive].sectors = 17; /* sectors */
+ if (xd_geo[3*drive]) {
+ xd_info[drive].heads = (u_char)(xd_geo[3*drive+1]);
+ xd_info[drive].cylinders = (u_short)(xd_geo[3*drive]);
+ xd_info[drive].sectors = (u_char)(xd_geo[3*drive+2]);
+ }
#if 0
xd_info[drive].rwrite = ((u_short *) (buf))[0xD8]; /* reduced write */
xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA]; /* write precomp */
@@ -619,18 +673,50 @@
printk("xd_wd_init_drive: error reading geometry for drive %d\n",drive);
}

-static void xd_seagate_init_controller (u_char *address)
+static void xd_wd1002_init_drive (u_char drive)
{
- switch ((u_long) address) {
- case 0xC8000: xd_iobase = 0x320; break;
- case 0xD0000: xd_iobase = 0x324; break;
- case 0xD8000: xd_iobase = 0x328; break;
- case 0xE0000: xd_iobase = 0x32C; break;
- default: printk("xd_seagate_init_controller: unsupported BIOS address %p\n",address);
- xd_iobase = 0x320; break;
+ u_char cmdblk[6],buf[0x200];
+
+ xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0);
+ if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
+ xd_info[drive].heads = buf[0x1AF]; /* heads */
+ xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6]; /* cylinders */
+ xd_info[drive].sectors = 17; /* sectors */
+ if (xd_geo[3*drive]) {
+ xd_info[drive]..heads = (u_char)(xd_geo[3*drive+1]);
+ xd_info[drive].cylinders = (u_short)(xd_geo[3*drive]);
+ xd_info[drive].sectors = (u_char)(xd_geo[3*drive+2]);
+ }
+#if 0
+ xd_info[drive].rwrite = ((u_short *) (buf))[0xD8]; /* reduced write */
+ xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA]; /* write precomp */
+ xd_info[drive].ecc = buf[0x1B4]; /* ecc length */
+#endif /* 0 */
+ xd_info[drive].control = buf[0x1B5]; /* control byte */
+
+/* xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);*/
+/* commented out - above doesn't work with WD1002-27X */
+
}
- xd_irq = 5; /* the IRQ and DMA channel are fixed on the Seagate controllers */
- xd_dma = 3;
+ else
+ printk("xd_wd_init_drive: error reading geometry for drive %d\n",drive);
+}
+
+static void xd_seagate_init_controller (u_char *address)
+{
+ if (!xd_iobase) /* if not set manually...*/
+ switch ((u_long) address) {
+ case 0xC8000: xd_iobase = 0x320; break;
+ case 0xD0000: xd_iobase = 0x324; break;
+ case 0xD8000: xd_iobase = 0x328; break;
+ case 0xE0000: xd_iobase = 0x32C; break;
+ default: printk("xd_seagate_init_controller: unsupported BIOS address %p\n",address);
+ xd_iobase = 0x320; break;
+ }
+ if (!xd_irq) /* if not set manually...*/
+ xd_irq = 5; /* the IRQ and DMA channel are fixed on the Seagate controllers */
+ if (!xd_dma) /* if not set manually...*/
+ xd_dma = 3;
xd_maxsectors = 0x40;

outb(0,XD_RESET); /* reset the controller */
@@ -654,17 +740,20 @@
/* Omti support courtesy Dirk Melchers */
static void xd_omti_init_controller (u_char *address)
{
- switch ((u_long) address) {
- case 0xC8000: xd_iobase = 0x320; break;
- case 0xD0000: xd_iobase = 0x324; break;
- case 0xD8000: xd_iobase = 0x328; break;
- case 0xE0000: xd_iobase = 0x32C; break;
- default: printk("xd_omti_init_controller: unsupported BIOS address %p\n",address);
- xd_iobase = 0x320; break;
- }
+ if (!xd_iobase) /* if not set manually...*/
+ switch ((u_long) address) {
+ case 0xC8000: xd_iobase = 0x320; break;
+ case 0xD0000: xd_iobase = 0x324; break;
+ case 0xD8000: xd_iobase = 0x328; break;
+ case 0xE0000: xd_iobase = 0x32C; break;
+ default: printk("xd_omti_init_controller: unsupported BIOS address %p\n",address);
+ xd_iobase = 0x320; break;
+ }

- xd_irq = 5; /* the IRQ and DMA channel are fixed on the Omti controllers */
- xd_dma = 3;
+ if (!xd_irq) /* if not set manually...*/
+ xd_irq = 5; /* the IRQ and DMA channel are fixed on the Omti controllers */
+ if (!xd_dma) /* if not set manually...*/
+ xd_dma = 3;
xd_maxsectors = 0x40;

outb(0,XD_RESET); /* reset the controller */
@@ -703,19 +792,37 @@
xd_info[drive].control = 0;
}

-/* xd_setup: initialise from command line parameters */
+/* xd_setup: initialise controler from command line parameters */
void xd_setup (char *command,int *integers)
{
- xd_override = 1;
-
- xd_type = integers[1];
- xd_irq = integers[2];
- xd_iobase = integers[3];
- xd_dma = integers[4];
-
+ switch (integers[0]) {
+ case 4: xd_dma = integers[4];
+ case 3: xd_iobase = integers[3];
+ case 2: xd_irq = integers[2];
+ case 1: xd_override = 1;
+ xd_type = integers[1];
+ case 0: break;
+ default:printk("xd_setup: too many parameters\n");
+ }
xd_maxsectors = 0x01;
}

+#ifndef MODULE
+/* xd_manual_geo: initialise drive geometry from command line parameters
+ (used only for WD drives) */
+void xd_manual_geo (char *command,int *integers)
+{
+ int i;
+ if (integers[0]%3 != 0) {
+ printk("xd_manual_geo: incorrect number of parameters\n");
+ return;
+ }
+ for (i = 0; (i < integers[0]) && (i < 3*XD_MAXDRIVES); i++) {
+ xd_geo[i] = integers[i+1];
+ }
+}
+#endif /* MODULE */
+
/* xd_setparam: set the drive characteristics */
static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)
{
@@ -737,13 +844,28 @@


#ifdef MODULE
+int xd[5] = { 0,0,0,0,0 };
+
int init_module(void)
{
+ int i,count = 0;
int error = xd_init();
if (!error)
{
printk(KERN_INFO "XD: Loaded as a module.\n");
+ for (i = 4; i > 0; i--)
+ if ((xd[i]=xd[i-1]) && !count)
+ count = i;
+ if ((xd[0]=count))
+ xd_setup(NULL, xd);
xd_geninit(&(struct gendisk) { 0,0,0,0,0,0,0,0,0,0,0 });
+ if (!xd_drives) {
+ /* no drives detected - unload module */
+ unregister_blkdev(MAJOR_NR, "xd");
+ return (-1);
+ }
+ for (i = 0; i < xd_drives; i++)
+ resetup_one_dev(&xd_gendisk, i);
}

return error;
******************************************************************************

-- 
=======================================================================
  Andrzej M. Krzysztofowicz               ankry@mif.pg.gda.pl
  tel.  (0-58) 47 14 61
Wydz.Fizyki Technicznej i Matematyki Stosowanej Politechniki Gdanskiej