2000-12-17 12:57:09

by Tim Waugh

[permalink] [raw]
Subject: [patch] 2.4.0-test13-pre2: ppa 2.07

Hi Linus,

This patch fixes some timing issues with ppa.

Tim.
*/

2000-12-13 Tim Waugh <[email protected]>

* drivers/scsi/ppa.c, drivers/scsi/ppa.h: Timing fixes. New
parameter "recon_tmo=". This is 2.07-for-2.4.x.

--- linux-2.4.0-test12/drivers/scsi/ppa.c.ppa207 Tue Dec 12 13:03:27 2000
+++ linux-2.4.0-test12/drivers/scsi/ppa.c Thu Dec 14 17:18:53 2000
@@ -31,6 +31,7 @@
Scsi_Cmnd *cur_cmd; /* Current queued command */
struct tq_struct ppa_tq; /* Polling interupt stuff */
unsigned long jstart; /* Jiffies at start */
+ unsigned long recon_tmo; /* How many usecs to wait for reconnection (6th bit) */
unsigned int failed:1; /* Failure flag */
unsigned int p_busy:1; /* Parport sharing busy flag */
} ppa_struct;
@@ -43,6 +44,7 @@
cur_cmd: NULL, \
ppa_tq: { routine: ppa_interrupt }, \
jstart: 0, \
+ recon_tmo: PPA_RECON_TMO, \
failed: 0, \
p_busy: 0 \
}
@@ -248,6 +250,12 @@
ppa_hosts[hostno].mode = x;
return length;
}
+ if ((length > 10) && (strncmp(buffer, "recon_tmo=", 10) == 0)) {
+ x = simple_strtoul(buffer + 10, NULL, 0);
+ ppa_hosts[hostno].recon_tmo = x;
+ printk("ppa: recon_tmo set to %ld\n", x);
+ return length;
+ }
printk("ppa /proc: invalid variable\n");
return (-EINVAL);
}
@@ -268,6 +276,9 @@
len += sprintf(buffer + len, "Version : %s\n", PPA_VERSION);
len += sprintf(buffer + len, "Parport : %s\n", ppa_hosts[i].dev->port->name);
len += sprintf(buffer + len, "Mode : %s\n", PPA_MODE_STRING[ppa_hosts[i].mode]);
+#if PPA_DEBUG > 0
+ len += sprintf(buffer + len, "recon_tmo : %lu\n", ppa_hosts[i].recon_tmo);
+#endif

/* Request for beyond end of buffer */
if (offset > length)
@@ -556,6 +567,7 @@
k = PPA_SELECT_TMO;
do {
k--;
+ udelay(1);
} while ((r_str(ppb) & 0x40) && (k));
if (!k)
return 0;
@@ -569,6 +581,7 @@
k = PPA_SELECT_TMO;
do {
k--;
+ udelay(1);
}
while (!(r_str(ppb) & 0x40) && (k));
if (!k)
@@ -652,6 +665,7 @@
* 1 Finished data transfer
*/
int host_no = cmd->host->unique_id;
+ unsigned short ppb = PPA_BASE(host_no);
unsigned long start_jiffies = jiffies;

unsigned char r, v;
@@ -663,7 +677,11 @@
(v == WRITE_6) ||
(v == WRITE_10));

- r = ppa_wait(host_no); /* Need a ppa_wait() - PJC */
+ /*
+ * We only get here if the drive is ready to comunicate,
+ * hence no need for a full ppa_wait.
+ */
+ r = (r_str(ppb) & 0xf0);

while (r != (unsigned char) 0xf0) {
/*
@@ -673,12 +691,36 @@
if (time_after(jiffies, start_jiffies + 1))
return 0;

- if (((r & 0xc0) != 0xc0) || (cmd->SCp.this_residual <= 0)) {
+ if ((cmd->SCp.this_residual <= 0)) {
ppa_fail(host_no, DID_ERROR);
return -1; /* ERROR_RETURN */
}
- /* determine if we should use burst I/O */ fast = (bulk && (cmd->SCp.this_residual >= PPA_BURST_SIZE))
- ? PPA_BURST_SIZE : 1;
+
+ /* On some hardware we have SCSI disconnected (6th bit low)
+ * for about 100usecs. It is too expensive to wait a
+ * tick on every loop so we busy wait for no more than
+ * 500usecs to give the drive a chance first. We do not
+ * change things for "normal" hardware since generally
+ * the 6th bit is always high.
+ * This makes the CPU load higher on some hardware
+ * but otherwise we can not get more then 50K/secs
+ * on this problem hardware.
+ */
+ if ((r & 0xc0) != 0xc0) {
+ /* Wait for reconnection should be no more than
+ * jiffy/2 = 5ms = 5000 loops
+ */
+ unsigned long k = ppa_hosts[host_no].recon_tmo;
+ for (; k && ((r = (r_str(ppb) & 0xf0)) & 0xc0) != 0xc0; k--)
+ udelay(1);
+
+ if(!k)
+ return 0;
+ }
+
+ /* determine if we should use burst I/O */
+ fast = (bulk && (cmd->SCp.this_residual >= PPA_BURST_SIZE))
+ ? PPA_BURST_SIZE : 1;

if (r == (unsigned char) 0xc0)
status = ppa_out(host_no, cmd->SCp.ptr, fast);
@@ -701,7 +743,7 @@
}
}
/* Now check to see if the drive is ready to comunicate */
- r = ppa_wait(host_no); /* need ppa_wait() - PJC */
+ r = (r_str(ppb) & 0xf0);
/* If not, drop back down to the scheduler and wait a timer tick */
if (!(r & 0x80))
return 0;
--- linux-2.4.0-test12/drivers/scsi/ppa.h.ppa207 Tue Dec 12 13:03:27 2000
+++ linux-2.4.0-test12/drivers/scsi/ppa.h Thu Dec 14 17:19:16 2000
@@ -10,7 +10,7 @@
#ifndef _PPA_H
#define _PPA_H

-#define PPA_VERSION "2.06 (for Linux 2.2.x)"
+#define PPA_VERSION "2.07 (for Linux 2.4.x)"

/*
* this driver has been hacked by Matteo Frigo ([email protected])
@@ -56,11 +56,20 @@
* Add ppa_wait() calls to ppa_completion()
* by Peter Cherriman <[email protected]> and
* Tim Waugh <[email protected]>
- * [2.04]
+ * [2.04]
+ *
* Fix kernel panic on scsi timeout, 2000-08-18 [2.05]
*
* Avoid io_request_lock problems.
* John Cavan <[email protected]> [2.06]
+ *
+ * Busy wait for connected status bit in ppa_completion()
+ * in order to cope with some hardware that has this bit low
+ * for short periods of time.
+ * Add udelay() to ppa_select()
+ * by Peter Cherriman <[email protected]> and
+ * Oleg Makarenko <[email protected]>
+ * [2.07]
*/
/* ------ END OF USER CONFIGURABLE PARAMETERS ----- */

@@ -116,6 +125,7 @@
#define PPA_BURST_SIZE 512 /* data burst size */
#define PPA_SELECT_TMO 5000 /* how long to wait for target ? */
#define PPA_SPIN_TMO 50000 /* ppa_wait loop limiter */
+#define PPA_RECON_TMO 500 /* scsi reconnection loop limiter */
#define PPA_DEBUG 0 /* debuging option */
#define IN_EPP_MODE(x) (x == PPA_EPP_8 || x == PPA_EPP_16 || x == PPA_EPP_32)