summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2007-11-19 18:05:48 +0000
committersos <sos@FreeBSD.org>2007-11-19 18:05:48 +0000
commit24ced90f97f7dc7365541adcf3e3e8610e935957 (patch)
tree491ed6ea353a84da21e00c0036f398cb187a6bce /sys/dev/ata
parent4833340b9c0071527738ef27c1ac7180cd04a59d (diff)
downloadFreeBSD-src-24ced90f97f7dc7365541adcf3e3e8610e935957.zip
FreeBSD-src-24ced90f97f7dc7365541adcf3e3e8610e935957.tar.gz
Fix the problem with certain ATAPI commands on AHCI devices.
Revert the probe in atapi-cd.c to the old usage now its fixed on AHCI. THis change also fixes using virtual CD's om fx parallels. Still leaves the GEOM problem of telling media vs device access apart in the access function.
Diffstat (limited to 'sys/dev/ata')
-rw-r--r--sys/dev/ata/ata-chipset.c40
-rw-r--r--sys/dev/ata/atapi-cd.c37
2 files changed, 58 insertions, 19 deletions
diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c
index 9d13617..4f8943b 100644
--- a/sys/dev/ata/ata-chipset.c
+++ b/sys/dev/ata/ata-chipset.c
@@ -460,7 +460,11 @@ ata_ahci_ident(device_t dev)
if (pci_read_config(dev, PCIR_PROGIF, 1) != PCIP_STORAGE_SATA_AHCI_1_0)
return ENXIO;
- sprintf(buffer, "%s AHCI controller", ata_pcivendor2str(dev));
+ if (bootverbose)
+ sprintf(buffer, "%s (ID=%08x) AHCI controller",
+ ata_pcivendor2str(dev), pci_get_devid(dev));
+ else
+ sprintf(buffer, "%s AHCI controller", ata_pcivendor2str(dev));
device_set_desc_copy(dev, buffer);
ctlr->chipinit = ata_ahci_chipinit;
return 0;
@@ -591,16 +595,44 @@ ata_ahci_status(device_t dev)
if (action & (1 << ch->unit)) {
u_int32_t istatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset);
+ u_int32_t cstatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset);
/* clear interrupt(s) */
ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, action & (1 << ch->unit));
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, istatus);
/* do we have any PHY events ? */
+ /* XXX SOS check istatus phy bits */
ata_sata_phy_check_events(dev);
- /* do we have any device action ? */
- return (!(ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset) & (1 << tag)));
+ /* do we have a potentially hanging engine to take care of? */
+ if ((istatus & 0x78400050) && (cstatus & (1 << tag))) {
+
+ u_int32_t cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
+ int timeout = 0;
+
+ /* kill off all activity on this channel */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
+ cmd & ~(ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST));
+
+ /* XXX SOS this is not entirely wrong */
+ do {
+ DELAY(1000);
+ if (timeout++ > 500) {
+ device_printf(dev, "stopping AHCI engine failed\n");
+ break;
+ }
+ } while (ATA_INL(ctlr->r_res2,
+ ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR);
+
+ /* start operations on this channel */
+ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
+ cmd | (ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST));
+
+ return 1;
+ }
+ else
+ return (!(cstatus & (1 << tag)));
}
return 0;
}
@@ -655,7 +687,7 @@ ata_ahci_begin_transaction(struct ata_request *request)
ATA_IDX_OUTL(ch, ATA_SACTIVE, ATA_IDX_INL(ch, ATA_SACTIVE) & (1 << tag));
/* set command type bit */
- if (ch->devices & ATA_ATAPI_MASTER)
+ if (request->flags & ATA_R_ATAPI)
ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) |
ATA_AHCI_P_CMD_ATAPI);
diff --git a/sys/dev/ata/atapi-cd.c b/sys/dev/ata/atapi-cd.c
index 4c6b55d..22caf9b 100644
--- a/sys/dev/ata/atapi-cd.c
+++ b/sys/dev/ata/atapi-cd.c
@@ -689,25 +689,32 @@ acd_geom_access(struct g_provider *pp, int dr, int dw, int de)
{
device_t dev = pp->geom->softc;
struct acd_softc *cdp = device_get_ivars(dev);
+ struct ata_request *request;
+ int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int timeout = 60, track;
- /* check for media present, waiting for loading medium just in case */
+ if (!(request = ata_alloc_request()))
+ return ENOMEM;
+
+ /* wait if drive is not finished loading the medium */
while (timeout--) {
- if (!acd_mode_sense(dev, ATAPI_CDROM_CAP_PAGE,
- (caddr_t)&cdp->cap, sizeof(cdp->cap)) &&
- cdp->cap.page_code == ATAPI_CDROM_CAP_PAGE) {
- if ((cdp->cap.medium_type == MST_FMT_NONE) ||
- (cdp->cap.medium_type == MST_NO_DISC) ||
- (cdp->cap.medium_type == MST_DOOR_OPEN) ||
- (cdp->cap.medium_type == MST_FMT_ERROR))
- return EIO;
- else
- break;
- }
- pause("acdld", hz / 2);
+ bzero(request, sizeof(struct ata_request));
+ request->dev = dev;
+ bcopy(ccb, request->u.atapi.ccb, 16);
+ request->flags = ATA_R_ATAPI;
+ request->timeout = 5;
+ ata_queue_request(request);
+ if (!request->error &&
+ (request->u.atapi.sense.key == 2 ||
+ request->u.atapi.sense.key == 7) &&
+ request->u.atapi.sense.asc == 4 &&
+ request->u.atapi.sense.ascq == 1)
+ pause("acdld", hz / 2);
+ else
+ break;
}
- if (timeout <= 0)
- return EIO;
+ ata_free_request(request);
if (pp->acr == 0) {
acd_prevent_allow(dev, 1);
OpenPOWER on IntegriCloud