PERFORCE change 177369 for review
Alexander Motin
mav at FreeBSD.org
Mon Apr 26 19:01:51 UTC 2010
http://p4web.freebsd.org/@@177369?ac=10
Change 177369 by mav at mav_mavtest on 2010/04/26 19:01:38
Add ATAPI DMA support.
Affected files ...
.. //depot/projects/scottl-camlock/src/sys/dev/mvs/mvs.c#13 edit
.. //depot/projects/scottl-camlock/src/sys/dev/mvs/mvs.h#10 edit
Differences ...
==== //depot/projects/scottl-camlock/src/sys/dev/mvs/mvs.c#13 (text+ko) ====
@@ -421,7 +421,7 @@
{
struct mvs_channel *ch = device_get_softc(dev);
int timeout;
- uint32_t ecfg, fcfg, hc, ltm;
+ uint32_t ecfg, fcfg, hc, ltm, unkn;
if (mode == ch->curr_mode)
return;
@@ -489,6 +489,14 @@
ATA_OUTL(ch->r_mem, SATA_FISC, fcfg);
ATA_OUTL(ch->r_mem, SATA_LTM, ltm);
ATA_OUTL(ch->r_mem, EDMA_HC, hc);
+ /* This is some magic, required to handle several DRQs
+ * with basic DMA. */
+ unkn = ATA_INL(ch->r_mem, EDMA_UNKN_RESD);
+ if (mode == MVS_EDMA_OFF)
+ unkn |= 1;
+ else
+ unkn &= ~1;
+ ATA_OUTL(ch->r_mem, EDMA_UNKN_RESD, unkn);
}
// device_printf(dev, "fisc %08x\n",ATA_INL(ch->r_mem, SATA_FISC));
// device_printf(dev, "ltmode %08x\n",ATA_INL(ch->r_mem, SATA_LTM));
@@ -755,8 +763,11 @@
/* Wait a bit for late !BUSY status update. */
if (status & ATA_S_BUSY) {
DELAY(100);
- if ((status = mvs_getstatus(dev, 1)) & ATA_S_BUSY)
- return;
+ if ((status = mvs_getstatus(dev, 1)) & ATA_S_BUSY) {
+ DELAY(1000);
+ if ((status = mvs_getstatus(dev, 1)) & ATA_S_BUSY)
+ return;
+ }
}
/* if we got an error we are done with the HW */
if (status & ATA_S_ERROR) {
@@ -802,7 +813,14 @@
return;
}
}
- } else {
+ } else if (ch->basic_dma) { /* ATAPI DMA */
+ if (status & ATA_S_DWF)
+ et = MVS_ERR_TFE;
+ else if (ATA_INL(ch->r_mem, DMA_S) & DMA_S_ERR)
+ et = MVS_ERR_TFE;
+ ATA_OUTL(ch->r_mem, DMA_C, 0);
+ goto end_finished;
+ } else { /* ATAPI PIO */
length = ATA_INB(ch->r_mem,ATA_CYL_LSB) | (ATA_INB(ch->r_mem,ATA_CYL_MSB) << 8);
ireason = ATA_INB(ch->r_mem,ATA_IREASON);
//device_printf(dev, "status %02x, ireason %02x, length %d\n", status, ireason, length);
@@ -1083,9 +1101,23 @@
ch->aslots |= (1 << slot->slot);
}
} else {
+ uint8_t *cdb = (ccb->ccb_h.flags & CAM_CDB_POINTER) ?
+ ccb->csio.cdb_io.cdb_ptr : ccb->csio.cdb_io.cdb_bytes;
ch->numpslots++;
+ if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE &&
+ ch->curr[ccb->ccb_h.target_id].mode >= ATA_DMA &&
+ (cdb[0] == 0x08 ||
+ cdb[0] == 0x0a ||
+ cdb[0] == 0x28 ||
+ cdb[0] == 0x2a ||
+ cdb[0] == 0x88 ||
+ cdb[0] == 0x8a ||
+ cdb[0] == 0xa8 ||
+ cdb[0] == 0xaa)) {
+ ch->basic_dma = 1;
+ }
}
- if (ch->numpslots == 0) {
+ if (ch->numpslots == 0 || ch->basic_dma) {
void *buf;
bus_size_t size;
@@ -1105,11 +1137,53 @@
}
}
+/* Locked by busdma engine. */
+static void
+mvs_dmasetprd(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+ struct mvs_slot *slot = arg;
+ struct mvs_channel *ch = device_get_softc(slot->dev);
+ struct mvs_eprd *eprd;
+ int i;
+
+ if (error) {
+ device_printf(slot->dev, "DMA load error\n");
+ mvs_end_transaction(slot, MVS_ERR_INVALID);
+ return;
+ }
+ KASSERT(nsegs <= MVS_SG_ENTRIES, ("too many DMA segment entries\n"));
+ /* If there is only one segment - no need to use S/G table on Gen-IIe. */
+ if (nsegs == 1 && ch->basic_dma == 0 && (ch->quirks & MVS_Q_GENIIE)) {
+ slot->dma.addr = segs[0].ds_addr;
+ slot->dma.len = segs[0].ds_len;
+ } else {
+ slot->dma.addr = 0;
+ /* Get a piece of the workspace for this EPRD */
+ eprd = (struct mvs_eprd *)
+ (ch->dma.workrq + MVS_EPRD_OFFSET + (MVS_EPRD_SIZE * slot->slot));
+ /* Fill S/G table */
+ for (i = 0; i < nsegs; i++) {
+ eprd[i].prdbal = htole32(segs[i].ds_addr);
+ eprd[i].bytecount = htole32(segs[i].ds_len & MVS_EPRD_MASK);
+ eprd[i].prdbah = htole32((segs[i].ds_addr >> 16) >> 16);
+ }
+ eprd[i - 1].bytecount |= htole32(MVS_EPRD_EOF);
+ }
+ bus_dmamap_sync(ch->dma.data_tag, slot->dma.data_map,
+ ((slot->ccb->ccb_h.flags & CAM_DIR_IN) ?
+ BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE));
+ if (ch->basic_dma)
+ mvs_legacy_execute_transaction(slot);
+ else
+ mvs_execute_transaction(slot);
+}
+
static void
mvs_legacy_execute_transaction(struct mvs_slot *slot)
{
device_t dev = slot->dev;
struct mvs_channel *ch = device_get_softc(dev);
+ bus_addr_t eprd;
union ccb *ccb = slot->ccb;
int port = ccb->ccb_h.target_id & 0x0f;
int timeout;
@@ -1148,14 +1222,21 @@
ch->transfersize / 2);
}
} else {
-// device_printf(dev, "%d ATAPI command %02x size %d\n",
-// port, ccb->csio.cdb_io.cdb_bytes[0], ccb->csio.dxfer_len);
+// device_printf(dev, "%d ATAPI command %02x size %d dma %d\n",
+// port, ccb->csio.cdb_io.cdb_bytes[0], ccb->csio.dxfer_len,
+// ch->basic_dma);
ch->donecount = 0;
ch->transfersize = min(ccb->csio.dxfer_len,
ch->curr[port].bytecount);
- ATA_OUTB(ch->r_mem, ATA_FEATURE, 0);
- ATA_OUTB(ch->r_mem, ATA_CYL_LSB, ch->transfersize);
- ATA_OUTB(ch->r_mem, ATA_CYL_MSB, ch->transfersize >> 8);
+ if (ch->basic_dma) {
+ ATA_OUTB(ch->r_mem, ATA_FEATURE, ATA_F_DMA);
+ ATA_OUTB(ch->r_mem, ATA_CYL_LSB, 0);
+ ATA_OUTB(ch->r_mem, ATA_CYL_MSB, 0);
+ } else {
+ ATA_OUTB(ch->r_mem, ATA_FEATURE, 0);
+ ATA_OUTB(ch->r_mem, ATA_CYL_LSB, ch->transfersize);
+ ATA_OUTB(ch->r_mem, ATA_CYL_MSB, ch->transfersize >> 8);
+ }
ATA_OUTB(ch->r_mem, ATA_COMMAND, ATA_PACKET_CMD);
ch->fake_busy = 1;
/* wait for ready to write ATAPI command block */
@@ -1183,53 +1264,23 @@
(uint16_t *)((ccb->ccb_h.flags & CAM_CDB_POINTER) ?
ccb->csio.cdb_io.cdb_ptr : ccb->csio.cdb_io.cdb_bytes),
ch->curr[port].atapi / 2);
- if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
+ DELAY(10);
+ if (ch->basic_dma) {
+ eprd = ch->dma.workrq_bus + MVS_EPRD_OFFSET +
+ (MVS_EPRD_SIZE * slot->slot);
+ ATA_OUTL(ch->r_mem, DMA_DTLBA, eprd);
+ ATA_OUTL(ch->r_mem, DMA_DTHBA, (eprd >> 16) >> 16);
+ ATA_OUTL(ch->r_mem, DMA_C, DMA_C_START |
+ (((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) ?
+ DMA_C_READ : 0));
+ } else if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
ch->fake_busy = 1;
- DELAY(10);
}
/* Start command execution timeout */
callout_reset(&slot->timeout, (int)ccb->ccb_h.timeout * hz / 1000,
(timeout_t*)mvs_timeout, slot);
}
-/* Locked by busdma engine. */
-static void
-mvs_dmasetprd(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
-{
- struct mvs_slot *slot = arg;
- struct mvs_channel *ch = device_get_softc(slot->dev);
- struct mvs_eprd *eprd;
- int i;
-
- if (error) {
- device_printf(slot->dev, "DMA load error\n");
- mvs_end_transaction(slot, MVS_ERR_INVALID);
- return;
- }
- KASSERT(nsegs <= MVS_SG_ENTRIES, ("too many DMA segment entries\n"));
- /* If there is only one segment - no need to use S/G table on Gen-IIe. */
- if (nsegs == 1 && (ch->quirks & MVS_Q_GENIIE)) {
- slot->dma.addr = segs[0].ds_addr;
- slot->dma.len = segs[0].ds_len;
- } else {
- slot->dma.addr = 0;
- /* Get a piece of the workspace for this EPRD */
- eprd = (struct mvs_eprd *)
- (ch->dma.workrq + MVS_EPRD_OFFSET + (MVS_EPRD_SIZE * slot->slot));
- /* Fill S/G table */
- for (i = 0; i < nsegs; i++) {
- eprd[i].prdbal = htole32(segs[i].ds_addr);
- eprd[i].bytecount = htole32(segs[i].ds_len & MVS_EPRD_MASK);
- eprd[i].prdbah = htole32((segs[i].ds_addr >> 16) >> 16);
- }
- eprd[i - 1].bytecount |= htole32(MVS_EPRD_EOF);
- }
- bus_dmamap_sync(ch->dma.data_tag, slot->dma.data_map,
- ((slot->ccb->ccb_h.flags & CAM_DIR_IN) ?
- BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE));
- mvs_execute_transaction(slot);
-}
-
/* Must be called with channel locked. */
static void
mvs_execute_transaction(struct mvs_slot *slot)
@@ -1438,7 +1489,7 @@
} else
bzero(res, sizeof(*res));
}
- if (ch->numpslots == 0) {
+ if (ch->numpslots == 0 || ch->basic_dma) {
if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
bus_dmamap_sync(ch->dma.data_tag, slot->dma.data_map,
(ccb->ccb_h.flags & CAM_DIR_IN) ?
@@ -1523,8 +1574,10 @@
} else {
ch->numpslots--;
}
- } else
+ } else {
ch->numpslots--;
+ ch->basic_dma = 0;
+ }
/* If it was our READ LOG command - process it. */
if (ch->readlog) {
mvs_process_read_log(dev, ccb);
@@ -1718,6 +1771,7 @@
mvs_requeue_frozen(dev);
/* Kill the engine and requeue all running commands. */
mvs_set_edma_mode(dev, MVS_EDMA_OFF);
+ ATA_OUTL(ch->r_mem, DMA_C, 0);
for (i = 0; i < MVS_MAX_SLOTS; i++) {
/* Do we have a running request on slot? */
if (ch->slot[i].state < MVS_SLOT_RUNNING)
==== //depot/projects/scottl-camlock/src/sys/dev/mvs/mvs.h#10 (text+ko) ====
@@ -171,6 +171,7 @@
#define EDMA_IORT 0x34 /* IORdy Timeout */
#define EDMA_CDT 0x40 /* Command Delay Threshold */
#define EDMA_HC 0x60 /* Halt Condition */
+#define EDMA_UNKN_RESD 0x6C /* Unknown register */
#define EDMA_CQDCQOS(x) (0x90 + ((x) << 2)
/* NCQ Done/TCQ Outstanding Status */
@@ -235,6 +236,10 @@
#define DMA_C_CONTFROMPREV (1 << 10)
#define DMA_C_DRBC(n) (((n) & 0xffff) << 16)
#define DMA_S 0x228 /* Basic DMA Status */
+#define DMA_S_ACT (1 << 0) /* Active */
+#define DMA_S_ERR (1 << 1) /* Error */
+#define DMA_S_PAUSED (1 << 2) /* Paused */
+#define DMA_S_LAST (1 << 3) /* Last */
#define DMA_DTLBA 0x22c /* Descriptor Table Low Base Address */
#define DMA_DTLBA_MASK 0xfffffff0
#define DMA_DTHBA 0x230 /* Descriptor Table High Base Address */
@@ -556,6 +561,7 @@
int in_idx; /* Next read CRPB */
u_int transfersize; /* PIO transfer size */
u_int donecount; /* PIO bytes sent/received */
+ u_int basic_dma; /* Basic DMA used for ATAPI */
u_int fake_busy; /* Fake busy bit after command submission */
union ccb *frozen; /* Frozen command */
struct callout pm_timer; /* Power management events */
More information about the p4-projects
mailing list