Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/jdolecek-ncq]: src/sys/dev Add NCQ support to siisata(4).



details:   https://anonhg.NetBSD.org/src/rev/8dbb9509bf3d
branches:  jdolecek-ncq
changeset: 352669:8dbb9509bf3d
user:      jakllsch <jakllsch%NetBSD.org@localhost>
date:      Tue Jun 13 00:02:19 2017 +0000

description:
Add NCQ support to siisata(4).

There are still issues that need to be address before I consider this
mergable.

diffstat:

 sys/dev/ata/TODO.ncq    |    2 +-
 sys/dev/ic/siisata.c    |  274 +++++++++++++++++++++++++++++------------------
 sys/dev/ic/siisatavar.h |    4 +-
 3 files changed, 171 insertions(+), 109 deletions(-)

diffs (truncated from 693 to 300 lines):

diff -r 391facd5ec33 -r 8dbb9509bf3d sys/dev/ata/TODO.ncq
--- a/sys/dev/ata/TODO.ncq      Mon Jun 12 23:51:40 2017 +0000
+++ b/sys/dev/ata/TODO.ncq      Tue Jun 13 00:02:19 2017 +0000
@@ -3,7 +3,7 @@
 
 test crashdump with ahci
 
-siisata - fix all 'XXX slot' -- jakllsch has this done but uncommited
+siisata - fix all new XXX and unmergable bits
 
 test crashdump with siisata
 
diff -r 391facd5ec33 -r 8dbb9509bf3d sys/dev/ic/siisata.c
--- a/sys/dev/ic/siisata.c      Mon Jun 12 23:51:40 2017 +0000
+++ b/sys/dev/ic/siisata.c      Tue Jun 13 00:02:19 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: siisata.c,v 1.30.4.14 2017/04/24 21:19:21 jakllsch Exp $ */
+/* $NetBSD: siisata.c,v 1.30.4.15 2017/06/13 00:02:19 jakllsch Exp $ */
 
 /* from ahcisata_core.c */
 
@@ -79,7 +79,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.14 2017/04/24 21:19:21 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.15 2017/06/13 00:02:19 jakllsch Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -148,7 +148,7 @@
 
 void siisata_cmd_start(struct ata_channel *, struct ata_xfer *);
 int siisata_cmd_complete(struct ata_channel *, struct ata_xfer *, int);
-void siisata_cmd_done(struct ata_channel *, struct ata_xfer *, int);
+void siisata_cmd_done(struct ata_channel *, struct ata_xfer *);
 void siisata_cmd_kill_xfer(struct ata_channel *, struct ata_xfer *, int);
 
 void siisata_bio_start(struct ata_channel *, struct ata_xfer *);
@@ -209,7 +209,7 @@
        SIISATA_DEBUG_PRINT(("%s: %s: GR_GC: 0x%08x\n",
            SIISATANAME(sc), __func__, GRREAD(sc, GR_GC)), DEBUG_FUNCS);
 
-       sc->sc_atac.atac_cap = ATAC_CAP_DMA | ATAC_CAP_UDMA;
+       sc->sc_atac.atac_cap = ATAC_CAP_DMA | ATAC_CAP_UDMA | ATAC_CAP_NCQ;
        sc->sc_atac.atac_pio_cap = 4;
        sc->sc_atac.atac_dma_cap = 2;
        sc->sc_atac.atac_udma_cap = 6;
@@ -246,10 +246,7 @@
 {
        struct siisata_softc *sc = (struct siisata_softc *)chp->ch_atac;
 
-       /* clear any interrupts */
-       (void)PRREAD(sc, PRX(chp->ch_channel, PRO_PSS));
-       PRWRITE(sc, PRX(chp->ch_channel, PRO_PIS), 0xffffffff);
-       /* and enable CmdErrr+CmdCmpl interrupting */
+       /* enable CmdErrr+CmdCmpl interrupting */
        PRWRITE(sc, PRX(chp->ch_channel, PRO_PIES),
            PR_PIS_CMDERRR | PR_PIS_CMDCMPL);
 }
@@ -263,9 +260,12 @@
        schp = &sc->sc_channels[port];
        chp = (struct ata_channel *)schp;
 
-       /* come out of reset, 64-bit activation */
+       /*
+        * Come out of reset. Disable no clearing of PR_PIS_CMDCMPL on read
+        * of PR_PSS. Disable 32-bit PRB activation, we use 64-bit activation.
+        */
        PRWRITE(sc, PRX(chp->ch_channel, PRO_PCC),
-           PR_PC_32BA | PR_PC_PORT_RESET);
+           PR_PC_32BA | PR_PC_INCOR | PR_PC_PORT_RESET);
        /* initialize port */
        siisata_reinit_port(chp);
        /* enable CmdErrr+CmdCmpl interrupting */
@@ -473,53 +473,71 @@
        struct siisata_softc *sc;
        struct ata_channel *chp;
        struct ata_xfer *xfer;
-       int slot;
+       u_int slot;
        uint32_t pss, pis;
        uint32_t prbfis;
 
        sc = (struct siisata_softc *)schp->ata_channel.ch_atac;
        chp = &schp->ata_channel;
-       xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, 0); /* XXX slot */
-       slot = SIISATA_NON_NCQ_SLOT;
+
+       /* get slot status, clearing completion interrupt (PR_PIS_CMDCMPL) */
+       pss = PRREAD(sc, PRX(chp->ch_channel, PRO_PSS));
+       SIISATA_DEBUG_PRINT(("%s: %s port %d, pss 0x%x\n",
+           SIISATANAME(sc), __func__, chp->ch_channel, pss), DEBUG_INTR);
+
+       for (slot = 0; slot < SIISATA_MAX_SLOTS; slot++) {
+               if (((schp->sch_active_slots >> slot) & 1) == 0)
+                       /* there's nothing executing here, skip */
+                       continue;
+               if (((pss >> slot) & 1) != 0)
+                       /* execution is incomplete or unsuccessful, skip for now */
+                       continue;
+               xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, slot);
+               if (xfer->c_intr == NULL) {
+                       wakeup(schp);
+                       continue;
+               }
+               KASSERT(xfer != NULL);
+               KASSERT(xfer->c_intr != NULL);
+               xfer->c_intr(chp, xfer, 0);
+       }
+       /* if no errors, we're done now */
+       if ((pss & PR_PSS_ATTENTION) == 0) {
+               pis = PRREAD(sc, PRX(chp->ch_channel, PRO_PIS));
+               pis &= 0xffff;
+               if (pis) {
+                       PRWRITE(sc, PRX(chp->ch_channel, PRO_PIS),
+                           pis & 0xfffcfffc);
+               }
+               return;
+       }
 
        pis = PRREAD(sc, PRX(chp->ch_channel, PRO_PIS));
 
        SIISATA_DEBUG_PRINT(("%s: %s port %d, pis 0x%x ", SIISATANAME(sc),
            __func__, chp->ch_channel, pis), DEBUG_INTR);
 
-       if (pis & PR_PIS_CMDCMPL) {
-               /* get slot status, clearing completion interrupt */
-               pss = PRREAD(sc, PRX(chp->ch_channel, PRO_PSS));
-               SIISATA_DEBUG_PRINT(("pss 0x%x\n", pss), DEBUG_INTR);
-               /* is this expected? */
-               /* XXX improve */
-               if ((schp->sch_active_slots & __BIT(slot)) == 0) {
-                       aprint_error( "%s: unexpected command "
-                           "completion on port %d\n",
-                           SIISATANAME(sc), chp->ch_channel);
-                       return;
-               }
-               if ((~pss & __BIT(slot)) == 0) {
-                       aprint_error( "%s: unknown slot "
-                           "completion on port %d, pss 0x%x\n",
-                           SIISATANAME(sc), chp->ch_channel, pss);
-                       return;
-               }
-       } else if (pis & PR_PIS_CMDERRR) {
+       if (pis & PR_PIS_CMDERRR) {
                uint32_t ec;
+               uint32_t ps;
+
+               ps = PRREAD(sc, PRX(chp->ch_channel, PRO_PS));
+               ec = PRREAD(sc, PRX(chp->ch_channel, PRO_PCE));
+               SIISATA_DEBUG_PRINT(("ec %d\n", ec), DEBUG_INTR);
+
+               slot = PR_PS_ACTIVE_SLOT(ps); /* XXX invalid for NCQ? */
 
                /* emulate a CRC error by default */
                chp->ch_status = WDCS_ERR;
                chp->ch_error = WDCE_CRC;
 
-               ec = PRREAD(sc, PRX(chp->ch_channel, PRO_PCE));
-               SIISATA_DEBUG_PRINT(("ec %d\n", ec), DEBUG_INTR);
                if (ec <= PR_PCE_DATAFISERROR) {
-                       if (ec == PR_PCE_DEVICEERROR && xfer != NULL) {
+                       if (ec == PR_PCE_DEVICEERROR) {
                                /* read in specific information about error */
                                prbfis = bus_space_read_stream_4(
                                    sc->sc_prt, sc->sc_prh,
-                                   PRSX(chp->ch_channel, slot, PRSO_FIS));
+                                   PRSX(chp->ch_channel, slot,
+                                   PRSO_FIS));
                                /* set ch_status and ch_error */
                                satafis_rdh_parse(chp, (uint8_t *)&prbfis);
                        }
@@ -532,12 +550,19 @@
                        /* okay, we have a "Fatal Error" */
                        siisata_device_reset(chp);
                }
+               for (slot = 0; slot < SIISATA_MAX_SLOTS; slot++) {
+                       /* there's nothing executing here, skip */
+                       if (((schp->sch_active_slots >> slot) & 1) == 0)
+                               continue;
+                       xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, slot);
+                       if (xfer == NULL)
+                               continue;
+                       xfer->c_intr(chp, xfer, 0);
+               }
        }
 
-       /* clear some (ok, all) ints */
-       PRWRITE(sc, PRX(chp->ch_channel, PRO_PIS), 0xffffffff);
-       if (xfer && xfer->c_intr)
-               xfer->c_intr(chp, xfer, 0);
+       /* clear */
+       PRWRITE(sc, PRX(chp->ch_channel, PRO_PIS), pis);
 
        return;
 }
@@ -549,49 +574,80 @@
        struct siisata_softc *sc = (struct siisata_softc *)chp->ch_atac;
        struct siisata_channel *schp = (struct siisata_channel *)chp;
        struct siisata_prb *prb;
-       int slot = SIISATA_NON_NCQ_SLOT;
+       struct ata_xfer *xfer;
+       uint32_t pss, pis;
        int i;
 
        /* wait for ready */
        while (!(PRREAD(sc, PRX(chp->ch_channel, PRO_PS)) & PR_PS_PORT_READY))
                DELAY(10);
 
-       prb = schp->sch_prb[slot];
+       xfer = ata_get_xfer(chp);  /* Is this right?  What if the slots are full? */
+       if (xfer == NULL)
+               return;
+
+       prb = schp->sch_prb[xfer->c_slot];
        memset(prb, 0, SIISATA_CMD_SIZE);
        prb->prb_control =
-           htole16(PRB_CF_SOFT_RESET | PRB_CF_INTERRUPT_MASK);
+           htole16(PRB_CF_SOFT_RESET /* | PRB_CF_INTERRUPT_MASK */);
        KASSERT(drvp->drive <= PMP_PORT_CTL);
        prb->prb_fis[rhd_c] = drvp->drive;
 
-       siisata_activate_prb(schp, slot);
+       ata_activate_xfer(chp, xfer);
+       siisata_activate_prb(schp, xfer->c_slot);
 
        for(i = 0; i < 3100; i++) {
-               if ((PRREAD(sc, PRX(chp->ch_channel, PRO_PSS)) &
-                   PR_PXSS(slot)) == 0)
+#if 0          /* XXX-jak-jd-ncq this block needs re-work... XXX */
+               PRWRITE(sc, PRX(chp->ch_channel, PRO_PCS), PR_PC_INCOR);
+               pss = PRREAD(sc, PRX(chp->ch_channel, PRO_PSS));
+               PRWRITE(sc, PRX(chp->ch_channel, PRO_PCC), PR_PC_INCOR);
+               if ((pss & PR_PXSS(xfer->c_slot)) == 0)
                        break;
-               if (flags & AT_WAIT)
+               if (pss & PR_PSS_ATTENTION)
+                       break;
+#else
+               pss = PR_PXSS(xfer->c_slot);
+               /* XXX DO NOT MERGE UNTIL THIS IS FIXED XXX */
+#endif
+               if ((flags & AT_POLL) == 0)
                        tsleep(schp, PRIBIO, "siiprb", mstohz(10));
                else
                        DELAY(10000);
        }
 
-       siisata_deactivate_prb(schp, slot);
+       siisata_deactivate_prb(schp, xfer->c_slot);
+
+       if ((pss & PR_PSS_ATTENTION) != 0) {
+               pis = PRREAD(sc, PRX(chp->ch_channel, PRO_PIS));
+               const uint32_t ps = PRREAD(sc, PRX(chp->ch_channel, PRO_PS));
+               const u_int slot = PR_PS_ACTIVE_SLOT(ps);
+               if (slot != xfer->c_slot)
+                       device_printf(sc->sc_atac.atac_dev, "%s port %d "
+                           "drive %d slot %d c_slot %d", __func__,
+                           chp->ch_channel, drvp->drive, slot, xfer->c_slot);
+               PRWRITE(sc, PRX(chp->ch_channel, PRO_PIS), pis &
+                   PR_PIS_CMDERRR);
+       }
+
        if (i == 3100) {
                /* timeout */
-               siisata_device_reset(chp);
+               siisata_device_reset(chp);      /* XXX is this right? */
                if (sigp)
                        *sigp = 0xffffffff;
        } else {
                /* read the signature out of the FIS */
                if (sigp) {
                        *sigp = 0;
-                       *sigp |= (PRREAD(sc, PRSX(chp->ch_channel, slot,
+                       *sigp |= (PRREAD(sc, PRSX(chp->ch_channel, xfer->c_slot,
                            PRSO_FIS+0x4)) & 0x00ffffff) << 8;
-                       *sigp |= PRREAD(sc, PRSX(chp->ch_channel, slot,
+                       *sigp |= PRREAD(sc, PRSX(chp->ch_channel, xfer->c_slot,
                            PRSO_FIS+0xc)) & 0xff;
                }
        }
 
+       ata_deactivate_xfer(chp, xfer);
+       ata_free_xfer(chp, xfer);
+
 #if 1
        /* attempt to downgrade signaling in event of CRC error */
        /* XXX should be part of the MI (S)ATA subsystem */
@@ -624,8 +680,8 @@
        struct siisata_softc *sc = (struct siisata_softc *)chp->ch_atac;
        struct siisata_channel *schp = (struct siisata_channel *)chp;
 
-       SIISATA_DEBUG_PRINT(("%s: %s\n", SIISATANAME(sc), __func__),
-           DEBUG_FUNCS);
+       SIISATA_DEBUG_PRINT(("%s: %s channel %d\n", SIISATANAME(sc), __func__,
+           chp->ch_channel), DEBUG_FUNCS);
 
        if (sata_reset_interface(chp, sc->sc_prt, schp->sch_scontrol,
            schp->sch_sstatus, flags) != SStatus_DET_DEV) {



Home | Main Index | Thread Index | Old Index