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