Skip site navigation (1)Skip section navigation (2)
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>