1183724Ssos/*-
2183724Ssos * Copyright (c) 1998 - 2008 S�ren Schmidt <sos@FreeBSD.org>
3183724Ssos * All rights reserved.
4183724Ssos *
5183724Ssos * Redistribution and use in source and binary forms, with or without
6183724Ssos * modification, are permitted provided that the following conditions
7183724Ssos * are met:
8183724Ssos * 1. Redistributions of source code must retain the above copyright
9183724Ssos *    notice, this list of conditions and the following disclaimer,
10183724Ssos *    without modification, immediately at the beginning of the file.
11183724Ssos * 2. Redistributions in binary form must reproduce the above copyright
12183724Ssos *    notice, this list of conditions and the following disclaimer in the
13183724Ssos *    documentation and/or other materials provided with the distribution.
14183724Ssos *
15183724Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16183724Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17183724Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18183724Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19183724Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20183724Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21183724Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22183724Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23183724Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24183724Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25183724Ssos */
26183724Ssos
27183724Ssos#include <sys/cdefs.h>
28183724Ssos__FBSDID("$FreeBSD$");
29183724Ssos
30183724Ssos#include "opt_ata.h"
31183724Ssos#include <sys/param.h>
32183724Ssos#include <sys/module.h>
33183724Ssos#include <sys/systm.h>
34183724Ssos#include <sys/kernel.h>
35183724Ssos#include <sys/ata.h>
36183724Ssos#include <sys/bus.h>
37183724Ssos#include <sys/endian.h>
38183724Ssos#include <sys/malloc.h>
39183724Ssos#include <sys/lock.h>
40183724Ssos#include <sys/mutex.h>
41183724Ssos#include <sys/sema.h>
42183724Ssos#include <sys/taskqueue.h>
43183724Ssos#include <vm/uma.h>
44183724Ssos#include <machine/stdarg.h>
45183724Ssos#include <machine/resource.h>
46183724Ssos#include <machine/bus.h>
47183724Ssos#include <sys/rman.h>
48183724Ssos#include <dev/pci/pcivar.h>
49183724Ssos#include <dev/pci/pcireg.h>
50183724Ssos#include <dev/ata/ata-all.h>
51183724Ssos#include <dev/ata/ata-pci.h>
52183724Ssos#include <ata_if.h>
53183724Ssos
54183724Ssos/* local prototypes */
55199322Smavstatic int ata_ahci_ch_attach(device_t dev);
56199322Smavstatic int ata_ahci_ch_detach(device_t dev);
57199322Smavstatic int ata_ahci_ch_suspend(device_t dev);
58199322Smavstatic int ata_ahci_ch_resume(device_t dev);
59199322Smavstatic int ata_ahci_ctlr_reset(device_t dev);
60199322Smavstatic void ata_ahci_reset(device_t dev);
61183724Ssosstatic int ata_ahci_suspend(device_t dev);
62183724Ssosstatic int ata_ahci_status(device_t dev);
63183724Ssosstatic int ata_ahci_begin_transaction(struct ata_request *request);
64183724Ssosstatic int ata_ahci_end_transaction(struct ata_request *request);
65183724Ssosstatic int ata_ahci_pm_read(device_t dev, int port, int reg, u_int32_t *result);
66183724Ssosstatic int ata_ahci_pm_write(device_t dev, int port, int reg, u_int32_t result);
67190581Smavstatic int ata_ahci_hardreset(device_t dev, int port, uint32_t *signature);
68183724Ssosstatic u_int32_t ata_ahci_softreset(device_t dev, int port);
69183724Ssosstatic void ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error);
70183724Ssosstatic int ata_ahci_setup_fis(struct ata_ahci_cmd_tab *ctp, struct ata_request *equest);
71188769Smavstatic void ata_ahci_dmainit(device_t dev);
72190581Smavstatic void ata_ahci_start(device_t dev);
73190581Smavstatic void ata_ahci_stop(device_t dev);
74190581Smavstatic void ata_ahci_clo(device_t dev);
75190581Smavstatic void ata_ahci_start_fr(device_t dev);
76190581Smavstatic void ata_ahci_stop_fr(device_t dev);
77183724Ssos
78183724Ssos/*
79183724Ssos * AHCI v1.x compliant SATA chipset support functions
80183724Ssos */
81183724Ssosstatic int
82183724Ssosata_ahci_probe(device_t dev)
83183724Ssos{
84183724Ssos    struct ata_pci_controller *ctlr = device_get_softc(dev);
85183724Ssos    char buffer[64];
86183724Ssos
87183724Ssos    /* is this a possible AHCI candidate ? */
88186296Smav    if (pci_get_class(dev) != PCIC_STORAGE ||
89186296Smav	pci_get_subclass(dev) != PCIS_STORAGE_SATA)
90186296Smav	    return (ENXIO);
91183724Ssos
92183724Ssos    /* is this PCI device flagged as an AHCI compliant chip ? */
93191601Sjkim    if (pci_get_progif(dev) != PCIP_STORAGE_SATA_AHCI_1_0)
94191600Sjkim	return (ENXIO);
95183724Ssos
96183724Ssos    if (bootverbose)
97183724Ssos	sprintf(buffer, "%s (ID=%08x) AHCI controller",
98183724Ssos		ata_pcivendor2str(dev), pci_get_devid(dev));
99183724Ssos    else
100183724Ssos	sprintf(buffer, "%s AHCI controller", ata_pcivendor2str(dev));
101183724Ssos    device_set_desc_copy(dev, buffer);
102183724Ssos    ctlr->chipinit = ata_ahci_chipinit;
103191600Sjkim    return (BUS_PROBE_GENERIC);
104183724Ssos}
105183724Ssos
106199322Smavstatic int
107199322Smavata_ahci_ata_probe(device_t dev)
108199322Smav{
109199322Smav    struct ata_pci_controller *ctlr = device_get_softc(dev);
110199322Smav
111199322Smav    if ((intptr_t)device_get_ivars(dev) >= 0)
112199322Smav	    return (ENXIO);
113199322Smav    device_set_desc_copy(dev, "AHCI SATA controller");
114199322Smav    ctlr->chipinit = ata_ahci_chipinit;
115199322Smav    return (BUS_PROBE_GENERIC);
116199322Smav}
117199322Smav
118199322Smavstatic int
119199322Smavata_ahci_ata_attach(device_t dev)
120199322Smav{
121199322Smav    struct ata_pci_controller *ctlr = device_get_softc(dev);
122199322Smav    device_t child;
123199322Smav    int unit;
124199322Smav
125199322Smav    /* do chipset specific setups only needed once */
126199322Smav    ctlr->legacy = 0;
127199322Smav    ctlr->ichannels = -1;
128199322Smav    ctlr->ch_attach = ata_pci_ch_attach;
129199322Smav    ctlr->ch_detach = ata_pci_ch_detach;
130199322Smav    ctlr->dev = dev;
131199322Smav    if (ctlr->chipinit(dev))
132199322Smav	return ENXIO;
133199322Smav    /* attach all channels on this controller */
134199322Smav    for (unit = 0; unit < ctlr->channels; unit++) {
135199322Smav	if ((ctlr->ichannels & (1 << unit)) == 0)
136199322Smav	    continue;
137199322Smav	child = device_add_child(dev, "ata",
138199322Smav	    ((unit == 0 || unit == 1) && ctlr->legacy) ?
139199322Smav	    unit : devclass_find_free_unit(ata_devclass, 2));
140199322Smav	if (child == NULL)
141199322Smav	    device_printf(dev, "failed to add ata child device\n");
142199322Smav	else
143199322Smav	    device_set_ivars(child, (void *)(intptr_t)unit);
144199322Smav    }
145199322Smav    bus_generic_attach(dev);
146199322Smav    return 0;
147199322Smav}
148199322Smav
149183724Ssosint
150183724Ssosata_ahci_chipinit(device_t dev)
151183724Ssos{
152183724Ssos    struct ata_pci_controller *ctlr = device_get_softc(dev);
153193277Smav    int error, speed;
154193277Smav    u_int32_t caps, version;
155183724Ssos
156183724Ssos    /* if we have a memory BAR(5) we are likely on an AHCI part */
157183724Ssos    ctlr->r_type2 = SYS_RES_MEMORY;
158183724Ssos    ctlr->r_rid2 = PCIR_BAR(5);
159183724Ssos    if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2,
160183724Ssos					       &ctlr->r_rid2, RF_ACTIVE)))
161183724Ssos	return ENXIO;
162183724Ssos
163183724Ssos    /* setup interrupt delivery if not done allready by a vendor driver */
164183724Ssos    if (!ctlr->r_irq) {
165186250Smav	if (ata_setup_interrupt(dev, ata_generic_intr)) {
166186250Smav	    bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2);
167183724Ssos	    return ENXIO;
168186250Smav	}
169183724Ssos    }
170183724Ssos    else
171183724Ssos	device_printf(dev, "AHCI called from vendor specific driver\n");
172183724Ssos
173183724Ssos    /* reset controller */
174186250Smav    if ((error = ata_ahci_ctlr_reset(dev)) != 0) {
175186250Smav	bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2);
176186250Smav	return (error);
177186250Smav    };
178183724Ssos
179183724Ssos    /* get the number of HW channels */
180188694Smav    ctlr->ichannels = ATA_INL(ctlr->r_res2, ATA_AHCI_PI);
181199322Smav    ctlr->channels = MAX(flsl(ctlr->ichannels),
182191674Smav	    (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_NPMASK) + 1);
183232716Smav    if (pci_get_devid(dev) == ATA_M88SE6111)
184199322Smav	    ctlr->channels = 1;
185232716Smav    else if (pci_get_devid(dev) == ATA_M88SE6121)
186199322Smav	    ctlr->channels = 2;
187232716Smav    else if (pci_get_devid(dev) == ATA_M88SE6141 ||
188232716Smav	pci_get_devid(dev) == ATA_M88SE6145)
189199322Smav	    ctlr->channels = 4;
190183724Ssos
191183724Ssos    ctlr->reset = ata_ahci_reset;
192188765Smav    ctlr->ch_attach = ata_ahci_ch_attach;
193188769Smav    ctlr->ch_detach = ata_ahci_ch_detach;
194190581Smav    ctlr->ch_suspend = ata_ahci_ch_suspend;
195190581Smav    ctlr->ch_resume = ata_ahci_ch_resume;
196183724Ssos    ctlr->setmode = ata_sata_setmode;
197200171Smav    ctlr->getrev = ata_sata_getrev;
198183724Ssos    ctlr->suspend = ata_ahci_suspend;
199183724Ssos    ctlr->resume = ata_ahci_ctlr_reset;
200183724Ssos
201193277Smav	/* announce we support the HW */
202193277Smav	version = ATA_INL(ctlr->r_res2, ATA_AHCI_VS);
203193277Smav	caps = ATA_INL(ctlr->r_res2, ATA_AHCI_CAP);
204193277Smav	speed = (caps & ATA_AHCI_CAP_ISS) >> ATA_AHCI_CAP_ISS_SHIFT;
205193277Smav	device_printf(dev,
206193277Smav		    "AHCI v%x.%02x controller with %d %sGbps ports, PM %s\n",
207193277Smav		    ((version >> 20) & 0xf0) + ((version >> 16) & 0x0f),
208193277Smav		    ((version >> 4) & 0xf0) + (version & 0x0f),
209193277Smav		    (caps & ATA_AHCI_CAP_NPMASK) + 1,
210193277Smav		    ((speed == 1) ? "1.5":((speed == 2) ? "3":
211193277Smav		    ((speed == 3) ? "6":"?"))),
212193277Smav		    (caps & ATA_AHCI_CAP_SPM) ?
213193277Smav		    "supported" : "not supported");
214193277Smav	if (bootverbose) {
215193277Smav		device_printf(dev, "Caps:%s%s%s%s%s%s%s%s %sGbps",
216193277Smav		    (caps & ATA_AHCI_CAP_64BIT) ? " 64bit":"",
217193277Smav		    (caps & ATA_AHCI_CAP_SNCQ) ? " NCQ":"",
218193277Smav		    (caps & ATA_AHCI_CAP_SSNTF) ? " SNTF":"",
219193277Smav		    (caps & ATA_AHCI_CAP_SMPS) ? " MPS":"",
220193277Smav		    (caps & ATA_AHCI_CAP_SSS) ? " SS":"",
221193277Smav		    (caps & ATA_AHCI_CAP_SALP) ? " ALP":"",
222193277Smav		    (caps & ATA_AHCI_CAP_SAL) ? " AL":"",
223193277Smav		    (caps & ATA_AHCI_CAP_SCLO) ? " CLO":"",
224193277Smav		    ((speed == 1) ? "1.5":((speed == 2) ? "3":
225193277Smav		    ((speed == 3) ? "6":"?"))));
226193277Smav		printf("%s%s%s%s%s%s %dcmd%s%s%s %dports\n",
227193277Smav		    (caps & ATA_AHCI_CAP_SAM) ? " AM":"",
228193277Smav		    (caps & ATA_AHCI_CAP_SPM) ? " PM":"",
229193277Smav		    (caps & ATA_AHCI_CAP_FBSS) ? " FBS":"",
230193277Smav		    (caps & ATA_AHCI_CAP_PMD) ? " PMD":"",
231193277Smav		    (caps & ATA_AHCI_CAP_SSC) ? " SSC":"",
232193277Smav		    (caps & ATA_AHCI_CAP_PSC) ? " PSC":"",
233193277Smav		    ((caps & ATA_AHCI_CAP_NCS) >> ATA_AHCI_CAP_NCS_SHIFT) + 1,
234193277Smav		    (caps & ATA_AHCI_CAP_CCCS) ? " CCC":"",
235193277Smav		    (caps & ATA_AHCI_CAP_EMS) ? " EM":"",
236193277Smav		    (caps & ATA_AHCI_CAP_SXS) ? " eSATA":"",
237193277Smav		    (caps & ATA_AHCI_CAP_NPMASK) + 1);
238193277Smav	}
239193277Smav	return 0;
240183724Ssos}
241183724Ssos
242199322Smavstatic int
243183724Ssosata_ahci_ctlr_reset(device_t dev)
244183724Ssos{
245183724Ssos    struct ata_pci_controller *ctlr = device_get_softc(dev);
246188621Smav    int timeout;
247183724Ssos
248183724Ssos    /* enable AHCI mode */
249183724Ssos    ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE);
250183724Ssos
251183724Ssos    /* reset AHCI controller */
252188621Smav    ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE|ATA_AHCI_GHC_HR);
253188621Smav    for (timeout = 1000; timeout > 0; timeout--) {
254188621Smav	    DELAY(1000);
255188621Smav	    if ((ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & ATA_AHCI_GHC_HR) == 0)
256188621Smav		    break;
257188621Smav    }
258188621Smav    if (timeout == 0) {
259183724Ssos	device_printf(dev, "AHCI controller reset failure\n");
260183724Ssos	return ENXIO;
261183724Ssos    }
262183724Ssos
263183724Ssos    /* reenable AHCI mode */
264183724Ssos    ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE);
265183724Ssos
266183724Ssos    /* clear interrupts */
267183724Ssos    ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, ATA_INL(ctlr->r_res2, ATA_AHCI_IS));
268183724Ssos
269183724Ssos    /* enable AHCI interrupts */
270183724Ssos    ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
271183724Ssos	     ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_IE);
272183724Ssos
273183724Ssos    return 0;
274183724Ssos}
275183724Ssos
276183724Ssosstatic int
277183724Ssosata_ahci_suspend(device_t dev)
278183724Ssos{
279183724Ssos    struct ata_pci_controller *ctlr = device_get_softc(dev);
280183724Ssos
281183724Ssos    /* disable interupts so the state change(s) doesn't trigger */
282183724Ssos    ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC,
283183724Ssos             ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & (~ATA_AHCI_GHC_IE));
284183724Ssos    return 0;
285183724Ssos}
286183724Ssos
287199322Smavstatic int
288188765Smavata_ahci_ch_attach(device_t dev)
289183724Ssos{
290183724Ssos    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
291183724Ssos    struct ata_channel *ch = device_get_softc(dev);
292183724Ssos    int offset = ch->unit << 7;
293183724Ssos
294188765Smav    ata_ahci_dmainit(dev);
295188765Smav
296183724Ssos    /* set the SATA resources */
297183724Ssos    ch->r_io[ATA_SSTATUS].res = ctlr->r_res2;
298183724Ssos    ch->r_io[ATA_SSTATUS].offset = ATA_AHCI_P_SSTS + offset;
299183724Ssos    ch->r_io[ATA_SERROR].res = ctlr->r_res2;
300183724Ssos    ch->r_io[ATA_SERROR].offset = ATA_AHCI_P_SERR + offset;
301183724Ssos    ch->r_io[ATA_SCONTROL].res = ctlr->r_res2;
302183724Ssos    ch->r_io[ATA_SCONTROL].offset = ATA_AHCI_P_SCTL + offset;
303183724Ssos    ch->r_io[ATA_SACTIVE].res = ctlr->r_res2;
304183724Ssos    ch->r_io[ATA_SACTIVE].offset = ATA_AHCI_P_SACT + offset;
305183724Ssos
306183724Ssos    ch->hw.status = ata_ahci_status;
307183724Ssos    ch->hw.begin_transaction = ata_ahci_begin_transaction;
308183724Ssos    ch->hw.end_transaction = ata_ahci_end_transaction;
309183724Ssos    ch->hw.command = NULL;      /* not used here */
310183724Ssos    ch->hw.softreset = ata_ahci_softreset;
311183724Ssos    ch->hw.pm_read = ata_ahci_pm_read;
312183724Ssos    ch->hw.pm_write = ata_ahci_pm_write;
313200171Smav    ch->flags |= ATA_NO_SLAVE;
314200171Smav    ch->flags |= ATA_SATA;
315183724Ssos
316190581Smav    ata_ahci_ch_resume(dev);
317183724Ssos    return 0;
318183724Ssos}
319183724Ssos
320199322Smavstatic int
321188769Smavata_ahci_ch_detach(device_t dev)
322188769Smav{
323219337Smarius    struct ata_channel *ch = device_get_softc(dev);
324219337Smarius
325219337Smarius    if (ch->dma.work_tag && ch->dma.work_map)
326219337Smarius	bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map,
327219337Smarius	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
328190581Smav    ata_ahci_ch_suspend(dev);
329190581Smav    ata_dmafini(dev);
330190581Smav    return (0);
331190581Smav}
332190581Smav
333199322Smavstatic int
334190581Smavata_ahci_ch_suspend(device_t dev)
335190581Smav{
336188877Smav    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
337188877Smav    struct ata_channel *ch = device_get_softc(dev);
338188877Smav    int offset = ch->unit << 7;
339188769Smav
340188877Smav    /* Disable port interrupts. */
341188877Smav    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, 0);
342188877Smav    /* Reset command register. */
343190581Smav    ata_ahci_stop(dev);
344190581Smav    ata_ahci_stop_fr(dev);
345188877Smav    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, 0);
346188877Smav
347188877Smav    /* Allow everything including partial and slumber modes. */
348188877Smav    ATA_IDX_OUTL(ch, ATA_SCONTROL, 0);
349188877Smav    /* Request slumber mode transition and give some time to get there. */
350188877Smav    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, ATA_AHCI_P_CMD_SLUMBER);
351188877Smav    DELAY(100);
352188877Smav    /* Disable PHY. */
353188877Smav    ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_DISABLE);
354188877Smav
355188769Smav    return (0);
356188769Smav}
357188769Smav
358199322Smavstatic int
359190581Smavata_ahci_ch_resume(device_t dev)
360190581Smav{
361190581Smav    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
362190581Smav    struct ata_channel *ch = device_get_softc(dev);
363190581Smav    uint64_t work;
364190581Smav    int offset = ch->unit << 7;
365190581Smav
366190581Smav    /* Disable port interrupts */
367190581Smav    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, 0);
368190581Smav
369190581Smav    /* setup work areas */
370190581Smav    work = ch->dma.work_bus + ATA_AHCI_CL_OFFSET;
371190581Smav    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLB + offset, work & 0xffffffff);
372190581Smav    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLBU + offset, work >> 32);
373190581Smav
374190581Smav    work = ch->dma.work_bus + ATA_AHCI_FB_OFFSET;
375190581Smav    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FB + offset, work & 0xffffffff);
376190581Smav    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBU + offset, work >> 32);
377190581Smav
378190581Smav    /* activate the channel and power/spin up device */
379190581Smav    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
380191674Smav	     (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD |
381191674Smav	     ((ch->pm_level > 1) ? ATA_AHCI_P_CMD_ALPE : 0) |
382191674Smav	     ((ch->pm_level > 2) ? ATA_AHCI_P_CMD_ASP : 0 )));
383190581Smav    ata_ahci_start_fr(dev);
384190581Smav    ata_ahci_start(dev);
385190581Smav
386190581Smav    return (0);
387190581Smav}
388190581Smav
389183724Ssosstatic int
390183724Ssosata_ahci_status(device_t dev)
391183724Ssos{
392183724Ssos    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
393183724Ssos    struct ata_channel *ch = device_get_softc(dev);
394183724Ssos    u_int32_t action = ATA_INL(ctlr->r_res2, ATA_AHCI_IS);
395183724Ssos    int offset = ch->unit << 7;
396183724Ssos
397183724Ssos#define ATA_AHCI_STATBITS \
398183724Ssos	(ATA_AHCI_P_IX_IF|ATA_AHCI_P_IX_HBD|ATA_AHCI_P_IX_HBF|ATA_AHCI_P_IX_TFE)
399183724Ssos
400183724Ssos    if (action & (1 << ch->unit)) {
401183724Ssos	u_int32_t istatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset);
402183724Ssos	u_int32_t cstatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset);
403183724Ssos
404183724Ssos	/* clear interrupt(s) */
405183724Ssos	ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, istatus);
406188658Smav	ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, 1 << ch->unit);
407183724Ssos
408183724Ssos	/* do we have any PHY events ? */
409183724Ssos	if (istatus & (ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC))
410214016Smav	    ata_sata_phy_check_events(dev, -1);
411183724Ssos
412183724Ssos	/* do we have a potentially hanging engine to take care of? */
413183724Ssos	/* XXX SOS what todo on NCQ */
414183724Ssos	if ((istatus & ATA_AHCI_STATBITS) && (cstatus & 1)) {
415183724Ssos
416183724Ssos	    u_int32_t cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
417183724Ssos	    int timeout = 0;
418183724Ssos
419183724Ssos	    /* kill off all activity on this channel */
420183724Ssos	    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
421183724Ssos		     cmd & ~(ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST));
422183724Ssos
423183724Ssos	    /* XXX SOS this is not entirely wrong */
424183724Ssos	    do {
425183724Ssos		DELAY(1000);
426183724Ssos		if (timeout++ > 1000) {
427183724Ssos		    device_printf(dev, "stopping AHCI engine failed\n");
428183724Ssos		    break;
429183724Ssos		}
430183724Ssos    	    } while (ATA_INL(ctlr->r_res2,
431183724Ssos			     ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR);
432183724Ssos
433183724Ssos	    /* start operations on this channel */
434183724Ssos	    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
435183724Ssos		     cmd | (ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST));
436183724Ssos
437183724Ssos	    return 1;
438183724Ssos	}
439183724Ssos	else
440183724Ssos	    /* XXX SOS what todo on NCQ */
441183724Ssos	    return (!(cstatus & 1));
442183724Ssos    }
443183724Ssos    return 0;
444183724Ssos}
445183724Ssos
446183724Ssos/* must be called with ATA channel locked and state_mtx held */
447183724Ssosstatic int
448183724Ssosata_ahci_begin_transaction(struct ata_request *request)
449183724Ssos{
450198717Smav    struct ata_pci_controller *ctlr=device_get_softc(device_get_parent(request->parent));
451183724Ssos    struct ata_channel *ch = device_get_softc(request->parent);
452183724Ssos    struct ata_ahci_cmd_tab *ctp;
453183724Ssos    struct ata_ahci_cmd_list *clp;
454183724Ssos    int offset = ch->unit << 7;
455198717Smav    int port = request->unit & 0x0f;
456183724Ssos    int entries = 0;
457183724Ssos    int fis_size;
458183724Ssos
459183724Ssos    /* get a piece of the workspace for this request */
460183724Ssos    ctp = (struct ata_ahci_cmd_tab *)
461198717Smav	  (ch->dma.work + ATA_AHCI_CT_OFFSET);
462183724Ssos
463183724Ssos    /* setup the FIS for this request */
464183724Ssos    if (!(fis_size = ata_ahci_setup_fis(ctp, request))) {
465198717Smav	device_printf(request->parent, "setting up SATA FIS failed\n");
466183724Ssos	request->result = EIO;
467183724Ssos	return ATA_OP_FINISHED;
468183724Ssos    }
469183724Ssos
470183724Ssos    /* if request moves data setup and load SG list */
471183724Ssos    if (request->flags & (ATA_R_READ | ATA_R_WRITE)) {
472183724Ssos	if (ch->dma.load(request, ctp->prd_tab, &entries)) {
473198717Smav	    device_printf(request->parent, "setting up DMA failed\n");
474183724Ssos	    request->result = EIO;
475183724Ssos	    return ATA_OP_FINISHED;
476183724Ssos	}
477183724Ssos    }
478183724Ssos
479183724Ssos    /* setup the command list entry */
480183724Ssos    clp = (struct ata_ahci_cmd_list *)
481198717Smav	  (ch->dma.work + ATA_AHCI_CL_OFFSET);
482183724Ssos
483183724Ssos    clp->prd_length = entries;
484183724Ssos    clp->cmd_flags = (request->flags & ATA_R_WRITE ? ATA_AHCI_CMD_WRITE : 0) |
485183724Ssos		     (request->flags & ATA_R_ATAPI ?
486183724Ssos		      (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH) : 0) |
487183724Ssos		     (fis_size / sizeof(u_int32_t)) |
488183724Ssos    		     (port << 12);
489183724Ssos    clp->bytecount = 0;
490198717Smav    clp->cmd_table_phys = htole64(ch->dma.work_bus + ATA_AHCI_CT_OFFSET);
491183724Ssos
492183724Ssos    /* set command type bit */
493183724Ssos    if (request->flags & ATA_R_ATAPI)
494183724Ssos	ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
495183724Ssos		 ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) |
496183724Ssos		 ATA_AHCI_P_CMD_ATAPI);
497183724Ssos    else
498183724Ssos	ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
499183724Ssos		 ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) &
500183724Ssos		 ~ATA_AHCI_P_CMD_ATAPI);
501183724Ssos
502219337Smarius    bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map,
503219337Smarius	BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
504219337Smarius
505183724Ssos    /* issue command to controller */
506198717Smav    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, 1);
507183724Ssos
508183724Ssos    if (!(request->flags & ATA_R_ATAPI)) {
509183724Ssos	/* device reset doesn't interrupt */
510183724Ssos	if (request->u.ata.command == ATA_DEVICE_RESET) {
511183724Ssos	    u_int32_t tf_data;
512183724Ssos	    int timeout = 1000000;
513183724Ssos
514183724Ssos	    do {
515183724Ssos		DELAY(10);
516183724Ssos		tf_data = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + (ch->unit<<7));
517183724Ssos	    } while ((tf_data & ATA_S_BUSY) && timeout--);
518183724Ssos	    if (bootverbose)
519183724Ssos		device_printf(ch->dev, "device_reset timeout=%dus\n",
520183724Ssos			      (1000000-timeout)*10);
521183724Ssos	    request->status = tf_data;
522183724Ssos	    if (request->status & ATA_S_ERROR)
523183724Ssos		request->error = tf_data >> 8;
524183724Ssos	    return ATA_OP_FINISHED;
525183724Ssos	}
526183724Ssos    }
527183724Ssos
528183724Ssos    /* start the timeout */
529183724Ssos    callout_reset(&request->callout, request->timeout * hz,
530183724Ssos		  (timeout_t*)ata_timeout, request);
531183724Ssos    return ATA_OP_CONTINUES;
532183724Ssos}
533183724Ssos
534183724Ssos/* must be called with ATA channel locked and state_mtx held */
535183724Ssosstatic int
536183724Ssosata_ahci_end_transaction(struct ata_request *request)
537183724Ssos{
538198717Smav    struct ata_pci_controller *ctlr=device_get_softc(device_get_parent(request->parent));
539183724Ssos    struct ata_channel *ch = device_get_softc(request->parent);
540183724Ssos    struct ata_ahci_cmd_list *clp;
541183724Ssos    u_int32_t tf_data;
542183724Ssos    int offset = ch->unit << 7;
543183724Ssos
544183724Ssos    /* kill the timeout */
545183724Ssos    callout_stop(&request->callout);
546183724Ssos
547219337Smarius    bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map,
548219337Smarius	BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
549219337Smarius
550183724Ssos    /* get status */
551183724Ssos    tf_data = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset);
552183724Ssos    request->status = tf_data;
553183724Ssos
554183724Ssos    /* if error status get details */
555183724Ssos    if (request->status & ATA_S_ERROR)
556183724Ssos	request->error = tf_data >> 8;
557183724Ssos
558243125Smav    /* Read back registers to the request struct. */
559243125Smav    if ((request->flags & ATA_R_ATAPI) == 0 &&
560243125Smav	((request->status & ATA_S_ERROR) ||
561243125Smav	 (request->flags & (ATA_R_CONTROL | ATA_R_NEEDRESULT)))) {
562183724Ssos	u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40;
563183724Ssos
564183724Ssos	request->u.ata.count = fis[12] | ((u_int16_t)fis[13] << 8);
565183724Ssos	request->u.ata.lba = fis[4] | ((u_int64_t)fis[5] << 8) |
566183724Ssos			     ((u_int64_t)fis[6] << 16);
567198717Smav	if (request->flags & ATA_R_48BIT)
568183724Ssos	    request->u.ata.lba |= ((u_int64_t)fis[8] << 24) |
569183724Ssos				  ((u_int64_t)fis[9] << 32) |
570183724Ssos				  ((u_int64_t)fis[10] << 40);
571183724Ssos	else
572183724Ssos	    request->u.ata.lba |= ((u_int64_t)(fis[7] & 0x0f) << 24);
573183724Ssos    }
574183724Ssos
575183724Ssos    /* record how much data we actually moved */
576183724Ssos    clp = (struct ata_ahci_cmd_list *)
577198717Smav	  (ch->dma.work + ATA_AHCI_CL_OFFSET);
578213092Smav    request->donecount = le32toh(clp->bytecount);
579183724Ssos
580183724Ssos    /* release SG list etc */
581183724Ssos    ch->dma.unload(request);
582183724Ssos
583183724Ssos    return ATA_OP_FINISHED;
584183724Ssos}
585183724Ssos
586183724Ssosstatic int
587183724Ssosata_ahci_issue_cmd(device_t dev, u_int16_t flags, int timeout)
588183724Ssos{
589183724Ssos    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
590183724Ssos    struct ata_channel *ch = device_get_softc(dev);
591183724Ssos    struct ata_ahci_cmd_list *clp =
592183724Ssos	(struct ata_ahci_cmd_list *)(ch->dma.work + ATA_AHCI_CL_OFFSET);
593183724Ssos    struct ata_ahci_cmd_tab *ctp =
594183724Ssos	(struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET);
595183724Ssos    u_int32_t status = 0;
596183724Ssos    int offset = ch->unit << 7;
597183724Ssos    int port = (ctp->cfis[1] & 0x0f);
598183724Ssos    int count;
599183724Ssos
600183724Ssos    clp->prd_length = 0;
601183724Ssos    clp->cmd_flags = (20 / sizeof(u_int32_t)) | flags | (port << 12);
602183724Ssos    clp->bytecount = 0;
603183724Ssos    clp->cmd_table_phys = htole64(ch->dma.work_bus + ATA_AHCI_CT_OFFSET);
604183724Ssos
605219337Smarius    bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map,
606219337Smarius	BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
607219337Smarius
608183724Ssos    /* issue command to controller */
609183724Ssos    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, 1);
610183724Ssos
611183724Ssos    /* poll for command finished */
612183724Ssos    for (count = 0; count < timeout; count++) {
613183724Ssos        DELAY(1000);
614183724Ssos        if (!((status = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset)) & 1))
615183724Ssos            break;
616183724Ssos    }
617183724Ssos
618219337Smarius    bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map,
619219337Smarius	BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
620219337Smarius
621183724Ssos    /* clear interrupts */
622183724Ssos    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset,
623190581Smav	    ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset));
624183724Ssos
625188918Smav    if (timeout && (count >= timeout)) {
626188918Smav	if (bootverbose) {
627188918Smav	    device_printf(dev, "ahci_issue_cmd timeout: %d of %dms, status=%08x\n",
628188918Smav		      count, timeout, status);
629188918Smav	}
630183724Ssos	return EIO;
631188918Smav    }
632183724Ssos
633183724Ssos    return 0;
634183724Ssos}
635183724Ssos
636183724Ssosstatic int
637183724Ssosata_ahci_pm_read(device_t dev, int port, int reg, u_int32_t *result)
638183724Ssos{
639183724Ssos    struct ata_channel *ch = device_get_softc(dev);
640183724Ssos    struct ata_ahci_cmd_tab *ctp =
641183724Ssos	(struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET);
642183724Ssos    u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40;
643183724Ssos
644214016Smav    if (port < 0) {
645214016Smav	*result = ATA_IDX_INL(ch, reg);
646214016Smav	return (0);
647214016Smav    }
648214016Smav    if (port < ATA_PM) {
649214016Smav	switch (reg) {
650214016Smav	case ATA_SSTATUS:
651214016Smav	    reg = 0;
652214016Smav	    break;
653214016Smav	case ATA_SERROR:
654214016Smav	    reg = 1;
655214016Smav	    break;
656214016Smav	case ATA_SCONTROL:
657214016Smav	    reg = 2;
658214016Smav	    break;
659214016Smav	default:
660214016Smav	    return (EINVAL);
661214016Smav	}
662214016Smav    }
663183724Ssos    bzero(ctp->cfis, 64);
664183724Ssos    ctp->cfis[0] = 0x27;	/* host to device */
665183724Ssos    ctp->cfis[1] = 0x8f;	/* command FIS to PM port */
666183724Ssos    ctp->cfis[2] = ATA_READ_PM;
667183724Ssos    ctp->cfis[3] = reg;
668183724Ssos    ctp->cfis[7] = port | ATA_D_LBA;
669183724Ssos    ctp->cfis[15] = ATA_A_4BIT;
670183724Ssos
671183724Ssos    if (ata_ahci_issue_cmd(dev, 0, 10)) {
672183724Ssos	device_printf(dev, "error reading PM port\n");
673183724Ssos	return EIO;
674183724Ssos    }
675183724Ssos
676183724Ssos    *result = fis[12] | (fis[4] << 8) | (fis[5] << 16) | (fis[6] << 24);
677183724Ssos    return 0;
678183724Ssos}
679183724Ssos
680183724Ssosstatic int
681183724Ssosata_ahci_pm_write(device_t dev, int port, int reg, u_int32_t value)
682183724Ssos{
683183724Ssos    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
684183724Ssos    struct ata_channel *ch = device_get_softc(dev);
685183724Ssos    struct ata_ahci_cmd_tab *ctp =
686183724Ssos	(struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET);
687183724Ssos    int offset = ch->unit << 7;
688183724Ssos
689214016Smav    if (port < 0) {
690214016Smav	ATA_IDX_OUTL(ch, reg, value);
691214016Smav	return (0);
692214016Smav    }
693214016Smav    if (port < ATA_PM) {
694214016Smav	switch (reg) {
695214016Smav	case ATA_SSTATUS:
696214016Smav	    reg = 0;
697214016Smav	    break;
698214016Smav	case ATA_SERROR:
699214016Smav	    reg = 1;
700214016Smav	    break;
701214016Smav	case ATA_SCONTROL:
702214016Smav	    reg = 2;
703214016Smav	    break;
704214016Smav	default:
705214016Smav	    return (EINVAL);
706214016Smav	}
707214016Smav    }
708183724Ssos    bzero(ctp->cfis, 64);
709183724Ssos    ctp->cfis[0] = 0x27;	/* host to device */
710183724Ssos    ctp->cfis[1] = 0x8f;	/* command FIS to PM port */
711183724Ssos    ctp->cfis[2] = ATA_WRITE_PM;
712183724Ssos    ctp->cfis[3] = reg;
713183724Ssos    ctp->cfis[7] = port | ATA_D_LBA;
714183724Ssos    ctp->cfis[12] = value & 0xff;
715201758Smbr    ctp->cfis[4] = (value >> 8) & 0xff;
716201758Smbr    ctp->cfis[5] = (value >> 16) & 0xff;
717201758Smbr    ctp->cfis[6] = (value >> 24) & 0xff;
718183724Ssos    ctp->cfis[15] = ATA_A_4BIT;
719183724Ssos
720183724Ssos    if (ata_ahci_issue_cmd(dev, 0, 100)) {
721183724Ssos	device_printf(dev, "error writing PM port\n");
722183724Ssos	return ATA_E_ABORT;
723183724Ssos    }
724183724Ssos
725183724Ssos    return (ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset) >> 8) & 0xff;
726183724Ssos}
727183724Ssos
728183724Ssosstatic void
729188621Smavata_ahci_stop(device_t dev)
730183724Ssos{
731183724Ssos    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
732183724Ssos    struct ata_channel *ch = device_get_softc(dev);
733183724Ssos    u_int32_t cmd;
734183724Ssos    int offset = ch->unit << 7;
735183724Ssos    int timeout;
736183724Ssos
737183724Ssos    /* kill off all activity on this channel */
738183724Ssos    cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
739183724Ssos    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
740190581Smav	     cmd & ~ATA_AHCI_P_CMD_ST);
741183724Ssos
742183724Ssos    /* XXX SOS this is not entirely wrong */
743183724Ssos    timeout = 0;
744183724Ssos    do {
745183724Ssos	DELAY(1000);
746183724Ssos	if (timeout++ > 1000) {
747183724Ssos	    device_printf(dev, "stopping AHCI engine failed\n");
748183724Ssos	    break;
749183724Ssos	}
750183724Ssos    }
751183724Ssos    while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR);
752188621Smav}
753183724Ssos
754188621Smavstatic void
755188621Smavata_ahci_clo(device_t dev)
756188621Smav{
757188621Smav    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
758188621Smav    struct ata_channel *ch = device_get_softc(dev);
759188621Smav    u_int32_t cmd;
760188621Smav    int offset = ch->unit << 7;
761188621Smav    int timeout;
762188621Smav
763183724Ssos    /* issue Command List Override if supported */
764193277Smav    if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SCLO) {
765183724Ssos	cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
766183724Ssos	cmd |= ATA_AHCI_P_CMD_CLO;
767183724Ssos	ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd);
768183724Ssos	timeout = 0;
769183724Ssos	do {
770183724Ssos	    DELAY(1000);
771183724Ssos	    if (timeout++ > 1000) {
772183724Ssos		device_printf(dev, "executing CLO failed\n");
773183724Ssos		break;
774183724Ssos	    }
775183724Ssos        }
776183724Ssos	while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD+offset)&ATA_AHCI_P_CMD_CLO);
777183724Ssos    }
778188621Smav}
779183724Ssos
780188621Smavstatic void
781188621Smavata_ahci_start(device_t dev)
782188621Smav{
783188621Smav    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
784188621Smav    struct ata_channel *ch = device_get_softc(dev);
785188621Smav    u_int32_t cmd;
786188621Smav    int offset = ch->unit << 7;
787188621Smav
788183724Ssos    /* clear SATA error register */
789183724Ssos    ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR));
790183724Ssos
791183724Ssos    /* clear any interrupts pending on this channel */
792183724Ssos    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset,
793183724Ssos	     ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset));
794183724Ssos
795183724Ssos    /* start operations on this channel */
796183724Ssos    cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
797183724Ssos    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset,
798190581Smav	     cmd | ATA_AHCI_P_CMD_ST |
799183724Ssos	     (ch->devices & ATA_PORTMULTIPLIER ? ATA_AHCI_P_CMD_PMA : 0));
800183724Ssos}
801183724Ssos
802190581Smavstatic void
803190581Smavata_ahci_stop_fr(device_t dev)
804190581Smav{
805190581Smav    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
806190581Smav    struct ata_channel *ch = device_get_softc(dev);
807190581Smav    u_int32_t cmd;
808190581Smav    int offset = ch->unit << 7;
809190581Smav    int timeout;
810190581Smav
811190581Smav    /* kill off all activity on this channel */
812190581Smav    cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
813190581Smav    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd & ~ATA_AHCI_P_CMD_FRE);
814190581Smav
815190581Smav    timeout = 0;
816190581Smav    do {
817190581Smav	DELAY(1000);
818190581Smav	if (timeout++ > 1000) {
819190581Smav	    device_printf(dev, "stopping AHCI FR engine failed\n");
820190581Smav	    break;
821190581Smav	}
822190581Smav    }
823190581Smav    while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_FR);
824190581Smav}
825190581Smav
826190581Smavstatic void
827190581Smavata_ahci_start_fr(device_t dev)
828190581Smav{
829190581Smav    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
830190581Smav    struct ata_channel *ch = device_get_softc(dev);
831190581Smav    u_int32_t cmd;
832190581Smav    int offset = ch->unit << 7;
833190581Smav
834190581Smav    /* start FIS reception on this channel */
835190581Smav    cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset);
836190581Smav    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd | ATA_AHCI_P_CMD_FRE);
837190581Smav}
838190581Smav
839188648Smavstatic int
840188905Smavata_ahci_wait_ready(device_t dev, int t)
841188621Smav{
842188621Smav    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
843188621Smav    struct ata_channel *ch = device_get_softc(dev);
844188621Smav    int offset = ch->unit << 7;
845188621Smav    int timeout = 0;
846190581Smav    uint32_t val;
847188621Smav
848190581Smav    while ((val = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset)) &
849188621Smav	(ATA_S_BUSY | ATA_S_DRQ)) {
850188621Smav	    DELAY(1000);
851188905Smav	    if (timeout++ > t) {
852190581Smav		device_printf(dev, "port is not ready (timeout %dms) tfd = %08x\n", t, val);
853190581Smav		return (EBUSY);
854188621Smav	    }
855188621Smav    }
856188621Smav    if (bootverbose)
857188621Smav	device_printf(dev, "ready wait time=%dms\n", timeout);
858188648Smav    return (0);
859188621Smav}
860188621Smav
861190581Smavstatic int
862190581Smavata_ahci_hardreset(device_t dev, int port, uint32_t *signature)
863190581Smav{
864190581Smav    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
865190581Smav    struct ata_channel *ch = device_get_softc(dev);
866190581Smav    int offset = ch->unit << 7;
867190581Smav
868190581Smav    *signature = 0xffffffff;
869190581Smav    ata_ahci_stop(dev);
870190581Smav    /* Reset port */
871190581Smav    if (!ata_sata_phy_reset(dev, port, 0))
872190581Smav	return (ENOENT);
873190581Smav    /* Wait for clearing busy status. */
874212081Smav    if (ata_ahci_wait_ready(dev, 15000)) {
875190581Smav	device_printf(dev, "hardware reset timeout\n");
876190581Smav	return (EBUSY);
877190581Smav    }
878190581Smav    *signature = ATA_INL(ctlr->r_res2, ATA_AHCI_P_SIG + offset);
879190581Smav    ata_ahci_start(dev);
880190581Smav    return (0);
881190581Smav}
882190581Smav
883183724Ssosstatic u_int32_t
884183724Ssosata_ahci_softreset(device_t dev, int port)
885183724Ssos{
886183724Ssos    struct ata_channel *ch = device_get_softc(dev);
887183724Ssos    struct ata_ahci_cmd_tab *ctp =
888183724Ssos	(struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET);
889200117Smav    u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40;
890183724Ssos
891188918Smav    if (bootverbose)
892188918Smav	device_printf(dev, "software reset port %d...\n", port);
893188918Smav
894188621Smav    /* kick controller into sane state */
895188621Smav    ata_ahci_stop(dev);
896188621Smav    ata_ahci_clo(dev);
897188621Smav    ata_ahci_start(dev);
898183724Ssos
899183724Ssos    /* pull reset active */
900183724Ssos    bzero(ctp->cfis, 64);
901183724Ssos    ctp->cfis[0] = 0x27;
902183724Ssos    ctp->cfis[1] = port & 0x0f;
903183724Ssos    //ctp->cfis[7] = ATA_D_LBA | ATA_D_IBM;
904183724Ssos    ctp->cfis[15] = (ATA_A_4BIT | ATA_A_RESET);
905183724Ssos
906188918Smav    if (ata_ahci_issue_cmd(dev, ATA_AHCI_CMD_RESET | ATA_AHCI_CMD_CLR_BUSY,100)) {
907188918Smav	device_printf(dev, "software reset set timeout\n");
908188918Smav	return (-1);
909188918Smav    }
910183724Ssos
911188862Smav    ata_udelay(50);
912183724Ssos
913183724Ssos    /* pull reset inactive -> device softreset */
914183724Ssos    bzero(ctp->cfis, 64);
915183724Ssos    ctp->cfis[0] = 0x27;
916183724Ssos    ctp->cfis[1] = port & 0x0f;
917183724Ssos    //ctp->cfis[7] = ATA_D_LBA | ATA_D_IBM;
918183724Ssos    ctp->cfis[15] = ATA_A_4BIT;
919190581Smav    ata_ahci_issue_cmd(dev, 0, 3000);
920183724Ssos
921190581Smav    if (ata_ahci_wait_ready(dev, 0)) {
922188918Smav	device_printf(dev, "software reset clear timeout\n");
923188648Smav	return (-1);
924188918Smav    }
925183724Ssos
926200117Smav    return (((u_int32_t)fis[6] << 24) |
927200117Smav	    ((u_int32_t)fis[5] << 16) |
928200117Smav	    ((u_int32_t)fis[4] << 8) |
929200117Smav	     (u_int32_t)fis[12]);
930183724Ssos}
931183724Ssos
932199322Smavstatic void
933183724Ssosata_ahci_reset(device_t dev)
934183724Ssos{
935183724Ssos    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
936183724Ssos    struct ata_channel *ch = device_get_softc(dev);
937188621Smav    u_int32_t signature;
938183724Ssos    int offset = ch->unit << 7;
939183724Ssos
940188918Smav    if (bootverbose)
941188918Smav        device_printf(dev, "AHCI reset...\n");
942188918Smav
943188861Smav    /* Disable port interrupts */
944188861Smav    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, 0);
945188861Smav
946190581Smav    if (ata_ahci_hardreset(dev, -1, &signature)) {
947183724Ssos	if (bootverbose)
948188918Smav	    device_printf(dev, "AHCI reset done: phy reset found no device\n");
949183724Ssos	ch->devices = 0;
950183724Ssos
951188621Smav	/* enable wanted port interrupts */
952188621Smav	ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset,
953188621Smav	     (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC));
954183724Ssos	return;
955183724Ssos    }
956183724Ssos
957188621Smav    /* enable wanted port interrupts */
958188621Smav    ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset,
959188621Smav	     (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF |
960188621Smav	      ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF |
961191674Smav	      ((ch->pm_level == 0) ? ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC : 0) |
962191674Smav	      ATA_AHCI_P_IX_DP | ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB |
963191674Smav	      ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR));
964199262Smav    /*
965199262Smav     * Only probe for PortMultiplier if HW has support.
966199262Smav     * Ignore Marvell, which is not working,
967199262Smav     */
968199262Smav    if ((ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SPM) &&
969199262Smav	    pci_get_vendor(ctlr->dev) != 0x11ab) {
970183724Ssos	signature = ata_ahci_softreset(dev, ATA_PM);
971188648Smav	/* Workaround for some ATI chips, failing to soft-reset
972188648Smav	 * when port multiplicator supported, but absent.
973188648Smav	 * XXX: We can also check PxIS.IPMS==1 here to be sure. */
974188648Smav	if (signature == 0xffffffff)
975188648Smav	    signature = ata_ahci_softreset(dev, 0);
976188648Smav    } else {
977183724Ssos	signature = ata_ahci_softreset(dev, 0);
978183724Ssos    }
979183724Ssos    if (bootverbose)
980183724Ssos	device_printf(dev, "SIGNATURE: %08x\n", signature);
981183724Ssos
982188906Smav    switch (signature >> 16) {
983188906Smav    case 0x0000:
984183724Ssos	ch->devices = ATA_ATA_MASTER;
985183724Ssos	break;
986188906Smav    case 0x9669:
987183724Ssos	ch->devices = ATA_PORTMULTIPLIER;
988183724Ssos	ata_pm_identify(dev);
989183724Ssos	break;
990188906Smav    case 0xeb14:
991183724Ssos	ch->devices = ATA_ATAPI_MASTER;
992183724Ssos	break;
993183724Ssos    default: /* SOS XXX */
994183724Ssos	if (bootverbose)
995188935Smav	    device_printf(dev, "Unknown signature, assuming disk device\n");
996183724Ssos	ch->devices = ATA_ATA_MASTER;
997183724Ssos    }
998183724Ssos    if (bootverbose)
999188918Smav        device_printf(dev, "AHCI reset done: devices=%08x\n", ch->devices);
1000183724Ssos}
1001183724Ssos
1002183724Ssosstatic void
1003183724Ssosata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
1004183724Ssos{
1005183724Ssos    struct ata_dmasetprd_args *args = xsc;
1006183724Ssos    struct ata_ahci_dma_prd *prd = args->dmatab;
1007183724Ssos    int i;
1008183724Ssos
1009183724Ssos    if (!(args->error = error)) {
1010183724Ssos	for (i = 0; i < nsegs; i++) {
1011183724Ssos	    prd[i].dba = htole64(segs[i].ds_addr);
1012183724Ssos	    prd[i].dbc = htole32((segs[i].ds_len - 1) & ATA_AHCI_PRD_MASK);
1013183724Ssos	}
1014183724Ssos    }
1015183724Ssos
1016183724Ssos    KASSERT(nsegs <= ATA_AHCI_DMA_ENTRIES, ("too many DMA segment entries\n"));
1017183724Ssos    args->nsegs = nsegs;
1018183724Ssos}
1019183724Ssos
1020188769Smavstatic void
1021183724Ssosata_ahci_dmainit(device_t dev)
1022183724Ssos{
1023183724Ssos    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
1024183724Ssos    struct ata_channel *ch = device_get_softc(dev);
1025183724Ssos
1026183724Ssos    /* note start and stop are not used here */
1027183724Ssos    ch->dma.setprd = ata_ahci_dmasetprd;
1028195439Smav    ch->dma.max_iosize = (ATA_AHCI_DMA_ENTRIES - 1) * PAGE_SIZE;
1029183724Ssos    if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_64BIT)
1030183724Ssos	ch->dma.max_address = BUS_SPACE_MAXADDR;
1031216013Smarius    ata_dmainit(dev);
1032183724Ssos}
1033183724Ssos
1034183724Ssosstatic int
1035183724Ssosata_ahci_setup_fis(struct ata_ahci_cmd_tab *ctp, struct ata_request *request)
1036183724Ssos{
1037183724Ssos    bzero(ctp->cfis, 64);
1038183724Ssos    if (request->flags & ATA_R_ATAPI) {
1039183724Ssos	bzero(ctp->acmd, 32);
1040183724Ssos	bcopy(request->u.atapi.ccb, ctp->acmd, 16);
1041183724Ssos    }
1042183724Ssos    return ata_request2fis_h2d(request, &ctp->cfis[0]);
1043183724Ssos}
1044183724Ssos
1045183724SsosATA_DECLARE_DRIVER(ata_ahci);
1046199322Smavstatic device_method_t ata_ahci_ata_methods[] = {
1047199322Smav    DEVMETHOD(device_probe,     ata_ahci_ata_probe),
1048199322Smav    DEVMETHOD(device_attach,    ata_ahci_ata_attach),
1049199322Smav    DEVMETHOD(device_detach,    ata_pci_detach),
1050199322Smav    DEVMETHOD(device_suspend,   ata_pci_suspend),
1051199322Smav    DEVMETHOD(device_resume,    ata_pci_resume),
1052199322Smav    DEVMETHOD(device_shutdown,  bus_generic_shutdown),
1053199322Smav    DEVMETHOD(bus_read_ivar,		ata_pci_read_ivar),
1054199322Smav    DEVMETHOD(bus_write_ivar,		ata_pci_write_ivar),
1055199322Smav    DEVMETHOD(bus_alloc_resource,       ata_pci_alloc_resource),
1056199322Smav    DEVMETHOD(bus_release_resource,     ata_pci_release_resource),
1057199322Smav    DEVMETHOD(bus_activate_resource,    bus_generic_activate_resource),
1058199322Smav    DEVMETHOD(bus_deactivate_resource,  bus_generic_deactivate_resource),
1059199322Smav    DEVMETHOD(bus_setup_intr,           ata_pci_setup_intr),
1060199322Smav    DEVMETHOD(bus_teardown_intr,        ata_pci_teardown_intr),
1061233717Smarius    DEVMETHOD_END
1062199322Smav};
1063199322Smavstatic driver_t ata_ahci_ata_driver = {
1064199322Smav        "atapci",
1065199322Smav        ata_ahci_ata_methods,
1066199322Smav        sizeof(struct ata_pci_controller)
1067199322Smav};
1068233717SmariusDRIVER_MODULE(ata_ahci_ata, atapci, ata_ahci_ata_driver, ata_pci_devclass,
1069233717Smarius    NULL, NULL);
1070