]> Zhao Yanbai Git Server - minix.git/commitdiff
newer at_wini.c (really incl atapi dma this time)
authorBen Gras <ben@minix3.org>
Mon, 19 Oct 2009 15:45:14 +0000 (15:45 +0000)
committerBen Gras <ben@minix3.org>
Mon, 19 Oct 2009 15:45:14 +0000 (15:45 +0000)
drivers/at_wini/at_wini.c

index b9bb397ef8f7d6ad6ba097c928f645eb430c8897..684078bd06b40e1e8e50c7964c3631b34737dd45 100644 (file)
@@ -257,7 +257,8 @@ struct command {
 /* Timeouts and max retries. */
 int timeout_ticks = DEF_TIMEOUT_TICKS, max_errors = MAX_ERRORS;
 long w_standard_timeouts = 0, w_pci_debug = 0, w_instance = 0,
-       disable_dma = 0, atapi_debug = 0, w_identify_wakeup_ticks, wakeup_ticks;
+       disable_dma = 0, atapi_debug = 0, w_identify_wakeup_ticks,
+       wakeup_ticks, w_atapi_dma;
 
 int w_testing = 0, w_silent = 0;
 
@@ -375,8 +376,8 @@ FORWARD _PROTOTYPE( int w_waitfor, (int mask, int value)            );
 FORWARD _PROTOTYPE( int w_waitfor_dma, (int mask, int value)           );
 FORWARD _PROTOTYPE( void w_geometry, (struct partition *entry)                 );
 #if ENABLE_ATAPI
-FORWARD _PROTOTYPE( int atapi_sendpacket, (u8_t *packet, unsigned cnt)         );
-FORWARD _PROTOTYPE( int atapi_intr_wait, (void)                        );
+FORWARD _PROTOTYPE( int atapi_sendpacket, (u8_t *packet, unsigned cnt, int do_dma)     );
+FORWARD _PROTOTYPE( int atapi_intr_wait, (int dma, size_t max)         );
 FORWARD _PROTOTYPE( int atapi_open, (void)                             );
 FORWARD _PROTOTYPE( void atapi_close, (void)                           );
 FORWARD _PROTOTYPE( int atapi_transfer, (int proc_nr, int opcode,
@@ -475,6 +476,7 @@ PRIVATE void init_params()
   env_parse(NO_DMA_VAR, "d", 0, &disable_dma, 0, 1);
   env_parse("ata_id_timeout", "d", 0, &wakeup_secs, 1, 60);
   env_parse("atapi_debug", "d", 0, &atapi_debug, 0, 1);
+  env_parse("atapi_dma", "d", 0, &w_atapi_dma, 0, 1);
 
   w_identify_wakeup_ticks = wakeup_secs * system_hz;
 
@@ -860,6 +862,104 @@ prev_wn = w_wn;
   return(w_dv);
 }
 
+#define id_byte(n)     (&tmp_buf[2 * (n)])
+#define id_word(n)     (((u16_t) id_byte(n)[0] <<  0) \
+                       |((u16_t) id_byte(n)[1] <<  8))
+#define id_longword(n) (((u32_t) id_byte(n)[0] <<  0) \
+                       |((u32_t) id_byte(n)[1] <<  8) \
+                       |((u32_t) id_byte(n)[2] << 16) \
+                       |((u32_t) id_byte(n)[3] << 24))
+
+/*===========================================================================*
+ *                             check_dma                                    *
+ *===========================================================================*/
+void
+check_dma(struct wini *wn)
+{
+       unsigned long dma_status = 0;
+       u32_t dma_base;
+       int id_dma, ultra_dma;
+       u16_t w;
+       int driveno, drive1;
+
+       driveno = wn - wini;
+       drive1 = driveno % 2;
+
+       wn->dma= 0;
+
+       if (disable_dma)
+               return;
+
+       w= id_word(ID_CAPABILITIES);
+       id_dma= !!(w & ID_CAP_DMA);
+       w= id_byte(ID_FIELD_VALIDITY)[0];
+       ultra_dma= !!(w & ID_FV_88);
+       dma_base= wn->base_dma;
+
+       if (dma_base) {
+               if (sys_inb(dma_base + DMA_STATUS, &dma_status) != OK) {
+                       panic(w_name(),
+                               "unable to read DMA status register",
+                               NO_NUM);
+               }
+       }
+
+       if (id_dma && dma_base) {
+               w= id_word(ID_MULTIWORD_DMA);
+               if (w_pci_debug &&
+               (w & (ID_MWDMA_2_SUP|ID_MWDMA_1_SUP|ID_MWDMA_0_SUP))) {
+                       printf(
+                       "%s: multiword DMA modes supported:%s%s%s\n",
+                               w_name(),
+                               (w & ID_MWDMA_0_SUP) ? " 0" : "",
+                               (w & ID_MWDMA_1_SUP) ? " 1" : "",
+                               (w & ID_MWDMA_2_SUP) ? " 2" : "");
+               }
+               if (w_pci_debug &&
+               (w & (ID_MWDMA_0_SEL|ID_MWDMA_1_SEL|ID_MWDMA_2_SEL))) {
+                       printf(
+                       "%s: multiword DMA mode selected:%s%s%s\n",
+                               w_name(),
+                               (w & ID_MWDMA_0_SEL) ? " 0" : "",
+                               (w & ID_MWDMA_1_SEL) ? " 1" : "",
+                               (w & ID_MWDMA_2_SEL) ? " 2" : "");
+               }
+               if (w_pci_debug && ultra_dma) {
+                       w= id_word(ID_ULTRA_DMA);
+                       if (w & (ID_UDMA_0_SUP|ID_UDMA_1_SUP|
+                               ID_UDMA_2_SUP|ID_UDMA_3_SUP|
+                               ID_UDMA_4_SUP|ID_UDMA_5_SUP)) {
+                               printf(
+                       "%s: Ultra DMA modes supported:%s%s%s%s%s%s\n",
+                               w_name(),
+                               (w & ID_UDMA_0_SUP) ? " 0" : "",
+                               (w & ID_UDMA_1_SUP) ? " 1" : "",
+                               (w & ID_UDMA_2_SUP) ? " 2" : "",
+                               (w & ID_UDMA_3_SUP) ? " 3" : "",
+                               (w & ID_UDMA_4_SUP) ? " 4" : "",
+                               (w & ID_UDMA_5_SUP) ? " 5" : "");
+                       }
+                       if (w & (ID_UDMA_0_SEL|ID_UDMA_1_SEL|
+                               ID_UDMA_2_SEL|ID_UDMA_3_SEL|
+                               ID_UDMA_4_SEL|ID_UDMA_5_SEL)) {
+                               printf(
+                       "%s: Ultra DMA mode selected:%s%s%s%s%s%s\n",
+                               w_name(),
+                               (w & ID_UDMA_0_SEL) ? " 0" : "",
+                               (w & ID_UDMA_1_SEL) ? " 1" : "",
+                               (w & ID_UDMA_2_SEL) ? " 2" : "",
+                               (w & ID_UDMA_3_SEL) ? " 3" : "",
+                               (w & ID_UDMA_4_SEL) ? " 4" : "",
+                               (w & ID_UDMA_5_SEL) ? " 5" : "");
+                       }
+               }
+               wn->dma= 1;
+       } else if (id_dma || dma_base) {
+               printf("id_dma %d, dma_base 0x%x\n", id_dma, dma_base);
+       } else
+               printf("no DMA support\n");
+}
+
 /*===========================================================================*
  *                             w_identify                                   *
  *===========================================================================*/
@@ -872,20 +972,10 @@ PRIVATE int w_identify()
   struct wini *wn = w_wn;
   struct command cmd;
   int i, s;
-  int id_dma, ultra_dma;
-  u32_t dma_base;
   u16_t w;
-  unsigned long dma_status;
   unsigned long size;
   int prev_wakeup;
   int r;
-#define id_byte(n)     (&tmp_buf[2 * (n)])
-#define id_word(n)     (((u16_t) id_byte(n)[0] <<  0) \
-                       |((u16_t) id_byte(n)[1] <<  8))
-#define id_longword(n) (((u32_t) id_byte(n)[0] <<  0) \
-                       |((u32_t) id_byte(n)[1] <<  8) \
-                       |((u32_t) id_byte(n)[2] << 16) \
-                       |((u32_t) id_byte(n)[3] << 24))
 
   /* Try to identify the device. */
   cmd.ldh     = wn->ldhpref;
@@ -954,96 +1044,7 @@ PRIVATE int w_identify()
                        wn->lba48 = 1;
                }
 
-               /* Check for DMA. Assume that only LBA capable devices can do
-                * DMA.
-                */
-               w= id_word(ID_CAPABILITIES);
-               id_dma= !!(w & ID_CAP_DMA);
-               w= id_byte(ID_FIELD_VALIDITY)[0];
-               ultra_dma= !!(w & ID_FV_88);
-               dma_base= wn->base_dma;
-               if (dma_base)
-               {
-                       if (sys_inb(dma_base + DMA_STATUS, &dma_status) != OK)
-                       {
-                               panic(w_name(),
-                                       "unable to read DMA status register",
-                                       NO_NUM);
-                       }
-               }
-               if (disable_dma)
-                       ;       /* DMA is disabled */
-               else if (id_dma && dma_base)
-               {
-                       w= id_word(ID_MULTIWORD_DMA);
-                       if (w_pci_debug &&
-                       (w & (ID_MWDMA_2_SUP|ID_MWDMA_1_SUP|ID_MWDMA_0_SUP)))
-                       {
-                               printf(
-                               "%s: multiword DMA modes supported:%s%s%s\n",
-                                       w_name(),
-                                       (w & ID_MWDMA_0_SUP) ? " 0" : "",
-                                       (w & ID_MWDMA_1_SUP) ? " 1" : "",
-                                       (w & ID_MWDMA_2_SUP) ? " 2" : "");
-                       }
-                       if (w_pci_debug &&
-                       (w & (ID_MWDMA_0_SEL|ID_MWDMA_1_SEL|ID_MWDMA_2_SEL)))
-                       {
-                               printf(
-                               "%s: multiword DMA mode selected:%s%s%s\n",
-                                       w_name(),
-                                       (w & ID_MWDMA_0_SEL) ? " 0" : "",
-                                       (w & ID_MWDMA_1_SEL) ? " 1" : "",
-                                       (w & ID_MWDMA_2_SEL) ? " 2" : "");
-                       }
-                       if (w_pci_debug && ultra_dma) 
-                       {
-                               w= id_word(ID_ULTRA_DMA);
-                               if (w & (ID_UDMA_0_SUP|ID_UDMA_1_SUP|
-                                       ID_UDMA_2_SUP|ID_UDMA_3_SUP|
-                                       ID_UDMA_4_SUP|ID_UDMA_5_SUP))
-                               {
-                                       printf(
-                               "%s: Ultra DMA modes supported:%s%s%s%s%s%s\n",
-                                       w_name(),
-                                       (w & ID_UDMA_0_SUP) ? " 0" : "",
-                                       (w & ID_UDMA_1_SUP) ? " 1" : "",
-                                       (w & ID_UDMA_2_SUP) ? " 2" : "",
-                                       (w & ID_UDMA_3_SUP) ? " 3" : "",
-                                       (w & ID_UDMA_4_SUP) ? " 4" : "",
-                                       (w & ID_UDMA_5_SUP) ? " 5" : "");
-                               }
-                               if (w & (ID_UDMA_0_SEL|ID_UDMA_1_SEL|
-                                       ID_UDMA_2_SEL|ID_UDMA_3_SEL|
-                                       ID_UDMA_4_SEL|ID_UDMA_5_SEL))
-                               {
-                                       printf(
-                               "%s: Ultra DMA mode selected:%s%s%s%s%s%s\n",
-                                       w_name(),
-                                       (w & ID_UDMA_0_SEL) ? " 0" : "",
-                                       (w & ID_UDMA_1_SEL) ? " 1" : "",
-                                       (w & ID_UDMA_2_SEL) ? " 2" : "",
-                                       (w & ID_UDMA_3_SEL) ? " 3" : "",
-                                       (w & ID_UDMA_4_SEL) ? " 4" : "",
-                                       (w & ID_UDMA_5_SEL) ? " 5" : "");
-                               }
-                       }
-                       wn->dma= 1;
-               }
-               else if (id_dma || dma_base)
-               {
-                       printf("id_dma %d, dma_base 0x%x\n", id_dma, dma_base);
-               }
-               else
-                       printf("no DMA support\n");
-
-#if 0
-               if (wn->dma && wn == &wini[0])
-               {
-                       printf("disabling DMA for drive 0\n");
-                       wn->dma= 0;
-               }
-#endif
+               check_dma(wn);
        }
 
        if (wn->lcylinders == 0 || wn->lheads == 0 || wn->lsectors == 0) {
@@ -1069,6 +1070,7 @@ PRIVATE int w_identify()
                panic(w_name(),"Call to sys_insw() failed", s);
 
        size = 0;       /* Size set later. */
+       check_dma(wn);
 #endif
   } else {
        /* Not an ATA device; no translations, no special features.  Don't
@@ -1298,14 +1300,13 @@ PRIVATE int do_transfer(struct wini *wn, unsigned int precomp,
        return com_out(&cmd);
 }
 
-
 void stop_dma(struct wini *wn)
 {
        int r;
 
        /* Stop bus master operation */
        r= sys_outb(wn->base_dma + DMA_COMMAND, 0);
-       if (r != 0) panic("at_wini", "setup_dma: sys_outb failed", r);
+       if (r != 0) panic("at_wini", "stop_dma: sys_outb failed", r);
 }
 
 void start_dma(struct wini *wn, int do_write)
@@ -1321,9 +1322,41 @@ void start_dma(struct wini *wn, int do_write)
                v |= DMA_CMD_WRITE;     
        }
        r= sys_outb(wn->base_dma + DMA_COMMAND, v);
-       if (r != 0) panic("at_wini", "setup_dma: sys_outb failed", r);
+       if (r != 0) panic("at_wini", "start_dma: sys_outb failed", r);
+}
+
+int error_dma(struct wini *wn)
+{
+       int r;
+       u32_t v;
+
+#define DMAERR(msg) \
+       printf("at_wini%d: bad DMA: %s. Disabling DMA for drive %d.\n", \
+               w_instance, msg, wn - wini);                            \
+       printf("at_wini%d: workaround: set %s=1 in boot monitor.\n", \
+               w_instance, NO_DMA_VAR); \
+       return 1;       \
+
+       r= sys_inb(wn->base_dma + DMA_STATUS, &v);
+       if (r != 0) panic("at_wini", "w_transfer: sys_inb failed", r);
+
+       if (!wn->dma_intseen) {
+               /* DMA did not complete successfully */
+               if (v & DMA_ST_BM_ACTIVE) {
+                       DMAERR("DMA did not complete");
+               } else if (v & DMA_ST_ERROR) {
+                       DMAERR("DMA error");
+               } else {
+                       DMAERR("DMA buffer too small");
+               }
+       } else if ((v & DMA_ST_BM_ACTIVE)) {
+               DMAERR("DMA buffer too large");
+       }
+
+       return 0;
 }
 
+
 /*===========================================================================*
  *                             w_transfer                                   *
  *===========================================================================*/
@@ -1378,10 +1411,8 @@ int safe;                        /* iov contains addresses (0) or grants? */
        /* First check to see if a reinitialization is needed. */
        if (!(wn->state & INITIALIZED) && w_specify() != OK) return(EIO);
 
-       stop_dma(wn);
-
-       if (do_dma)
-       {
+       if (do_dma) {
+               stop_dma(wn);
                setup_dma(&nbytes, proc_nr, iov, addr_offset, do_write,
                        &do_copyout, safe);
 #if 0
@@ -1393,7 +1424,8 @@ int safe;                 /* iov contains addresses (0) or grants? */
        r = do_transfer(wn, wn->precomp, (nbytes >> SECTOR_SHIFT),
                block, opcode, do_dma);
 
-       start_dma(wn, do_write);
+       if (do_dma)
+               start_dma(wn, do_write);
 
        if (opcode == DEV_SCATTER_S) {
                /* The specs call for a 400 ns wait after issuing the command.
@@ -1404,8 +1436,7 @@ int safe;                 /* iov contains addresses (0) or grants? */
                        panic(w_name(), "couldn't get status", NO_NUM);
        }
 
-       if (do_dma)
-       {
+       if (do_dma) {
                /* Wait for the interrupt, check DMA status and optionally
                 * copy out.
                 */
@@ -1427,41 +1458,11 @@ int safe;                       /* iov contains addresses (0) or grants? */
                if(!wn->dma_intseen) {
                        if(w_waitfor_dma(DMA_ST_INT, DMA_ST_INT))
                                wn->dma_intseen = 1;
-               }
-
-               r= sys_inb(wn->base_dma + DMA_STATUS, &v);
-               if (r != 0) panic("at_wini", "w_transfer: sys_inb failed", r);
-#if 0
-               if (sys_outb(wn->base_dma + DMA_STATUS, v) != OK) {
-                       panic(w_name(), "couldn't ack irq on (out dma)\n", NO_NUM);
-               }
-#endif
-
-#define BAD_DMA_CONTINUE(msg) {                                                \
-       printf("at_wini%d: bad DMA: %s. Disabling DMA for drive %d.\n", \
-               w_instance, msg, wn - wini);                            \
-       printf("at_wini%d: workaround: set %s=1 in boot monitor.\n", \
-               w_instance, NO_DMA_VAR); \
-       wn->dma = 0;                                                    \
-       continue;                                                       \
-}
-
+               } 
 
-#if 0
-               printf("dma_status: 0x%x\n", v);
-#endif
-               if (!wn->dma_intseen) {
-                       /* DMA did not complete successfully */
-                       if (v & DMA_ST_BM_ACTIVE) {
-                               BAD_DMA_CONTINUE("DMA did not complete");
-                       } else if (v & DMA_ST_ERROR) {
-                               BAD_DMA_CONTINUE("DMA error");
-                       } else {
-                               BAD_DMA_CONTINUE("DMA buffer too small");
-                       }
-               }
-               else if ((v & DMA_ST_BM_ACTIVE)) {
-                       BAD_DMA_CONTINUE("DMA buffer too large");
+               if(error_dma(wn)) {
+                       wn->dma = 0;
+                       continue;
                }
 
                stop_dma(wn);
@@ -1702,7 +1703,6 @@ struct command *cmd;              /* Command block */
 
   return(OK);
 }
-
 /*===========================================================================*
  *                             setup_dma                                    *
  *===========================================================================*/
@@ -1721,6 +1721,7 @@ int safe;
        int i, j, r, bad;
        unsigned long v;
        struct wini *wn = w_wn;
+       int verbose = 0;
 
        /* First try direct scatter/gather to the supplied buffers */
        size= *sizep;
@@ -1729,17 +1730,16 @@ int safe;
        bad= 0;
        offset= 0;      /* Offset in current iov */
 
-#if 0
-       printf("at_wini: setup_dma: proc_nr %d\n", proc_nr);
-#endif
+       if(verbose)
+               printf("at_wini: setup_dma: proc_nr %d\n", proc_nr);
 
        while (size > 0)
        {
-#if 0
+          if(verbose)  {
                printf(
                "at_wini: setup_dma: iov[%d]: addr 0x%x, size %d offset %d, size %d\n",
                        i, iov[i].iov_addr, iov[i].iov_size, offset, size);
-#endif
+          }
                        
                n= iov[i].iov_size-offset;
                if (n > size)
@@ -1776,6 +1776,7 @@ int safe;
                if (j >= N_PRDTE)
                {
                        /* Too many entries */
+
                        bad= 1;
                        break;
                }
@@ -1803,14 +1804,14 @@ int safe;
                        panic("at_wini", "bad prdt index", j);
                prdt[j-1].prdte_flags |= PRDTE_FL_EOT;
 
-#if 0
-               for (i= 0; i<j; i++)
-               {
+          if(verbose) {
+               printf("dma not bad\n");
+               for (i= 0; i<j; i++) {
                        printf("prdt[%d]: base 0x%x, size %d, flags 0x%x\n",
                                i, prdt[i].prdte_base, prdt[i].prdte_count,
                                prdt[i].prdte_flags);
                }
-#endif
+          }
        }
 
        /* The caller needs to perform a copy-out from the dma buffer if
@@ -1821,6 +1822,8 @@ int safe;
 
        if (bad)
        {
+               if(verbose)
+                       printf("partially bad dma\n");
                /* Adjust request size */
                size= *sizep;
                if (size > ATA_DMA_BUF_SIZE)
@@ -1899,14 +1902,14 @@ int safe;
                if (size != 0)
                        panic("at_wini", "size to large for prdt", NO_NUM);
 
-#if 0
+          if(verbose) {
                for (i= 0; i<=j; i++)
                {
                        printf("prdt[%d]: base 0x%x, size %d, flags 0x%x\n",
                                i, prdt[i].prdte_base, prdt[i].prdte_count,
                                prdt[i].prdte_flags);
                }
-#endif
+         }
        }
 
        /* Verify that the bus master is not active */
@@ -1923,6 +1926,7 @@ int safe;
        /* Clear interrupt and error flags */
        r= sys_outb(wn->base_dma + DMA_STATUS, DMA_ST_INT | DMA_ST_ERROR);
        if (r != 0) panic("at_wini", "setup_dma: sys_outb failed", r);
+
 }
 
 
@@ -2261,9 +2265,9 @@ void sense_request(void)
        packet[11] = 0;
 
        for(i = 0; i < SENSE_PACKETSIZE; i++) sense[i] = 0xff;
-       r = atapi_sendpacket(packet, SENSE_PACKETSIZE);
+       r = atapi_sendpacket(packet, SENSE_PACKETSIZE, 0);
        if (r != OK) { printf("request sense command failed\n"); return; }
-       if (atapi_intr_wait() <= 0) { printf("WARNING: request response failed\n"); }
+       if (atapi_intr_wait(0, 0) <= 0) { printf("WARNING: request response failed\n"); }
 
        if (sys_insw(w_wn->base_cmd + REG_DATA, SELF, (void *) sense, SENSE_PACKETSIZE) != OK)
                printf("WARNING: sense reading failed\n");
@@ -2290,13 +2294,15 @@ int safe;                       /* use safecopies? */
   u64_t pos;
   unsigned long block;
   u64_t dv_size = w_dv->dv_size;
-  unsigned nbytes, nblocks, count, before, chunk;
+  unsigned nbytes, nblocks, before, chunk;
   static u8_t packet[ATAPI_PACKETSIZE];
   size_t addr_offset = 0;
+  int dmabytes = 0, piobytes = 0;
 
   errors = fresh = 0;
 
   while (nr_req > 0 && !fresh) {
+       int do_dma = wn->dma && w_atapi_dma;
        /* The Minix block size is smaller than the CD block size, so we
         * may have to read extra before or after the good data.
         */
@@ -2304,16 +2310,17 @@ int safe;                       /* use safecopies? */
        block = div64u(pos, CD_SECTOR_SIZE);
        before = rem64u(pos, CD_SECTOR_SIZE);
 
+       if(before)
+               do_dma = 0;
+
        /* How many bytes to transfer? */
-       nbytes = count = 0;
+       nbytes = 0;
        for (iop = iov; iop < iov_end; iop++) {
                nbytes += iop->iov_size;
-               if ((before + nbytes) % CD_SECTOR_SIZE == 0) count = nbytes;
+               if(iop->iov_size % CD_SECTOR_SIZE)
+                       do_dma = 0;
        }
 
-       /* Does one of the memory chunks end nicely on a CD sector multiple? */
-       if (count != 0) nbytes = count;
-
        /* Data comes in as words, so we have to enforce even byte counts. */
        if ((before | nbytes) & 1) return(EINVAL);
 
@@ -2323,10 +2330,6 @@ int safe;                        /* use safecopies? */
                nbytes = diff64(dv_size, position);
 
        nblocks = (before + nbytes + CD_SECTOR_SIZE - 1) / CD_SECTOR_SIZE;
-       if (ATAPI_DEBUG) {
-               printf("block=%lu, before=%u, nbytes=%u, nblocks=%u\n",
-                       block, before, nbytes, nblocks);
-       }
 
        /* First check to see if a reinitialization is needed. */
        if (!(wn->state & INITIALIZED) && w_specify() != OK) return(EIO);
@@ -2345,25 +2348,63 @@ int safe;                       /* use safecopies? */
        packet[10] = 0;
        packet[11] = 0;
 
+       if(do_dma) {
+               int do_copyout = 0;
+               stop_dma(wn);
+               setup_dma(&nbytes, proc_nr, iov, addr_offset, 0,
+                       &do_copyout, safe);
+               if(do_copyout || (nbytes != nblocks * CD_SECTOR_SIZE)) {
+                       stop_dma(wn);
+                       do_dma = 0;
+               }
+       }
+
        /* Tell the controller to execute the packet command. */
-       r = atapi_sendpacket(packet, nblocks * CD_SECTOR_SIZE);
+       r = atapi_sendpacket(packet, nblocks * CD_SECTOR_SIZE, do_dma);
        if (r != OK) goto err;
 
+       if(do_dma) {
+               wn->dma_intseen = 0;
+               start_dma(wn, 0);
+               w_intr_wait();
+               if(!wn->dma_intseen) {
+                       if(w_waitfor_dma(DMA_ST_INT, DMA_ST_INT)) {
+                               wn->dma_intseen = 1;
+                       }
+               }
+               if(error_dma(wn)) {
+                       printf("Disabling DMA (ATAPI)\n");
+                       wn->dma = 0;
+               } else {
+                       dmabytes += nbytes;
+                       while (nbytes > 0) {
+                               size_t chunk;
+                               chunk = nbytes;
+                               if (chunk > iov->iov_size)
+                                       chunk = iov->iov_size;
+                               position= add64ul(position, chunk);
+                               nbytes -= chunk;
+                               if ((iov->iov_size -= chunk) == 0) {
+                                       iov++;
+                                       nr_req--;
+                               }
+                       }
+               }
+               continue;
+       }
+
        /* Read chunks of data. */
-       while ((r = atapi_intr_wait()) > 0) {
+       while ((r = atapi_intr_wait(do_dma, nblocks * CD_SECTOR_SIZE)) > 0) {
+               size_t count;
                count = r;
 
-               if (ATAPI_DEBUG) {
-                       printf("before=%u, nbytes=%u, count=%u\n",
-                               before, nbytes, count);
-               }
-
                while (before > 0 && count > 0) {       /* Discard before. */
                        chunk = before;
                        if (chunk > count) chunk = count;
                        if (chunk > DMA_BUF_SIZE) chunk = DMA_BUF_SIZE;
-       if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, chunk)) != OK)
-               panic(w_name(),"Call to sys_insw() failed", s);
+                       if ((s=sys_insw(wn->base_cmd + REG_DATA,
+                               SELF, tmp_buf, chunk)) != OK)
+                               panic(w_name(),"Call to sys_insw() failed", s);
                        before -= chunk;
                        count -= chunk;
                }
@@ -2385,6 +2426,7 @@ int safe;                 /* use safecopies? */
                        nbytes -= chunk;
                        count -= chunk;
                        addr_offset += chunk;
+                       piobytes += chunk;
                        fresh = 0;
                        if ((iov->iov_size -= chunk) == 0) {
                                iov++;
@@ -2392,13 +2434,15 @@ int safe;                       /* use safecopies? */
                                fresh = 1;      /* new element is optional */
                                addr_offset = 0;
                        }
+
                }
 
                while (count > 0) {             /* Excess data. */
                        chunk = count;
                        if (chunk > DMA_BUF_SIZE) chunk = DMA_BUF_SIZE;
-       if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, chunk)) != OK)
-               panic(w_name(),"Call to sys_insw() failed", s);
+                       if ((s=sys_insw(wn->base_cmd + REG_DATA,
+                               SELF, tmp_buf, chunk)) != OK)
+                               panic(w_name(),"Call to sys_insw() failed", s);
                        count -= chunk;
                }
        }
@@ -2415,6 +2459,12 @@ int safe;                        /* use safecopies? */
        }
   }
 
+#if 0
+  if(dmabytes) printf("dmabytes %d ", dmabytes);
+  if(piobytes) printf("piobytes %d", piobytes);
+  if(dmabytes || piobytes) printf("\n");
+#endif
+
   w_command = CMD_IDLE;
   return(OK);
 }
@@ -2422,9 +2472,10 @@ int safe;                        /* use safecopies? */
 /*===========================================================================*
  *                             atapi_sendpacket                             *
  *===========================================================================*/
-PRIVATE int atapi_sendpacket(packet, cnt)
+PRIVATE int atapi_sendpacket(packet, cnt, do_dma)
 u8_t *packet;
 unsigned cnt;
+int do_dma;
 {
 /* Send an Atapi Packet Command */
   struct wini *wn = w_wn;
@@ -2455,7 +2506,7 @@ unsigned cnt;
 #endif
 
   w_command = ATAPI_PACKETCMD;
-  pv_set(outbyte[0], wn->base_cmd + REG_FEAT, 0);
+  pv_set(outbyte[0], wn->base_cmd + REG_FEAT, do_dma ? FEAT_DMA : 0);
   pv_set(outbyte[1], wn->base_cmd + REG_IRR, 0);
   pv_set(outbyte[2], wn->base_cmd + REG_SAMTAG, 0);
   pv_set(outbyte[3], wn->base_cmd + REG_CNT_LO, (cnt >> 0) & 0xFF);
@@ -2475,14 +2526,6 @@ unsigned cnt;
   if ((s=sys_outsw(wn->base_cmd + REG_DATA, SELF, packet, ATAPI_PACKETSIZE)) != OK)
        panic(w_name(),"sys_outsw() failed", s);
 
- {
- int p;
- if (atapi_debug) {
-       printf("sent command:");
-        for(p = 0; p < ATAPI_PACKETSIZE; p++) { printf(" %02x", packet[p]); }
-        printf("\n");
-       }
- }
   return(OK);
 }
 
@@ -2656,7 +2699,7 @@ char *strerr(int e)
 /*===========================================================================*
  *                             atapi_intr_wait                              *
  *===========================================================================*/
-PRIVATE int atapi_intr_wait()
+PRIVATE int atapi_intr_wait(int do_dma, size_t max)
 {
 /* Wait for an interrupt and study the results.  Returns a number of bytes
  * that need to be transferred, or an error code.
@@ -2684,9 +2727,6 @@ PRIVATE int atapi_intr_wait()
   len |= inbyte[2].value << 8;
   irr = inbyte[3].value;
 
-#if ATAPI_DEBUG
-       printf("wn %p  S=%x=%s E=%02x=%s L=%04x I=%02x\n", wn, wn->w_status, strstatus(wn->w_status), e, strerr(e), len, irr);
-#endif
   if (wn->w_status & (STATUS_BSY | STATUS_CHECK)) {
        if (atapi_debug) {
                printf("atapi fail:  S=%x=%s E=%02x=%s L=%04x I=%02x\n", wn->w_status, strstatus(wn->w_status), e, strerr(e), len, irr);
@@ -2723,12 +2763,6 @@ PRIVATE int atapi_intr_wait()
        break;
   }
 
-#if 0
-  /* retry if the media changed */
-  XXX while (phase == (IRR_IO | IRR_COD) && (wn->w_status & STATUS_CHECK)
-       && (e & ERROR_SENSE) == SENSE_UATTN && --try > 0);
-#endif
-
   wn->w_status |= STATUS_ADMBSY;       /* Assume not done yet. */
   return(r);
 }