Date: Mon, 21 Jul 2008 12:55:58 +0200 From: =?ISO-8859-1?Q?S=F8ren_Schmidt?= <sos@FreeBSD.ORG> To: "Andrey V. Elsukov" <bu7cher@yandex.ru> Cc: freebsd-current@FreeBSD.ORG, Sergey G Nasonov <snasonov@bcc.ru> Subject: Re: RFC, RFT: AHCI driver reorganization (was: Re: ATA subsystem lost drive after resume process) Message-ID: <4DCB1935-4248-472B-8328-E0365306B953@FreeBSD.ORG> In-Reply-To: <4884668C.5060606@yandex.ru> References: <200807151124.36621.snasonov@bcc.ru> <4884668C.5060606@yandex.ru>
next in thread | previous in thread | raw e-mail | index | archive | help
Hi Just a short notice from here, I'm on vacation and cannot look into =20 this for about 2 weeks. This does massive changes to the way AHCI devices are treated, so it =20 will need testing on all the AHCI platforms currently supported to =20 make sure nothing breaks. The adding of PM learned me this is a =20 critical part to touch, ouch :) At any rate, fixing the suspend / resume problems should be dealt with =20= in a more generic manner, not just for AHCI, by splitting the work =20 done by the _chipinit and _allocate functions so that just the chipset =20= specifics can be restored on resume, not the allocations etc. I'm in doubt as to what makes most sense todo, I'm spare time limitted =20= still, so progress here is slow, heck my WIP on NCQ support is still =20 just that and touches the same code parts in ACHI so they willl get =20 even more behind, oh well... I'm starting to wonder if I should just let it go and leave ATA to its =20= own faith, and get on with other things... laters... -S=F8ren On 21Jul, 2008, at 12:35 , Andrey V. Elsukov wrote: > Sergey G Nasonov wrote: >> to disk. So the basic issue preventing normal suspend/resume >> process on modern Lenovo laptops is ata subsystem. Does anyone can >> help with this problem? I can test any path or provide additional >> info. > > Hi, All. > > I wrote patch for AHCI driver and Sergey tested it. > So, He reported that now "suspend/resume" works on his laptop. > I'll try to describe all changes which my patch makes. > > 1. Initialization: > > * Global AHCI reset code moved to ata_ahci_reset_controller() > function (it will be reused in ata_ahci_resume). > > * Detection of implemented ports moved to ata_ahci_allocate() > function (i think it isn't needed to detect it on each reset). > > * =46rom ata_ahci_allocate() function removed all working code, > only initialization code is here. > > 2. Resetting: > > * ata_ahci_reset() function reorganized and splitted to several > functions: > ata_ahci_stop_channel() - stop all port activity; > ata_ahci_fre_stop() - disable FIS receiving; > ata_ahci_fre_start() - setup work areas and enable FIS receiving; > ata_ahci_clo_enable() - enable command list override. > > * working code from ata_ahci_allocate moved to ata_ahci_reset. > > * CLO shall only be set immediately prior to setting the PxCMD.ST > bit to '1' (from AHCI spec). > > * Software shall not set PxCMD.ST to 1 until it is determined that a > functional device is present on the port (from AHCI spec). > > * removed hack when didn't detect signature asuming disk device (it > may broke some systems, but it needs testing). > > 3. Interrupts handling: > > * Call ata_sata_phy_check_events() only when PHY changing detected. > > * Fatal error handling changed. > > 4. Suspend/resume: > > * Added new methods to atapci(4) driver > > * Added suspend/resume implementation for AHCI: > + Software must disable interrupts prior to requesting a > transition of the HBA to the D3 state. > + Reset controller and enable interrupts before resume. > > > So, any comments and suggestions are welcome. > > --=20 > WBR, Andrey V. Elsukov > > Index: src/sys/dev/ata/ata-all.h > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > RCS file: /ncvs/src/sys/dev/ata/ata-all.h,v > retrieving revision 1.133 > diff -u -b -p -r1.133 ata-all.h > --- src/sys/dev/ata/ata-all.h 17 Apr 2008 12:29:35 -0000 1.133 > +++ src/sys/dev/ata/ata-all.h 21 Jul 2008 09:23:31 -0000 > @@ -188,6 +188,9 @@ > #define ATA_AHCI_P_IX_HBF 0x20000000 > #define ATA_AHCI_P_IX_TFE 0x40000000 > #define ATA_AHCI_P_IX_CPD 0x80000000 > +#define ATA_AHCI_P_IX_FE \ > + (ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF |\ > + ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF) > > #define ATA_AHCI_P_CMD 0x118 > #define ATA_AHCI_P_CMD_ST 0x00000001 > Index: src/sys/dev/ata/ata-chipset.c > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > RCS file: /ncvs/src/sys/dev/ata/ata-chipset.c,v > retrieving revision 1.224 > diff -u -b -p -r1.224 ata-chipset.c > --- src/sys/dev/ata/ata-chipset.c 10 Jul 2008 21:36:53 -0000 = 1.224 > +++ src/sys/dev/ata/ata-chipset.c 21 Jul 2008 09:23:31 -0000 > @@ -62,6 +62,9 @@ static int ata_sata_connect(struct ata_c > static void ata_sata_setmode(device_t dev, int mode); > static int ata_request2fis_h2d(struct ata_request *request, u_int8_t =20= > *fis); > static int ata_ahci_chipinit(device_t dev); > +static int ata_ahci_suspend(device_t dev); > +static int ata_ahci_resume(device_t dev); > +static int ata_ahci_reset_controller(device_t dev); > static int ata_ahci_allocate(device_t dev); > static int ata_ahci_status(device_t dev); > static int ata_ahci_begin_transaction(struct ata_request *request); > @@ -69,6 +72,11 @@ static int ata_ahci_end_transaction(stru > static int ata_ahci_pm_read(device_t dev, int port, int reg, =20 > u_int32_t *result); > static int ata_ahci_pm_write(device_t dev, int port, int reg, =20 > u_int32_t result); > static u_int32_t ata_ahci_softreset(device_t dev, int port); > +static void ata_ahci_fre_start(struct ata_channel *ch); > +static void ata_ahci_fre_stop(struct ata_channel *ch); > +static void ata_ahci_stop_channel(struct ata_channel *ch); > +static void ata_ahci_restart_channel(struct ata_channel *ch); > +static void ata_ahci_clo_enable(struct ata_channel *ch); > static void ata_ahci_reset(device_t dev); > static void ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, =20 > int nsegs, int error); > static void ata_ahci_dmainit(device_t dev); > @@ -582,6 +590,29 @@ ata_ahci_ident(device_t dev) > } > > static int > +ata_ahci_reset_controller(device_t dev) > +{ > + struct ata_pci_controller *ctlr =3D device_get_softc(dev); > + > + /* enable AHCI mode */ > + ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE); > + > + /* reset AHCI controller */ > + ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_HR); > + DELAY(1000000); > + if (ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & ATA_AHCI_GHC_HR) { > + bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr-=20 > >r_res2); > + device_printf(dev, "AHCI controller reset failure\n"); > + return ENXIO; > + } > + > + /* reenable AHCI mode */ > + ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE); > + > + return 0; > +} > + > +static int > ata_ahci_chipinit(device_t dev) > { > struct ata_pci_controller *ctlr =3D device_get_softc(dev); > @@ -602,20 +633,8 @@ ata_ahci_chipinit(device_t dev) > else > device_printf(dev, "AHCI called from vendor specific driver\n"); > > - /* enable AHCI mode */ > - ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE); > - > - /* reset AHCI controller */ > - ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_HR); > - DELAY(1000000); > - if (ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & ATA_AHCI_GHC_HR) { > - bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr-=20 > >r_res2); > - device_printf(dev, "AHCI controller reset failure\n"); > + if (ata_ahci_reset_controller(dev)) > return ENXIO; > - } > - > - /* reenable AHCI mode */ > - ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE); > > /* get the number of HW channels */ > ctlr->channels =3D > @@ -633,6 +652,8 @@ ata_ahci_chipinit(device_t dev) > ctlr->dmainit =3D ata_ahci_dmainit; > ctlr->allocate =3D ata_ahci_allocate; > ctlr->setmode =3D ata_sata_setmode; > + ctlr->resume =3D ata_ahci_resume; > + ctlr->suspend =3D ata_ahci_suspend; > > /* enable PCI interrupt */ > pci_write_config(dev, PCIR_COMMAND, > @@ -655,9 +676,13 @@ ata_ahci_allocate(device_t dev) > { > struct ata_pci_controller *ctlr =3D =20 > device_get_softc(device_get_parent(dev)); > struct ata_channel *ch =3D device_get_softc(dev); > - u_int64_t work; > int offset =3D ch->unit << 7; > > + if (!(ATA_INL(ctlr->r_res2, ATA_AHCI_PI) & (1 << ch->unit))) { > + device_printf(dev, "port not implemented\n"); > + return ENXIO; > + } > + > /* set the SATA resources */ > ch->r_io[ATA_SSTATUS].res =3D ctlr->r_res2; > ch->r_io[ATA_SSTATUS].offset =3D ATA_AHCI_P_SSTS + offset; > @@ -676,30 +701,45 @@ ata_ahci_allocate(device_t dev) > ch->hw.pm_read =3D ata_ahci_pm_read; > ch->hw.pm_write =3D ata_ahci_pm_write; > > - /* setup work areas */ > - work =3D ch->dma.work_bus + ATA_AHCI_CL_OFFSET; > - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLB + offset, work & =20 > 0xffffffff); > - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLBU + offset, work >> 32); > + return 0; > +} > > - work =3D ch->dma.work_bus + ATA_AHCI_FB_OFFSET; > - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FB + offset, work & =20 > 0xffffffff); > - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBU + offset, work >> 32); > +static int > +ata_ahci_suspend(device_t dev) > +{ > + struct ata_pci_controller *ctlr =3D device_get_softc(dev); > > - /* enable wanted port interrupts */ > - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, > - (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF = | > - ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF | > - ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC | ATA_AHCI_P_IX_DP | > - ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | ATA_AHCI_P_IX_DS | > - ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR)); > + /* XXX: PxCMD.ST must be cleared to '0' before entry into the > + * D3 power state. > + */ > > - /* enable FIS based switching */ > - //ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBS + offset, 0x00000003); > + /* Software must disable interrupts (GHC.IE must be cleared to 0) > + * prior to requesting a transition of the HBA to the D3 state. > + */ > > - /* start operations on this channel */ > - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, > - (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE | > - ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | = ATA_AHCI_P_CMD_ST)); > + ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, > + ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & (~ATA_AHCI_GHC_IE)); > + > + return 0; > +} > + > +static int > +ata_ahci_resume(device_t dev) > +{ > + struct ata_pci_controller *ctlr =3D device_get_softc(dev); > + > + /* reset controller */ > + if (ata_ahci_reset_controller(dev)) > + return ENXIO; /* XXX */ > + > + /* clear interrupts */ > + ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, ATA_INL(ctlr->r_res2, =20 > ATA_AHCI_IS)); > + > + /* enable AHCI interrupts */ > + ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, > + ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_IE); > + > + /* next part will be done by ata_resume */ > return 0; > } > > @@ -716,38 +756,24 @@ ata_ahci_status(device_t dev) > u_int32_t cstatus =3D ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + = offset); > > /* clear interrupt(s) */ > - ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, action & (1 << ch->unit)); > ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, istatus); > + ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, action & (1 << ch->unit)); > > /* do we have any PHY events ? */ > - /* XXX SOS check istatus phy bits */ > + if (istatus & (ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC)) > ata_sata_phy_check_events(dev); > > /* do we have a potentially hanging engine to take care of? */ > /* XXX SOS what todo on NCQ */ > - if ((istatus & 0x78400050) && (cstatus & 1)) { > - > - u_int32_t cmd =3D ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + = offset); > - int timeout =3D 0; > - > - /* kill off all activity on this channel */ > - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, > - cmd & ~(ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST)); > - > - /* XXX SOS this is not entirely wrong */ > - do { > - DELAY(1000); > - if (timeout++ > 1000) { > - device_printf(dev, "stopping AHCI engine failed\n"); > - break; > - } > - } while (ATA_INL(ctlr->r_res2, > - ATA_AHCI_P_CMD + offset) & = ATA_AHCI_P_CMD_CR); > - > - /* start operations on this channel */ > - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, > - cmd | (ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST)); > - > + if ((istatus & ATA_AHCI_P_IX_FE) && (cstatus & 1)) { > + if (bootverbose) > + device_printf(dev, "PHY fatal error: PxIS =3D 0x%08x\n", > + istatus); > + /* To recover fatal errors, the port must be restarted; > + * the port is restarted by clearing PxCMD.ST to '0' and > + * then setting PxCMD.ST to '1'. > + */ > + ata_ahci_restart_channel(ch); > return 1; > } > else > @@ -998,46 +1024,107 @@ ata_ahci_pm_write(device_t dev, int port > return (ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset) >> 8) & =20 > 0xff; > } > > +/* CLO shall only be set immediately prior to setting > + * the PxCMD.ST bit to '1' from a previous value of '0' > + */ > static void > -ata_ahci_restart(device_t dev) > +ata_ahci_clo_enable(struct ata_channel *ch) > { > - struct ata_pci_controller *ctlr =3D =20 > device_get_softc(device_get_parent(dev)); > - struct ata_channel *ch =3D device_get_softc(dev); > - u_int32_t cmd; > + struct ata_pci_controller *ctlr =3D =20 > device_get_softc(device_get_parent(ch->dev)); > int offset =3D ch->unit << 7; > - int timeout; > + int timeout =3D 0; > + u_int32_t cmd; > > - /* kill off all activity on this channel */ > + if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_CLO) { > cmd =3D ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); > ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, > - cmd & ~(ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST)); > - > - /* XXX SOS this is not entirely wrong */ > - timeout =3D 0; > + cmd | ATA_AHCI_P_CMD_CLO); > do { > DELAY(1000); > if (timeout++ > 1000) { > - device_printf(dev, "stopping AHCI engine failed\n"); > + device_printf(ch->dev, "executing CLO failed\n"); > break; > } > + } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) > + & ATA_AHCI_P_CMD_CLO); > } > - while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & =20 > ATA_AHCI_P_CMD_CR); > +} > + > +/* When PxCMD.FR and PxCMD.FRE are both cleared to '0', software =20 > may update > + * the values of PxFB and PxFBU. Prior to setting PxCMD.FRE to '1', =20= > software > + * shall ensure that PxFB and PxFBU are set to valid values. =20 > Software shall > + * not write PxFB and PxFBU while PxCMD.FRE is set to '1'. > + */ > +static void > +ata_ahci_fre_start(struct ata_channel *ch) > +{ > + struct ata_pci_controller *ctlr =3D =20 > device_get_softc(device_get_parent(ch->dev)); > + u_int32_t offset =3D ch->unit << 7; > + u_int64_t work; > + > + /* setup work areas */ > + work =3D ch->dma.work_bus + ATA_AHCI_CL_OFFSET; > + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLB + offset, work & =20 > 0xffffffff); > + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLBU + offset, work >> 32); > + > + work =3D ch->dma.work_bus + ATA_AHCI_FB_OFFSET; > + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FB + offset, work & =20 > 0xffffffff); > + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBU + offset, work >> 32); > + > + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, > + ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) | =20 > ATA_AHCI_P_CMD_FRE); > +} > + > +static void > +ata_ahci_fre_stop(struct ata_channel *ch) > +{ > + struct ata_pci_controller *ctlr =3D =20 > device_get_softc(device_get_parent(ch->dev)); > + u_int32_t offset =3D ch->unit << 7; > + int timeout =3D 0; > + > + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, > + ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & =20 > (~ATA_AHCI_P_CMD_FRE)); > > - /* issue Command List Override if supported */ > - if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_CLO) { > - cmd =3D ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); > - cmd |=3D ATA_AHCI_P_CMD_CLO; > - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd); > - timeout =3D 0; > do { > DELAY(1000); > if (timeout++ > 1000) { > - device_printf(dev, "executing CLO failed\n"); > + device_printf(ch->dev, "ata_ahci_fre_stop failed\n"); > break; > } > + } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & =20 > ATA_AHCI_P_CMD_FR); > +} > + > +static void > +ata_ahci_stop_channel(struct ata_channel *ch) > +{ > + struct ata_pci_controller *ctlr =3D =20 > device_get_softc(device_get_parent(ch->dev)); > + u_int32_t cmd, offset =3D ch->unit << 7; > + int timeout =3D 0; > + > + cmd =3D ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); > + if ((cmd & (ATA_AHCI_P_CMD_ST | ATA_AHCI_P_CMD_CR)) =3D=3D 0) > + return; > + > + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, > + cmd & (~ATA_AHCI_P_CMD_ST)); > + do { > + DELAY(1000); > + if (timeout++ > 1000) { > + device_printf(ch->dev, "ata_ahci_stop_channel failed\n"); > + break; > } > - while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD=20 > +offset)&ATA_AHCI_P_CMD_CLO); > - } > + } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & =20 > ATA_AHCI_P_CMD_CR); > +} > + > + > +static void > +ata_ahci_restart_channel(struct ata_channel *ch) > +{ > + struct ata_pci_controller *ctlr =3D =20 > device_get_softc(device_get_parent(ch->dev)); > + int offset =3D ch->unit << 7; > + > + /* kill off all activity on this channel */ > + ata_ahci_stop_channel(ch); > > /* clear SATA error register */ > ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR)); > @@ -1046,11 +1133,12 @@ ata_ahci_restart(device_t dev) > ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, > ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset)); > > + /* issue Command List Override if supported */ > + ata_ahci_clo_enable(ch); > + > /* start operations on this channel */ > ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, > - (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE | > - ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | = ATA_AHCI_P_CMD_ST) > - | (ch->devices & ATA_PORTMULTIPLIER ? ATA_AHCI_P_CMD_PMA : = 0)); > + ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) | =20 > ATA_AHCI_P_CMD_ST); > } > > static u_int32_t > @@ -1065,7 +1153,7 @@ ata_ahci_softreset(device_t dev, int por > (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); > > /* kick controller into sane state if needed */ > - ata_ahci_restart(dev); > + ata_ahci_restart_channel(ch); > > /* pull reset active */ > bzero(ctp->cfis, 64); > @@ -1094,7 +1182,7 @@ ata_ahci_softreset(device_t dev, int por > #endif > do { > DELAY(1000); > - if (timeout++ > 1000) { > + if (timeout++ > 5000) { > device_printf(dev, "still BUSY after softreset\n"); > break; > } > @@ -1110,19 +1198,35 @@ ata_ahci_reset(device_t dev) > { > struct ata_pci_controller *ctlr =3D =20 > device_get_softc(device_get_parent(dev)); > struct ata_channel *ch =3D device_get_softc(dev); > - u_int32_t signature; > + u_int32_t signature, offset =3D ch->unit << 7; > + ch->devices =3D 0; > > - if (!(ATA_INL(ctlr->r_res2, ATA_AHCI_PI) & (1 << ch->unit))) { > - device_printf(dev, "port not implemented\n"); > - return; > - } > + /* kill off all activity on this channel */ > + ata_ahci_stop_channel(ch); > + ata_ahci_fre_stop(ch); > + > + /* setup work areas and enable FIS receiving */ > + ata_ahci_fre_start(ch); > + > + /* clear SATA error register */ > + ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR)); > + > + /* clear port interrupts */ > + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, > + ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset)); > + ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, (1 << ch->unit)); > > - ata_ahci_restart(dev); > + /* enable wanted port interrupts */ > + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, > + (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF = | > + ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF | > + ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC | ATA_AHCI_P_IX_DP | > + ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | ATA_AHCI_P_IX_DS | > + ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR)); > > if (!ata_sata_phy_reset(dev)) { > if (bootverbose) > device_printf(dev, "phy reset found no device\n"); > - ch->devices =3D 0; > return; > } > > @@ -1146,13 +1250,24 @@ ata_ahci_reset(device_t dev) > case 0xeb140101: > ch->devices =3D ATA_ATAPI_MASTER; > break; > - default: /* SOS XXX */ > + default: > if (bootverbose) > device_printf(dev, "No signature, asuming disk device\n"); > - ch->devices =3D ATA_ATA_MASTER; > } > if (bootverbose) > device_printf(dev, "ahci_reset devices=3D%08x\n", = ch->devices); > + > + /* Software shall not set PxCMD.ST to 1 until it is determined > + * that a functional device is present on the port. > + */ > + if (ch->devices) { > + /* issue Command List Override if supported */ > + ata_ahci_clo_enable(ch); > + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, > + ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) | =20 > ATA_AHCI_P_CMD_SUD | > + ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_POD | =20 > ATA_AHCI_P_CMD_ST | > + (ch->devices & ATA_PORTMULTIPLIER ? = ATA_AHCI_P_CMD_PMA : 0)); > + } > } > > static void > Index: src/sys/dev/ata/ata-pci.c > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > RCS file: /ncvs/src/sys/dev/ata/ata-pci.c,v > retrieving revision 1.128 > diff -u -b -p -r1.128 ata-pci.c > --- src/sys/dev/ata/ata-pci.c 11 Jun 2008 06:44:58 -0000 1.128 > +++ src/sys/dev/ata/ata-pci.c 21 Jul 2008 09:23:31 -0000 > @@ -262,6 +262,32 @@ ata_pci_detach(device_t dev) > return 0; > } > > +int > +ata_pci_suspend(device_t dev) > +{ > + struct ata_pci_controller *ctlr =3D device_get_softc(dev); > + int error =3D 0; > + > + bus_generic_suspend(dev); > + if (ctlr->suspend) > + error =3D ctlr->suspend(dev); > + > + return error; > +} > + > +int > +ata_pci_resume(device_t dev) > +{ > + struct ata_pci_controller *ctlr =3D device_get_softc(dev); > + int error =3D 0; > + > + if (ctlr->resume) > + error =3D ctlr->resume(dev); > + bus_generic_resume(dev); > + > + return error; > +} > + > struct resource * > ata_pci_alloc_resource(device_t dev, device_t child, int type, int =20 > *rid, > u_long start, u_long end, u_long count, u_int = flags) > @@ -556,8 +582,8 @@ static device_method_t ata_pci_methods[] > DEVMETHOD(device_attach, ata_pci_attach), > DEVMETHOD(device_detach, ata_pci_detach), > DEVMETHOD(device_shutdown, bus_generic_shutdown), > - DEVMETHOD(device_suspend, bus_generic_suspend), > - DEVMETHOD(device_resume, bus_generic_resume), > + DEVMETHOD(device_suspend, ata_pci_suspend), > + DEVMETHOD(device_resume, ata_pci_resume), > > /* bus methods */ > DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource), > Index: src/sys/dev/ata/ata-pci.h > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > RCS file: /ncvs/src/sys/dev/ata/ata-pci.h,v > retrieving revision 1.89 > diff -u -b -p -r1.89 ata-pci.h > --- src/sys/dev/ata/ata-pci.h 10 Jul 2008 21:36:53 -0000 1.89 > +++ src/sys/dev/ata/ata-pci.h 21 Jul 2008 09:23:31 -0000 > @@ -55,6 +55,8 @@ struct ata_pci_controller { > void (*reset)(device_t); > void (*dmainit)(device_t); > void (*setmode)(device_t, int); > + int (*suspend)(device_t); > + int (*resume)(device_t); > struct { > void (*function)(void *); > void *argument; > @@ -460,6 +462,8 @@ struct ata_connect_task { > int ata_pci_probe(device_t dev); > int ata_pci_attach(device_t dev); > int ata_pci_detach(device_t dev); > +int ata_pci_suspend(device_t dev); > +int ata_pci_resume(device_t dev); > struct resource * ata_pci_alloc_resource(device_t dev, device_t =20 > child, int type, int *rid, u_long start, u_long end, u_long count, =20 > u_int flags); > int ata_pci_release_resource(device_t dev, device_t child, int type, =20= > int rid, struct resource *r); > int ata_pci_setup_intr(device_t dev, device_t child, struct resource =20= > *irq, int flags, driver_filter_t *filter, driver_intr_t *function, =20 > void *argument, void **cookiep); -S=F8ren
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4DCB1935-4248-472B-8328-E0365306B953>