tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: Nvidia MCP67 SATA controller
On Wed, Jun 18, 2008 at 08:04:21PM +0200, Manuel Bouyer wrote:
> On Wed, Jun 18, 2008 at 07:30:41PM +0200, Dieter Baron wrote:
> > hi,
> >
> > the Nvidia MCP67 SATA controller does not work using the viaide driver
> > (in native pci compatibility mode), as various users have reported.
> >
> > Attached is a diff that forces it into AHCI mode and thus attaches
> > ahcisata. The method to switch to AHCI mode was taken from the
> > FreeBSD source tree.
> >
> > This works quite well most of the time, but sometimes the chip seems
> > to get in a strange state after the switch. It then returns bogus
> > data when identifying the drive:
> > wd0 at atabus1 drive 0: <ST506>
> > (or similar, written from memory) instead of
> > wd0 at atabus1 drive 0: <Hitachi HDT725032VLA360>
> > and hangs when trying to read from the disk (still during boot).
> >
> > If the boot is successful, the controller is stable. I've used it
> > to reconstruct a 320gb raid1.
> >
> >
> > Any idea why this sometimes fails? Any other comments about the
> > patch (the debug printf()s will be removed)? I want to commit it once
> > it's fixed and cleaned up.
> >
> > Anyone have the datasheet for the MCP67 SATA controller?
> >
> > thanks,
> > dillo
>
> > Index: ahcisata_pci.c
> > ===================================================================
> > RCS file: /cvsroot/src/sys/dev/pci/ahcisata_pci.c,v
> > retrieving revision 1.11
> > diff -u -r1.11 ahcisata_pci.c
> > --- ahcisata_pci.c 20 Mar 2008 16:15:57 -0000 1.11
> > +++ ahcisata_pci.c 18 Jun 2008 17:21:32 -0000
> > @@ -60,6 +60,9 @@
> > static void ahci_pci_attach(device_t, device_t, void *);
> > static bool ahci_pci_resume(device_t PMF_FN_PROTO);
> >
> > +static bool ahci_pci_enable_ahci_mode(bus_space_tag_t, bus_space_handle_t,
> > + uint32_t);
> > +
> >
> > CFATTACH_DECL_NEW(ahcisata_pci, sizeof(struct ahci_pci_softc),
> > ahci_pci_match, ahci_pci_attach, NULL, NULL);
> > @@ -71,12 +74,21 @@
> > bus_space_tag_t regt;
> > bus_space_handle_t regh;
> > bus_size_t size;
> > + uint32_t ghc;
> > int ret = 0;
> > + int force_ahci = 0;
> > +
> > + if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NVIDIA &&
> > + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NVIDIA_MCP67_SATA) {
> > + printf("ahcisata: forcing ahci mode for MCP67\n");
> > + force_ahci = 1;
> > + }
> >
> > if (PCI_CLASS(pa->pa_class) == PCI_CLASS_MASS_STORAGE &&
> > ((PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_SATA &&
> > PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_SATA_AHCI) ||
> > - PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_RAID)) {
> > + PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_RAID ||
> > + force_ahci)) {
> > /* check if the chip is in ahci mode */
> > if (pci_mapreg_map(pa, AHCI_PCI_ABAR,
> > PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0,
> > @@ -85,8 +97,16 @@
> > if (PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_SATA
> > && PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_SATA_AHCI)
> > ret = 3;
> > - else if (bus_space_read_4(regt, regh, AHCI_GHC) & AHCI_GHC_AE)
> > - ret = 3;
> > + else {
> > + ghc = bus_space_read_4(regt, regh, AHCI_GHC);
> > + printf("ahcisata: ghc=[%08x]\n", (int)ghc);
> > + if (ghc & AHCI_GHC_AE)
> > + ret = 3;
> > + else if (force_ahci) {
> > + if (ahci_pci_enable_ahci_mode(regt, regh, ghc))
> > + ret = 3;
> > + }
> > + }
> > bus_space_unmap(regt, regh, size);
> > return ret;
> > }
> > @@ -164,3 +184,36 @@
> >
> > return true;
> > }
> > +
> > +
> > +static bool
> > +ahci_pci_enable_ahci_mode(bus_space_tag_t regt, bus_space_handle_t regh,
> > + uint32_t ghc)
> > +{
> > + printf("ahcisata: putting chip in AHCI mode\n");
> > +
> > + ghc |= AHCI_GHC_AE;
> > + bus_space_write_4(regt, regh, AHCI_GHC, ghc);
> > +
> > + ghc |= AHCI_GHC_HR;
> > + bus_space_write_4(regt, regh, AHCI_GHC, ghc);
> > +
> > + DELAY(1000000);
> > +
> > + ghc = bus_space_read_4(regt, regh, AHCI_GHC);
> > + if (ghc & AHCI_GHC_HR) {
> > + printf("ahcisata: reset faild\n");
> > + return false;
> > + }
> > +
> > + ghc |= AHCI_GHC_AE;
> > + bus_space_write_4(regt, regh, AHCI_GHC, ghc);
> > +
> > + ghc = bus_space_read_4(regt, regh, AHCI_GHC);
> > + if ((ghc & AHCI_GHC_AE) == 0) {
> > + printf("ahcisata: enabling ahci mode failed\n");
> > + return false;
> > + }
> > +
> > + return true;
> > +}
>
> This is almost a duplicate of ahci_reset(), which is the first thing done
> in ahci_attach(). I think you don't need this function at all,
> just set the AHCI_GHC_AE bit in the force_ahci case, and let ahci_attach()
> to the reset.
I tried that first, but then it never worked the first time after
power on. I had to do a reset when the first boot hung, then the
second boot would succeed.
yours,
dillo
Home |
Main Index |
Thread Index |
Old Index