Date: Mon, 26 Apr 2010 19:01:50 GMT From: Alexander Motin <mav@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 177369 for review Message-ID: <201004261901.o3QJ1o9E067474@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@177369?ac=10 Change 177369 by mav@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 */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201004261901.o3QJ1o9E067474>