Author: mav
Date: Mon Nov  8 15:36:15 2010
New Revision: 214988
URL: http://svn.freebsd.org/changeset/base/214988

Log:
  Teach ahci(4), siis(4) and ATA_CAM ata(4) wrapper report to CAM residual
  I/O length on underruns, that often happens for some SCSI commands.

Modified:
  head/sys/dev/ahci/ahci.c
  head/sys/dev/ata/ata-all.c
  head/sys/dev/siis/siis.c

Modified: head/sys/dev/ahci/ahci.c
==============================================================================
--- head/sys/dev/ahci/ahci.c    Mon Nov  8 15:25:12 2010        (r214987)
+++ head/sys/dev/ahci/ahci.c    Mon Nov  8 15:36:15 2010        (r214988)
@@ -1625,12 +1625,13 @@ ahci_execute_transaction(struct ahci_slo
        /* Setup the command list entry */
        clp = (struct ahci_cmd_list *)
            (ch->dma.work + AHCI_CL_OFFSET + (AHCI_CL_SIZE * slot->slot));
-       clp->prd_length = slot->dma.nsegs;
-       clp->cmd_flags = (ccb->ccb_h.flags & CAM_DIR_OUT ? AHCI_CMD_WRITE : 0) |
-                    (ccb->ccb_h.func_code == XPT_SCSI_IO ?
-                     (AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH) : 0) |
-                    (fis_size / sizeof(u_int32_t)) |
-                    (port << 12);
+       clp->cmd_flags = htole16(
+                   (ccb->ccb_h.flags & CAM_DIR_OUT ? AHCI_CMD_WRITE : 0) |
+                   (ccb->ccb_h.func_code == XPT_SCSI_IO ?
+                    (AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH) : 0) |
+                   (fis_size / sizeof(u_int32_t)) |
+                   (port << 12));
+       clp->prd_length = htole16(slot->dma.nsegs);
        /* Special handling for Soft Reset command. */
        if ((ccb->ccb_h.func_code == XPT_ATA_IO) &&
            (ccb->ataio.cmd.flags & CAM_ATAIO_CONTROL)) {
@@ -1650,7 +1651,7 @@ ahci_execute_transaction(struct ahci_slo
        clp->cmd_table_phys = htole64(ch->dma.work_bus + AHCI_CT_OFFSET +
                                  (AHCI_CT_SIZE * slot->slot));
        bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map,
-           BUS_DMASYNC_PREWRITE);
+           BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
        bus_dmamap_sync(ch->dma.rfis_tag, ch->dma.rfis_map,
            BUS_DMASYNC_PREREAD);
        /* Set ACTIVE bit for NCQ commands. */
@@ -1855,10 +1856,13 @@ ahci_end_transaction(struct ahci_slot *s
        device_t dev = slot->dev;
        struct ahci_channel *ch = device_get_softc(dev);
        union ccb *ccb = slot->ccb;
+       struct ahci_cmd_list *clp;
        int lastto;
 
        bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map,
-           BUS_DMASYNC_POSTWRITE);
+           BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+       clp = (struct ahci_cmd_list *)
+           (ch->dma.work + AHCI_CL_OFFSET + (AHCI_CL_SIZE * slot->slot));
        /* Read result registers to the result struct
         * May be incorrect if several commands finished same time,
         * so read only when sure or have to.
@@ -1893,6 +1897,16 @@ ahci_end_transaction(struct ahci_slot *s
                        res->sector_count_exp = fis[13];
                } else
                        bzero(res, sizeof(*res));
+               if ((ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA) == 0 &&
+                   (ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
+                       ccb->ataio.resid =
+                           ccb->ataio.dxfer_len - le32toh(clp->bytecount);
+               }
+       } else {
+               if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
+                       ccb->csio.resid =
+                           ccb->csio.dxfer_len - le32toh(clp->bytecount);
+               }
        }
        if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
                bus_dmamap_sync(ch->dma.data_tag, slot->dma.data_map,

Modified: head/sys/dev/ata/ata-all.c
==============================================================================
--- head/sys/dev/ata/ata-all.c  Mon Nov  8 15:25:12 2010        (r214987)
+++ head/sys/dev/ata/ata-all.c  Mon Nov  8 15:36:15 2010        (r214988)
@@ -1517,6 +1517,15 @@ ata_cam_end_transaction(device_t dev, st
                res->sector_count = request->u.ata.count;
                res->sector_count_exp = request->u.ata.count >> 8;
        }
+       if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
+               if (ccb->ccb_h.func_code == XPT_ATA_IO) {
+                       ccb->ataio.resid =
+                           ccb->ataio.dxfer_len - request->donecount;
+               } else {
+                       ccb->csio.resid =
+                           ccb->csio.dxfer_len - request->donecount;
+               }
+       }
        ata_free_request(request);
        xpt_done(ccb);
        /* Do error recovery if needed. */

Modified: head/sys/dev/siis/siis.c
==============================================================================
--- head/sys/dev/siis/siis.c    Mon Nov  8 15:25:12 2010        (r214987)
+++ head/sys/dev/siis/siis.c    Mon Nov  8 15:36:15 2010        (r214988)
@@ -1208,6 +1208,17 @@ siis_end_transaction(struct siis_slot *s
                        res->sector_count_exp = ATA_INB(ch->r_mem, offs + 13);
                } else
                        bzero(res, sizeof(*res));
+               if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN &&
+                   ch->numrslots == 1) {
+                       ccb->ataio.resid = ccb->ataio.dxfer_len -
+                           ATA_INL(ch->r_mem, SIIS_P_LRAM_SLOT(slot->slot) + 
4);
+               }
+       } else {
+               if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN &&
+                   ch->numrslots == 1) {
+                       ccb->csio.resid = ccb->csio.dxfer_len -
+                           ATA_INL(ch->r_mem, SIIS_P_LRAM_SLOT(slot->slot) + 
4);
+               }
        }
        if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
                bus_dmamap_sync(ch->dma.data_tag, slot->dma.data_map,
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to