summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2011-04-21 02:37:32 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2011-04-21 02:37:32 +0000
commita01774f581da39178a640874db822c8f29f9b634 (patch)
tree57c44ba108c5683987d29f9edd47d463379de0ed
parent07f3d2f37336ab69e771c0f554497ae688a243c2 (diff)
ahci asks atascsi to reserve a ccb to use for error handling, but then
atascsi goes and throws away all the ccbs that the disk wont use, including the reserved one. this makes ahci reserve its own ccb. light testing by krw@ without regression.
-rw-r--r--sys/dev/pci/ahci.c22
1 files changed, 15 insertions, 7 deletions
diff --git a/sys/dev/pci/ahci.c b/sys/dev/pci/ahci.c
index 299b387a026..a66c52663fd 100644
--- a/sys/dev/pci/ahci.c
+++ b/sys/dev/pci/ahci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ahci.c,v 1.174 2011/04/07 15:30:16 miod Exp $ */
+/* $OpenBSD: ahci.c,v 1.175 2011/04/21 02:37:31 dlg Exp $ */
/*
* Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
@@ -373,6 +373,7 @@ struct ahci_port {
TAILQ_HEAD(, ahci_ccb) ap_ccb_free;
TAILQ_HEAD(, ahci_ccb) ap_ccb_pending;
struct mutex ap_ccb_mtx;
+ struct ahci_ccb *ap_ccb_err;
u_int32_t ap_state;
#define AP_S_NORMAL 0
@@ -863,8 +864,7 @@ noccc:
aaa.aaa_methods = &ahci_atascsi_methods;
aaa.aaa_minphys = NULL;
aaa.aaa_nports = AHCI_MAX_PORTS;
- aaa.aaa_ncmds = sc->sc_ncmds;
- aaa.aaa_capability = ASAA_CAP_NEEDS_RESERVED;
+ aaa.aaa_ncmds = sc->sc_ncmds - 1;
if (!(sc->sc_flags & AHCI_F_NO_NCQ) &&
(sc->sc_cap & AHCI_REG_CAP_SNCQ)) {
aaa.aaa_capability |= ASAA_CAP_NCQ | ASAA_CAP_PMP_NCQ;
@@ -1292,6 +1292,10 @@ nomem:
ahci_enable_interrupts(ap);
+ /* grab a ccb for use during error recovery */
+ ap->ap_ccb_err = &ap->ap_ccbs[sc->sc_ncmds - 1];
+ TAILQ_REMOVE(&ap->ap_ccb_free, ap->ap_ccb_err, ccb_entry);
+
freeport:
if (rc != 0)
ahci_port_free(sc, port);
@@ -1313,6 +1317,9 @@ ahci_port_free(struct ahci_softc *sc, u_int port)
ahci_write(sc, AHCI_REG_IS, 1 << port);
}
+ if (ap->ap_ccb_err)
+ ahci_put_ccb(ap->ap_ccb_err);
+
if (ap->ap_ccbs) {
while ((ccb = ahci_get_ccb(ap)) != NULL)
bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
@@ -3012,12 +3019,11 @@ ahci_get_err_ccb(struct ahci_port *ap)
* Grab a CCB to use for error recovery. This should never fail, as
* we ask atascsi to reserve one for us at init time.
*/
- err_ccb = ahci_get_ccb(ap);
- KASSERT(err_ccb != NULL);
+ err_ccb = ap->ap_ccb_err;
err_ccb->ccb_xa.flags = 0;
err_ccb->ccb_done = ahci_empty_done;
- return err_ccb;
+ return (err_ccb);
}
void
@@ -3037,8 +3043,10 @@ ahci_put_err_ccb(struct ahci_ccb *ccb)
printf("ahci_port_err_ccb_restore but SACT %08x != 0?\n", sact);
KASSERT(ahci_pread(ap, AHCI_PREG_CI) == 0);
+#ifdef DIAGNOSTIC
/* Done with the CCB */
- ahci_put_ccb(ccb);
+ KASSERT(ccb == ap->ap_ccb_err);
+#endif
/* Restore outstanding command state */
ap->ap_sactive = ap->ap_err_saved_sactive;