From 6b899f5077d33c863c733c94686cf42253b9a7f2 Mon Sep 17 00:00:00 2001 From: Søren Schmidt Date: Mon, 19 Nov 2007 18:05:48 +0000 Subject: 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. --- sys/dev/ata/ata-chipset.c | 40 ++++++++++++++++++++++++++++++++++++---- sys/dev/ata/atapi-cd.c | 37 ++++++++++++++++++++++--------------- 2 files changed, 58 insertions(+), 19 deletions(-) (limited to 'sys/dev') diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c index 9d136173f57f0..4f8943b8c5316 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 4c6b55dc45caf..22caf9b8926fb 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); -- cgit v1.3