2001-11-22 07:38:47

by Paul Bristow

[permalink] [raw]
Subject: [PATCH] ide-floppy update to fix lockups with ZIP + Via chipset

diff -urN -X dontdiff linux-2.4.14-clean/drivers/ide/ide-floppy.c linux-2.4.14/drivers/ide/ide-floppy.c
--- linux-2.4.14-clean/drivers/ide/ide-floppy.c Thu Oct 11 18:14:32 2001
+++ linux-2.4.14/drivers/ide/ide-floppy.c Wed Nov 21 22:39:44 2001
@@ -71,9 +71,20 @@
* including set_bit patch from Rusty Russel
* Ver 0.97 Jul 22 01 Merge 0.91-0.96 onto 0.9.sv for ac series
* Ver 0.97.sv Aug 3 01 Backported from 2.4.7-ac3
+ * Ver 0.98 Nov 8 01 There is a bug with the Via82c686b chip when used with
+ * an ATAPI ZIP drive. The problem occurs when issuing write
+ * commands to the drive, and it doesn't happen with the promise
+ * pdc20265 chipset. Both Skip Gaede ([email protected]) and
+ * Timo Teras ([email protected]) discovered that including
+ * a delay fixed the problem. Gadi Oxman suggested using the timer
+ * queue instead of counting, and Timo implemented code to limit
+ * the delay to machines having the via chipset. A delay of 50
+ * msec works on my system. The variable ticks is exposed
+ * in /proc/ide/hdx/settings. Each tick is 10 msec. If ticks is
+ * set to zero, the driver reverts to the old algorithm. --Skip
*/

-#define IDEFLOPPY_VERSION "0.97.sv"
+#define IDEFLOPPY_VERSION "0.98"

#include <linux/config.h>
#include <linux/module.h>
@@ -276,6 +287,7 @@
* Last error information
*/
byte sense_key, asc, ascq;
+ byte ticks; /* delay this long before sending packet command */
int progress_indication;

/*
@@ -287,8 +299,18 @@
int wp; /* Write protect */
int srfp; /* Supports format progress report */
unsigned long flags; /* Status/Action flags */
+ unsigned long via_kludge; /* holds jiffies after write cmds */
} idefloppy_floppy_t;

+/*
+ * default delay for VIA chipset (50 ms, or 5 ticks)
+ * This value is exposed as the variable ticks and may be adjusted if necessary.
+ * On my system, a 1200 mhz Athlon with the Asus A7V133 board. this is the minimum
+ * delay. If set to zero, the standard algorithm is used. Note: my board also has a
+ * Promise PDC20265 (ATA100) controller. The ZIP drive works fine on the other chipset.
+ */
+#define IDEFLOPPY_TICKS_DELAY ((50 * HZ) / 1000)
+
/*
* Floppy flag bits values.
*/
@@ -296,8 +318,8 @@
#define IDEFLOPPY_MEDIA_CHANGED 1 /* Media may have changed */
#define IDEFLOPPY_USE_READ12 2 /* Use READ12/WRITE12 or READ10/WRITE10 */
#define IDEFLOPPY_FORMAT_IN_PROGRESS 3 /* Format in progress */
-#define IDEFLOPPY_CLIK_DRIVE 4 /* Avoid commands not supported in Clik drive */
-
+#define IDEFLOPPY_CLIK_DRIVE 4 /* Avoid commands not supported in Clik drive */
+#define IDEFLOPPY_SLOW_DRIVE 5 /* Need two stage algorithm */

/*
* ATAPI floppy drive packet commands
@@ -1001,6 +1023,11 @@
return ide_started;
}

+/*
+ * This is the standard routine that does the packet transfer. On systems with
+ * a VIA chip and ATAPI ZIP drives, routines transfer_pc1 and transfer_pc2
+ * are used instead. The algorithm is selected in idefloppy_issue_pc
+ */
static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
{
ide_startstop_t startstop;
@@ -1021,6 +1048,55 @@
return ide_started;
}

+
+/*
+ * Transfer_pc1 is called when the device says it's ready for a packet.
+ * The packet transfer occurs 50 msec (5 ticks) later in transfer_pc2.
+ */
+static int idefloppy_transfer_pc2 (ide_drive_t *drive)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+
+ atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
+ return IDEFLOPPY_WAIT_CMD; /* Timeout for the packet command */
+}
+
+static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+ ide_startstop_t startstop;
+ idefloppy_ireason_reg_t ireason;
+ unsigned long wait=0;
+
+ if (floppy->via_kludge) {
+ if (time_before(jiffies,floppy->via_kludge)) {
+ wait = floppy->via_kludge - jiffies;
+ }
+ floppy->via_kludge = 0;
+ }
+
+ if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+ printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n");
+ return startstop;
+ }
+ ireason.all=IN_BYTE (IDE_IREASON_REG);
+ if (!ireason.b.cod || ireason.b.io) {
+ printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
+ return ide_do_reset (drive);
+ }
+ /*
+ * We set the handler for the interrupt in response to the packet written
+ * in transfer_pc2. Transfer_pc2 will be called after the variable number
+ * of ticks has expired, and it will then set the timeout for the packet
+ * command interrupt. This is a work around for the via82c686b chip.
+ */
+ ide_set_handler (drive,
+ &idefloppy_pc_intr, /* service routine for next interrupt */
+ wait, /* wait before back to back writes */
+ &idefloppy_transfer_pc2); /* called when timeout occurs to write packet */
+ return ide_started;
+}
+
/*
* Issue a packet command
*/
@@ -1029,6 +1105,7 @@
idefloppy_floppy_t *floppy = drive->driver_data;
idefloppy_bcount_reg_t bcount;
int dma_ok = 0;
+ ide_handler_t *pkt_xfer_routine;

#if IDEFLOPPY_DEBUG_BUGS
if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD && pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
@@ -1088,23 +1165,43 @@
}
#endif /* CONFIG_BLK_DEV_IDEDMA */

+ /* Can we transfer the packet when we get the interrupt or wait? */
+ if (floppy->ticks && /* if user has not disabled this, and */
+ floppy->via_kludge && /* it might be the right thing to do, and */
+ time_before(jiffies, floppy->via_kludge)) { /* a delay is needed */
+ pkt_xfer_routine = &idefloppy_transfer_pc1; /* wait */
+ } else {
+ floppy->via_kludge = 0;
+ pkt_xfer_routine = &idefloppy_transfer_pc; /* immediate */
+ }
+
if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
- ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD, NULL);
+ ide_set_handler (drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL);
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */
return ide_started;
} else {
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
- return idefloppy_transfer_pc (drive);
+ return (*pkt_xfer_routine) (drive);
}
}

static void idefloppy_rw_callback (ide_drive_t *drive)
{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+
#if IDEFLOPPY_DEBUG_LOG
printk (KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n");
#endif /* IDEFLOPPY_DEBUG_LOG */

idefloppy_end_request(1, HWGROUP(drive));
+
+ if (test_bit(IDEFLOPPY_SLOW_DRIVE, &floppy->flags) &&
+ (floppy->pc->c[0] == IDEFLOPPY_WRITE10_CMD ||
+ floppy->pc->c[0] == IDEFLOPPY_WRITE12_CMD)) {
+ floppy->via_kludge = jiffies + floppy->ticks;
+ /* time when we can do next write */
+ }
+
return;
}

@@ -1242,6 +1339,8 @@
}
switch (rq->cmd) {
case READ:
+ floppy->via_kludge = 0; /* not back to back writes */
+ /* fall through */
case WRITE:
if (rq->sector % floppy->bs_factor || rq->nr_sectors % floppy->bs_factor) {
printk ("%s: unsupported r/w request size\n", drive->name);
@@ -1914,14 +2013,18 @@
{
int major = HWIF(drive)->major;
int minor = drive->select.b.unit << PARTN_BITS;
+ idefloppy_floppy_t *floppy = drive->driver_data;

- ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_INT, 0, 1023, 1, 1, &drive->bios_cyl, NULL);
- ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL);
- ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL);
- ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL);
- ide_add_setting(drive, "file_readahead", SETTING_RW, BLKFRAGET, BLKFRASET, TYPE_INTA, 0, INT_MAX, 1, 1024, &max_readahead[major][minor], NULL);
- ide_add_setting(drive, "max_kb_per_request", SETTING_RW, BLKSECTGET, BLKSECTSET, TYPE_INTA, 1, 255, 1, 2, &max_sectors[major][minor], NULL);
-
+/*
+ * drive setting name read/write ioctl ioctl data type min max mul_factor div_factor data pointer set function
+ */
+ ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_INT, 0, 1023, 1, 1, &drive->bios_cyl, NULL);
+ ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL);
+ ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL);
+ ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL);
+ ide_add_setting(drive, "file_readahead", SETTING_RW, BLKFRAGET, BLKFRASET, TYPE_INTA, 0, INT_MAX, 1, 1024, &max_readahead[major][minor], NULL);
+ ide_add_setting(drive, "max_kb_per_request", SETTING_RW, BLKSECTGET, BLKSECTSET, TYPE_INTA, 1, 255, 1, 2, &max_sectors[major][minor], NULL);
+ ide_add_setting(drive, "ticks", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &floppy->ticks, NULL);
}

/*
@@ -1941,6 +2044,9 @@
floppy->pc = floppy->pc_stack;
if (gcw.drq_type == 1)
set_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
+ /* the following value can be tweaked under /proc/ide/hdx/settings */
+ floppy->ticks = IDEFLOPPY_TICKS_DELAY;
+
/*
* We used to check revisions here. At this point however
* I'm giving up. Just assume they are all broken, its easier.
@@ -1954,20 +2060,13 @@

if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0)
{
+ if (HWIF(drive)->chipset == ide_via82cxxx) {
+ /* FIXME: appropriate for other drives as well?? */
+ set_bit(IDEFLOPPY_SLOW_DRIVE, &floppy->flags);
+ }
for (i = 0; i < 1 << PARTN_BITS; i++)
max_sectors[major][minor + i] = 64;
}
- /*
- * Guess what? The IOMEGA Clik! drive also needs the
- * above fix. It makes nasty clicking noises without
- * it, so please don't remove this.
- */
- if (strcmp(drive->id->model, "IOMEGA Clik! 40 CZ ATAPI") == 0)
- {
- for (i = 0; i < 1 << PARTN_BITS; i++)
- max_sectors[major][minor + i] = 64;
- set_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags);
- }

/*
* Guess what? The IOMEGA Clik! drive also needs the
@@ -2057,8 +2156,6 @@
NULL
};

-MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
-
static void __exit idefloppy_exit (void)
{
ide_drive_t *drive;
@@ -2086,7 +2183,6 @@
idefloppy_floppy_t *floppy;
int failed = 0;

- printk("ide-floppy driver " IDEFLOPPY_VERSION "\n");
MOD_INC_USE_COUNT;
while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) {
if (!idefloppy_identify_device (drive, drive->id)) {
@@ -2117,3 +2213,6 @@
module_init(idefloppy_init);
module_exit(idefloppy_exit);
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Maintainer: Paul Bristow <[email protected]>");
+MODULE_DESCRIPTION("ATAPI Floppy Driver V"IDEFLOPPY_VERSION);
+
diff -urN -X dontdiff linux-2.4.14-clean/drivers/ide/via82cxxx.c linux-2.4.14/drivers/ide/via82cxxx.c
--- linux-2.4.14-clean/drivers/ide/via82cxxx.c Tue Sep 11 17:40:36 2001
+++ linux-2.4.14/drivers/ide/via82cxxx.c Wed Nov 21 19:23:04 2001
@@ -510,6 +510,7 @@
hwif->tuneproc = &via82cxxx_tune_drive;
hwif->speedproc = &via_set_drive;
hwif->autodma = 0;
+ hwif->chipset = ide_via82cxxx; /* Timo's patch */

for (i = 0; i < 2; i++) {
hwif->drives[i].io_32bit = 1;
diff -urN -X dontdiff linux-2.4.14-clean/include/linux/ide.h linux-2.4.14/include/linux/ide.h
--- linux-2.4.14-clean/include/linux/ide.h Mon Nov 5 21:43:28 2001
+++ linux-2.4.14/include/linux/ide.h Wed Nov 21 20:27:56 2001
@@ -449,7 +449,7 @@
ide_qd65xx, ide_umc8672, ide_ht6560b,
ide_pdc4030, ide_rz1000, ide_trm290,
ide_cmd646, ide_cy82c693, ide_4drives,
- ide_pmac, ide_etrax100
+ ide_pmac, ide_etrax100, ide_via82cxxx
} hwif_chipset_t;

#define IDE_CHIPSET_PCI_MASK \


Attachments:
via-patch-paul (11.65 kB)