Source-Changes-HG archive

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

[src/trunk]: src/sys This change adds SATA port multiplier support to mvsata(4).



details:   https://anonhg.NetBSD.org/src/rev/0a2acf9d339c
branches:  trunk
changeset: 784826:0a2acf9d339c
user:      jakllsch <jakllsch%NetBSD.org@localhost>
date:      Sun Feb 10 21:21:29 2013 +0000

description:
This change adds SATA port multiplier support to mvsata(4).

diffstat:

 sys/conf/files      |    4 +-
 sys/dev/ic/mvsata.c |  203 +++++++++++++++++++++++++++++++++++----------------
 2 files changed, 139 insertions(+), 68 deletions(-)

diffs (truncated from 489 to 300 lines):

diff -r a3d040bf7a3a -r 0a2acf9d339c sys/conf/files
--- a/sys/conf/files    Sun Feb 10 20:25:56 2013 +0000
+++ b/sys/conf/files    Sun Feb 10 21:21:29 2013 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files,v 1.1062 2013/01/09 22:23:45 skrll Exp $
+#      $NetBSD: files,v 1.1063 2013/02/10 21:21:29 jakllsch Exp $
 #      @(#)files.newconf       7.5 (Berkeley) 5/10/93
 
 version        20100430
@@ -994,7 +994,7 @@
 # Marvell Serial-ATA Host Controller
 define mvsata
 file dev/ic/mvsata.c                   mvsata
-device mvsata: ata, ata_dma, ata_udma, wdc_common, sata, mvsata
+device mvsata: ata, ata_dma, ata_udma, wdc_common, sata, sata_pmp, mvsata
 defflag opt_mvsata.h           MVSATA_WITHOUTDMA
 
 # DECchip 21x4x Ethernet controller family, and assorted clones.
diff -r a3d040bf7a3a -r 0a2acf9d339c sys/dev/ic/mvsata.c
--- a/sys/dev/ic/mvsata.c       Sun Feb 10 20:25:56 2013 +0000
+++ b/sys/dev/ic/mvsata.c       Sun Feb 10 21:21:29 2013 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: mvsata.c,v 1.28 2013/02/10 20:13:53 jakllsch Exp $     */
+/*     $NetBSD: mvsata.c,v 1.29 2013/02/10 21:21:29 jakllsch Exp $     */
 /*
  * Copyright (c) 2008 KIYOHARA Takashi
  * All rights reserved.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.28 2013/02/10 20:13:53 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.29 2013/02/10 21:21:29 jakllsch Exp $");
 
 #include "opt_mvsata.h"
 
@@ -51,6 +51,7 @@
 #include <dev/ata/atareg.h>
 #include <dev/ata/atavar.h>
 #include <dev/ic/wdcvar.h>
+#include <dev/ata/satapmpreg.h>
 #include <dev/ata/satareg.h>
 #include <dev/ata/satavar.h>
 
@@ -178,8 +179,8 @@
 static void mvsata_hreset_port(struct mvsata_port *);
 static void mvsata_reset_port(struct mvsata_port *);
 static void mvsata_reset_hc(struct mvsata_hc *);
+static uint32_t mvsata_softreset(struct mvsata_port *, int);
 #ifndef MVSATA_WITHOUTDMA
-static void mvsata_softreset(struct mvsata_port *, int);
 static void mvsata_edma_reset_qptr(struct mvsata_port *);
 static inline void mvsata_edma_enable(struct mvsata_port *);
 static int mvsata_edma_disable(struct mvsata_port *, int, int);
@@ -204,6 +205,7 @@
 static void mvsata_print_eprd(struct mvsata_port *, int);
 #endif
 
+static void mvsata_probe_drive(struct ata_channel *);
 
 struct ata_bustype mvsata_ata_bustype = {
        SCSIPI_BUSTYPE_ATA,
@@ -229,6 +231,23 @@
 #endif /* NATAPIBUS */
 #endif
 
+static void
+mvsata_pmp_select(struct mvsata_port *mvport, int pmpport)
+{
+       uint32_t ifctl;
+
+       KASSERT(pmpport < PMP_MAX_DRIVES);
+#if defined(DIAGNOSTIC) || defined(MVSATA_DEBUG)
+       if ((MVSATA_EDMA_READ_4(mvport, EDMA_CMD) & EDMA_CMD_EENEDMA) != 0) {
+               panic("EDMA enabled");
+       }
+#endif
+
+       ifctl = MVSATA_EDMA_READ_4(mvport, SATA_SATAICTL);
+       ifctl &= ~0xf;
+       ifctl |= pmpport;
+       MVSATA_EDMA_WRITE_4(mvport, SATA_SATAICTL, ifctl);
+}
 
 int
 mvsata_attach(struct mvsata_softc *sc, struct mvsata_product *product,
@@ -309,7 +328,7 @@
 #endif
 #endif
        sc->sc_wdcdev.wdc_maxdrives = 1;        /* SATA is always 1 drive */
-       sc->sc_wdcdev.sc_atac.atac_probe = wdc_sataprobe;
+       sc->sc_wdcdev.sc_atac.atac_probe = mvsata_probe_drive;
        sc->sc_wdcdev.sc_atac.atac_set_modes = mvsata_setup_channel;
 
        sc->sc_wdc_regs =
@@ -415,9 +434,20 @@
 {
        struct mvsata_softc *sc = device_private(MVSATA_DEV2(mvport));
        uint32_t cause;
-       int handled = 0;
 
        cause = MVSATA_EDMA_READ_4(mvport, EDMA_IEC);
+       /*
+        * We must ack SATA_SE and SATA_FISIC before acking coresponding bits
+        * in EDMA_IEC.
+        */
+       if (cause & EDMA_IE_SERRINT) {
+               MVSATA_EDMA_WRITE_4(mvport, SATA_SE,
+                   MVSATA_EDMA_READ_4(mvport, SATA_SEIM));
+       }
+       if (cause & EDMA_IE_ETRANSINT) {
+               MVSATA_EDMA_WRITE_4(mvport, SATA_FISIC,
+                   ~MVSATA_EDMA_READ_4(mvport, SATA_FISIM));
+       }
        MVSATA_EDMA_WRITE_4(mvport, EDMA_IEC, ~cause);
 
        DPRINTFN(3, ("%s:%d:%d:"
@@ -430,25 +460,16 @@
        if (!cause)
                return 0;
 
-       /* If PM connected, connect/disconnect interrupts storm could happen */
-       if (MVSATA_EDMA_READ_4(mvport, EDMA_IEC) &
-           (EDMA_IE_EDEVDIS | EDMA_IE_EDEVCON))
-               if (sc->sc_gen == gen2 || sc->sc_gen == gen2e) {
-                       delay(20 * 1000);
-                       cause = MVSATA_EDMA_READ_4(mvport, EDMA_IEC);
-                       MVSATA_EDMA_WRITE_4(mvport, EDMA_IEC, ~cause);
-               }
-
-       if (cause & EDMA_IE_EDEVDIS)
+       if (cause & EDMA_IE_EDEVDIS) {
                aprint_normal("%s:%d:%d: device disconnect\n",
                    device_xname(MVSATA_DEV2(mvport)),
                    mvport->port_hc->hc, mvport->port);
+       }
        if (cause & EDMA_IE_EDEVCON) {
                if (sc->sc_gen == gen1)
                        mvsata_devconn_gen1(mvport);
 
                DPRINTFN(3, ("    device connected\n"));
-               handled = 1;
        }
 #ifndef MVSATA_WITHOUTDMA
        if ((sc->sc_gen == gen1 && cause & EDMA_IE_ETRANSINT) ||
@@ -472,7 +493,6 @@
                            mvport->port_hc->hc, mvport->port, cause);
                        break;
                }
-               handled = 1;
        }
 #endif
        if (cause & EDMA_IE_ETRANSINT) {
@@ -482,7 +502,7 @@
                    mvport->port_hc->hc, mvport->port);
        }
 
-       return handled;
+       return 1;
 }
 
 
@@ -490,6 +510,25 @@
  * ATA callback entry points
  */
 
+static void
+mvsata_probe_drive(struct ata_channel *chp)
+{
+       struct mvsata_port * const mvport = (struct mvsata_port *)chp;
+       uint32_t sstat, sig;
+
+       sstat = sata_reset_interface(chp, mvport->port_iot,
+           mvport->port_sata_scontrol, mvport->port_sata_sstatus);
+       switch (sstat) {
+       case SStatus_DET_DEV:
+               mvsata_pmp_select(mvport, PMP_PORT_CTL);
+               sig = mvsata_softreset(mvport, AT_WAIT);
+               sata_interpret_sig(chp, 0, sig);
+               break;
+       default:
+               break;
+       }
+}
+
 #ifndef MVSATA_WITHOUTDMA
 static int
 mvsata_bio(struct ata_drive_datas *drvp, struct ata_bio *ata_bio)
@@ -529,8 +568,7 @@
        struct ata_channel *chp = drvp->chnl_softc;
        struct mvsata_port *mvport = (struct mvsata_port *)chp;
        uint32_t edma_c;
-
-       KASSERT(sigp == NULL);
+       uint32_t sig;
 
        edma_c = MVSATA_EDMA_READ_4(mvport, EDMA_CMD);
 
@@ -541,7 +579,12 @@
        if (edma_c & EDMA_CMD_EENEDMA)
                mvsata_edma_disable(mvport, 10000, flags & AT_WAIT);
 
-       mvsata_softreset(mvport, flags & AT_WAIT);
+       mvsata_pmp_select(mvport, drvp->drive);
+
+       sig = mvsata_softreset(mvport, flags & AT_WAIT);
+
+       if (sigp)
+               *sigp = sig;
 
        if (edma_c & EDMA_CMD_EENEDMA) {
                mvsata_edma_reset_qptr(mvport);
@@ -609,11 +652,11 @@
        int rv, s;
 
        DPRINTFN(1, ("%s:%d: mvsata_exec_command: drive=%d, bcount=%d,"
-           " r_command=0x%x, r_head=0x%x, r_cyl=0x%x, r_sector=0x%x,"
-           " r_count=0x%x, r_features=0x%x\n",
+           " r_lba=0x%012"PRIx64", r_count=0x%04x, r_features=0x%04x,"
+           " r_device=0x%02x, r_command=0x%02x\n",
            device_xname(MVSATA_DEV2(mvport)), chp->ch_channel,
-           drvp->drive, ata_c->bcount, ata_c->r_command, ata_c->r_head,
-           ata_c->r_cyl, ata_c->r_sector, ata_c->r_count, ata_c->r_features));
+           drvp->drive, ata_c->bcount, ata_c->r_lba, ata_c->r_count,
+           ata_c->r_features, ata_c->r_device, ata_c->r_command));
 
        xfer = ata_get_xfer(ata_c->flags & AT_WAIT ? ATAXF_CANSLEEP :
            ATAXF_NOSLEEP);
@@ -1138,6 +1181,8 @@
                if (mvport->port_edmamode != nodma)
                        mvsata_edma_disable(mvport, 10 /* ms */, wait_flags);
 
+               mvsata_pmp_select(mvport, xfer->c_drive);
+
                /* Do control operations specially. */
                if (__predict_false(drvp->state < READY)) {
                        /*
@@ -1173,10 +1218,10 @@
                        return;
                }
                if (ata_bio->flags & ATA_LBA48)
-                       wdccommandext(chp, xfer->c_drive, atacmd_to48(cmd),
+                       wdccommandext(chp, 0, atacmd_to48(cmd),
                            ata_bio->blkno, nblks, 0, WDSD_LBA);
                else
-                       wdccommand(chp, xfer->c_drive, cmd, cyl,
+                       wdccommand(chp, 0, cmd, cyl,
                            head, sect, nblks,
                            (ata_bio->lp->d_type == DTYPE_ST506) ?
                            ata_bio->lp->d_precompcyl / 4 : 0);
@@ -1423,8 +1468,6 @@
        struct ata_drive_datas *drvp = &chp->ch_drive[drive];
        const char *errstring;
 
-       flags |= AT_POLL;       /* XXX */
-
        /*
         * disable interrupts, all commands here should be quick
         * enough to be able to poll, and we don't go here that often
@@ -1435,8 +1478,8 @@
        errstring = "wait";
        if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags))
                goto ctrltimeout;
-       wdccommandshort(chp, drive, WDCC_RECAL);
-       /* Wait for at last 400ns for status bit to be valid */
+       wdccommandshort(chp, 0, WDCC_RECAL);
+       /* Wait for at least 400ns for status bit to be valid */
        DELAY(1);
        errstring = "recal";
        if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags))
@@ -1449,7 +1492,7 @@
        /* Also don't try if the drive didn't report its mode */
        if ((drvp->drive_flags & ATA_DRIVE_MODE) == 0)
                goto geometry;
-       wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
+       wdccommand(chp, 0, SET_FEATURES, 0, 0, 0,
            0x08 | drvp->PIO_mode, WDSF_SET_MODE);
        errstring = "piomode";
        if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags))
@@ -1457,10 +1500,10 @@
        if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
                goto ctrlerror;
        if (drvp->drive_flags & ATA_DRIVE_UDMA)
-               wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
+               wdccommand(chp, 0, SET_FEATURES, 0, 0, 0,
                    0x40 | drvp->UDMA_mode, WDSF_SET_MODE);
        else if (drvp->drive_flags & ATA_DRIVE_DMA)
-               wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
+               wdccommand(chp, 0, SET_FEATURES, 0, 0, 0,
                    0x20 | drvp->DMA_mode, WDSF_SET_MODE);
        else
                goto geometry;
@@ -1472,7 +1515,7 @@
 geometry:
        if (ata_bio->flags & ATA_LBA)
                goto multimode;
-       wdccommand(chp, drive, WDCC_IDP, ata_bio->lp->d_ncylinders,
+       wdccommand(chp, 0, WDCC_IDP, ata_bio->lp->d_ncylinders,
            ata_bio->lp->d_ntracks - 1, 0, ata_bio->lp->d_nsectors,
            (ata_bio->lp->d_type == DTYPE_ST506) ?



Home | Main Index | Thread Index | Old Index