[Midnightbsd-cvs] src: dev/ata: Our first pass at SATA DVD drive support.

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Fri Sep 7 11:16:34 EDT 2007


Log Message:
-----------
Our first pass at SATA DVD drive support.  This has only been tested on Intel hardware, based on a patch from Richard Burton.

(atapi sata cd/dvd ahci)

Modified Files:
--------------
    src/sys/dev/ata:
        ata-chipset.c (r1.7 -> r1.8)
        atapi-cd.c (r1.3 -> r1.4)

-------------- next part --------------
Index: ata-chipset.c
===================================================================
RCS file: /home/cvs/src/sys/dev/ata/ata-chipset.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -Lsys/dev/ata/ata-chipset.c -Lsys/dev/ata/ata-chipset.c -u -r1.7 -r1.8
--- sys/dev/ata/ata-chipset.c
+++ sys/dev/ata/ata-chipset.c
@@ -68,6 +68,8 @@
 static void ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error);
 static void ata_ahci_dmainit(device_t dev);
 static int ata_ahci_setup_fis(u_int8_t *fis, struct ata_request *request);
+/* rgb add engine restart */
+static void ata_ahci_restart_engine(device_t dev);
 static int ata_acard_chipinit(device_t dev);
 static int ata_acard_allocate(device_t dev);
 static int ata_acard_status(device_t dev);
@@ -455,7 +457,7 @@
 
     /* setup legacy cruft we need */
     ch->r_io[ATA_CYL_LSB].res = ctlr->r_res2;
-    ch->r_io[ATA_CYL_LSB].offset = ATA_AHCI_P_SIG + 1 + offset;
+    ch->r_io[ATA_CYL_LSB].offset = ATA_AHCI_P_SIG + 2 + offset;
     ch->r_io[ATA_CYL_MSB].res = ctlr->r_res2;
     ch->r_io[ATA_CYL_MSB].offset = ATA_AHCI_P_SIG + 3 + offset;
     ch->r_io[ATA_STATUS].res = ctlr->r_res2;
@@ -496,7 +498,14 @@
 	      ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR));
 
     /* start operations on this channel */
-    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
+    /* rgb - add ATAPI cmd */
+    if (ch->devices & ATA_ATAPI_MASTER)
+      ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
+             (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE |
+              ATA_AHCI_P_CMD_ATAPI |
+              ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | ATA_AHCI_P_CMD_ST));
+    else
+      ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
 	     (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE |
 	      ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | ATA_AHCI_P_CMD_ST));
     return 0;
@@ -509,6 +518,9 @@
     struct ata_channel *ch = device_get_softc(dev);
     struct ata_connect_task *tp;
     u_int32_t action, istatus, sstatus, error, issued;
+    /* rgb - add tfd_data */
+    u_int32_t tf_data;
+    /* end rgb additions */
     int offset = (ch->unit << 7);
     int tag = 0;
 
@@ -561,8 +573,24 @@
 	}
 
 	/* do we have any device action ? */
-	if (!(issued & (1 << tag)))
+	if (!(issued & (1 << tag))) 
 	    return 1;
+
+	/* rgb - check for error - This is necessary for atapi
+		code to work, and it seems to also prevent
+		occasional disk timeouts that sometimes cause
+		boot to fail
+        */
+         tf_data = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset);
+         if (tf_data & ATA_S_ERROR) {
+		if ((tf_data & ATA_S_BUSY) || (tf_data & ATA_S_DRQ))
+	        	return 0;   /* for now, let timeout do reset */
+		else {
+			/* restart engine to clear ATA_AHCI_P_CI */
+			ata_ahci_restart_engine(ch->dev);
+	 	        return 1;
+		}
+         }
     }
     return 0;
 }
@@ -582,6 +610,14 @@
     ctp = (struct ata_ahci_cmd_tab *)
 	  (ch->dma->work + ATA_AHCI_CT_OFFSET + (ATA_AHCI_CT_SIZE * tag));
 
+    /* rgb - if ATAPI request moves data, make it dma */
+    if (request->flags & ATA_R_ATAPI) {
+	if (request->bytecount && !(request->flags & ATA_R_READ))
+		request->flags |= ATA_R_WRITE;
+	if (request->flags & (ATA_R_READ | ATA_R_WRITE))
+		request->flags |= ATA_R_DMA;
+    }
+
     /* setup the FIS for this request */ /* XXX SOS ATAPI missing still */
     if (!(fis_size = ata_ahci_setup_fis(&ctp->cfis[0], request))) {
 	device_printf(request->dev, "setting up SATA FIS failed\n");
@@ -607,10 +643,17 @@
     clp->prd_length = entries;
     clp->cmd_flags = (request->flags & ATA_R_WRITE ? (1<<6) : 0) |
 		     (request->flags & ATA_R_ATAPI ? (1<<5) : 0) |
+/*  rgb - set prefetch flag if ATAPI */
+		     (request->flags & ATA_R_ATAPI ? (1<<7) : 0) |
 		     (fis_size / sizeof(u_int32_t));
     clp->bytecount = 0;
     clp->cmd_table_phys = htole64(ch->dma->work_bus + ATA_AHCI_CT_OFFSET +
 				  (ATA_AHCI_CT_SIZE * tag));
+    /* rgb - add atapi request */
+    if (request->flags & ATA_R_ATAPI) {
+          bzero(ctp->acmd, 32);
+          bcopy(request->u.atapi.ccb, ctp->acmd, 16);
+    }
 
     /* clear eventual ACTIVE bit */
     ATA_IDX_OUTL(ch, ATA_SACTIVE, ATA_IDX_INL(ch, ATA_SACTIVE) & (1 << tag));
@@ -618,6 +661,28 @@
     /* issue the command */
     ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + (ch->unit << 7), (1 << tag));
 
+    /* rgb - handle ATA_DEVICE_RESET requests */
+    if (!(request->flags & ATA_R_ATAPI)) {
+	if (request->u.ata.command == ATA_DEVICE_RESET) {
+		u_int32_t tf_data;
+		int timeout = 1000000;
+		do {
+  		   DELAY(10);
+		   tf_data = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + (ch->unit << 7));
+		} while (tf_data & ATA_S_BUSY && timeout--);
+		request->status = tf_data;
+		if (timeout <= 0) {
+		    device_printf(request->dev, "ATA_DEVICE_RESET timeout\n");
+		    /* should probably do softreset */
+		}
+		if (request->status & ATA_S_ERROR) {
+			request->error = tf_data >> 8;
+			ata_ahci_restart_engine(ch->dev);
+		}
+		return ATA_OP_FINISHED;
+	}
+    }
+
     /* start the timeout */
     callout_reset(&request->callout, request->timeout * hz,
 		  (timeout_t*)ata_timeout, request);
@@ -656,6 +721,36 @@
     return ATA_OP_FINISHED;
 }
 
+/* rgb add ahci_restart_engine */
+static void
+ata_ahci_restart_engine(device_t dev)
+{
+    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+    struct ata_channel *ch = device_get_softc(dev);
+    int tmp, offset = (ch->unit <<7); 
+    int timeout = 0;
+
+    /*  stop engine  */
+    tmp = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
+    tmp &= ~ATA_AHCI_P_CMD_ST;
+    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, tmp);
+	    do {
+		DELAY (1000);
+		if (timeout++ >500) {
+		    device_printf(ch->dev, "stopping AHCI engine failed\n");
+		    break;
+		}
+	    }
+            while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) &
+			ATA_AHCI_P_CMD_CR);
+
+    /*  restart engine  */
+    tmp = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
+    tmp |= ATA_AHCI_P_CMD_ST;
+    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, tmp);
+}
+ 
+
 static void
 ata_ahci_reset(device_t dev)
 {
@@ -704,7 +799,14 @@
 	     ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset));
 
     /* start operations on this channel */
-    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
+    /* rgb - add ATAPI cmd */
+    if (ch->devices & ATA_ATAPI_MASTER)
+      ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
+	     (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE |
+	      ATA_AHCI_P_CMD_ATAPI |
+	      ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | ATA_AHCI_P_CMD_ST));
+    else
+      ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
 	     (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE |
 	      ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | ATA_AHCI_P_CMD_ST));
 }
@@ -749,6 +851,11 @@
 
     fis[idx++] = 0x27;  /* host to device */
     fis[idx++] = 0x80;  /* command FIS (note PM goes here) */
+
+    /* rgb - add atapi request */
+    switch (request->flags & ATA_R_ATAPI) {
+
+    default:
     fis[idx++] = request->u.ata.command;
     fis[idx++] = request->u.ata.feature;
 
@@ -775,6 +882,40 @@
     fis[idx++] = 0x00;
     fis[idx++] = 0x00;
     fis[idx++] = 0x00;
+    break;
+
+    case ATA_R_ATAPI:
+    fis[idx++] = ATA_PACKET_CMD;
+    if (request->flags & ATA_R_DMA) {
+	fis[idx++] = ATA_F_DMA;
+	fis[idx++] = 0x00;
+	fis[idx++] = 0x00;
+	fis[idx++] = 0x00;
+    }
+    else {
+	fis[idx++] = 0x00;
+	fis[idx++] = 0x00;
+	fis[idx++] = request->transfersize;
+	fis[idx++] = request->transfersize >> 8;
+    }
+    fis[idx++] = atadev->unit;
+
+    fis[idx++] = 0x00;
+    fis[idx++] = 0x00;
+    fis[idx++] = 0x00;
+    fis[idx++] = 0x00;
+    fis[idx++] = 0x00;
+    fis[idx++] = 0x00;
+    fis[idx++] = 0x00;
+    fis[idx++] = ATA_A_4BIT;
+
+    fis[idx++] = 0x00;
+    fis[idx++] = 0x00;
+    fis[idx++] = 0x00;
+    fis[idx++] = 0x00;
+    break;
+    } 
+
     return idx;
 }
 
Index: atapi-cd.c
===================================================================
RCS file: /home/cvs/src/sys/dev/ata/atapi-cd.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -Lsys/dev/ata/atapi-cd.c -Lsys/dev/ata/atapi-cd.c -u -r1.3 -r1.4
--- sys/dev/ata/atapi-cd.c
+++ sys/dev/ata/atapi-cd.c
@@ -699,7 +699,10 @@
 	request->dev = dev;
 	bcopy(ccb, request->u.atapi.ccb, 16);
 	request->flags = ATA_R_ATAPI;
+	/* rgb - up timeout to 10 
 	request->timeout = 5;
+	*/
+	request->timeout = 10;
 	ata_queue_request(request);
 	if (!request->error &&
 	    (request->u.atapi.sense.key == 2 ||
@@ -1234,7 +1237,10 @@
     request->flags = ATA_R_ATAPI | ATA_R_READ;
     request->timeout = 30;
     ata_queue_request(request);
+/*  rgb - fix for pr 109270 from Martin Birgmeier
     if (!request->error && request->u.atapi.sense.error & ATA_SENSE_VALID)
+*/
+    if (!request->error && request->u.atapi.sense.specific & ATA_SENSE_SPEC_VALID)
 	*finished = ((request->u.atapi.sense.specific2 |
 		     (request->u.atapi.sense.specific1<<8))*100)/65535;
     else


More information about the Midnightbsd-cvs mailing list