Fwd: Re: Workaround for VIA chipset+ATAPI ZIP 100 problem

Top Page

Reply to this message
Author: Frederic Mantegazza
Date:  
To: ML Guilde
Subject: Fwd: Re: Workaround for VIA chipset+ATAPI ZIP 100 problem
Concernant le probleme du ZIP IDE qui merdouille, apres avoir contacte une
personne qui avait poste un patch sur une ML, j'ai eu la reponse
ci-dessous. Je precise que je n'ai pas teste ce truc, vu que je n'ai pas
de noyau 2.4.13. Je tenterai ca lorsque la Debian woody sortira (noyau
2.4.12) en upgradant le noyau en 2.4.13, qui est celui de sid (qui devrait
donc passer en testing a ce moment la).

-------------------------------------------------------

Frederic Mantegazza wrote:

> I found you mail on a mailing list, where you give a patch to solve the
> problem with ZIP 100 IDE drive. As I have this problem, I would like to
> know for which kernel the patch is ?


I just recently (yesterday or so) received a mail regarding patch.
I understood from it that the patch will be applied to stock
linux kernel in near future (perhaps 2.4.15 or the -ac series even
sooner).
The patch attached was sent to me by the maintainer of the affected
linux subsystem. It should apply at least to 2.4.13 kernel. You
might want to try it before the patch will be applied to regular
kernels.

Regards,
Timo

--
timo teräs
software engineer
votek oy (http://www.votek.com)
tiedepuisto 4c, 28600 pori, finland

tel: +358 2 6250 5224
email: timo.teras@???

-------------------------------------------------------

-- 
    Frederic

--- linux/drivers/ide/ide-floppy.c~    Wed Nov 7 18:32:41 2001
+++ linux/drivers/ide/ide-floppy.c    Wed Nov  7 19:24:32 2001
@@ -71,9 +71,18 @@
  *                       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  Oct 26 01   Split idefloppy_transfer_pc into two pieces to
+ *                        fix a lost interrupt problem. It appears the busy
+ *                        bit was being deasserted by my IOMEGA ATAPI ZIP 100
+ *                        drive before the drive was actually ready. Skip Gaede
+ *                        (sgaede@???) with help from Gadi Oxman.
+ * Ver 0.98a Oct 29 01   Expose delay value so we can play.
+ * Ver 0.98b Nov  1 01   Make the WAIT_CMD variable and exposed
+ * Ver 0.98c Nov  7 01   Incorporate Timo Teras' (timo.teras@???) patch:
+ *                        delay only on back to back writes with via chipset
  */


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

 #include <linux/config.h>
 #include <linux/module.h>
@@ -113,6 +122,7 @@
  *    Some drives require a longer irq timeout.
  */
 #define IDEFLOPPY_WAIT_CMD        (5 * WAIT_CMD)
+#define IDEFLOPPY_WAIT_CMD_ZIP        (WAIT_CMD / 2)


 /*
  *    After each failed packet command we issue a request sense command
@@ -276,6 +286,7 @@
      *    Last error information
      */
     byte sense_key, asc, ascq;
+    byte ticks;        /* delay this long before sending packet command */
     int progress_indication;


     /*
@@ -286,9 +297,21 @@
     idefloppy_flexible_disk_page_t flexible_disk_page;    /* Copy of the flexible disk page */
     int wp;                            /* Write protect */
     int srfp;            /* Supports format progress report */
+    int timeout;            /* how long to wait */
     unsigned long flags;            /* Status/Action flags */
+
+    /*
+     * a theory as to what's happening: on writes the transferred data is
+     * moved to a buffer (4 sectors). If the drive says it's ready and the
+     * buffer is full, bad things happen. So, introduce a small delay after
+     * a write command to give the drive time to empty the buffer.
+     */
+
+    unsigned long via_kludge;            /* holds jiffies after write cmds */
 } idefloppy_floppy_t;


+#define IDEFLOPPY_TICKS_DELAY        5    /* default delay for VIA chipset */
+
 /*
  *    Floppy flag bits values.
  */
@@ -296,8 +319,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
@@ -975,7 +998,7 @@
             if (temp > pc->buffer_size) {
                 printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n");
                 idefloppy_discard_data (drive,bcount.all);
-                ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);
+                ide_set_handler (drive,&idefloppy_pc_intr,floppy->timeout,NULL);
                 return ide_started;
             }
 #if IDEFLOPPY_DEBUG_LOG
@@ -997,10 +1020,16 @@
     pc->actually_transferred+=bcount.all;                /* Update the current position */
     pc->current_position+=bcount.all;


-    ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);        /* And set the interrupt handler again */
+    ide_set_handler (drive,&idefloppy_pc_intr,floppy->timeout, NULL);        /* And set the interrupt handler again */
     return ide_started;
 }


+/*
+ * This is the original routine that did the packet transfer.
+ * It fails at high speeds on the Iomega ZIP drive, so there's a slower version
+ * for that drive below. The algorithm is chosen based on via_kludge in
+ * idefloppy_issue_pc
+ */
 static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
 {
     ide_startstop_t startstop;
@@ -1016,8 +1045,67 @@
         printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
         return ide_do_reset (drive);
     }
-    ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);    /* Set the interrupt routine */
+    ide_set_handler (drive, &idefloppy_pc_intr, floppy->timeout, NULL);    /* Set the interrupt routine */
+    atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
+    return ide_started;
+}
+
+
+/*
+ * What we have here is a classic case of a top half / bottom half
+ * interrupt service routine. In interrupt mode, the device sends
+ * an interrupt to signal it's ready to receive a packet. However,
+ * we need to delay about 2-3 ticks before issuing the packet or we
+ * get in trouble.
+ *
+ * Transfer_pc1 is called as an interrupt (or directly). In either
+ * case, when the device says it's ready for a packet, we schedule
+ * the packet transfer to occur 2-3 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 floppy->timeout;        /* 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;
+    
+    if (floppy->via_kludge) {
+        if (time_before(jiffies,floppy->via_kludge)) {
+            wait = floppy->via_kludge - jiffies;
+        } else {
+            wait = 0;
+        }
+        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);
+    }
+    /* 
+     * The following delay solves a problem with ATAPI Zip 100 drives where the
+     * Busy flag was apparently being deasserted before the unit was ready to
+     * receive data. This was happening on a 1200 MHz Athlon system. 10/26/01
+     * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will 
+     * not be actually used until after the packet is moved in about 50 msec.
+     */
+    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;
 }


@@ -1029,6 +1117,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 +1177,41 @@
     }
 #endif /* CONFIG_BLK_DEV_IDEDMA */


+    /* Can we transfer the packet when we get the interrupt or wait? */
+    if (floppy->via_kludge && time_before(jiffies, floppy->via_kludge)) {
+        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, floppy->timeout, 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 +1349,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);
@@ -1750,7 +1859,7 @@
     if (!drive->usage) {
         idefloppy_floppy_t *floppy = drive->driver_data;


-        invalidate_bdev (inode->i_bdev, 0);
+        invalidate_buffers (inode->i_rdev);


         /* IOMEGA Clik! drives do not support lock/unlock commands */
                 if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
@@ -1914,13 +2023,19 @@
 {
     int major = HWIF(drive)->major;
     int minor = drive->select.b.unit << PARTN_BITS;
+    idefloppy_floppy_t *floppy = drive->driver_data;


+/*
+ *            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);
+    ide_add_setting(drive,    "timeout",        SETTING_RW,                    -1,            -1,            TYPE_INT,    0,    10000,                1,    1,    &floppy->timeout,        NULL);


}

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


     if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0)
     {
+        /* This value can be adjusted in the /proc/ide/hdx/settings */
+        if (HWIF(drive)->chipset == ide_via82cxxx) {
+            set_bit(IDEFLOPPY_SLOW_DRIVE, &floppy->flags);
+        }
+        floppy->timeout = IDEFLOPPY_WAIT_CMD_ZIP;
         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
@@ -2116,4 +2228,3 @@


 module_init(idefloppy_init);
 module_exit(idefloppy_exit);
-MODULE_LICENSE("GPL");
--- linux/drivers/ide/via82cxxx.c~    Wed Nov  7 18:28:38 2001
+++ linux/drivers/ide/via82cxxx.c    Wed Nov  7 16:54:38 2001
@@ -510,6 +510,7 @@
     hwif->tuneproc = &via82cxxx_tune_drive;
     hwif->speedproc = &via_set_drive;
     hwif->autodma = 0;
+    hwif->chipset = ide_via82cxxx;    /* Timas' patch */


     for (i = 0; i < 2; i++) {
         hwif->drives[i].io_32bit = 1;
--- linux/include/linux/ide.h~    Wed Nov  7 18:26:57 2001
+++ linux/include/linux/ide.h    Wed Nov  7 16:57:15 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    \