Subject: Re: wdc0:0:0 lost interrupt
To: None <mw@blobulent.com>
From: Andrew Cagney <cagney@mac.com>
List: port-macppc
Date: 07/25/2001 12:40:05
This is a multi-part message in MIME format.
--------------090203080106070409080706
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

> Y'all,
> 
> I'm still trying to get my PowerBook (FireWire) working again after
> upgrading to -current, and haven't gotten a satisfactory kernel built.
> 
> My latest failure was with sources updated today failing to mount /:
> 
> wdc0:0:0 lost interrupt
> 	type: ata tc_bcount: 512 tc_skip: 0
> wdc0:0:0 recal timed out
> wd0c: device timedout reading fsbn 0 (wd0 bn 0; cn 0 tn 0 sn 0), retrying
> 
> I thought we had this wdc0 lost interrupt business licked?


I got sufficiently curious to try and figure this out.

Exhibit A is diff from a merge in progress between 1.12+exhibit.c (the 
original patch that ``worked'') and 1.13 (the committed broken change).

Exhibit B is the dmesg output from an earlier 1.13-exibit.a.

Exhibit C is the original wdc patch (slightly white space munged) that 
wasn't committed.

So, having confused everyone ...


The file with the original patch contained something like:


*** 265,294 ****
                                 dmamode = drvp->DMA_mode;
                 }
         }
- printf ("piomode %d, dmamode %d\n", piomode, dmamode);
-        if (dmamode == -1)
-                /* No active DMA mode is found...  Do nothing. */
-                return;
         for (drive = 0; drive < 2; drive++) {
                 drvp = &chp->ch_drive[drive];
                 if (drvp->drive_flags & DRIVE) {

while the new file had that test moved to near the end of the function. 
  Looking at my dmesg:

cd0(wdc1:0:0): using PIO mode 4, DMA mode 2 (using DMA data transfers)
wdc2 at obio0 offset 0x21000 irq 21: DMA transfer
piomode -1, dmamode -1

one begins to suspect that the code might have been doing something 
useful.  Examining 1.13, you find that it is going to eventually execute 
the statements:

         min_cycle = pio_timing[piomode].cycle;
         min_active = pio_timing[piomode].active;

where piomode==-1.  Er, outch!!

Well, thats my theory at least :-)

	Andrew

--------------090203080106070409080706
Content-Type: text/plain;
 name="exhibit.a"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="exhibit.a"

*** wdc_obio.c	Wed Jul 25 12:10:29 2001
--- wdc_obio.c,1.13	Wed Jul 18 21:42:19 2001
***************
*** 223,229 ****
  	int cycle;	/* minimum cycle time [ns] */
  	int active;	/* minimum command active time [ns] */
  };
- #if 0
  static struct ide_timings pio_timing[5] = {
  	{ 600, 165 },    /* Mode 0 */
  	{ 383, 125 },    /*      1 */
--- 223,228 ----
***************
*** 231,237 ****
  	{ 180,  80 },    /*      3 */
  	{ 120,  70 }     /*      4 */
  };
- #endif
  static struct ide_timings dma_timing[3] = {
  	{ 480, 215 },	/* Mode 0 */
  	{ 150,  80 },	/* Mode 1 */
--- 230,235 ----
***************
*** 265,294 ****
  				dmamode = drvp->DMA_mode;
  		}
  	}
- printf ("piomode %d, dmamode %d\n", piomode, dmamode);
-        if (dmamode == -1)
-                /* No active DMA mode is found...  Do nothing. */
-                return;
  	for (drive = 0; drive < 2; drive++) {
  		drvp = &chp->ch_drive[drive];
  		if (drvp->drive_flags & DRIVE) {
! printf ("drvp->PIO_mode = piomode; [%d->%d = %d]\n", drive, drvp->PIO_mode, piomode);
! printf ("if (drvp->drive_flags & DRIVE_DMA) [%d->%x & %x]\n", drive, drvp->drive_flags, DRIVE_DMA);
  				drvp->DMA_mode = dmamode;
  		}
  	}
!  	min_cycle = dma_timing[dmamode].cycle;
! 	min_active = dma_timing[dmamode].active;
  
  	cycle_tick = TIME_TO_TICK(min_cycle);
  	act_tick = TIME_TO_TICK(min_active);
  	inact_tick = cycle_tick - act_tick - 1;
  	if (inact_tick < 1)
  		inact_tick = 1;
! 
! 	half_tick = 0;	/* XXX */
! 	conf = (half_tick << 21) | (inact_tick << 16) | (act_tick << 11);
! 	if (dmamode != -1 && 0) {
  		/* there are active  DMA mode */
  
  		min_cycle = dma_timing[dmamode].cycle;
--- 263,286 ----
  				dmamode = drvp->DMA_mode;
  		}
  	}
  	for (drive = 0; drive < 2; drive++) {
  		drvp = &chp->ch_drive[drive];
  		if (drvp->drive_flags & DRIVE) {
! 			drvp->PIO_mode = piomode;
! 			if (drvp->drive_flags & DRIVE_DMA)
  				drvp->DMA_mode = dmamode;
  		}
  	}
! 	min_cycle = pio_timing[piomode].cycle;
! 	min_active = pio_timing[piomode].active;
  
  	cycle_tick = TIME_TO_TICK(min_cycle);
  	act_tick = TIME_TO_TICK(min_active);
  	inact_tick = cycle_tick - act_tick - 1;
  	if (inact_tick < 1)
  		inact_tick = 1;
! 	conf = (inact_tick << 5) | act_tick;
! 	if (dmamode != -1) {
  		/* there are active  DMA mode */
  
  		min_cycle = dma_timing[dmamode].cycle;

--------------090203080106070409080706
Content-Type: text/plain;
 name="exhibit.b"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="exhibit.b"

wdc0 at obio0 offset 0x1f000 irq 19: DMA transfer
wd0 at wdc0 channel 0 drive 0: <IBM-DJSA-220>
wd0: drive supports 16-sector PIO transfers, LBA addressing
wd0: 19077 MB, 16383 cyl, 16 head, 63 sec, 512 bytes/sect x 39070080 sectors
wd0: drive supports PIO mode 4, DMA mode 2, Ultra-DMA mode 4 (Ultra/66)
piomode 4, dmamode 2
drvp->PIO_mode = piomode;
if (drvp->drive_flags & DRIVE_DMA)
wd0(wdc0:0:0): using PIO mode 4, DMA mode 2 (using DMA data transfers)
wdc1 at obio0 offset 0x20000 irq 20: DMA transfer
atapibus0 at wdc1 channel 0: 2 targets
cd0 at atapibus0 drive 0: <MATSHITADVD-ROM SR-8187, , HA18> type 5 cdrom removable
cd0: drive supports PIO mode 4, DMA mode 2, Ultra-DMA mode 2 (Ultra/33)
piomode 4, dmamode 2
drvp->PIO_mode = piomode;
if (drvp->drive_flags & DRIVE_DMA)
cd0(wdc1:0:0): using PIO mode 4, DMA mode 2 (using DMA data transfers)
wdc2 at obio0 offset 0x21000 irq 21: DMA transfer
piomode -1, dmamode -1

--------------090203080106070409080706
Content-Type: text/plain;
 name="exhibit.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="exhibit.c"

Index: wdc_obio.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/macppc/dev/wdc_obio.c,v
retrieving revision 1.12
diff -u -r1.12 wdc_obio.c
--- wdc_obio.c  2001/06/08 00:32:02     1.12
+++ wdc_obio.c  2001/06/12 13:15:56
@@ -167,10 +167,13 @@
                sc->sc_dmacmd = dbdma_alloc(sizeof(dbdma_command_t) * 20);
                sc->sc_dmareg = mapiodev(ca->ca_baseaddr + ca->ca_reg[2],
                                         ca->ca_reg[3]);
-               sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA;
+               sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_MODE;
+               sc->sc_wdcdev.PIO_cap = 4;
+               sc->sc_wdcdev.DMA_cap = 2;
+       } else {
+               sc->sc_wdcdev.PIO_cap = 0;
        }
        sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16;
-       sc->sc_wdcdev.PIO_cap = 0;
        sc->wdc_chanptr = chp;
        sc->sc_wdcdev.channels = &sc->wdc_chanptr;
        sc->sc_wdcdev.nchannels = 1;
@@ -178,6 +181,7 @@
        sc->sc_wdcdev.dma_init = wdc_obio_dma_init;
        sc->sc_wdcdev.dma_start = wdc_obio_dma_start;
        sc->sc_wdcdev.dma_finish = wdc_obio_dma_finish;
+       sc->sc_wdcdev.set_modes = adjust_timing;
        chp->channel = 0;
        chp->wdc = &sc->sc_wdcdev;
        chp->ch_queue = malloc(sizeof(struct channel_queue),
@@ -207,7 +211,6 @@
        if (use_dma)
                adjust_timing(chp);
 
-       wdc_print_modes(chp);
 }
 
 /* Multiword DMA transfer timings */
@@ -228,24 +231,34 @@
 adjust_timing(chp)
        struct channel_softc *chp;
 {
-        struct ataparams params;
-       struct ata_drive_datas *drvp = &chp->ch_drive[0];       /* XXX */
+       struct ata_drive_datas *drvp;
        u_int conf;
-       int mode;
-       int cycle, active, min_cycle, min_active;
+       int drive;
+       int mode = -1;
+       int min_cycle, min_active;
        int cycle_tick, act_tick, inact_tick, half_tick;
 
-       if (ata_get_params(drvp, AT_POLL, &params) != CMD_OK)
-               return;
 
-       for (mode = 2; mode >= 0; mode--)
-               if (params.atap_dmamode_act & (1 << mode))
-                       goto found;
+       for (drive = 0; drive < 2; drive++) {
+               drvp = &chp->ch_drive[drive];
+               if ((drvp->drive_flags & DRIVE) == 0)
+                       continue;
+               if (drvp->drive_flags & DRIVE_DMA) {
+                       if (mode == -1 || mode > drvp->DMA_mode)
+                               mode = drvp->DMA_mode;
+               }
+       }
+       if (mode == -1)
+               /* No active DMA mode is found...  Do nothing. */
+               return;
 
-       /* No active DMA mode is found...  Do nothing. */
-       return;
+       for (drive = 0; drive < 2; drive++) {
+               drvp = &chp->ch_drive[drive];
+               if (drvp->drive_flags & DRIVE)
+                       drvp->DMA_mode = mode;
+       }
 
-found:
+               
        min_cycle = dma_timing[mode].cycle;
        min_active = dma_timing[mode].active;
 
@@ -254,11 +267,8 @@
        if (ohare && params.atap_dmatiming_recom < 150)
                params.atap_dmatiming_recom = 150;
 #endif
-       cycle = max(min_cycle, params.atap_dmatiming_recom);
-       active = min_active + (cycle - min_cycle);              /* XXX */
-
-       cycle_tick = TIME_TO_TICK(cycle);
-       act_tick = TIME_TO_TICK(active);
+       cycle_tick = TIME_TO_TICK(min_cycle);
+       act_tick = TIME_TO_TICK(min_active);
        inact_tick = cycle_tick - act_tick - 1;
        if (inact_tick < 1)
                inact_tick = 1;
@@ -267,8 +277,9 @@
        bus_space_write_4(chp->cmd_iot, chp->cmd_ioh, CONFIG_REG, conf);
 #if 0
        printf("conf = 0x%x, cyc = %d (%d ns), act = %d (%d ns), inact = %d\n",
-           conf, cycle_tick, cycle, act_tick, active, inact_tick);
+           conf, cycle_tick, min_cycle, act_tick, min_active, inact_tick);
 #endif
+       wdc_print_modes(chp);
 }
 
 int

--------------090203080106070409080706--