svn commit: r212359 - in head/sys/dev/ata: . chipsets

Nathan Whitehorn nwhitehorn at FreeBSD.org
Thu Sep 9 13:17:31 UTC 2010


Author: nwhitehorn
Date: Thu Sep  9 13:17:30 2010
New Revision: 212359
URL: http://svn.freebsd.org/changeset/base/212359

Log:
  Fix a problem where device detection would work unreliably on Serverworks
  K2 SATA controllers. The chip's status register must be read first, and
  as a long, for other registers to be correctly updated after a command, and
  this includes the command sequence in device detection as well as the
  previously handled case after interrupts. While here, clean up some
  previous hacks related to this controller.
  
  Reported by:	many
  Reviewed by:	mav
  MFC after:	3 weeks

Modified:
  head/sys/dev/ata/ata-all.h
  head/sys/dev/ata/ata-lowlevel.c
  head/sys/dev/ata/chipsets/ata-serverworks.c

Modified: head/sys/dev/ata/ata-all.h
==============================================================================
--- head/sys/dev/ata/ata-all.h	Thu Sep  9 11:10:15 2010	(r212358)
+++ head/sys/dev/ata/ata-all.h	Thu Sep  9 13:17:30 2010	(r212359)
@@ -566,6 +566,7 @@ struct ata_channel {
 #define         ATA_SATA		0x80
 #define         ATA_DMA_BEFORE_CMD	0x100
 #define         ATA_KNOWN_PRESENCE	0x200
+#define         ATA_STATUS_IS_LONG	0x400
 
     int				pm_level;	/* power management level */
     int                         devices;        /* what is present */

Modified: head/sys/dev/ata/ata-lowlevel.c
==============================================================================
--- head/sys/dev/ata/ata-lowlevel.c	Thu Sep  9 11:10:15 2010	(r212358)
+++ head/sys/dev/ata/ata-lowlevel.c	Thu Sep  9 13:17:30 2010	(r212359)
@@ -516,10 +516,13 @@ ata_generic_reset(device_t dev)
 	if ((mask & 0x01) && (stat0 & ATA_S_BUSY)) {
 	    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(ATA_MASTER));
 	    DELAY(10);
+	    if (ch->flags & ATA_STATUS_IS_LONG)
+		    stat0 = ATA_IDX_INL(ch, ATA_STATUS) & 0xff;
+	    else
+		    stat0 = ATA_IDX_INB(ch, ATA_STATUS);
 	    err = ATA_IDX_INB(ch, ATA_ERROR);
 	    lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
 	    msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
-	    stat0 = ATA_IDX_INB(ch, ATA_STATUS);
 	    if (bootverbose)
 		device_printf(dev,
 			      "stat0=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n",
@@ -546,10 +549,13 @@ ata_generic_reset(device_t dev)
 	    !((mask & 0x01) && (stat0 & ATA_S_BUSY))) {
 	    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(ATA_SLAVE));
 	    DELAY(10);
+	    if (ch->flags & ATA_STATUS_IS_LONG)
+		    stat1 = ATA_IDX_INL(ch, ATA_STATUS) & 0xff;
+	    else
+		    stat1 = ATA_IDX_INB(ch, ATA_STATUS);
 	    err = ATA_IDX_INB(ch, ATA_ERROR);
 	    lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
 	    msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
-	    stat1 = ATA_IDX_INB(ch, ATA_STATUS);
 	    if (bootverbose)
 		device_printf(dev,
 			      "stat1=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n",

Modified: head/sys/dev/ata/chipsets/ata-serverworks.c
==============================================================================
--- head/sys/dev/ata/chipsets/ata-serverworks.c	Thu Sep  9 11:10:15 2010	(r212358)
+++ head/sys/dev/ata/chipsets/ata-serverworks.c	Thu Sep  9 13:17:30 2010	(r212359)
@@ -58,9 +58,8 @@ static int ata_serverworks_ch_detach(dev
 static void ata_serverworks_tf_read(struct ata_request *request);
 static void ata_serverworks_tf_write(struct ata_request *request);
 static int ata_serverworks_setmode(device_t dev, int target, int mode);
-#ifdef __powerpc__
+static void ata_serverworks_sata_reset(device_t dev);
 static int ata_serverworks_status(device_t dev);
-#endif
 
 /* misc defines */
 #define SWKS_33		0
@@ -101,7 +100,6 @@ ata_serverworks_probe(device_t dev)
     return (BUS_PROBE_DEFAULT);
 }
 
-#ifdef __powerpc__
 static int
 ata_serverworks_status(device_t dev)
 {
@@ -123,7 +121,6 @@ ata_serverworks_status(device_t dev)
 
     return ata_pci_status(dev);
 }
-#endif
 
 static int
 ata_serverworks_chipinit(device_t dev)
@@ -145,6 +142,7 @@ ata_serverworks_chipinit(device_t dev)
 	ctlr->ch_detach = ata_serverworks_ch_detach;
 	ctlr->setmode = ata_sata_setmode;
 	ctlr->getrev = ata_sata_getrev;
+	ctlr->reset = ata_serverworks_sata_reset;
 	return 0;
     }
     else if (ctlr->chip->cfg1 == SWKS_33) {
@@ -210,30 +208,20 @@ ata_serverworks_ch_attach(device_t dev)
     ch->r_io[ATA_SERROR].offset = ch_offset + 0x44;
     ch->r_io[ATA_SCONTROL].offset = ch_offset + 0x48;
 
-    ch->flags |= ATA_NO_SLAVE;
-    ch->flags |= ATA_SATA;
+    ch->flags |= ATA_NO_SLAVE | ATA_SATA | ATA_KNOWN_PRESENCE;
     ata_pci_hw(dev);
     ch->hw.tf_read = ata_serverworks_tf_read;
     ch->hw.tf_write = ata_serverworks_tf_write;
-#ifdef __powerpc__
-    ch->hw.status = ata_serverworks_status;
-#endif
 
     if (ctlr->chip->chipid == ATA_K2) {
 	/*
-	 * The revision 1 K2 SATA controller has interesting bugs. Patch them.
-	 * These magic numbers regulate interrupt delivery in the first few
-	 * cases and are pure magic in the last case.
-	 *
-	 * Values obtained from the Darwin driver.
+	 * Set SICR registers to turn off waiting for a status message
+	 * before sending FIS. Values obtained from the Darwin driver.
 	 */
 
-	ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, 0x04);
-	ATA_IDX_OUTL(ch, ATA_SERROR, 0xffffffff);
-	ATA_IDX_OUTL(ch, ATA_SCONTROL, 0x00000300);
-	ATA_OUTL(ctlr->r_res2, ch_offset + 0x88, 0);
 	ATA_OUTL(ctlr->r_res2, ch_offset + 0x80,
 	    ATA_INL(ctlr->r_res2, ch_offset + 0x80) & ~0x00040000);
+	ATA_OUTL(ctlr->r_res2, ch_offset + 0x88, 0);
 
 	/*
 	 * Some controllers have a bug where they will send the command
@@ -244,6 +232,14 @@ ata_serverworks_ch_attach(device_t dev)
 	 */
 
 	ch->flags |= ATA_DMA_BEFORE_CMD;
+
+	/*
+	 * The status register must be read as a long to fill the other
+	 * registers.
+	 */
+	
+	ch->hw.status = ata_serverworks_status;
+	ch->flags |= ATA_STATUS_IS_LONG;
     }
 
     /* chip does not reliably do 64K DMA transfers */
@@ -404,4 +400,15 @@ ata_serverworks_setmode(device_t dev, in
 	return (mode);
 }
 
+static void
+ata_serverworks_sata_reset(device_t dev)
+{
+	struct ata_channel *ch = device_get_softc(dev);
+
+	if (ata_sata_phy_reset(dev, -1, 1))
+		ata_generic_reset(dev);
+	else
+		ch->devices = 0;
+}
+
 ATA_DECLARE_DRIVER(ata_serverworks);


More information about the svn-src-head mailing list