[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