xref: /dflybsd-src/sys/dev/disk/ahci/ahci.c (revision 074579dffc8ecd16b19974dbc7c7c19f92160f39)
1258223a3SMatthew Dillon /*
2258223a3SMatthew Dillon  * Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
3258223a3SMatthew Dillon  *
4258223a3SMatthew Dillon  * Permission to use, copy, modify, and distribute this software for any
5258223a3SMatthew Dillon  * purpose with or without fee is hereby granted, provided that the above
6258223a3SMatthew Dillon  * copyright notice and this permission notice appear in all copies.
7258223a3SMatthew Dillon  *
8258223a3SMatthew Dillon  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9258223a3SMatthew Dillon  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10258223a3SMatthew Dillon  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11258223a3SMatthew Dillon  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12258223a3SMatthew Dillon  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13258223a3SMatthew Dillon  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14258223a3SMatthew Dillon  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15258223a3SMatthew Dillon  *
16258223a3SMatthew Dillon  *
17258223a3SMatthew Dillon  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
18258223a3SMatthew Dillon  *
19258223a3SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
20258223a3SMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
21258223a3SMatthew Dillon  *
22258223a3SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
23258223a3SMatthew Dillon  * modification, are permitted provided that the following conditions
24258223a3SMatthew Dillon  * are met:
25258223a3SMatthew Dillon  *
26258223a3SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
27258223a3SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
28258223a3SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
29258223a3SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
30258223a3SMatthew Dillon  *    the documentation and/or other materials provided with the
31258223a3SMatthew Dillon  *    distribution.
32258223a3SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
33258223a3SMatthew Dillon  *    contributors may be used to endorse or promote products derived
34258223a3SMatthew Dillon  *    from this software without specific, prior written permission.
35258223a3SMatthew Dillon  *
36258223a3SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
37258223a3SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
38258223a3SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
39258223a3SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
40258223a3SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
41258223a3SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
42258223a3SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43258223a3SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
44258223a3SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45258223a3SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46258223a3SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47258223a3SMatthew Dillon  * SUCH DAMAGE.
48258223a3SMatthew Dillon  *
49258223a3SMatthew Dillon  * $OpenBSD: ahci.c,v 1.147 2009/02/16 21:19:07 miod Exp $
50258223a3SMatthew Dillon  */
51258223a3SMatthew Dillon 
52258223a3SMatthew Dillon #include "ahci.h"
53258223a3SMatthew Dillon 
54f4553de1SMatthew Dillon int	ahci_port_start(struct ahci_port *ap);
55f4553de1SMatthew Dillon int	ahci_port_stop(struct ahci_port *ap, int stop_fis_rx);
56f4553de1SMatthew Dillon int	ahci_port_clo(struct ahci_port *ap);
57f4553de1SMatthew Dillon void	ahci_port_interrupt_enable(struct ahci_port *ap);
58258223a3SMatthew Dillon 
59258223a3SMatthew Dillon int	ahci_load_prdt(struct ahci_ccb *);
60258223a3SMatthew Dillon void	ahci_unload_prdt(struct ahci_ccb *);
61258223a3SMatthew Dillon static void ahci_load_prdt_callback(void *info, bus_dma_segment_t *segs,
62258223a3SMatthew Dillon 				    int nsegs, int error);
63258223a3SMatthew Dillon void	ahci_start(struct ahci_ccb *);
6417eab71eSMatthew Dillon int	ahci_port_softreset(struct ahci_port *ap);
651980eff3SMatthew Dillon int	ahci_port_pmprobe(struct ahci_port *ap);
661980eff3SMatthew Dillon int	ahci_port_hardreset(struct ahci_port *ap, int hard);
67cf5f3a81SMatthew Dillon void	ahci_port_hardstop(struct ahci_port *ap);
68cf5f3a81SMatthew Dillon void	ahci_flush_tfd(struct ahci_port *ap);
69258223a3SMatthew Dillon 
70831bc9e3SMatthew Dillon static void ahci_ata_cmd_timeout_unserialized(void *);
71831bc9e3SMatthew Dillon void	ahci_quick_timeout(struct ahci_ccb *ccb);
72831bc9e3SMatthew Dillon void	ahci_check_active_timeouts(struct ahci_port *ap);
73258223a3SMatthew Dillon 
74831bc9e3SMatthew Dillon void	ahci_beg_exclusive_access(struct ahci_port *ap, struct ata_port *at);
75831bc9e3SMatthew Dillon void	ahci_end_exclusive_access(struct ahci_port *ap, struct ata_port *at);
764c339a5fSMatthew Dillon void	ahci_issue_pending_commands(struct ahci_port *ap, struct ahci_ccb *ccb);
774c339a5fSMatthew Dillon void	ahci_issue_saved_commands(struct ahci_port *ap, u_int32_t mask);
78258223a3SMatthew Dillon 
79258223a3SMatthew Dillon int	ahci_port_read_ncq_error(struct ahci_port *, int *);
80258223a3SMatthew Dillon 
81258223a3SMatthew Dillon struct ahci_dmamem *ahci_dmamem_alloc(struct ahci_softc *, bus_dma_tag_t tag);
82258223a3SMatthew Dillon void	ahci_dmamem_free(struct ahci_softc *, struct ahci_dmamem *);
83258223a3SMatthew Dillon static void ahci_dmamem_saveseg(void *info, bus_dma_segment_t *segs, int nsegs, int error);
84258223a3SMatthew Dillon 
85258223a3SMatthew Dillon void	ahci_empty_done(struct ahci_ccb *ccb);
86258223a3SMatthew Dillon void	ahci_ata_cmd_done(struct ahci_ccb *ccb);
87258223a3SMatthew Dillon 
88258223a3SMatthew Dillon /* Wait for all bits in _b to be cleared */
89cec85a37SMatthew Dillon #define ahci_pwait_clr(_ap, _r, _b) \
90cec85a37SMatthew Dillon 	ahci_pwait_eq((_ap), AHCI_PWAIT_TIMEOUT, (_r), (_b), 0)
91cec85a37SMatthew Dillon #define ahci_pwait_clr_to(_ap, _to,  _r, _b) \
92cec85a37SMatthew Dillon 	ahci_pwait_eq((_ap), _to, (_r), (_b), 0)
93258223a3SMatthew Dillon 
94258223a3SMatthew Dillon /* Wait for all bits in _b to be set */
95cec85a37SMatthew Dillon #define ahci_pwait_set(_ap, _r, _b) \
96cec85a37SMatthew Dillon 	ahci_pwait_eq((_ap), AHCI_PWAIT_TIMEOUT, (_r), (_b), (_b))
97cec85a37SMatthew Dillon #define ahci_pwait_set_to(_ap, _to, _r, _b) \
98cec85a37SMatthew Dillon 	ahci_pwait_eq((_ap), _to, (_r), (_b), (_b))
99cec85a37SMatthew Dillon 
100cec85a37SMatthew Dillon #define AHCI_PWAIT_TIMEOUT	1000
101258223a3SMatthew Dillon 
102fd8bd957SMatthew Dillon /*
103fd8bd957SMatthew Dillon  * Initialize the global AHCI hardware.  This code does not set up any of
104fd8bd957SMatthew Dillon  * its ports.
105fd8bd957SMatthew Dillon  */
106258223a3SMatthew Dillon int
107258223a3SMatthew Dillon ahci_init(struct ahci_softc *sc)
108258223a3SMatthew Dillon {
109258223a3SMatthew Dillon 	u_int32_t	cap, pi;
110831bc9e3SMatthew Dillon 	int		i;
111831bc9e3SMatthew Dillon 	struct ahci_port *ap;
112258223a3SMatthew Dillon 
113258223a3SMatthew Dillon 	DPRINTF(AHCI_D_VERBOSE, " GHC 0x%b",
114258223a3SMatthew Dillon 		ahci_read(sc, AHCI_REG_GHC), AHCI_FMT_GHC);
115258223a3SMatthew Dillon 
116258223a3SMatthew Dillon 	/* save BIOS initialised parameters, enable staggered spin up */
117258223a3SMatthew Dillon 	cap = ahci_read(sc, AHCI_REG_CAP);
118258223a3SMatthew Dillon 	cap &= AHCI_REG_CAP_SMPS;
119258223a3SMatthew Dillon 	cap |= AHCI_REG_CAP_SSS;
120258223a3SMatthew Dillon 	pi = ahci_read(sc, AHCI_REG_PI);
121258223a3SMatthew Dillon 
122831bc9e3SMatthew Dillon #if 1
123831bc9e3SMatthew Dillon 	/*
124831bc9e3SMatthew Dillon 	 * This is a hack that currently does not appear to have
125831bc9e3SMatthew Dillon 	 * a significant effect, but I noticed the port registers
126831bc9e3SMatthew Dillon 	 * do not appear to be completely cleared after the host
127831bc9e3SMatthew Dillon 	 * controller is reset.
128831bc9e3SMatthew Dillon 	 */
129831bc9e3SMatthew Dillon 	ap = kmalloc(sizeof(*ap), M_DEVBUF, M_WAITOK | M_ZERO);
130831bc9e3SMatthew Dillon 	ap->ap_sc = sc;
131831bc9e3SMatthew Dillon 	for (i = 0; i < AHCI_MAX_PMPORTS; ++i) {
132831bc9e3SMatthew Dillon 		if ((pi & (1 << i)) == 0)
133831bc9e3SMatthew Dillon 			continue;
134831bc9e3SMatthew Dillon 		if (bus_space_subregion(sc->sc_iot, sc->sc_ioh,
135831bc9e3SMatthew Dillon 		    AHCI_PORT_REGION(i), AHCI_PORT_SIZE, &ap->ap_ioh) != 0) {
136831bc9e3SMatthew Dillon 			device_printf(sc->sc_dev, "can't map port\n");
137831bc9e3SMatthew Dillon 			return (1);
138831bc9e3SMatthew Dillon 		}
139831bc9e3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SCTL, AHCI_PREG_SCTL_IPM_DISABLED |
140831bc9e3SMatthew Dillon 						AHCI_PREG_SCTL_DET_DISABLE);
141831bc9e3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SERR, -1);
142831bc9e3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IE, 0);
143831bc9e3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CMD, 0);
144831bc9e3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS, 0);
145831bc9e3SMatthew Dillon 	}
146831bc9e3SMatthew Dillon 	kfree(ap, M_DEVBUF);
147831bc9e3SMatthew Dillon #endif
148831bc9e3SMatthew Dillon 
14917eab71eSMatthew Dillon 	/*
15017eab71eSMatthew Dillon 	 * Unconditionally reset the controller, do not conditionalize on
15117eab71eSMatthew Dillon 	 * trying to figure it if it was previously active or not.
152831bc9e3SMatthew Dillon 	 *
153831bc9e3SMatthew Dillon 	 * NOTE BRICKS (1)
154831bc9e3SMatthew Dillon 	 *
155831bc9e3SMatthew Dillon 	 *	If you have a port multiplier and it does not have a device
156831bc9e3SMatthew Dillon 	 *	in target 0, and it probes normally, but a later operation
157831bc9e3SMatthew Dillon 	 *	mis-probes a target behind that PM, it is possible for the
158831bc9e3SMatthew Dillon 	 *	port to brick such that only (a) a power cycle of the host
159831bc9e3SMatthew Dillon 	 *	or (b) placing a device in target 0 will fix the problem.
160831bc9e3SMatthew Dillon 	 *	Power cycling the PM has no effect (it works fine on another
161831bc9e3SMatthew Dillon 	 *	host port).  This issue is unrelated to CLO.
16217eab71eSMatthew Dillon 	 */
163258223a3SMatthew Dillon 	ahci_write(sc, AHCI_REG_GHC, AHCI_REG_GHC_HR);
164831bc9e3SMatthew Dillon 	if (ahci_wait_ne(sc, AHCI_REG_GHC,
165831bc9e3SMatthew Dillon 			 AHCI_REG_GHC_HR, AHCI_REG_GHC_HR) != 0) {
166258223a3SMatthew Dillon 		device_printf(sc->sc_dev,
167258223a3SMatthew Dillon 			      "unable to reset controller\n");
168258223a3SMatthew Dillon 		return (1);
169258223a3SMatthew Dillon 	}
170831bc9e3SMatthew Dillon 	ahci_os_sleep(100);
171258223a3SMatthew Dillon 
172258223a3SMatthew Dillon 	/* enable ahci (global interrupts disabled) */
173258223a3SMatthew Dillon 	ahci_write(sc, AHCI_REG_GHC, AHCI_REG_GHC_AE);
174258223a3SMatthew Dillon 
175258223a3SMatthew Dillon 	/* restore parameters */
176258223a3SMatthew Dillon 	ahci_write(sc, AHCI_REG_CAP, cap);
177258223a3SMatthew Dillon 	ahci_write(sc, AHCI_REG_PI, pi);
178258223a3SMatthew Dillon 
179258223a3SMatthew Dillon 	return (0);
180258223a3SMatthew Dillon }
181258223a3SMatthew Dillon 
182fd8bd957SMatthew Dillon /*
183fd8bd957SMatthew Dillon  * Allocate and initialize an AHCI port.
184fd8bd957SMatthew Dillon  */
185258223a3SMatthew Dillon int
186258223a3SMatthew Dillon ahci_port_alloc(struct ahci_softc *sc, u_int port)
187258223a3SMatthew Dillon {
188258223a3SMatthew Dillon 	struct ahci_port	*ap;
1891980eff3SMatthew Dillon 	struct ata_port		*at;
190258223a3SMatthew Dillon 	struct ahci_ccb		*ccb;
191258223a3SMatthew Dillon 	u_int64_t		dva;
192258223a3SMatthew Dillon 	u_int32_t		cmd;
193258223a3SMatthew Dillon 	struct ahci_cmd_hdr	*hdr;
194258223a3SMatthew Dillon 	struct ahci_cmd_table	*table;
195258223a3SMatthew Dillon 	int	rc = ENOMEM;
196258223a3SMatthew Dillon 	int	error;
197258223a3SMatthew Dillon 	int	i;
198258223a3SMatthew Dillon 
199258223a3SMatthew Dillon 	ap = kmalloc(sizeof(*ap), M_DEVBUF, M_WAITOK | M_ZERO);
200258223a3SMatthew Dillon 
201258223a3SMatthew Dillon 	ksnprintf(ap->ap_name, sizeof(ap->ap_name), "%s%d.%d",
202258223a3SMatthew Dillon 		  device_get_name(sc->sc_dev),
203258223a3SMatthew Dillon 		  device_get_unit(sc->sc_dev),
204258223a3SMatthew Dillon 		  port);
205258223a3SMatthew Dillon 	sc->sc_ports[port] = ap;
206258223a3SMatthew Dillon 
2071980eff3SMatthew Dillon 	/*
2081980eff3SMatthew Dillon 	 * Allocate enough so we never have to reallocate, it makes
2091980eff3SMatthew Dillon 	 * it easier.
2101980eff3SMatthew Dillon 	 *
2111980eff3SMatthew Dillon 	 * ap_pmcount will be reduced by the scan if we encounter the
2121980eff3SMatthew Dillon 	 * port multiplier port prior to target 15.
2131980eff3SMatthew Dillon 	 */
2141980eff3SMatthew Dillon 	if (ap->ap_ata == NULL) {
2151980eff3SMatthew Dillon 		ap->ap_ata = kmalloc(sizeof(*ap->ap_ata) * AHCI_MAX_PMPORTS,
2161980eff3SMatthew Dillon 				     M_DEVBUF, M_INTWAIT | M_ZERO);
2171980eff3SMatthew Dillon 		for (i = 0; i < AHCI_MAX_PMPORTS; ++i) {
2181980eff3SMatthew Dillon 			at = &ap->ap_ata[i];
2191980eff3SMatthew Dillon 			at->at_ahci_port = ap;
2201980eff3SMatthew Dillon 			at->at_target = i;
2213209f581SMatthew Dillon 			at->at_probe = ATA_PROBE_NEED_INIT;
222831bc9e3SMatthew Dillon 			at->at_features |= ATA_PORT_F_RESCAN;
2231980eff3SMatthew Dillon 			ksnprintf(at->at_name, sizeof(at->at_name),
2241980eff3SMatthew Dillon 				  "%s.%d", ap->ap_name, i);
2251980eff3SMatthew Dillon 		}
2261980eff3SMatthew Dillon 	}
227258223a3SMatthew Dillon 	if (bus_space_subregion(sc->sc_iot, sc->sc_ioh,
228258223a3SMatthew Dillon 	    AHCI_PORT_REGION(port), AHCI_PORT_SIZE, &ap->ap_ioh) != 0) {
229258223a3SMatthew Dillon 		device_printf(sc->sc_dev,
230258223a3SMatthew Dillon 			      "unable to create register window for port %d\n",
231258223a3SMatthew Dillon 			      port);
232258223a3SMatthew Dillon 		goto freeport;
233258223a3SMatthew Dillon 	}
234258223a3SMatthew Dillon 
235258223a3SMatthew Dillon 	ap->ap_sc = sc;
236258223a3SMatthew Dillon 	ap->ap_num = port;
2373209f581SMatthew Dillon 	ap->ap_probe = ATA_PROBE_NEED_INIT;
238258223a3SMatthew Dillon 	TAILQ_INIT(&ap->ap_ccb_free);
239258223a3SMatthew Dillon 	TAILQ_INIT(&ap->ap_ccb_pending);
240258223a3SMatthew Dillon 	lockinit(&ap->ap_ccb_lock, "ahcipo", 0, 0);
241258223a3SMatthew Dillon 
242258223a3SMatthew Dillon 	/* Disable port interrupts */
243258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_IE, 0);
244831bc9e3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SERR, -1);
245258223a3SMatthew Dillon 
24617eab71eSMatthew Dillon 	/*
24717eab71eSMatthew Dillon 	 * Sec 10.1.2 - deinitialise port if it is already running
24817eab71eSMatthew Dillon 	 */
249258223a3SMatthew Dillon 	cmd = ahci_pread(ap, AHCI_PREG_CMD);
250258223a3SMatthew Dillon 	if ((cmd & (AHCI_PREG_CMD_ST | AHCI_PREG_CMD_CR |
251258223a3SMatthew Dillon 		    AHCI_PREG_CMD_FRE | AHCI_PREG_CMD_FR)) ||
252258223a3SMatthew Dillon 	    (ahci_pread(ap, AHCI_PREG_SCTL) & AHCI_PREG_SCTL_DET)) {
253258223a3SMatthew Dillon 		int r;
254258223a3SMatthew Dillon 
255258223a3SMatthew Dillon 		r = ahci_port_stop(ap, 1);
256258223a3SMatthew Dillon 		if (r) {
257258223a3SMatthew Dillon 			device_printf(sc->sc_dev,
258258223a3SMatthew Dillon 				  "unable to disable %s, ignoring port %d\n",
259258223a3SMatthew Dillon 				  ((r == 2) ? "CR" : "FR"), port);
260258223a3SMatthew Dillon 			rc = ENXIO;
261258223a3SMatthew Dillon 			goto freeport;
262258223a3SMatthew Dillon 		}
263258223a3SMatthew Dillon 
264258223a3SMatthew Dillon 		/* Write DET to zero */
265cf5f3a81SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SCTL, AHCI_PREG_SCTL_IPM_DISABLED);
266258223a3SMatthew Dillon 	}
267258223a3SMatthew Dillon 
268258223a3SMatthew Dillon 	/* Allocate RFIS */
269258223a3SMatthew Dillon 	ap->ap_dmamem_rfis = ahci_dmamem_alloc(sc, sc->sc_tag_rfis);
270258223a3SMatthew Dillon 	if (ap->ap_dmamem_rfis == NULL) {
271cf5f3a81SMatthew Dillon 		kprintf("%s: NORFIS\n", PORTNAME(ap));
272258223a3SMatthew Dillon 		goto nomem;
273258223a3SMatthew Dillon 	}
274258223a3SMatthew Dillon 
275258223a3SMatthew Dillon 	/* Setup RFIS base address */
276258223a3SMatthew Dillon 	ap->ap_rfis = (struct ahci_rfis *) AHCI_DMA_KVA(ap->ap_dmamem_rfis);
277258223a3SMatthew Dillon 	dva = AHCI_DMA_DVA(ap->ap_dmamem_rfis);
278258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_FBU, (u_int32_t)(dva >> 32));
279258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_FB, (u_int32_t)dva);
280258223a3SMatthew Dillon 
281831bc9e3SMatthew Dillon 	/* Clear SERR before starting FIS reception or ST or anything */
282831bc9e3SMatthew Dillon 	ahci_flush_tfd(ap);
283831bc9e3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SERR, -1);
284831bc9e3SMatthew Dillon 
285258223a3SMatthew Dillon 	/* Enable FIS reception and activate port. */
286258223a3SMatthew Dillon 	cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC;
2871980eff3SMatthew Dillon 	cmd &= ~(AHCI_PREG_CMD_CLO | AHCI_PREG_CMD_PMA);
288258223a3SMatthew Dillon 	cmd |= AHCI_PREG_CMD_FRE | AHCI_PREG_CMD_POD | AHCI_PREG_CMD_SUD;
289258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_CMD, cmd | AHCI_PREG_CMD_ICC_ACTIVE);
290258223a3SMatthew Dillon 
291258223a3SMatthew Dillon 	/* Check whether port activated.  Skip it if not. */
292258223a3SMatthew Dillon 	cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC;
293258223a3SMatthew Dillon 	if ((cmd & AHCI_PREG_CMD_FRE) == 0) {
294cf5f3a81SMatthew Dillon 		kprintf("%s: NOT-ACTIVATED\n", PORTNAME(ap));
295258223a3SMatthew Dillon 		rc = ENXIO;
296258223a3SMatthew Dillon 		goto freeport;
297258223a3SMatthew Dillon 	}
298258223a3SMatthew Dillon 
299258223a3SMatthew Dillon 	/* Allocate a CCB for each command slot */
300258223a3SMatthew Dillon 	ap->ap_ccbs = kmalloc(sizeof(struct ahci_ccb) * sc->sc_ncmds, M_DEVBUF,
301258223a3SMatthew Dillon 			      M_WAITOK | M_ZERO);
302258223a3SMatthew Dillon 	if (ap->ap_ccbs == NULL) {
303258223a3SMatthew Dillon 		device_printf(sc->sc_dev,
304258223a3SMatthew Dillon 			      "unable to allocate command list for port %d\n",
305258223a3SMatthew Dillon 			      port);
306258223a3SMatthew Dillon 		goto freeport;
307258223a3SMatthew Dillon 	}
308258223a3SMatthew Dillon 
309258223a3SMatthew Dillon 	/* Command List Structures and Command Tables */
310258223a3SMatthew Dillon 	ap->ap_dmamem_cmd_list = ahci_dmamem_alloc(sc, sc->sc_tag_cmdh);
311258223a3SMatthew Dillon 	ap->ap_dmamem_cmd_table = ahci_dmamem_alloc(sc, sc->sc_tag_cmdt);
312258223a3SMatthew Dillon 	if (ap->ap_dmamem_cmd_table == NULL ||
313258223a3SMatthew Dillon 	    ap->ap_dmamem_cmd_list == NULL) {
314258223a3SMatthew Dillon nomem:
315258223a3SMatthew Dillon 		device_printf(sc->sc_dev,
316258223a3SMatthew Dillon 			      "unable to allocate DMA memory for port %d\n",
317258223a3SMatthew Dillon 			      port);
318258223a3SMatthew Dillon 		goto freeport;
319258223a3SMatthew Dillon 	}
320258223a3SMatthew Dillon 
321258223a3SMatthew Dillon 	/* Setup command list base address */
322258223a3SMatthew Dillon 	dva = AHCI_DMA_DVA(ap->ap_dmamem_cmd_list);
323258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_CLBU, (u_int32_t)(dva >> 32));
324258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_CLB, (u_int32_t)dva);
325258223a3SMatthew Dillon 
326258223a3SMatthew Dillon 	/* Split CCB allocation into CCBs and assign to command header/table */
327258223a3SMatthew Dillon 	hdr = AHCI_DMA_KVA(ap->ap_dmamem_cmd_list);
328258223a3SMatthew Dillon 	table = AHCI_DMA_KVA(ap->ap_dmamem_cmd_table);
329258223a3SMatthew Dillon 	for (i = 0; i < sc->sc_ncmds; i++) {
330258223a3SMatthew Dillon 		ccb = &ap->ap_ccbs[i];
331258223a3SMatthew Dillon 
332258223a3SMatthew Dillon 		error = bus_dmamap_create(sc->sc_tag_data, BUS_DMA_ALLOCNOW,
333258223a3SMatthew Dillon 					  &ccb->ccb_dmamap);
334258223a3SMatthew Dillon 		if (error) {
335258223a3SMatthew Dillon 			device_printf(sc->sc_dev,
336258223a3SMatthew Dillon 				      "unable to create dmamap for port %d "
337258223a3SMatthew Dillon 				      "ccb %d\n", port, i);
338258223a3SMatthew Dillon 			goto freeport;
339258223a3SMatthew Dillon 		}
340258223a3SMatthew Dillon 
341258223a3SMatthew Dillon 		callout_init(&ccb->ccb_timeout);
342258223a3SMatthew Dillon 		ccb->ccb_slot = i;
343258223a3SMatthew Dillon 		ccb->ccb_port = ap;
344258223a3SMatthew Dillon 		ccb->ccb_cmd_hdr = &hdr[i];
345258223a3SMatthew Dillon 		ccb->ccb_cmd_table = &table[i];
346258223a3SMatthew Dillon 		dva = AHCI_DMA_DVA(ap->ap_dmamem_cmd_table) +
347258223a3SMatthew Dillon 		    ccb->ccb_slot * sizeof(struct ahci_cmd_table);
348258223a3SMatthew Dillon 		ccb->ccb_cmd_hdr->ctba_hi = htole32((u_int32_t)(dva >> 32));
349258223a3SMatthew Dillon 		ccb->ccb_cmd_hdr->ctba_lo = htole32((u_int32_t)dva);
350258223a3SMatthew Dillon 
351258223a3SMatthew Dillon 		ccb->ccb_xa.fis =
352258223a3SMatthew Dillon 		    (struct ata_fis_h2d *)ccb->ccb_cmd_table->cfis;
353258223a3SMatthew Dillon 		ccb->ccb_xa.packetcmd = ccb->ccb_cmd_table->acmd;
354258223a3SMatthew Dillon 		ccb->ccb_xa.tag = i;
355258223a3SMatthew Dillon 
356258223a3SMatthew Dillon 		ccb->ccb_xa.state = ATA_S_COMPLETE;
3571067474aSMatthew Dillon 
3581067474aSMatthew Dillon 		/*
3591067474aSMatthew Dillon 		 * CCB[1] is the error CCB and is not get or put.  It is
3601067474aSMatthew Dillon 		 * also used for probing.  Numerous HBAs only load the
3611067474aSMatthew Dillon 		 * signature from CCB[1] so it MUST be used for the second
3621067474aSMatthew Dillon 		 * FIS.
3631067474aSMatthew Dillon 		 */
3641067474aSMatthew Dillon 		if (i == 1)
3651067474aSMatthew Dillon 			ap->ap_err_ccb = ccb;
3661067474aSMatthew Dillon 		else
367258223a3SMatthew Dillon 			ahci_put_ccb(ccb);
368258223a3SMatthew Dillon 	}
369258223a3SMatthew Dillon 
370258223a3SMatthew Dillon 	/* Wait for ICC change to complete */
371258223a3SMatthew Dillon 	ahci_pwait_clr(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_ICC);
372258223a3SMatthew Dillon 
373fd8bd957SMatthew Dillon 	/*
374f4553de1SMatthew Dillon 	 * Start the port.  The helper thread will call ahci_port_init()
375f4553de1SMatthew Dillon 	 * so the ports can all be started in parallel.  A failure by
376f4553de1SMatthew Dillon 	 * ahci_port_init() does not deallocate the port since we still
377f4553de1SMatthew Dillon 	 * want hot-plug events.
378fd8bd957SMatthew Dillon 	 */
379f4553de1SMatthew Dillon 	ahci_os_start_port(ap);
380fd8bd957SMatthew Dillon 	return(0);
381fd8bd957SMatthew Dillon freeport:
382fd8bd957SMatthew Dillon 	ahci_port_free(sc, port);
383fd8bd957SMatthew Dillon 	return (rc);
384fd8bd957SMatthew Dillon }
385fd8bd957SMatthew Dillon 
386fd8bd957SMatthew Dillon /*
387fd8bd957SMatthew Dillon  * [re]initialize an idle port.  No CCBs should be active.
388fd8bd957SMatthew Dillon  *
3891980eff3SMatthew Dillon  * If at is NULL we are initializing a directly connected port, otherwise
3901980eff3SMatthew Dillon  * we are indirectly initializing a port multiplier port.
3911980eff3SMatthew Dillon  *
392fd8bd957SMatthew Dillon  * This function is called during the initial port allocation sequence
393fd8bd957SMatthew Dillon  * and is also called on hot-plug insertion.  We take no chances and
394fd8bd957SMatthew Dillon  * use a portreset instead of a softreset.
395fd8bd957SMatthew Dillon  *
39622181ab7SMatthew Dillon  * This function is the only way to move a failed port back to active
39722181ab7SMatthew Dillon  * status.
39822181ab7SMatthew Dillon  *
399fd8bd957SMatthew Dillon  * Returns 0 if a device is successfully detected.
400fd8bd957SMatthew Dillon  */
401fd8bd957SMatthew Dillon int
402f4553de1SMatthew Dillon ahci_port_init(struct ahci_port *ap, struct ata_port *atx)
403fd8bd957SMatthew Dillon {
404121d8e75SMatthew Dillon 	u_int32_t data;
405fd8bd957SMatthew Dillon 	int rc;
406fd8bd957SMatthew Dillon 
407fd8bd957SMatthew Dillon 	/*
4081980eff3SMatthew Dillon 	 * Clear all notification bits
409fd8bd957SMatthew Dillon 	 */
410121d8e75SMatthew Dillon 	if (atx == NULL && (ap->ap_sc->sc_cap & AHCI_REG_CAP_SSNTF))
4111980eff3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SNTF, -1);
4121980eff3SMatthew Dillon 
4131980eff3SMatthew Dillon 	/*
4141980eff3SMatthew Dillon 	 * Hard-reset the port.  If a device is detected but it is busy
4151980eff3SMatthew Dillon 	 * we try a second time, this time cycling the phy as well.
4161067474aSMatthew Dillon 	 *
4171067474aSMatthew Dillon 	 * XXX note: hard reset mode 2 (cycling the PHY) is not reliable.
4181980eff3SMatthew Dillon 	 */
419f4553de1SMatthew Dillon 	if (atx)
420f4553de1SMatthew Dillon 		atx->at_probe = ATA_PROBE_NEED_HARD_RESET;
421f4553de1SMatthew Dillon 	else
4221980eff3SMatthew Dillon 		ap->ap_probe = ATA_PROBE_NEED_HARD_RESET;
4231067474aSMatthew Dillon 
4241067474aSMatthew Dillon 	rc = ahci_port_reset(ap, atx, 1);
425831bc9e3SMatthew Dillon #if 0
426f4553de1SMatthew Dillon 	rc = ahci_port_reset(ap, atx, 1);
4271980eff3SMatthew Dillon 	if (rc == EBUSY) {
428f4553de1SMatthew Dillon 		rc = ahci_port_reset(ap, atx, 2);
42917eab71eSMatthew Dillon 	}
430831bc9e3SMatthew Dillon #endif
431fd8bd957SMatthew Dillon 
432258223a3SMatthew Dillon 	switch (rc) {
433258223a3SMatthew Dillon 	case ENODEV:
434fd8bd957SMatthew Dillon 		/*
435fd8bd957SMatthew Dillon 		 * We had problems talking to the device on the port.
436fd8bd957SMatthew Dillon 		 */
437121d8e75SMatthew Dillon 		if (atx) {
438121d8e75SMatthew Dillon 			ahci_pm_read(ap, atx->at_target,
439121d8e75SMatthew Dillon 				     AHCI_PMREG_SSTS, &data);
440121d8e75SMatthew Dillon 		} else {
441121d8e75SMatthew Dillon 			data = ahci_pread(ap, AHCI_PREG_SSTS);
442121d8e75SMatthew Dillon 		}
443121d8e75SMatthew Dillon 
444121d8e75SMatthew Dillon 		switch(data & AHCI_PREG_SSTS_DET) {
445258223a3SMatthew Dillon 		case AHCI_PREG_SSTS_DET_DEV_NE:
446121d8e75SMatthew Dillon 			kprintf("%s: Device not communicating\n",
447121d8e75SMatthew Dillon 				ATANAME(ap, atx));
448258223a3SMatthew Dillon 			break;
449258223a3SMatthew Dillon 		case AHCI_PREG_SSTS_DET_PHYOFFLINE:
450121d8e75SMatthew Dillon 			kprintf("%s: PHY offline\n",
451121d8e75SMatthew Dillon 				ATANAME(ap, atx));
452258223a3SMatthew Dillon 			break;
453258223a3SMatthew Dillon 		default:
454121d8e75SMatthew Dillon 			kprintf("%s: No device detected\n",
455121d8e75SMatthew Dillon 				ATANAME(ap, atx));
456258223a3SMatthew Dillon 			break;
457258223a3SMatthew Dillon 		}
458258223a3SMatthew Dillon 		break;
459258223a3SMatthew Dillon 
460258223a3SMatthew Dillon 	case EBUSY:
461fd8bd957SMatthew Dillon 		/*
46217eab71eSMatthew Dillon 		 * The device on the port is still telling us its busy,
46317eab71eSMatthew Dillon 		 * which means that it is not properly handling a SATA
46417eab71eSMatthew Dillon 		 * port COMRESET.
465fd8bd957SMatthew Dillon 		 *
46617eab71eSMatthew Dillon 		 * It may be possible to softreset the device using CLO
46717eab71eSMatthew Dillon 		 * and a device reset command.
468fd8bd957SMatthew Dillon 		 */
469121d8e75SMatthew Dillon 		if (atx) {
470121d8e75SMatthew Dillon 			kprintf("%s: Device on port is bricked, giving up\n",
471121d8e75SMatthew Dillon 				ATANAME(ap, atx));
472121d8e75SMatthew Dillon 		} else {
473121d8e75SMatthew Dillon 			kprintf("%s: Device on port is bricked, "
474121d8e75SMatthew Dillon 				"trying softreset\n", PORTNAME(ap));
475258223a3SMatthew Dillon 
476f4553de1SMatthew Dillon 			rc = ahci_port_reset(ap, atx, 0);
477258223a3SMatthew Dillon 			if (rc) {
47817eab71eSMatthew Dillon 				kprintf("%s: Unable unbrick device\n",
479fd8bd957SMatthew Dillon 					PORTNAME(ap));
480fd8bd957SMatthew Dillon 			} else {
48117eab71eSMatthew Dillon 				kprintf("%s: Successfully unbricked\n",
482fd8bd957SMatthew Dillon 					PORTNAME(ap));
483258223a3SMatthew Dillon 			}
484121d8e75SMatthew Dillon 		}
485258223a3SMatthew Dillon 		break;
486258223a3SMatthew Dillon 
487258223a3SMatthew Dillon 	default:
488258223a3SMatthew Dillon 		break;
489258223a3SMatthew Dillon 	}
490258223a3SMatthew Dillon 
491258223a3SMatthew Dillon 	/*
49217eab71eSMatthew Dillon 	 * Command transfers can only be enabled if a device was successfully
49317eab71eSMatthew Dillon 	 * detected.
4941980eff3SMatthew Dillon 	 *
4951980eff3SMatthew Dillon 	 * Allocate or deallocate the ap_ata array here too.
496258223a3SMatthew Dillon 	 */
497121d8e75SMatthew Dillon 	if (atx == NULL) {
4981980eff3SMatthew Dillon 		switch(ap->ap_type) {
4991980eff3SMatthew Dillon 		case ATA_PORT_T_NONE:
5001980eff3SMatthew Dillon 			ap->ap_pmcount = 0;
5011980eff3SMatthew Dillon 			break;
5021980eff3SMatthew Dillon 		case ATA_PORT_T_PM:
5031980eff3SMatthew Dillon 			/* already set */
5041980eff3SMatthew Dillon 			break;
5051980eff3SMatthew Dillon 		default:
5061980eff3SMatthew Dillon 			ap->ap_pmcount = 1;
5071980eff3SMatthew Dillon 			break;
5081980eff3SMatthew Dillon 		}
509121d8e75SMatthew Dillon 	}
5101980eff3SMatthew Dillon 
5111980eff3SMatthew Dillon 	/*
5121980eff3SMatthew Dillon 	 * Start the port if we succeeded.
5131980eff3SMatthew Dillon 	 *
5141980eff3SMatthew Dillon 	 * There's nothing to start for devices behind a port multiplier.
5151980eff3SMatthew Dillon 	 */
516f4553de1SMatthew Dillon 	if (rc == 0 && atx == NULL) {
51717eab71eSMatthew Dillon 		if (ahci_port_start(ap)) {
518fd8bd957SMatthew Dillon 			kprintf("%s: failed to start command DMA on port, "
519fd8bd957SMatthew Dillon 			        "disabling\n", PORTNAME(ap));
520258223a3SMatthew Dillon 			rc = ENXIO;	/* couldn't start port */
521258223a3SMatthew Dillon 		}
522258223a3SMatthew Dillon 	}
523258223a3SMatthew Dillon 
52417eab71eSMatthew Dillon 	/*
5253209f581SMatthew Dillon 	 * Flush interrupts on the port. XXX
5261980eff3SMatthew Dillon 	 *
5271980eff3SMatthew Dillon 	 * Enable interrupts on the port whether a device is sitting on
5281980eff3SMatthew Dillon 	 * it or not, to handle hot-plug events.
52917eab71eSMatthew Dillon 	 */
530f4553de1SMatthew Dillon 	if (atx == NULL) {
531258223a3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS, ahci_pread(ap, AHCI_PREG_IS));
532fd8bd957SMatthew Dillon 		ahci_write(ap->ap_sc, AHCI_REG_IS, 1 << ap->ap_num);
533258223a3SMatthew Dillon 
534f4553de1SMatthew Dillon 		ahci_port_interrupt_enable(ap);
535f4553de1SMatthew Dillon 	}
536f4553de1SMatthew Dillon 	return(rc);
537f4553de1SMatthew Dillon }
538f4553de1SMatthew Dillon 
539f4553de1SMatthew Dillon /*
540f4553de1SMatthew Dillon  * Enable or re-enable interrupts on a port.
541f4553de1SMatthew Dillon  *
542f4553de1SMatthew Dillon  * This routine is called from the port initialization code or from the
543f4553de1SMatthew Dillon  * helper thread as the real interrupt may be forced to turn off certain
544f4553de1SMatthew Dillon  * interrupt sources.
545f4553de1SMatthew Dillon  */
546f4553de1SMatthew Dillon void
547f4553de1SMatthew Dillon ahci_port_interrupt_enable(struct ahci_port *ap)
548f4553de1SMatthew Dillon {
549f4553de1SMatthew Dillon 	u_int32_t data;
550f4553de1SMatthew Dillon 
5511980eff3SMatthew Dillon 	data = AHCI_PREG_IE_TFEE | AHCI_PREG_IE_HBFE |
552258223a3SMatthew Dillon 	       AHCI_PREG_IE_IFE | AHCI_PREG_IE_OFE |
553258223a3SMatthew Dillon 	       AHCI_PREG_IE_DPE | AHCI_PREG_IE_UFE |
554258223a3SMatthew Dillon 	       AHCI_PREG_IE_PCE | AHCI_PREG_IE_PRCE |
5551980eff3SMatthew Dillon 	       AHCI_PREG_IE_DHRE;
5561980eff3SMatthew Dillon 	if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SSNTF)
5571980eff3SMatthew Dillon 		data |= AHCI_PREG_IE_SDBE;
558258223a3SMatthew Dillon #ifdef AHCI_COALESCE
5591980eff3SMatthew Dillon 	if (sc->sc_ccc_ports & (1 << port)
5601980eff3SMatthew Dillon 		data &= ~(AHCI_PREG_IE_SDBE | AHCI_PREG_IE_DHRE);
561258223a3SMatthew Dillon #endif
5621980eff3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_IE, data);
5631980eff3SMatthew Dillon }
564258223a3SMatthew Dillon 
565fd8bd957SMatthew Dillon /*
5663209f581SMatthew Dillon  * Run the port / target state machine from a main context.
5673209f581SMatthew Dillon  *
5683209f581SMatthew Dillon  * The state machine for the port is always run.
5693209f581SMatthew Dillon  *
5703209f581SMatthew Dillon  * If atx is non-NULL run the state machine for a particular target.
5713209f581SMatthew Dillon  * If atx is NULL run the state machine for all targets.
5723209f581SMatthew Dillon  */
5733209f581SMatthew Dillon void
574831bc9e3SMatthew Dillon ahci_port_state_machine(struct ahci_port *ap, int initial)
5753209f581SMatthew Dillon {
5763209f581SMatthew Dillon 	struct ata_port *at;
5773209f581SMatthew Dillon 	u_int32_t data;
5783209f581SMatthew Dillon 	int target;
5793209f581SMatthew Dillon 	int didsleep;
580831bc9e3SMatthew Dillon 	int loop;
5813209f581SMatthew Dillon 
582831bc9e3SMatthew Dillon 	/*
583831bc9e3SMatthew Dillon 	 * State machine for port.  Note that CAM is not yet associated
584831bc9e3SMatthew Dillon 	 * during the initial parallel probe and the port's probe state
585831bc9e3SMatthew Dillon 	 * will not get past ATA_PROBE_NEED_IDENT.
586831bc9e3SMatthew Dillon 	 */
587c408a8b3SMatthew Dillon 	{
5881067474aSMatthew Dillon 		if (initial == 0 && ap->ap_probe <= ATA_PROBE_NEED_HARD_RESET) {
5891067474aSMatthew Dillon 			kprintf("%s: Waiting 10 seconds on insertion\n",
5901067474aSMatthew Dillon 				PORTNAME(ap));
5911067474aSMatthew Dillon 			ahci_os_sleep(10000);
5921067474aSMatthew Dillon 			initial = 1;
5933209f581SMatthew Dillon 		}
5941067474aSMatthew Dillon 		if (ap->ap_probe == ATA_PROBE_NEED_INIT)
5953209f581SMatthew Dillon 			ahci_port_init(ap, NULL);
5963209f581SMatthew Dillon 		if (ap->ap_probe == ATA_PROBE_NEED_HARD_RESET)
5973209f581SMatthew Dillon 			ahci_port_reset(ap, NULL, 1);
5983209f581SMatthew Dillon 		if (ap->ap_probe == ATA_PROBE_NEED_SOFT_RESET)
5993209f581SMatthew Dillon 			ahci_port_reset(ap, NULL, 0);
6003209f581SMatthew Dillon 		if (ap->ap_probe == ATA_PROBE_NEED_IDENT)
6013209f581SMatthew Dillon 			ahci_cam_probe(ap, NULL);
6023209f581SMatthew Dillon 	}
6033209f581SMatthew Dillon 	if (ap->ap_type != ATA_PORT_T_PM) {
6043209f581SMatthew Dillon 		if (ap->ap_probe == ATA_PROBE_FAILED) {
6053209f581SMatthew Dillon 			ahci_cam_changed(ap, NULL, 0);
606f4553de1SMatthew Dillon 		} else if (ap->ap_probe >= ATA_PROBE_NEED_IDENT) {
6073209f581SMatthew Dillon 			ahci_cam_changed(ap, NULL, 1);
6083209f581SMatthew Dillon 		}
6093209f581SMatthew Dillon 		return;
6103209f581SMatthew Dillon 	}
6113209f581SMatthew Dillon 
612831bc9e3SMatthew Dillon 	/*
613831bc9e3SMatthew Dillon 	 * Port Multiplier state machine.
614831bc9e3SMatthew Dillon 	 *
615831bc9e3SMatthew Dillon 	 * Get a mask of changed targets and combine with any runnable
616831bc9e3SMatthew Dillon 	 * states already present.
617831bc9e3SMatthew Dillon 	 */
618831bc9e3SMatthew Dillon 	for (loop = 0; ;++loop) {
6193209f581SMatthew Dillon 		if (ahci_pm_read(ap, 15, AHCI_PMREG_EINFO, &data)) {
6203209f581SMatthew Dillon 			kprintf("%s: PM unable to read hot-plug bitmap\n",
6213209f581SMatthew Dillon 				PORTNAME(ap));
6223209f581SMatthew Dillon 			break;
6233209f581SMatthew Dillon 		}
6243209f581SMatthew Dillon 		data &= (1 << ap->ap_pmcount) - 1;
6253209f581SMatthew Dillon 
6263209f581SMatthew Dillon 		/*
627831bc9e3SMatthew Dillon 		 * Do at least one loop, then stop if no more state changes
628831bc9e3SMatthew Dillon 		 * have occured.  The PM might not generate a new
629831bc9e3SMatthew Dillon 		 * notification until we clear the entire bitmap.
6303209f581SMatthew Dillon 		 */
631831bc9e3SMatthew Dillon 		if (loop && data == 0)
6323209f581SMatthew Dillon 			break;
6333209f581SMatthew Dillon 
6343209f581SMatthew Dillon 		/*
6353209f581SMatthew Dillon 		 * New devices showing up in the bitmap require some spin-up
6363209f581SMatthew Dillon 		 * time before we start probing them.  Reset didsleep.  The
6373209f581SMatthew Dillon 		 * first new device we detect will sleep before probing.
638831bc9e3SMatthew Dillon 		 *
639831bc9e3SMatthew Dillon 		 * This only applies to devices whos change bit is set in
640831bc9e3SMatthew Dillon 		 * the data, and does not apply to the initial boot-time
641831bc9e3SMatthew Dillon 		 * probe.
6423209f581SMatthew Dillon 		 */
6433209f581SMatthew Dillon 		didsleep = 0;
6443209f581SMatthew Dillon 
6453209f581SMatthew Dillon 		for (target = 0; target < ap->ap_pmcount; ++target) {
6463209f581SMatthew Dillon 			at = &ap->ap_ata[target];
6473209f581SMatthew Dillon 
6483209f581SMatthew Dillon 			/*
6493209f581SMatthew Dillon 			 * Check the target state for targets behind the PM
6503209f581SMatthew Dillon 			 * which have changed state.  This will adjust
6513209f581SMatthew Dillon 			 * at_probe and set ATA_PORT_F_RESCAN
6523209f581SMatthew Dillon 			 *
6531067474aSMatthew Dillon 			 * We want to wait at least 10 seconds before probing
6543209f581SMatthew Dillon 			 * a newly inserted device.  If the check status
6553209f581SMatthew Dillon 			 * indicates a device is present and in need of a
6563209f581SMatthew Dillon 			 * hard reset, we make sure we have slept before
6573209f581SMatthew Dillon 			 * continuing.
658831bc9e3SMatthew Dillon 			 *
6591067474aSMatthew Dillon 			 * We also need to wait at least 1 second for the
6601067474aSMatthew Dillon 			 * PHY state to change after insertion, if we
6611067474aSMatthew Dillon 			 * haven't already waited the 10 seconds.
6621067474aSMatthew Dillon 			 *
663831bc9e3SMatthew Dillon 			 * NOTE: When pm_check_good finds a good port it
664831bc9e3SMatthew Dillon 			 *	 typically starts us in probe state
665831bc9e3SMatthew Dillon 			 *	 NEED_HARD_RESET rather than INIT.
6663209f581SMatthew Dillon 			 */
6673209f581SMatthew Dillon 			if (data & (1 << target)) {
6681067474aSMatthew Dillon 				if (initial == 0 && didsleep == 0)
6691067474aSMatthew Dillon 					ahci_os_sleep(1000);
6703209f581SMatthew Dillon 				ahci_pm_check_good(ap, target);
671831bc9e3SMatthew Dillon 				if (initial == 0 && didsleep == 0 &&
672831bc9e3SMatthew Dillon 				    at->at_probe <= ATA_PROBE_NEED_HARD_RESET
673831bc9e3SMatthew Dillon 				) {
6743209f581SMatthew Dillon 					didsleep = 1;
675121d8e75SMatthew Dillon 					kprintf("%s: Waiting 10 seconds on insertion\n", PORTNAME(ap));
676121d8e75SMatthew Dillon 					ahci_os_sleep(10000);
6773209f581SMatthew Dillon 				}
6783209f581SMatthew Dillon 			}
679831bc9e3SMatthew Dillon 
680831bc9e3SMatthew Dillon 			/*
681831bc9e3SMatthew Dillon 			 * Report hot-plug events before the probe state
682831bc9e3SMatthew Dillon 			 * really gets hot.  Only actual events are reported
683831bc9e3SMatthew Dillon 			 * here to reduce spew.
684831bc9e3SMatthew Dillon 			 */
685831bc9e3SMatthew Dillon 			if (data & (1 << target)) {
686831bc9e3SMatthew Dillon 				kprintf("%s: HOTPLUG (PM) - ", ATANAME(ap, at));
687831bc9e3SMatthew Dillon 				switch(at->at_probe) {
688831bc9e3SMatthew Dillon 				case ATA_PROBE_NEED_INIT:
689831bc9e3SMatthew Dillon 				case ATA_PROBE_NEED_HARD_RESET:
690831bc9e3SMatthew Dillon 					kprintf("Device inserted\n");
691831bc9e3SMatthew Dillon 					break;
692831bc9e3SMatthew Dillon 				case ATA_PROBE_FAILED:
693831bc9e3SMatthew Dillon 					kprintf("Device removed\n");
694831bc9e3SMatthew Dillon 					break;
695831bc9e3SMatthew Dillon 				default:
696831bc9e3SMatthew Dillon 					kprintf("Device probe in progress\n");
697831bc9e3SMatthew Dillon 					break;
698831bc9e3SMatthew Dillon 				}
6993209f581SMatthew Dillon 			}
7003209f581SMatthew Dillon 
7013209f581SMatthew Dillon 			/*
702831bc9e3SMatthew Dillon 			 * Run through the state machine as necessary if
703831bc9e3SMatthew Dillon 			 * the port is not marked failed.
704831bc9e3SMatthew Dillon 			 *
705831bc9e3SMatthew Dillon 			 * The state machine may stop at NEED_IDENT if
706831bc9e3SMatthew Dillon 			 * CAM is not yet attached.
707831bc9e3SMatthew Dillon 			 *
708831bc9e3SMatthew Dillon 			 * Acquire exclusive access to the port while we
709831bc9e3SMatthew Dillon 			 * are doing this.  This prevents command-completion
710831bc9e3SMatthew Dillon 			 * from queueing commands for non-polled targets
711831bc9e3SMatthew Dillon 			 * inbetween our probe steps.  We need to do this
712831bc9e3SMatthew Dillon 			 * because the reset probes can generate severe PHY
713831bc9e3SMatthew Dillon 			 * and protocol errors and soft-brick the port.
7143209f581SMatthew Dillon 			 */
715831bc9e3SMatthew Dillon 			if (at->at_probe != ATA_PROBE_FAILED &&
716831bc9e3SMatthew Dillon 			    at->at_probe != ATA_PROBE_GOOD) {
717831bc9e3SMatthew Dillon 				ahci_beg_exclusive_access(ap, at);
7183209f581SMatthew Dillon 				if (at->at_probe == ATA_PROBE_NEED_INIT)
7193209f581SMatthew Dillon 					ahci_port_init(ap, at);
7203209f581SMatthew Dillon 				if (at->at_probe == ATA_PROBE_NEED_HARD_RESET)
7213209f581SMatthew Dillon 					ahci_port_reset(ap, at, 1);
7223209f581SMatthew Dillon 				if (at->at_probe == ATA_PROBE_NEED_SOFT_RESET)
7233209f581SMatthew Dillon 					ahci_port_reset(ap, at, 0);
7243209f581SMatthew Dillon 				if (at->at_probe == ATA_PROBE_NEED_IDENT)
7253209f581SMatthew Dillon 					ahci_cam_probe(ap, at);
726831bc9e3SMatthew Dillon 				ahci_end_exclusive_access(ap, at);
7273209f581SMatthew Dillon 			}
7283209f581SMatthew Dillon 
7293209f581SMatthew Dillon 			/*
730831bc9e3SMatthew Dillon 			 * Add or remove from CAM
7313209f581SMatthew Dillon 			 */
7323209f581SMatthew Dillon 			if (at->at_features & ATA_PORT_F_RESCAN) {
7333209f581SMatthew Dillon 				at->at_features &= ~ATA_PORT_F_RESCAN;
7343209f581SMatthew Dillon 				if (at->at_probe == ATA_PROBE_FAILED) {
7353209f581SMatthew Dillon 					ahci_cam_changed(ap, at, 0);
736f4553de1SMatthew Dillon 				} else if (at->at_probe >= ATA_PROBE_NEED_IDENT) {
7373209f581SMatthew Dillon 					ahci_cam_changed(ap, at, 1);
7383209f581SMatthew Dillon 				}
7393209f581SMatthew Dillon 			}
7403209f581SMatthew Dillon 		}
7413209f581SMatthew Dillon 	}
7423209f581SMatthew Dillon }
7433209f581SMatthew Dillon 
7443209f581SMatthew Dillon 
7453209f581SMatthew Dillon /*
746fd8bd957SMatthew Dillon  * De-initialize and detach a port.
747fd8bd957SMatthew Dillon  */
748258223a3SMatthew Dillon void
749258223a3SMatthew Dillon ahci_port_free(struct ahci_softc *sc, u_int port)
750258223a3SMatthew Dillon {
751258223a3SMatthew Dillon 	struct ahci_port		*ap = sc->sc_ports[port];
752258223a3SMatthew Dillon 	struct ahci_ccb			*ccb;
753258223a3SMatthew Dillon 
75417eab71eSMatthew Dillon 	/*
75517eab71eSMatthew Dillon 	 * Ensure port is disabled and its interrupts are all flushed.
75617eab71eSMatthew Dillon 	 */
757258223a3SMatthew Dillon 	if (ap->ap_sc) {
75817eab71eSMatthew Dillon 		ahci_port_stop(ap, 1);
759f4553de1SMatthew Dillon 		ahci_os_stop_port(ap);
760258223a3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CMD, 0);
761258223a3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IE, 0);
762258223a3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS, ahci_pread(ap, AHCI_PREG_IS));
763258223a3SMatthew Dillon 		ahci_write(sc, AHCI_REG_IS, 1 << port);
764258223a3SMatthew Dillon 	}
765258223a3SMatthew Dillon 
766258223a3SMatthew Dillon 	if (ap->ap_ccbs) {
767258223a3SMatthew Dillon 		while ((ccb = ahci_get_ccb(ap)) != NULL) {
768258223a3SMatthew Dillon 			if (ccb->ccb_dmamap) {
769258223a3SMatthew Dillon 				bus_dmamap_destroy(sc->sc_tag_data,
770258223a3SMatthew Dillon 						   ccb->ccb_dmamap);
771258223a3SMatthew Dillon 				ccb->ccb_dmamap = NULL;
772258223a3SMatthew Dillon 			}
773258223a3SMatthew Dillon 		}
7741067474aSMatthew Dillon 		if ((ccb = ap->ap_err_ccb) != NULL) {
7751067474aSMatthew Dillon 			if (ccb->ccb_dmamap) {
7761067474aSMatthew Dillon 				bus_dmamap_destroy(sc->sc_tag_data,
7771067474aSMatthew Dillon 						   ccb->ccb_dmamap);
7781067474aSMatthew Dillon 				ccb->ccb_dmamap = NULL;
7791067474aSMatthew Dillon 			}
7801067474aSMatthew Dillon 			ap->ap_err_ccb = NULL;
7811067474aSMatthew Dillon 		}
782258223a3SMatthew Dillon 		kfree(ap->ap_ccbs, M_DEVBUF);
783258223a3SMatthew Dillon 		ap->ap_ccbs = NULL;
784258223a3SMatthew Dillon 	}
785258223a3SMatthew Dillon 
786258223a3SMatthew Dillon 	if (ap->ap_dmamem_cmd_list) {
787258223a3SMatthew Dillon 		ahci_dmamem_free(sc, ap->ap_dmamem_cmd_list);
788258223a3SMatthew Dillon 		ap->ap_dmamem_cmd_list = NULL;
789258223a3SMatthew Dillon 	}
790258223a3SMatthew Dillon 	if (ap->ap_dmamem_rfis) {
791258223a3SMatthew Dillon 		ahci_dmamem_free(sc, ap->ap_dmamem_rfis);
792258223a3SMatthew Dillon 		ap->ap_dmamem_rfis = NULL;
793258223a3SMatthew Dillon 	}
794258223a3SMatthew Dillon 	if (ap->ap_dmamem_cmd_table) {
795258223a3SMatthew Dillon 		ahci_dmamem_free(sc, ap->ap_dmamem_cmd_table);
796258223a3SMatthew Dillon 		ap->ap_dmamem_cmd_table = NULL;
797258223a3SMatthew Dillon 	}
7981980eff3SMatthew Dillon 	if (ap->ap_ata) {
7991980eff3SMatthew Dillon 		kfree(ap->ap_ata, M_DEVBUF);
8001980eff3SMatthew Dillon 		ap->ap_ata = NULL;
8011980eff3SMatthew Dillon 	}
802258223a3SMatthew Dillon 
803258223a3SMatthew Dillon 	/* bus_space(9) says we dont free the subregions handle */
804258223a3SMatthew Dillon 
805258223a3SMatthew Dillon 	kfree(ap, M_DEVBUF);
806258223a3SMatthew Dillon 	sc->sc_ports[port] = NULL;
807258223a3SMatthew Dillon }
808258223a3SMatthew Dillon 
809fd8bd957SMatthew Dillon /*
810fd8bd957SMatthew Dillon  * Start high-level command processing on the port
811fd8bd957SMatthew Dillon  */
812258223a3SMatthew Dillon int
81317eab71eSMatthew Dillon ahci_port_start(struct ahci_port *ap)
814258223a3SMatthew Dillon {
8158bf6a3ffSMatthew Dillon 	u_int32_t	r, oldr, s, olds, is, oldis, tfd, oldtfd;
816258223a3SMatthew Dillon 
81717eab71eSMatthew Dillon 	/*
81817eab71eSMatthew Dillon 	 * FRE must be turned on before ST.  Wait for FR to go active
81917eab71eSMatthew Dillon 	 * before turning on ST.  The spec doesn't seem to think this
82017eab71eSMatthew Dillon 	 * is necessary but waiting here avoids an on-off race in the
82117eab71eSMatthew Dillon 	 * ahci_port_stop() code.
82217eab71eSMatthew Dillon 	 */
823cec07d75SMatthew Dillon 	 /* XXX REMOVE ME */
8241980eff3SMatthew Dillon 	olds = ahci_pread(ap, AHCI_PREG_SERR);
8251980eff3SMatthew Dillon 	oldis= ahci_pread(ap, AHCI_PREG_IS);
8268bf6a3ffSMatthew Dillon 	oldtfd = ahci_pread(ap, AHCI_PREG_TFD);
8271980eff3SMatthew Dillon 	oldr = r = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC;
82817eab71eSMatthew Dillon 	if ((r & AHCI_PREG_CMD_FRE) == 0) {
829258223a3SMatthew Dillon 		r |= AHCI_PREG_CMD_FRE;
83017eab71eSMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CMD, r);
83117eab71eSMatthew Dillon 	}
83217eab71eSMatthew Dillon 	if ((ap->ap_sc->sc_flags & AHCI_F_IGN_FR) == 0) {
83317eab71eSMatthew Dillon 		if (ahci_pwait_set(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_FR)) {
83417eab71eSMatthew Dillon 			kprintf("%s: Cannot start FIS reception\n",
83517eab71eSMatthew Dillon 				PORTNAME(ap));
83617eab71eSMatthew Dillon 			return (2);
83717eab71eSMatthew Dillon 		}
83817eab71eSMatthew Dillon 	}
83917eab71eSMatthew Dillon 
84017eab71eSMatthew Dillon 	/*
84117eab71eSMatthew Dillon 	 * Turn on ST, wait for CR to come up.
84217eab71eSMatthew Dillon 	 */
843258223a3SMatthew Dillon 	r |= AHCI_PREG_CMD_ST;
844258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_CMD, r);
84517eab71eSMatthew Dillon 	if (ahci_pwait_set(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_CR)) {
8468bf6a3ffSMatthew Dillon 		s = ahci_pread(ap, AHCI_PREG_SERR);
8478bf6a3ffSMatthew Dillon 		is = ahci_pread(ap, AHCI_PREG_IS);
8488bf6a3ffSMatthew Dillon 		tfd = ahci_pread(ap, AHCI_PREG_TFD);
8491980eff3SMatthew Dillon 		kprintf("%s: Cannot start command DMA\n"
8501980eff3SMatthew Dillon 			"OCMD=%b OSERR=%b\n"
8511980eff3SMatthew Dillon 			"NCMP=%b NSERR=%b\n"
8528bf6a3ffSMatthew Dillon 			"OLDIS=%b\nNEWIS=%b\n"
8538bf6a3ffSMatthew Dillon 			"OLDTFD=%b\nNEWTFD=%b\n",
8541980eff3SMatthew Dillon 			PORTNAME(ap),
8551980eff3SMatthew Dillon 			oldr, AHCI_PFMT_CMD, olds, AHCI_PFMT_SERR,
8561980eff3SMatthew Dillon 			r, AHCI_PFMT_CMD, s, AHCI_PFMT_SERR,
8578bf6a3ffSMatthew Dillon 			oldis, AHCI_PFMT_IS, is, AHCI_PFMT_IS,
8588bf6a3ffSMatthew Dillon 			oldtfd, AHCI_PFMT_TFD_STS, tfd, AHCI_PFMT_TFD_STS);
85917eab71eSMatthew Dillon 		return (1);
86017eab71eSMatthew Dillon 	}
861258223a3SMatthew Dillon 
862258223a3SMatthew Dillon #ifdef AHCI_COALESCE
86317eab71eSMatthew Dillon 	/*
86417eab71eSMatthew Dillon 	 * (Re-)enable coalescing on the port.
86517eab71eSMatthew Dillon 	 */
866258223a3SMatthew Dillon 	if (ap->ap_sc->sc_ccc_ports & (1 << ap->ap_num)) {
867258223a3SMatthew Dillon 		ap->ap_sc->sc_ccc_ports_cur |= (1 << ap->ap_num);
868258223a3SMatthew Dillon 		ahci_write(ap->ap_sc, AHCI_REG_CCC_PORTS,
869258223a3SMatthew Dillon 		    ap->ap_sc->sc_ccc_ports_cur);
870258223a3SMatthew Dillon 	}
871258223a3SMatthew Dillon #endif
872258223a3SMatthew Dillon 
873258223a3SMatthew Dillon 	return (0);
874258223a3SMatthew Dillon }
875258223a3SMatthew Dillon 
876fd8bd957SMatthew Dillon /*
877fd8bd957SMatthew Dillon  * Stop high-level command processing on a port
8784c339a5fSMatthew Dillon  *
8794c339a5fSMatthew Dillon  * WARNING!  If the port is stopped while CR is still active our saved
8804c339a5fSMatthew Dillon  *	     CI/SACT will race any commands completed by the command
8814c339a5fSMatthew Dillon  *	     processor prior to being able to stop.  Thus we never call
8824c339a5fSMatthew Dillon  *	     this function unless we intend to dispose of any remaining
8834c339a5fSMatthew Dillon  *	     active commands.  In particular, this complicates the timeout
8844c339a5fSMatthew Dillon  *	     code.
885fd8bd957SMatthew Dillon  */
886258223a3SMatthew Dillon int
887258223a3SMatthew Dillon ahci_port_stop(struct ahci_port *ap, int stop_fis_rx)
888258223a3SMatthew Dillon {
889258223a3SMatthew Dillon 	u_int32_t			r;
890258223a3SMatthew Dillon 
891258223a3SMatthew Dillon #ifdef AHCI_COALESCE
89217eab71eSMatthew Dillon 	/*
89317eab71eSMatthew Dillon 	 * Disable coalescing on the port while it is stopped.
89417eab71eSMatthew Dillon 	 */
895258223a3SMatthew Dillon 	if (ap->ap_sc->sc_ccc_ports & (1 << ap->ap_num)) {
896258223a3SMatthew Dillon 		ap->ap_sc->sc_ccc_ports_cur &= ~(1 << ap->ap_num);
897258223a3SMatthew Dillon 		ahci_write(ap->ap_sc, AHCI_REG_CCC_PORTS,
898258223a3SMatthew Dillon 		    ap->ap_sc->sc_ccc_ports_cur);
899258223a3SMatthew Dillon 	}
900258223a3SMatthew Dillon #endif
901258223a3SMatthew Dillon 
90217eab71eSMatthew Dillon 	/*
90317eab71eSMatthew Dillon 	 * Turn off ST, then wait for CR to go off.
90417eab71eSMatthew Dillon 	 */
905258223a3SMatthew Dillon 	r = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC;
906258223a3SMatthew Dillon 	r &= ~AHCI_PREG_CMD_ST;
907258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_CMD, r);
908258223a3SMatthew Dillon 
90917eab71eSMatthew Dillon 	if (ahci_pwait_clr(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_CR)) {
91017eab71eSMatthew Dillon 		kprintf("%s: Port bricked, unable to stop (ST)\n",
91117eab71eSMatthew Dillon 			PORTNAME(ap));
912258223a3SMatthew Dillon 		return (1);
91317eab71eSMatthew Dillon 	}
914258223a3SMatthew Dillon 
9151980eff3SMatthew Dillon #if 0
91617eab71eSMatthew Dillon 	/*
91717eab71eSMatthew Dillon 	 * Turn off FRE, then wait for FR to go off.  FRE cannot
91817eab71eSMatthew Dillon 	 * be turned off until CR transitions to 0.
91917eab71eSMatthew Dillon 	 */
9201980eff3SMatthew Dillon 	if ((r & AHCI_PREG_CMD_FR) == 0) {
9211980eff3SMatthew Dillon 		kprintf("%s: FR stopped, clear FRE for next start\n",
9221980eff3SMatthew Dillon 			PORTNAME(ap));
9231980eff3SMatthew Dillon 		stop_fis_rx = 2;
9241980eff3SMatthew Dillon 	}
9251980eff3SMatthew Dillon #endif
92617eab71eSMatthew Dillon 	if (stop_fis_rx) {
92717eab71eSMatthew Dillon 		r &= ~AHCI_PREG_CMD_FRE;
92817eab71eSMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CMD, r);
92917eab71eSMatthew Dillon 		if (ahci_pwait_clr(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_FR)) {
93017eab71eSMatthew Dillon 			kprintf("%s: Port bricked, unable to stop (FRE)\n",
93117eab71eSMatthew Dillon 				PORTNAME(ap));
932258223a3SMatthew Dillon 			return (2);
93317eab71eSMatthew Dillon 		}
93417eab71eSMatthew Dillon 	}
935258223a3SMatthew Dillon 
936258223a3SMatthew Dillon 	return (0);
937258223a3SMatthew Dillon }
938258223a3SMatthew Dillon 
939fd8bd957SMatthew Dillon /*
940fd8bd957SMatthew Dillon  * AHCI command list override -> forcibly clear TFD.STS.{BSY,DRQ}
941fd8bd957SMatthew Dillon  */
942258223a3SMatthew Dillon int
943258223a3SMatthew Dillon ahci_port_clo(struct ahci_port *ap)
944258223a3SMatthew Dillon {
945258223a3SMatthew Dillon 	struct ahci_softc		*sc = ap->ap_sc;
946258223a3SMatthew Dillon 	u_int32_t			cmd;
947258223a3SMatthew Dillon 
948258223a3SMatthew Dillon 	/* Only attempt CLO if supported by controller */
949258223a3SMatthew Dillon 	if ((ahci_read(sc, AHCI_REG_CAP) & AHCI_REG_CAP_SCLO) == 0)
950258223a3SMatthew Dillon 		return (1);
951258223a3SMatthew Dillon 
952258223a3SMatthew Dillon 	/* Issue CLO */
953258223a3SMatthew Dillon 	cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC;
954258223a3SMatthew Dillon #ifdef DIAGNOSTIC
955258223a3SMatthew Dillon 	if (cmd & AHCI_PREG_CMD_ST) {
956258223a3SMatthew Dillon 		kprintf("%s: CLO requested while port running\n",
957258223a3SMatthew Dillon 			PORTNAME(ap));
958258223a3SMatthew Dillon 	}
959258223a3SMatthew Dillon #endif
960258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_CMD, cmd | AHCI_PREG_CMD_CLO);
961258223a3SMatthew Dillon 
962258223a3SMatthew Dillon 	/* Wait for completion */
963258223a3SMatthew Dillon 	if (ahci_pwait_clr(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_CLO)) {
964258223a3SMatthew Dillon 		kprintf("%s: CLO did not complete\n", PORTNAME(ap));
965258223a3SMatthew Dillon 		return (1);
966258223a3SMatthew Dillon 	}
967258223a3SMatthew Dillon 
968258223a3SMatthew Dillon 	return (0);
969258223a3SMatthew Dillon }
970258223a3SMatthew Dillon 
971fd8bd957SMatthew Dillon /*
9721980eff3SMatthew Dillon  * Reset a port.
97317eab71eSMatthew Dillon  *
9741980eff3SMatthew Dillon  * If hard is 0 perform a softreset of the port.
97517eab71eSMatthew Dillon  * If hard is 1 perform a hard reset of the port.
9761980eff3SMatthew Dillon  * If hard is 2 perform a hard reset of the port and cycle the phy.
9771980eff3SMatthew Dillon  *
9781980eff3SMatthew Dillon  * If at is non-NULL an indirect port via a port-multiplier is being
9791980eff3SMatthew Dillon  * reset, otherwise a direct port is being reset.
9801980eff3SMatthew Dillon  *
9811980eff3SMatthew Dillon  * NOTE: Indirect ports can only be soft-reset.
98217eab71eSMatthew Dillon  */
98317eab71eSMatthew Dillon int
9841980eff3SMatthew Dillon ahci_port_reset(struct ahci_port *ap, struct ata_port *at, int hard)
98517eab71eSMatthew Dillon {
98617eab71eSMatthew Dillon 	int rc;
98717eab71eSMatthew Dillon 
98817eab71eSMatthew Dillon 	if (hard) {
9891980eff3SMatthew Dillon 		if (at)
9901980eff3SMatthew Dillon 			rc = ahci_pm_hardreset(ap, at->at_target, hard);
9911980eff3SMatthew Dillon 		else
9921980eff3SMatthew Dillon 			rc = ahci_port_hardreset(ap, hard);
99317eab71eSMatthew Dillon 	} else {
9941980eff3SMatthew Dillon 		if (at)
9951980eff3SMatthew Dillon 			rc = ahci_pm_softreset(ap, at->at_target);
9961980eff3SMatthew Dillon 		else
99717eab71eSMatthew Dillon 			rc = ahci_port_softreset(ap);
99817eab71eSMatthew Dillon 	}
99917eab71eSMatthew Dillon 	return(rc);
100017eab71eSMatthew Dillon }
100117eab71eSMatthew Dillon 
100217eab71eSMatthew Dillon /*
1003fd8bd957SMatthew Dillon  * AHCI soft reset, Section 10.4.1
1004fd8bd957SMatthew Dillon  *
10051980eff3SMatthew Dillon  * (at) will be NULL when soft-resetting a directly-attached device, and
10061980eff3SMatthew Dillon  * non-NULL when soft-resetting a device through a port multiplier.
10071980eff3SMatthew Dillon  *
1008fd8bd957SMatthew Dillon  * This function keeps port communications intact and attempts to generate
10091980eff3SMatthew Dillon  * a reset to the connected device using device commands.
1010fd8bd957SMatthew Dillon  */
1011258223a3SMatthew Dillon int
1012258223a3SMatthew Dillon ahci_port_softreset(struct ahci_port *ap)
1013258223a3SMatthew Dillon {
1014258223a3SMatthew Dillon 	struct ahci_ccb		*ccb = NULL;
1015258223a3SMatthew Dillon 	struct ahci_cmd_hdr	*cmd_slot;
1016258223a3SMatthew Dillon 	u_int8_t		*fis;
10173209f581SMatthew Dillon 	int			error;
1018258223a3SMatthew Dillon 
10193209f581SMatthew Dillon 	error = EIO;
10201980eff3SMatthew Dillon 
1021*074579dfSMatthew Dillon 	if (bootverbose) {
10221980eff3SMatthew Dillon 		kprintf("%s: START SOFTRESET %b\n", PORTNAME(ap),
10231980eff3SMatthew Dillon 			ahci_pread(ap, AHCI_PREG_CMD), AHCI_PFMT_CMD);
1024*074579dfSMatthew Dillon 	}
10251980eff3SMatthew Dillon 
1026258223a3SMatthew Dillon 	DPRINTF(AHCI_D_VERBOSE, "%s: soft reset\n", PORTNAME(ap));
1027258223a3SMatthew Dillon 
1028258223a3SMatthew Dillon 	crit_enter();
10291980eff3SMatthew Dillon 	ap->ap_flags |= AP_F_IN_RESET;
10301980eff3SMatthew Dillon 	ap->ap_state = AP_S_NORMAL;
1031258223a3SMatthew Dillon 
10321980eff3SMatthew Dillon 	/*
10331980eff3SMatthew Dillon 	 * Remember port state in cmd (main to restore start/stop)
10341980eff3SMatthew Dillon 	 *
10351980eff3SMatthew Dillon 	 * Idle port.
10361980eff3SMatthew Dillon 	 */
1037258223a3SMatthew Dillon 	if (ahci_port_stop(ap, 0)) {
1038258223a3SMatthew Dillon 		kprintf("%s: failed to stop port, cannot softreset\n",
1039258223a3SMatthew Dillon 			PORTNAME(ap));
1040258223a3SMatthew Dillon 		goto err;
1041258223a3SMatthew Dillon 	}
1042cf5f3a81SMatthew Dillon 
1043cf5f3a81SMatthew Dillon 	/*
10441980eff3SMatthew Dillon 	 * Request CLO if device appears hung.
1045cf5f3a81SMatthew Dillon 	 */
1046258223a3SMatthew Dillon 	if (ahci_pread(ap, AHCI_PREG_TFD) &
1047258223a3SMatthew Dillon 		   (AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) {
1048258223a3SMatthew Dillon 		ahci_port_clo(ap);
1049258223a3SMatthew Dillon 	}
1050258223a3SMatthew Dillon 
10511980eff3SMatthew Dillon 	/*
10521980eff3SMatthew Dillon 	 * This is an attempt to clear errors so a new signature will
10531980eff3SMatthew Dillon 	 * be latched.  It isn't working properly.  XXX
10541980eff3SMatthew Dillon 	 */
1055cf5f3a81SMatthew Dillon 	ahci_flush_tfd(ap);
10561980eff3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SERR, -1);
1057258223a3SMatthew Dillon 
1058258223a3SMatthew Dillon 	/* Restart port */
105917eab71eSMatthew Dillon 	if (ahci_port_start(ap)) {
1060258223a3SMatthew Dillon 		kprintf("%s: failed to start port, cannot softreset\n",
1061258223a3SMatthew Dillon 		        PORTNAME(ap));
1062258223a3SMatthew Dillon 		goto err;
1063258223a3SMatthew Dillon 	}
1064258223a3SMatthew Dillon 
1065258223a3SMatthew Dillon 	/* Check whether CLO worked */
1066258223a3SMatthew Dillon 	if (ahci_pwait_clr(ap, AHCI_PREG_TFD,
1067258223a3SMatthew Dillon 			       AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) {
1068258223a3SMatthew Dillon 		kprintf("%s: CLO %s, need port reset\n",
1069258223a3SMatthew Dillon 			PORTNAME(ap),
1070258223a3SMatthew Dillon 			(ahci_read(ap->ap_sc, AHCI_REG_CAP) & AHCI_REG_CAP_SCLO)
1071258223a3SMatthew Dillon 			? "failed" : "unsupported");
10723209f581SMatthew Dillon 		error = EBUSY;
1073258223a3SMatthew Dillon 		goto err;
1074258223a3SMatthew Dillon 	}
1075258223a3SMatthew Dillon 
1076cec85a37SMatthew Dillon 	/*
1077cec85a37SMatthew Dillon 	 * Prep first D2H command with SRST feature & clear busy/reset flags
1078cec85a37SMatthew Dillon 	 *
1079cec85a37SMatthew Dillon 	 * It is unclear which other fields in the FIS are used.  Just zero
1080cec85a37SMatthew Dillon 	 * everything.
10811067474aSMatthew Dillon 	 *
10821067474aSMatthew Dillon 	 * NOTE!  This CCB is used for both the first and second commands.
10831067474aSMatthew Dillon 	 *	  The second command must use CCB slot 1 to properly load
10841067474aSMatthew Dillon 	 *	  the signature.
1085cec85a37SMatthew Dillon 	 */
1086258223a3SMatthew Dillon 	ccb = ahci_get_err_ccb(ap);
10871067474aSMatthew Dillon 	KKASSERT(ccb->ccb_slot == 1);
10881980eff3SMatthew Dillon 	ccb->ccb_xa.at = NULL;
1089258223a3SMatthew Dillon 	cmd_slot = ccb->ccb_cmd_hdr;
1090258223a3SMatthew Dillon 
1091258223a3SMatthew Dillon 	fis = ccb->ccb_cmd_table->cfis;
1092cec85a37SMatthew Dillon 	bzero(fis, sizeof(ccb->ccb_cmd_table->cfis));
10931980eff3SMatthew Dillon 	fis[0] = ATA_FIS_TYPE_H2D;
10941980eff3SMatthew Dillon 	fis[15] = ATA_FIS_CONTROL_SRST|ATA_FIS_CONTROL_4BIT;
1095258223a3SMatthew Dillon 
1096258223a3SMatthew Dillon 	cmd_slot->prdtl = 0;
1097258223a3SMatthew Dillon 	cmd_slot->flags = htole16(5);	/* FIS length: 5 DWORDS */
1098258223a3SMatthew Dillon 	cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_C); /* Clear busy on OK */
1099258223a3SMatthew Dillon 	cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_R); /* Reset */
1100258223a3SMatthew Dillon 
1101258223a3SMatthew Dillon 	ccb->ccb_xa.state = ATA_S_PENDING;
11025f8c1efdSMatthew Dillon 	ccb->ccb_xa.flags = 0;
1103831bc9e3SMatthew Dillon 	if (ahci_poll(ccb, 1000, ahci_quick_timeout) != ATA_S_COMPLETE) {
11045f8c1efdSMatthew Dillon 		kprintf("%s: First FIS failed\n", PORTNAME(ap));
1105258223a3SMatthew Dillon 		goto err;
1106cec85a37SMatthew Dillon 	}
1107258223a3SMatthew Dillon 
1108cec85a37SMatthew Dillon 	/*
1109831bc9e3SMatthew Dillon 	 * WARNING!	TIME SENSITIVE SPACE!	WARNING!
1110831bc9e3SMatthew Dillon 	 *
1111831bc9e3SMatthew Dillon 	 * The two FISes are supposed to be back to back.  Don't issue other
1112831bc9e3SMatthew Dillon 	 * commands or even delay if we can help it.
11131980eff3SMatthew Dillon 	 */
11141980eff3SMatthew Dillon 
11151980eff3SMatthew Dillon 	/*
1116cec85a37SMatthew Dillon 	 * Prep second D2H command to read status and complete reset sequence
1117cec85a37SMatthew Dillon 	 * AHCI 10.4.1 and "Serial ATA Revision 2.6".  I can't find the ATA
1118cec85a37SMatthew Dillon 	 * Rev 2.6 and it is unclear how the second FIS should be set up
1119cec85a37SMatthew Dillon 	 * from the AHCI document.
1120cec85a37SMatthew Dillon 	 *
1121b089d0bfSMatthew Dillon 	 * Give the device 3ms before sending the second FIS.
1122cec85a37SMatthew Dillon 	 *
1123cec85a37SMatthew Dillon 	 * It is unclear which other fields in the FIS are used.  Just zero
1124cec85a37SMatthew Dillon 	 * everything.
1125cec85a37SMatthew Dillon 	 */
1126cec85a37SMatthew Dillon 	bzero(fis, sizeof(ccb->ccb_cmd_table->cfis));
11271980eff3SMatthew Dillon 	fis[0] = ATA_FIS_TYPE_H2D;
11281980eff3SMatthew Dillon 	fis[15] = ATA_FIS_CONTROL_4BIT;
1129258223a3SMatthew Dillon 
1130258223a3SMatthew Dillon 	cmd_slot->prdtl = 0;
1131258223a3SMatthew Dillon 	cmd_slot->flags = htole16(5);	/* FIS length: 5 DWORDS */
1132258223a3SMatthew Dillon 
1133258223a3SMatthew Dillon 	ccb->ccb_xa.state = ATA_S_PENDING;
11345f8c1efdSMatthew Dillon 	ccb->ccb_xa.flags = 0;
1135831bc9e3SMatthew Dillon 	if (ahci_poll(ccb, 1000, ahci_quick_timeout) != ATA_S_COMPLETE) {
11365f8c1efdSMatthew Dillon 		kprintf("%s: Second FIS failed\n", PORTNAME(ap));
1137258223a3SMatthew Dillon 		goto err;
1138cec85a37SMatthew Dillon 	}
1139258223a3SMatthew Dillon 
11401980eff3SMatthew Dillon 	if (ahci_pwait_clr(ap, AHCI_PREG_TFD,
11411980eff3SMatthew Dillon 			    AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) {
1142258223a3SMatthew Dillon 		kprintf("%s: device didn't come ready after reset, TFD: 0x%b\n",
1143258223a3SMatthew Dillon 			PORTNAME(ap),
1144258223a3SMatthew Dillon 			ahci_pread(ap, AHCI_PREG_TFD), AHCI_PFMT_TFD_STS);
11453209f581SMatthew Dillon 		error = EBUSY;
1146258223a3SMatthew Dillon 		goto err;
1147258223a3SMatthew Dillon 	}
11483209f581SMatthew Dillon 	ahci_os_sleep(10);
1149258223a3SMatthew Dillon 
1150fd8bd957SMatthew Dillon 	/*
1151fd8bd957SMatthew Dillon 	 * If the softreset is trying to clear a BSY condition after a
1152fd8bd957SMatthew Dillon 	 * normal portreset we assign the port type.
1153fd8bd957SMatthew Dillon 	 *
1154fd8bd957SMatthew Dillon 	 * If the softreset is being run first as part of the ccb error
1155fd8bd957SMatthew Dillon 	 * processing code then report if the device signature changed
1156fd8bd957SMatthew Dillon 	 * unexpectedly.
1157fd8bd957SMatthew Dillon 	 */
11581980eff3SMatthew Dillon 	if (ap->ap_type == ATA_PORT_T_NONE) {
11591980eff3SMatthew Dillon 		ap->ap_type = ahci_port_signature_detect(ap, NULL);
1160fd8bd957SMatthew Dillon 	} else {
11611980eff3SMatthew Dillon 		if (ahci_port_signature_detect(ap, NULL) != ap->ap_type) {
11621980eff3SMatthew Dillon 			kprintf("%s: device signature unexpectedly "
11631980eff3SMatthew Dillon 				"changed\n", PORTNAME(ap));
11643209f581SMatthew Dillon 			error = EBUSY; /* XXX */
1165fd8bd957SMatthew Dillon 		}
1166fd8bd957SMatthew Dillon 	}
11673209f581SMatthew Dillon 	error = 0;
11681980eff3SMatthew Dillon 
11693209f581SMatthew Dillon 	ahci_os_sleep(3);
1170258223a3SMatthew Dillon err:
1171258223a3SMatthew Dillon 	if (ccb != NULL) {
1172258223a3SMatthew Dillon 		ahci_put_err_ccb(ccb);
11731980eff3SMatthew Dillon 
11741980eff3SMatthew Dillon 		/*
11751980eff3SMatthew Dillon 		 * If the target is busy use CLO to clear the busy
11761980eff3SMatthew Dillon 		 * condition.  The BSY should be cleared on the next
11771980eff3SMatthew Dillon 		 * start.
11781980eff3SMatthew Dillon 		 */
11791980eff3SMatthew Dillon 		if (ahci_pread(ap, AHCI_PREG_TFD) &
11801980eff3SMatthew Dillon 		    (AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) {
11811980eff3SMatthew Dillon 			ahci_port_clo(ap);
11821980eff3SMatthew Dillon 		}
1183258223a3SMatthew Dillon 	}
1184258223a3SMatthew Dillon 
1185cf5f3a81SMatthew Dillon 	/*
1186cf5f3a81SMatthew Dillon 	 * If we failed to softreset make the port quiescent, otherwise
1187cf5f3a81SMatthew Dillon 	 * make sure the port's start/stop state matches what it was on
1188cf5f3a81SMatthew Dillon 	 * entry.
11891980eff3SMatthew Dillon 	 *
11901980eff3SMatthew Dillon 	 * Don't kill the port if the softreset is on a port multiplier
11911980eff3SMatthew Dillon 	 * target, that would kill all the targets!
1192cf5f3a81SMatthew Dillon 	 */
11933209f581SMatthew Dillon 	if (error) {
1194cf5f3a81SMatthew Dillon 		ahci_port_hardstop(ap);
11953209f581SMatthew Dillon 		/* ap_probe set to failed */
1196cf5f3a81SMatthew Dillon 	} else {
11973209f581SMatthew Dillon 		ap->ap_probe = ATA_PROBE_NEED_IDENT;
11984c339a5fSMatthew Dillon 		ahci_port_start(ap);
1199cf5f3a81SMatthew Dillon 	}
12003209f581SMatthew Dillon 	ap->ap_flags &= ~AP_F_IN_RESET;
1201258223a3SMatthew Dillon 	crit_exit();
1202258223a3SMatthew Dillon 
1203*074579dfSMatthew Dillon 	if (bootverbose)
12041980eff3SMatthew Dillon 		kprintf("%s: END SOFTRESET\n", PORTNAME(ap));
12051980eff3SMatthew Dillon 
12063209f581SMatthew Dillon 	return (error);
1207258223a3SMatthew Dillon }
1208258223a3SMatthew Dillon 
1209fd8bd957SMatthew Dillon /*
1210fd8bd957SMatthew Dillon  * AHCI port reset, Section 10.4.2
1211fd8bd957SMatthew Dillon  *
1212fd8bd957SMatthew Dillon  * This function does a hard reset of the port.  Note that the device
1213fd8bd957SMatthew Dillon  * connected to the port could still end-up hung.
1214fd8bd957SMatthew Dillon  */
1215258223a3SMatthew Dillon int
12161980eff3SMatthew Dillon ahci_port_hardreset(struct ahci_port *ap, int hard)
1217258223a3SMatthew Dillon {
1218258223a3SMatthew Dillon 	u_int32_t cmd, r;
12193209f581SMatthew Dillon 	int	error;
12201980eff3SMatthew Dillon 	int	loop;
12211980eff3SMatthew Dillon 	int	type;
1222258223a3SMatthew Dillon 
1223258223a3SMatthew Dillon 	DPRINTF(AHCI_D_VERBOSE, "%s: port reset\n", PORTNAME(ap));
1224258223a3SMatthew Dillon 
12251980eff3SMatthew Dillon 	ap->ap_flags |= AP_F_IN_RESET;
1226cf5f3a81SMatthew Dillon 
1227cf5f3a81SMatthew Dillon 	/*
12281980eff3SMatthew Dillon 	 * Idle the port,
12291980eff3SMatthew Dillon 	 */
12301980eff3SMatthew Dillon 	ahci_port_stop(ap, 0);
12311980eff3SMatthew Dillon 	ap->ap_state = AP_S_NORMAL;
12323209f581SMatthew Dillon 	error = 0;
12331980eff3SMatthew Dillon 
12341980eff3SMatthew Dillon 	/*
12351980eff3SMatthew Dillon 	 * The port may have been quiescent with its SUD bit cleared, so
12361980eff3SMatthew Dillon 	 * set the SUD (spin up device).
1237cf5f3a81SMatthew Dillon 	 */
1238cf5f3a81SMatthew Dillon 	cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC;
1239cf5f3a81SMatthew Dillon 	cmd |= AHCI_PREG_CMD_SUD;
1240cf5f3a81SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_CMD, cmd);
1241258223a3SMatthew Dillon 
12421980eff3SMatthew Dillon 	/*
12431980eff3SMatthew Dillon 	 * Perform device detection.  Cycle the PHY off, wait 10ms.
12441980eff3SMatthew Dillon 	 * This simulates the SATA cable being physically unplugged.
12451067474aSMatthew Dillon 	 *
12461067474aSMatthew Dillon 	 * NOTE: hard reset mode 2 (cycling the PHY) is not reliable
12471067474aSMatthew Dillon 	 *       and not currently used.
12481980eff3SMatthew Dillon 	 */
12491980eff3SMatthew Dillon 	ap->ap_type = ATA_PORT_T_NONE;
1250258223a3SMatthew Dillon 
12511980eff3SMatthew Dillon 	r = AHCI_PREG_SCTL_IPM_DISABLED;
12521980eff3SMatthew Dillon 	if (hard == 2)
12531980eff3SMatthew Dillon 		r |= AHCI_PREG_SCTL_DET_DISABLE;
12541980eff3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SCTL, r);
12553209f581SMatthew Dillon 	ahci_os_sleep(10);
12561980eff3SMatthew Dillon 
12571980eff3SMatthew Dillon 	/*
12581980eff3SMatthew Dillon 	 * Start transmitting COMRESET.  COMRESET must be sent for at
12591980eff3SMatthew Dillon 	 * least 1ms.
12601980eff3SMatthew Dillon 	 */
12611980eff3SMatthew Dillon 	r = AHCI_PREG_SCTL_IPM_DISABLED | AHCI_PREG_SCTL_DET_INIT;
1262*074579dfSMatthew Dillon 	if (AhciForceGen1 & (1 << ap->ap_num))
1263258223a3SMatthew Dillon 		r |= AHCI_PREG_SCTL_SPD_GEN1;
1264*074579dfSMatthew Dillon 	else
1265258223a3SMatthew Dillon 		r |= AHCI_PREG_SCTL_SPD_ANY;
1266258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SCTL, r);
1267831bc9e3SMatthew Dillon 
1268831bc9e3SMatthew Dillon 	/*
1269831bc9e3SMatthew Dillon 	 * Through trial and error it seems to take around 100ms
1270831bc9e3SMatthew Dillon 	 * for the detect logic to settle down.  If this is too
1271831bc9e3SMatthew Dillon 	 * short the softreset code will fail.
1272831bc9e3SMatthew Dillon 	 */
1273831bc9e3SMatthew Dillon 	ahci_os_sleep(100);
1274cf5f3a81SMatthew Dillon 
1275cf5f3a81SMatthew Dillon 	/*
1276cf5f3a81SMatthew Dillon 	 * Only SERR_DIAG_X needs to be cleared for TFD updates, but
1277cf5f3a81SMatthew Dillon 	 * since we are hard-resetting the port we might as well clear
1278cf5f3a81SMatthew Dillon 	 * the whole enchillada
1279cf5f3a81SMatthew Dillon 	 */
1280cf5f3a81SMatthew Dillon 	ahci_flush_tfd(ap);
1281cf5f3a81SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SERR, -1);
1282258223a3SMatthew Dillon 	r &= ~AHCI_PREG_SCTL_DET_INIT;
1283258223a3SMatthew Dillon 	r |= AHCI_PREG_SCTL_DET_NONE;
1284258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SCTL, r);
1285258223a3SMatthew Dillon 
12861980eff3SMatthew Dillon 	/*
12871980eff3SMatthew Dillon 	 * Try to determine if there is a device on the port.
12881980eff3SMatthew Dillon 	 *
12891980eff3SMatthew Dillon 	 * Give the device 3/10 second to at least be detected.
12901980eff3SMatthew Dillon 	 * If we fail clear PRCS (phy detect) since we may cycled
12911980eff3SMatthew Dillon 	 * the phy and probably caused another PRCS interrupt.
12921980eff3SMatthew Dillon 	 */
12931980eff3SMatthew Dillon 	for (loop = 30; loop; --loop) {
12941980eff3SMatthew Dillon 		r = ahci_pread(ap, AHCI_PREG_SSTS);
12951980eff3SMatthew Dillon 		if (r & AHCI_PREG_SSTS_DET)
12961980eff3SMatthew Dillon 			break;
12973209f581SMatthew Dillon 		ahci_os_sleep(10);
12981980eff3SMatthew Dillon 	}
12991980eff3SMatthew Dillon 	if (loop == 0) {
13001980eff3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_PRCS);
1301*074579dfSMatthew Dillon 		if (bootverbose) {
13021980eff3SMatthew Dillon 			kprintf("%s: Port appears to be unplugged\n",
13031980eff3SMatthew Dillon 				PORTNAME(ap));
1304*074579dfSMatthew Dillon 		}
13053209f581SMatthew Dillon 		error = ENODEV;
1306258223a3SMatthew Dillon 	}
1307258223a3SMatthew Dillon 
1308cec85a37SMatthew Dillon 	/*
13091980eff3SMatthew Dillon 	 * There is something on the port.  Give the device 3 seconds
13101980eff3SMatthew Dillon 	 * to fully negotiate.
13111980eff3SMatthew Dillon 	 */
13123209f581SMatthew Dillon 	if (error == 0 &&
13131980eff3SMatthew Dillon 	    ahci_pwait_eq(ap, 3000, AHCI_PREG_SSTS,
13141980eff3SMatthew Dillon 			  AHCI_PREG_SSTS_DET, AHCI_PREG_SSTS_DET_DEV)) {
1315*074579dfSMatthew Dillon 		if (bootverbose) {
13161980eff3SMatthew Dillon 			kprintf("%s: Device may be powered down\n",
13171980eff3SMatthew Dillon 				PORTNAME(ap));
1318*074579dfSMatthew Dillon 		}
13193209f581SMatthew Dillon 		error = ENODEV;
13201980eff3SMatthew Dillon 	}
13211980eff3SMatthew Dillon 
1322c408a8b3SMatthew Dillon 	ahci_flush_tfd(ap);
1323c408a8b3SMatthew Dillon 
13241980eff3SMatthew Dillon 	/*
13251980eff3SMatthew Dillon 	 * Wait for the device to become ready.
1326cec85a37SMatthew Dillon 	 *
1327b089d0bfSMatthew Dillon 	 * This can take more then a second, give it 3 seconds.  If we
1328b089d0bfSMatthew Dillon 	 * succeed give the device another 3ms after that.
13291980eff3SMatthew Dillon 	 *
13303209f581SMatthew Dillon 	 * NOTE: Port multipliers can do two things here.  First they can
13311980eff3SMatthew Dillon 	 *	 return device-ready if a device is on target 0 and also
13321980eff3SMatthew Dillon 	 *	 return the signature for that device.  If there is no
13331980eff3SMatthew Dillon 	 *	 device on target 0 then BSY/DRQ is never cleared and
13341980eff3SMatthew Dillon 	 *	 it never comes ready.
1335cec85a37SMatthew Dillon 	 */
13363209f581SMatthew Dillon 	if (error == 0 &&
13371980eff3SMatthew Dillon 	    ahci_pwait_clr_to(ap, 3000, AHCI_PREG_TFD,
13381980eff3SMatthew Dillon 			    AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) {
13391980eff3SMatthew Dillon 		/*
13401980eff3SMatthew Dillon 		 * The device is bricked or its a port multiplier and will
13411980eff3SMatthew Dillon 		 * not unbusy until we do the pmprobe CLO softreset sequence.
13421980eff3SMatthew Dillon 		 */
13433209f581SMatthew Dillon 		error = ahci_port_pmprobe(ap);
13443209f581SMatthew Dillon 		if (error) {
1345258223a3SMatthew Dillon 			kprintf("%s: Device will not come ready 0x%b\n",
1346258223a3SMatthew Dillon 				PORTNAME(ap),
13471980eff3SMatthew Dillon 				ahci_pread(ap, AHCI_PREG_TFD),
13481980eff3SMatthew Dillon 				AHCI_PFMT_TFD_STS);
13491980eff3SMatthew Dillon 		} else {
13501980eff3SMatthew Dillon 			ap->ap_type = ATA_PORT_T_PM;
1351258223a3SMatthew Dillon 		}
13523209f581SMatthew Dillon 	} else if (error == 0) {
13531980eff3SMatthew Dillon 		/*
13541980eff3SMatthew Dillon 		 * We generally will not get a port multiplier signature in
13551980eff3SMatthew Dillon 		 * this case even if this is a port multiplier, because of
13561980eff3SMatthew Dillon 		 * Intel's stupidity.  We almost certainly got target 0
13571980eff3SMatthew Dillon 		 * behind the PM, if there is a PM.
13581980eff3SMatthew Dillon 		 *
13591980eff3SMatthew Dillon 		 * Save the signature and probe for a PM.  If we do not
13601980eff3SMatthew Dillon 		 * find a PM then use the saved signature and return
13611980eff3SMatthew Dillon 		 * success.
13621980eff3SMatthew Dillon 		 */
13631980eff3SMatthew Dillon 		type = ahci_port_signature_detect(ap, NULL);
13643209f581SMatthew Dillon 		error = ahci_port_pmprobe(ap);
13653209f581SMatthew Dillon 		if (error) {
13661980eff3SMatthew Dillon 			ap->ap_type = type;
13673209f581SMatthew Dillon 			error = 0;
13681980eff3SMatthew Dillon 		} else {
13691980eff3SMatthew Dillon 			ap->ap_type = ATA_PORT_T_PM;
13703209f581SMatthew Dillon 			kprintf("%s: Port multiplier detected\n",
13711980eff3SMatthew Dillon 				PORTNAME(ap));
13721980eff3SMatthew Dillon 		}
13731980eff3SMatthew Dillon 	}
1374258223a3SMatthew Dillon 
1375cf5f3a81SMatthew Dillon 	/*
13761980eff3SMatthew Dillon 	 * hard-stop the port if we failed.  This will set ap_probe
13771980eff3SMatthew Dillon 	 * to FAILED.
1378cf5f3a81SMatthew Dillon 	 */
13791980eff3SMatthew Dillon 	ap->ap_flags &= ~AP_F_IN_RESET;
13803209f581SMatthew Dillon 	if (error) {
13813209f581SMatthew Dillon 		ahci_port_hardstop(ap);
13823209f581SMatthew Dillon 		/* ap_probe set to failed */
13833209f581SMatthew Dillon 	} else {
1384f4553de1SMatthew Dillon 		if (ap->ap_type == ATA_PORT_T_PM)
1385f4553de1SMatthew Dillon 			ap->ap_probe = ATA_PROBE_GOOD;
1386f4553de1SMatthew Dillon 		else
1387f4553de1SMatthew Dillon 			ap->ap_probe = ATA_PROBE_NEED_SOFT_RESET;
13883209f581SMatthew Dillon 	}
13893209f581SMatthew Dillon 	return (error);
1390258223a3SMatthew Dillon }
1391258223a3SMatthew Dillon 
1392fd8bd957SMatthew Dillon /*
13931980eff3SMatthew Dillon  * AHCI port multiplier probe.  This routine is run by the hardreset code
13941980eff3SMatthew Dillon  * if it gets past the device detect, whether or not BSY is found to be
13951980eff3SMatthew Dillon  * stuck.
13961980eff3SMatthew Dillon  *
13971980eff3SMatthew Dillon  * We MUST use CLO to properly probe whether the port multiplier exists
13981980eff3SMatthew Dillon  * or not.
13991980eff3SMatthew Dillon  *
14001980eff3SMatthew Dillon  * Return 0 on success, non-zero on failure.
14011980eff3SMatthew Dillon  */
14021980eff3SMatthew Dillon int
14031980eff3SMatthew Dillon ahci_port_pmprobe(struct ahci_port *ap)
14041980eff3SMatthew Dillon {
14051980eff3SMatthew Dillon 	struct ahci_cmd_hdr *cmd_slot;
14061067474aSMatthew Dillon 	struct ata_port	*at;
14071980eff3SMatthew Dillon 	struct ahci_ccb	*ccb = NULL;
14081980eff3SMatthew Dillon 	u_int8_t	*fis = NULL;
1409831bc9e3SMatthew Dillon 	int		error = EIO;
14101980eff3SMatthew Dillon 	u_int32_t	cmd;
14111980eff3SMatthew Dillon 	int		count;
14121067474aSMatthew Dillon 	int		i;
14131980eff3SMatthew Dillon 
14141980eff3SMatthew Dillon 	/*
14151980eff3SMatthew Dillon 	 * If we don't support port multipliers don't try to detect one.
14161980eff3SMatthew Dillon 	 */
14171980eff3SMatthew Dillon 	if ((ap->ap_sc->sc_cap & AHCI_REG_CAP_SPM) == 0)
14181980eff3SMatthew Dillon 		return (ENODEV);
14191980eff3SMatthew Dillon 
14201980eff3SMatthew Dillon 	count = 2;
14211980eff3SMatthew Dillon retry:
14221980eff3SMatthew Dillon 	/*
14231980eff3SMatthew Dillon 	 * This code is only called from hardreset, which does not
14241980eff3SMatthew Dillon 	 * high level command processing.  The port should be stopped.
14251980eff3SMatthew Dillon 	 *
14261980eff3SMatthew Dillon 	 * Set PMA mode while the port is stopped.
14271980eff3SMatthew Dillon 	 *
14281980eff3SMatthew Dillon 	 * NOTE: On retry the port might be running, stopped, or failed.
14291980eff3SMatthew Dillon 	 */
14301980eff3SMatthew Dillon 	ahci_port_stop(ap, 0);
14311980eff3SMatthew Dillon 	ap->ap_state = AP_S_NORMAL;
14321980eff3SMatthew Dillon 	cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC;
1433831bc9e3SMatthew Dillon 	if ((cmd & AHCI_PREG_CMD_PMA) == 0) {
14341980eff3SMatthew Dillon 		cmd |= AHCI_PREG_CMD_PMA;
14351980eff3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CMD, cmd);
1436831bc9e3SMatthew Dillon 	}
14371980eff3SMatthew Dillon 
14381980eff3SMatthew Dillon 	/*
14391980eff3SMatthew Dillon 	 * Flush any errors and request CLO unconditionally, then start
14401980eff3SMatthew Dillon 	 * the port.
14411980eff3SMatthew Dillon 	 */
14421980eff3SMatthew Dillon 	ahci_flush_tfd(ap);
14431980eff3SMatthew Dillon 	ahci_port_clo(ap);
14441980eff3SMatthew Dillon 	if (ahci_port_start(ap)) {
14451980eff3SMatthew Dillon 		kprintf("%s: PMPROBE failed to start port, cannot softreset\n",
14461980eff3SMatthew Dillon 		        PORTNAME(ap));
14471980eff3SMatthew Dillon 		goto err;
14481980eff3SMatthew Dillon 	}
14491980eff3SMatthew Dillon 
14501980eff3SMatthew Dillon 	/*
14511980eff3SMatthew Dillon 	 * Check whether CLO worked
14521980eff3SMatthew Dillon 	 */
14531980eff3SMatthew Dillon 	if (ahci_pwait_clr(ap, AHCI_PREG_TFD,
14541980eff3SMatthew Dillon 			       AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) {
14551980eff3SMatthew Dillon 		kprintf("%s: PMPROBE CLO %s, need port reset\n",
14561980eff3SMatthew Dillon 			PORTNAME(ap),
14571980eff3SMatthew Dillon 			(ahci_read(ap->ap_sc, AHCI_REG_CAP) & AHCI_REG_CAP_SCLO)
14581980eff3SMatthew Dillon 			? "failed" : "unsupported");
1459831bc9e3SMatthew Dillon 		error = EBUSY;
14601980eff3SMatthew Dillon 		goto err;
14611980eff3SMatthew Dillon 	}
14621980eff3SMatthew Dillon 
14631980eff3SMatthew Dillon 	/*
14641067474aSMatthew Dillon 	 * Use the error CCB for all commands
14651067474aSMatthew Dillon 	 *
14661067474aSMatthew Dillon 	 * NOTE!  This CCB is used for both the first and second commands.
14671067474aSMatthew Dillon 	 *	  The second command must use CCB slot 1 to properly load
14681067474aSMatthew Dillon 	 *	  the signature.
14691980eff3SMatthew Dillon 	 */
14701980eff3SMatthew Dillon 	ccb = ahci_get_err_ccb(ap);
14711980eff3SMatthew Dillon 	cmd_slot = ccb->ccb_cmd_hdr;
1472ec8af2ccSMatthew Dillon 	KKASSERT(ccb->ccb_slot == 1);
14731067474aSMatthew Dillon 
14741067474aSMatthew Dillon 	/*
14751067474aSMatthew Dillon 	 * Prep the first H2D command with SRST feature & clear busy/reset
14761067474aSMatthew Dillon 	 * flags.
14771067474aSMatthew Dillon 	 */
14781980eff3SMatthew Dillon 
14791980eff3SMatthew Dillon 	fis = ccb->ccb_cmd_table->cfis;
14801980eff3SMatthew Dillon 	bzero(fis, sizeof(ccb->ccb_cmd_table->cfis));
14811980eff3SMatthew Dillon 	fis[0] = ATA_FIS_TYPE_H2D;
14821980eff3SMatthew Dillon 	fis[1] = 0x0F;			/* Target 15 */
14831980eff3SMatthew Dillon 	fis[15] = ATA_FIS_CONTROL_SRST | ATA_FIS_CONTROL_4BIT;
14841980eff3SMatthew Dillon 
14851980eff3SMatthew Dillon 	cmd_slot->prdtl = 0;
14861980eff3SMatthew Dillon 	cmd_slot->flags = htole16(5);	/* FIS length: 5 DWORDS */
14871980eff3SMatthew Dillon 	cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_C); /* Clear busy on OK */
14881980eff3SMatthew Dillon 	cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_R); /* Reset */
14891980eff3SMatthew Dillon 	cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_PMP); /* port 0xF */
14901980eff3SMatthew Dillon 
14911980eff3SMatthew Dillon 	ccb->ccb_xa.state = ATA_S_PENDING;
14921980eff3SMatthew Dillon 	ccb->ccb_xa.flags = 0;
14931980eff3SMatthew Dillon 
1494831bc9e3SMatthew Dillon 	if (ahci_poll(ccb, 1000, ahci_quick_timeout) != ATA_S_COMPLETE) {
14951980eff3SMatthew Dillon 		kprintf("%s: PMPROBE First FIS failed\n", PORTNAME(ap));
14961980eff3SMatthew Dillon 		if (--count) {
14971980eff3SMatthew Dillon 			ahci_put_err_ccb(ccb);
14981980eff3SMatthew Dillon 			goto retry;
14991980eff3SMatthew Dillon 		}
15001980eff3SMatthew Dillon 		goto err;
15011980eff3SMatthew Dillon 	}
15021980eff3SMatthew Dillon 	if (ahci_pwait_clr(ap, AHCI_PREG_TFD,
15031980eff3SMatthew Dillon 			       AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) {
15041980eff3SMatthew Dillon 		kprintf("%s: PMPROBE Busy after first FIS\n", PORTNAME(ap));
15051980eff3SMatthew Dillon 	}
15061980eff3SMatthew Dillon 
15071980eff3SMatthew Dillon 	/*
15081980eff3SMatthew Dillon 	 * The device may have muffed up the PHY when it reset.
15091980eff3SMatthew Dillon 	 */
1510831bc9e3SMatthew Dillon 	ahci_os_sleep(100);
15111980eff3SMatthew Dillon 	ahci_flush_tfd(ap);
15121980eff3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SERR, -1);
15131980eff3SMatthew Dillon 	/* ahci_pm_phy_status(ap, 15, &cmd); */
15141980eff3SMatthew Dillon 
15151980eff3SMatthew Dillon 	/*
15161980eff3SMatthew Dillon 	 * Prep second D2H command to read status and complete reset sequence
15171980eff3SMatthew Dillon 	 * AHCI 10.4.1 and "Serial ATA Revision 2.6".  I can't find the ATA
15181980eff3SMatthew Dillon 	 * Rev 2.6 and it is unclear how the second FIS should be set up
15191980eff3SMatthew Dillon 	 * from the AHCI document.
15201980eff3SMatthew Dillon 	 *
15211980eff3SMatthew Dillon 	 * Give the device 3ms before sending the second FIS.
15221980eff3SMatthew Dillon 	 *
15231980eff3SMatthew Dillon 	 * It is unclear which other fields in the FIS are used.  Just zero
15241980eff3SMatthew Dillon 	 * everything.
15251980eff3SMatthew Dillon 	 */
15261980eff3SMatthew Dillon 	bzero(fis, sizeof(ccb->ccb_cmd_table->cfis));
15271980eff3SMatthew Dillon 	fis[0] = ATA_FIS_TYPE_H2D;
15281980eff3SMatthew Dillon 	fis[1] = 0x0F;
15291980eff3SMatthew Dillon 	fis[15] = ATA_FIS_CONTROL_4BIT;
15301980eff3SMatthew Dillon 
15311980eff3SMatthew Dillon 	cmd_slot->prdtl = 0;
15321980eff3SMatthew Dillon 	cmd_slot->flags = htole16(5);	/* FIS length: 5 DWORDS */
15331980eff3SMatthew Dillon 	cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_PMP); /* port 0xF */
15341980eff3SMatthew Dillon 
15351980eff3SMatthew Dillon 	ccb->ccb_xa.state = ATA_S_PENDING;
15361980eff3SMatthew Dillon 	ccb->ccb_xa.flags = 0;
15371980eff3SMatthew Dillon 
1538831bc9e3SMatthew Dillon 	if (ahci_poll(ccb, 5000, ahci_quick_timeout) != ATA_S_COMPLETE) {
15391980eff3SMatthew Dillon 		kprintf("%s: PMPROBE Second FIS failed\n", PORTNAME(ap));
15401980eff3SMatthew Dillon 		if (--count) {
15411980eff3SMatthew Dillon 			ahci_put_err_ccb(ccb);
15421980eff3SMatthew Dillon 			goto retry;
15431980eff3SMatthew Dillon 		}
15441980eff3SMatthew Dillon 		goto err;
15451980eff3SMatthew Dillon 	}
15461980eff3SMatthew Dillon 
15471980eff3SMatthew Dillon 	/*
15481980eff3SMatthew Dillon 	 * What? We succeeded?  Yup, but for some reason the signature
15491980eff3SMatthew Dillon 	 * is still latched from the original detect (that saw target 0
15501980eff3SMatthew Dillon 	 * behind the PM), and I don't know how to clear the condition
15511980eff3SMatthew Dillon 	 * other then by retrying the whole reset sequence.
15521980eff3SMatthew Dillon 	 */
15531980eff3SMatthew Dillon 	if (--count) {
15541980eff3SMatthew Dillon 		fis[15] = 0;
15551980eff3SMatthew Dillon 		ahci_put_err_ccb(ccb);
15561980eff3SMatthew Dillon 		goto retry;
15571980eff3SMatthew Dillon 	}
15581980eff3SMatthew Dillon 
15591980eff3SMatthew Dillon 	/*
15601980eff3SMatthew Dillon 	 * Get the signature.  The caller sets the ap fields.
15611980eff3SMatthew Dillon 	 */
15621980eff3SMatthew Dillon 	if (ahci_port_signature_detect(ap, NULL) == ATA_PORT_T_PM) {
15631980eff3SMatthew Dillon 		ap->ap_ata[15].at_probe = ATA_PROBE_GOOD;
1564831bc9e3SMatthew Dillon 		error = 0;
15651980eff3SMatthew Dillon 	} else {
1566831bc9e3SMatthew Dillon 		error = EBUSY;
15671980eff3SMatthew Dillon 	}
15681980eff3SMatthew Dillon 
15691980eff3SMatthew Dillon 	/*
15701980eff3SMatthew Dillon 	 * Fall through / clean up the CCB and perform error processing.
15711980eff3SMatthew Dillon 	 */
15721980eff3SMatthew Dillon err:
1573831bc9e3SMatthew Dillon 	if (ccb != NULL)
15741980eff3SMatthew Dillon 		ahci_put_err_ccb(ccb);
15751980eff3SMatthew Dillon 
1576831bc9e3SMatthew Dillon 	if (error == 0 && ahci_pm_identify(ap)) {
15773209f581SMatthew Dillon 		kprintf("%s: PM - cannot identify port multiplier\n",
15783209f581SMatthew Dillon 			PORTNAME(ap));
1579831bc9e3SMatthew Dillon 		error = EBUSY;
15803209f581SMatthew Dillon 	}
15811067474aSMatthew Dillon 
15821067474aSMatthew Dillon 	/*
15831067474aSMatthew Dillon 	 * If we probed the PM reset the state for the targets behind
15841067474aSMatthew Dillon 	 * it so they get probed by the state machine.
15851067474aSMatthew Dillon 	 */
1586831bc9e3SMatthew Dillon 	if (error == 0) {
15871067474aSMatthew Dillon 		for (i = 0; i < AHCI_MAX_PMPORTS; ++i) {
15881067474aSMatthew Dillon 			at = &ap->ap_ata[i];
15891067474aSMatthew Dillon 			at->at_probe = ATA_PROBE_NEED_INIT;
15901067474aSMatthew Dillon 			at->at_features |= ATA_PORT_F_RESCAN;
15913209f581SMatthew Dillon 		}
15921067474aSMatthew Dillon 	}
15933209f581SMatthew Dillon 
15941980eff3SMatthew Dillon 	/*
15951980eff3SMatthew Dillon 	 * If we failed turn off PMA, otherwise identify the port multiplier.
15961980eff3SMatthew Dillon 	 * CAM will iterate the devices.
15971980eff3SMatthew Dillon 	 */
1598831bc9e3SMatthew Dillon 	if (error) {
15991980eff3SMatthew Dillon 		ahci_port_stop(ap, 0);
16001980eff3SMatthew Dillon 		cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC;
16011980eff3SMatthew Dillon 		cmd &= ~AHCI_PREG_CMD_PMA;
16021980eff3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CMD, cmd);
16031980eff3SMatthew Dillon 	}
16041980eff3SMatthew Dillon 	ahci_port_stop(ap, 0);
16051980eff3SMatthew Dillon 
1606831bc9e3SMatthew Dillon 	return(error);
16071980eff3SMatthew Dillon }
16081980eff3SMatthew Dillon 
16091980eff3SMatthew Dillon /*
1610cf5f3a81SMatthew Dillon  * Hard-stop on hot-swap device removal.  See 10.10.1
1611cf5f3a81SMatthew Dillon  *
1612cf5f3a81SMatthew Dillon  * Place the port in a mode that will allow it to detect hot-swap insertions.
1613cf5f3a81SMatthew Dillon  * This is a bit imprecise because just setting-up SCTL to DET_INIT doesn't
1614cf5f3a81SMatthew Dillon  * seem to do the job.
1615cf5f3a81SMatthew Dillon  */
1616cf5f3a81SMatthew Dillon void
1617cf5f3a81SMatthew Dillon ahci_port_hardstop(struct ahci_port *ap)
1618cf5f3a81SMatthew Dillon {
16191980eff3SMatthew Dillon 	struct ata_port *at;
1620cf5f3a81SMatthew Dillon 	u_int32_t r;
1621cf5f3a81SMatthew Dillon 	u_int32_t cmd;
16221980eff3SMatthew Dillon 	int i;
1623cf5f3a81SMatthew Dillon 
1624cf5f3a81SMatthew Dillon 	/*
1625cf5f3a81SMatthew Dillon 	 * Stop the port.  We can't modify things like SUD if the port
1626cf5f3a81SMatthew Dillon 	 * is running.
1627cf5f3a81SMatthew Dillon 	 */
1628cf5f3a81SMatthew Dillon 	ap->ap_state = AP_S_FATAL_ERROR;
16291980eff3SMatthew Dillon 	ap->ap_probe = ATA_PROBE_FAILED;
16301980eff3SMatthew Dillon 	ap->ap_type = ATA_PORT_T_NONE;
1631cf5f3a81SMatthew Dillon 	ahci_port_stop(ap, 0);
1632cf5f3a81SMatthew Dillon 	cmd = ahci_pread(ap, AHCI_PREG_CMD);
1633cf5f3a81SMatthew Dillon 
1634cf5f3a81SMatthew Dillon 	/*
16351980eff3SMatthew Dillon 	 * Clean up AT sub-ports on SATA port.
16361980eff3SMatthew Dillon 	 */
16371980eff3SMatthew Dillon 	for (i = 0; ap->ap_ata && i < AHCI_MAX_PMPORTS; ++i) {
16381980eff3SMatthew Dillon 		at = &ap->ap_ata[i];
16391980eff3SMatthew Dillon 		at->at_type = ATA_PORT_T_NONE;
16403209f581SMatthew Dillon 		at->at_probe = ATA_PROBE_FAILED;
16411980eff3SMatthew Dillon 	}
16421980eff3SMatthew Dillon 
16431980eff3SMatthew Dillon 	/*
16441980eff3SMatthew Dillon 	 * Turn off port-multiplier control bit
16451980eff3SMatthew Dillon 	 */
16461980eff3SMatthew Dillon 	if (cmd & AHCI_PREG_CMD_PMA) {
16471980eff3SMatthew Dillon 		cmd &= ~AHCI_PREG_CMD_PMA;
16481980eff3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CMD, cmd);
16491980eff3SMatthew Dillon 	}
16501980eff3SMatthew Dillon 
16511980eff3SMatthew Dillon 	/*
1652cf5f3a81SMatthew Dillon 	 * Make sure FRE is active.  There isn't anything we can do if it
1653cf5f3a81SMatthew Dillon 	 * fails so just ignore errors.
1654cf5f3a81SMatthew Dillon 	 */
1655cf5f3a81SMatthew Dillon 	if ((cmd & AHCI_PREG_CMD_FRE) == 0) {
1656cf5f3a81SMatthew Dillon 		cmd |= AHCI_PREG_CMD_FRE;
1657cf5f3a81SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CMD, cmd);
1658cf5f3a81SMatthew Dillon 		if ((ap->ap_sc->sc_flags & AHCI_F_IGN_FR) == 0)
1659cf5f3a81SMatthew Dillon 			ahci_pwait_set(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_FR);
1660cf5f3a81SMatthew Dillon 	}
1661cf5f3a81SMatthew Dillon 
1662cf5f3a81SMatthew Dillon 	/*
1663cf5f3a81SMatthew Dillon 	 * 10.10.3 DET must be set to 0 before setting SUD to 0.
1664cf5f3a81SMatthew Dillon 	 * 10.10.1 place us in the Listen state.
1665cf5f3a81SMatthew Dillon 	 *
1666cf5f3a81SMatthew Dillon 	 * Deactivating SUD only applies if the controller supports SUD.
1667cf5f3a81SMatthew Dillon 	 */
1668cf5f3a81SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SCTL, AHCI_PREG_SCTL_IPM_DISABLED);
16693209f581SMatthew Dillon 	ahci_os_sleep(1);
1670cf5f3a81SMatthew Dillon 	if (cmd & AHCI_PREG_CMD_SUD) {
1671cf5f3a81SMatthew Dillon 		cmd &= ~AHCI_PREG_CMD_SUD;
1672cf5f3a81SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CMD, cmd);
1673cf5f3a81SMatthew Dillon 	}
16743209f581SMatthew Dillon 	ahci_os_sleep(1);
1675cf5f3a81SMatthew Dillon 
1676cf5f3a81SMatthew Dillon 	/*
1677cf5f3a81SMatthew Dillon 	 * Transition su to the spin-up state.  HVA shall send COMRESET and
1678cf5f3a81SMatthew Dillon 	 * begin initialization sequence (whatever that means).
1679cf5f3a81SMatthew Dillon 	 *
1680cf5f3a81SMatthew Dillon 	 * This only applies if the controller supports SUD.
1681cf5f3a81SMatthew Dillon 	 */
1682cf5f3a81SMatthew Dillon 	cmd |= AHCI_PREG_CMD_SUD;
1683cf5f3a81SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_CMD, cmd);
16843209f581SMatthew Dillon 	ahci_os_sleep(1);
1685cf5f3a81SMatthew Dillon 
1686cf5f3a81SMatthew Dillon 	/*
1687cf5f3a81SMatthew Dillon 	 * Transition us to the Reset state.  Theoretically we send a
1688cf5f3a81SMatthew Dillon 	 * continuous stream of COMRESETs in this state.
1689cf5f3a81SMatthew Dillon 	 */
1690cf5f3a81SMatthew Dillon 	r = AHCI_PREG_SCTL_IPM_DISABLED | AHCI_PREG_SCTL_DET_INIT;
1691cf5f3a81SMatthew Dillon 	if (AhciForceGen1 & (1 << ap->ap_num)) {
1692cf5f3a81SMatthew Dillon 		kprintf("%s: Force 1.5Gbits\n", PORTNAME(ap));
1693cf5f3a81SMatthew Dillon 		r |= AHCI_PREG_SCTL_SPD_GEN1;
1694cf5f3a81SMatthew Dillon 	} else {
1695cf5f3a81SMatthew Dillon 		r |= AHCI_PREG_SCTL_SPD_ANY;
1696cf5f3a81SMatthew Dillon 	}
1697cf5f3a81SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SCTL, r);
16983209f581SMatthew Dillon 	ahci_os_sleep(1);
1699cf5f3a81SMatthew Dillon 
1700cf5f3a81SMatthew Dillon 	/*
1701cf5f3a81SMatthew Dillon 	 * Flush SERR_DIAG_X so the TFD can update.
1702cf5f3a81SMatthew Dillon 	 */
1703cf5f3a81SMatthew Dillon 	ahci_flush_tfd(ap);
1704cf5f3a81SMatthew Dillon 
1705cf5f3a81SMatthew Dillon 	/*
1706cf5f3a81SMatthew Dillon 	 * Leave us in COMRESET (both SUD and INIT active), the HBA should
1707cf5f3a81SMatthew Dillon 	 * hopefully send us a DIAG_X-related interrupt if it receives
1708cf5f3a81SMatthew Dillon 	 * a COMINIT, and if not that then at least a Phy transition
1709cf5f3a81SMatthew Dillon 	 * interrupt.
1710cf5f3a81SMatthew Dillon 	 *
1711cf5f3a81SMatthew Dillon 	 * If we transition INIT from 1->0 to begin the initalization
1712cf5f3a81SMatthew Dillon 	 * sequence it is unclear if that sequence will remain active
1713cf5f3a81SMatthew Dillon 	 * until the next device insertion.
1714cf5f3a81SMatthew Dillon 	 *
1715cf5f3a81SMatthew Dillon 	 * If we go back to the listen state it is unclear if the
1716cf5f3a81SMatthew Dillon 	 * device will actually send us a COMINIT, since we aren't
1717cf5f3a81SMatthew Dillon 	 * sending any COMRESET's
1718cf5f3a81SMatthew Dillon 	 */
1719cf5f3a81SMatthew Dillon 	/* NOP */
1720cf5f3a81SMatthew Dillon }
1721cf5f3a81SMatthew Dillon 
1722cf5f3a81SMatthew Dillon /*
1723c408a8b3SMatthew Dillon  * We can't loop on the X bit, a continuous COMINIT received will make
1724c408a8b3SMatthew Dillon  * it loop forever.  Just assume one event has built up and clear X
1725c408a8b3SMatthew Dillon  * so the task file descriptor can update.
1726cf5f3a81SMatthew Dillon  */
1727cf5f3a81SMatthew Dillon void
1728cf5f3a81SMatthew Dillon ahci_flush_tfd(struct ahci_port *ap)
1729cf5f3a81SMatthew Dillon {
1730cf5f3a81SMatthew Dillon 	u_int32_t r;
1731cf5f3a81SMatthew Dillon 
1732cf5f3a81SMatthew Dillon 	r = ahci_pread(ap, AHCI_PREG_SERR);
1733c408a8b3SMatthew Dillon 	if (r & AHCI_PREG_SERR_DIAG_X)
17341980eff3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SERR, AHCI_PREG_SERR_DIAG_X);
1735cf5f3a81SMatthew Dillon }
1736cf5f3a81SMatthew Dillon 
1737cf5f3a81SMatthew Dillon /*
1738fd8bd957SMatthew Dillon  * Figure out what type of device is connected to the port, ATAPI or
1739fd8bd957SMatthew Dillon  * DISK.
1740fd8bd957SMatthew Dillon  */
1741fd8bd957SMatthew Dillon int
17421980eff3SMatthew Dillon ahci_port_signature_detect(struct ahci_port *ap, struct ata_port *at)
1743fd8bd957SMatthew Dillon {
1744fd8bd957SMatthew Dillon 	u_int32_t sig;
1745fd8bd957SMatthew Dillon 
1746fd8bd957SMatthew Dillon 	sig = ahci_pread(ap, AHCI_PREG_SIG);
1747*074579dfSMatthew Dillon 	if (bootverbose)
17481980eff3SMatthew Dillon 		kprintf("%s: sig %08x\n", ATANAME(ap, at), sig);
1749fd8bd957SMatthew Dillon 	if ((sig & 0xffff0000) == (SATA_SIGNATURE_ATAPI & 0xffff0000)) {
1750fd8bd957SMatthew Dillon 		return(ATA_PORT_T_ATAPI);
17511980eff3SMatthew Dillon 	} else if ((sig & 0xffff0000) ==
17521980eff3SMatthew Dillon 		 (SATA_SIGNATURE_PORT_MULTIPLIER & 0xffff0000)) {
17531980eff3SMatthew Dillon 		return(ATA_PORT_T_PM);
1754fd8bd957SMatthew Dillon 	} else {
1755fd8bd957SMatthew Dillon 		return(ATA_PORT_T_DISK);
1756fd8bd957SMatthew Dillon 	}
1757fd8bd957SMatthew Dillon }
1758fd8bd957SMatthew Dillon 
1759fd8bd957SMatthew Dillon /*
1760fd8bd957SMatthew Dillon  * Load the DMA descriptor table for a CCB's buffer.
1761fd8bd957SMatthew Dillon  */
1762258223a3SMatthew Dillon int
1763258223a3SMatthew Dillon ahci_load_prdt(struct ahci_ccb *ccb)
1764258223a3SMatthew Dillon {
1765258223a3SMatthew Dillon 	struct ahci_port		*ap = ccb->ccb_port;
1766258223a3SMatthew Dillon 	struct ahci_softc		*sc = ap->ap_sc;
1767258223a3SMatthew Dillon 	struct ata_xfer			*xa = &ccb->ccb_xa;
1768258223a3SMatthew Dillon 	struct ahci_prdt		*prdt = ccb->ccb_cmd_table->prdt;
1769258223a3SMatthew Dillon 	bus_dmamap_t			dmap = ccb->ccb_dmamap;
1770258223a3SMatthew Dillon 	struct ahci_cmd_hdr		*cmd_slot = ccb->ccb_cmd_hdr;
1771258223a3SMatthew Dillon 	int				error;
1772258223a3SMatthew Dillon 
1773258223a3SMatthew Dillon 	if (xa->datalen == 0) {
1774258223a3SMatthew Dillon 		ccb->ccb_cmd_hdr->prdtl = 0;
1775258223a3SMatthew Dillon 		return (0);
1776258223a3SMatthew Dillon 	}
1777258223a3SMatthew Dillon 
1778258223a3SMatthew Dillon 	error = bus_dmamap_load(sc->sc_tag_data, dmap,
1779258223a3SMatthew Dillon 				xa->data, xa->datalen,
1780258223a3SMatthew Dillon 				ahci_load_prdt_callback,
1781258223a3SMatthew Dillon 				&prdt,
1782258223a3SMatthew Dillon 				((xa->flags & ATA_F_NOWAIT) ?
1783258223a3SMatthew Dillon 				    BUS_DMA_NOWAIT : BUS_DMA_WAITOK));
1784258223a3SMatthew Dillon 	if (error != 0) {
1785258223a3SMatthew Dillon 		kprintf("%s: error %d loading dmamap\n", PORTNAME(ap), error);
1786258223a3SMatthew Dillon 		return (1);
1787258223a3SMatthew Dillon 	}
1788258223a3SMatthew Dillon 	if (xa->flags & ATA_F_PIO)
1789258223a3SMatthew Dillon 		prdt->flags |= htole32(AHCI_PRDT_FLAG_INTR);
1790258223a3SMatthew Dillon 
1791258223a3SMatthew Dillon 	cmd_slot->prdtl = htole16(prdt - ccb->ccb_cmd_table->prdt + 1);
1792258223a3SMatthew Dillon 
1793258223a3SMatthew Dillon 	bus_dmamap_sync(sc->sc_tag_data, dmap,
1794258223a3SMatthew Dillon 			(xa->flags & ATA_F_READ) ?
1795258223a3SMatthew Dillon 			    BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
1796258223a3SMatthew Dillon 
1797258223a3SMatthew Dillon 	return (0);
1798258223a3SMatthew Dillon 
1799258223a3SMatthew Dillon #ifdef DIAGNOSTIC
1800258223a3SMatthew Dillon diagerr:
1801258223a3SMatthew Dillon 	bus_dmamap_unload(sc->sc_tag_data, dmap);
1802258223a3SMatthew Dillon 	return (1);
1803258223a3SMatthew Dillon #endif
1804258223a3SMatthew Dillon }
1805258223a3SMatthew Dillon 
1806258223a3SMatthew Dillon /*
1807258223a3SMatthew Dillon  * Callback from BUSDMA system to load the segment list.  The passed segment
1808258223a3SMatthew Dillon  * list is a temporary structure.
1809258223a3SMatthew Dillon  */
1810258223a3SMatthew Dillon static
1811258223a3SMatthew Dillon void
1812258223a3SMatthew Dillon ahci_load_prdt_callback(void *info, bus_dma_segment_t *segs, int nsegs,
1813258223a3SMatthew Dillon 			int error)
1814258223a3SMatthew Dillon {
1815258223a3SMatthew Dillon 	struct ahci_prdt *prd = *(void **)info;
1816258223a3SMatthew Dillon 	u_int64_t addr;
1817258223a3SMatthew Dillon 
1818258223a3SMatthew Dillon 	KKASSERT(nsegs <= AHCI_MAX_PRDT);
1819258223a3SMatthew Dillon 
1820258223a3SMatthew Dillon 	while (nsegs) {
1821258223a3SMatthew Dillon 		addr = segs->ds_addr;
1822258223a3SMatthew Dillon 		prd->dba_hi = htole32((u_int32_t)(addr >> 32));
1823258223a3SMatthew Dillon 		prd->dba_lo = htole32((u_int32_t)addr);
1824258223a3SMatthew Dillon #ifdef DIAGNOSTIC
1825258223a3SMatthew Dillon 		KKASSERT((addr & 1) == 0);
1826258223a3SMatthew Dillon 		KKASSERT((segs->ds_len & 1) == 0);
1827258223a3SMatthew Dillon #endif
1828258223a3SMatthew Dillon 		prd->flags = htole32(segs->ds_len - 1);
1829258223a3SMatthew Dillon 		--nsegs;
1830258223a3SMatthew Dillon 		if (nsegs)
1831258223a3SMatthew Dillon 			++prd;
1832258223a3SMatthew Dillon 		++segs;
1833258223a3SMatthew Dillon 	}
1834258223a3SMatthew Dillon 	*(void **)info = prd;	/* return last valid segment */
1835258223a3SMatthew Dillon }
1836258223a3SMatthew Dillon 
1837258223a3SMatthew Dillon void
1838258223a3SMatthew Dillon ahci_unload_prdt(struct ahci_ccb *ccb)
1839258223a3SMatthew Dillon {
1840258223a3SMatthew Dillon 	struct ahci_port		*ap = ccb->ccb_port;
1841258223a3SMatthew Dillon 	struct ahci_softc		*sc = ap->ap_sc;
1842258223a3SMatthew Dillon 	struct ata_xfer			*xa = &ccb->ccb_xa;
1843258223a3SMatthew Dillon 	bus_dmamap_t			dmap = ccb->ccb_dmamap;
1844258223a3SMatthew Dillon 
1845258223a3SMatthew Dillon 	if (xa->datalen != 0) {
1846258223a3SMatthew Dillon 		bus_dmamap_sync(sc->sc_tag_data, dmap,
1847258223a3SMatthew Dillon 				(xa->flags & ATA_F_READ) ?
1848258223a3SMatthew Dillon 				BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
1849258223a3SMatthew Dillon 
1850258223a3SMatthew Dillon 		bus_dmamap_unload(sc->sc_tag_data, dmap);
1851258223a3SMatthew Dillon 
1852258223a3SMatthew Dillon 		if (ccb->ccb_xa.flags & ATA_F_NCQ)
1853258223a3SMatthew Dillon 			xa->resid = 0;
1854258223a3SMatthew Dillon 		else
1855258223a3SMatthew Dillon 			xa->resid = xa->datalen -
1856258223a3SMatthew Dillon 			    le32toh(ccb->ccb_cmd_hdr->prdbc);
1857258223a3SMatthew Dillon 	}
1858258223a3SMatthew Dillon }
1859258223a3SMatthew Dillon 
18605f8c1efdSMatthew Dillon /*
18615f8c1efdSMatthew Dillon  * Start a command and poll for completion.
18625f8c1efdSMatthew Dillon  *
18633209f581SMatthew Dillon  * timeout is in ms and only counts once the command gets on-chip.
18643209f581SMatthew Dillon  *
1865831bc9e3SMatthew Dillon  * Returns ATA_S_* state, compare against ATA_S_COMPLETE to determine
1866831bc9e3SMatthew Dillon  * that no error occured.
1867831bc9e3SMatthew Dillon  *
18685f8c1efdSMatthew Dillon  * NOTE: If the caller specifies a NULL timeout function the caller is
18695f8c1efdSMatthew Dillon  *	 responsible for clearing hardware state on failure, but we will
18705f8c1efdSMatthew Dillon  *	 deal with removing the ccb from any pending queue.
18715f8c1efdSMatthew Dillon  *
18725f8c1efdSMatthew Dillon  * NOTE: NCQ should never be used with this function.
1873cf5f3a81SMatthew Dillon  *
1874cf5f3a81SMatthew Dillon  * NOTE: If the port is in a failed state and stopped we do not try
1875cf5f3a81SMatthew Dillon  *	 to activate the ccb.
18765f8c1efdSMatthew Dillon  */
1877258223a3SMatthew Dillon int
1878831bc9e3SMatthew Dillon ahci_poll(struct ahci_ccb *ccb, int timeout,
1879831bc9e3SMatthew Dillon 	  void (*timeout_fn)(struct ahci_ccb *))
1880258223a3SMatthew Dillon {
1881258223a3SMatthew Dillon 	struct ahci_port *ap = ccb->ccb_port;
1882258223a3SMatthew Dillon 
1883cf5f3a81SMatthew Dillon 	if (ccb->ccb_port->ap_state == AP_S_FATAL_ERROR) {
1884cf5f3a81SMatthew Dillon 		ccb->ccb_xa.state = ATA_S_ERROR;
1885831bc9e3SMatthew Dillon 		return(ccb->ccb_xa.state);
1886cf5f3a81SMatthew Dillon 	}
1887258223a3SMatthew Dillon 	crit_enter();
1888258223a3SMatthew Dillon 	ahci_start(ccb);
18891980eff3SMatthew Dillon 
1890258223a3SMatthew Dillon 	do {
1891f4553de1SMatthew Dillon 		ahci_port_intr(ap, 1);
1892831bc9e3SMatthew Dillon 		switch(ccb->ccb_xa.state) {
1893831bc9e3SMatthew Dillon 		case ATA_S_ONCHIP:
1894831bc9e3SMatthew Dillon 			timeout -= ahci_os_softsleep();
1895f4553de1SMatthew Dillon 			break;
1896831bc9e3SMatthew Dillon 		case ATA_S_PENDING:
1897831bc9e3SMatthew Dillon 			ahci_os_softsleep();
1898831bc9e3SMatthew Dillon 			ahci_check_active_timeouts(ap);
1899831bc9e3SMatthew Dillon 			break;
1900831bc9e3SMatthew Dillon 		default:
1901831bc9e3SMatthew Dillon 			crit_exit();
1902831bc9e3SMatthew Dillon 			return (ccb->ccb_xa.state);
1903f4553de1SMatthew Dillon 		}
19043209f581SMatthew Dillon 	} while (timeout > 0);
19055f8c1efdSMatthew Dillon 
1906831bc9e3SMatthew Dillon 	kprintf("%s: Poll timeout slot %d CMD: %b TFD: 0x%b SERR: %b\n",
1907831bc9e3SMatthew Dillon 		ATANAME(ap, ccb->ccb_xa.at), ccb->ccb_slot,
1908831bc9e3SMatthew Dillon 		ahci_pread(ap, AHCI_PREG_CMD), AHCI_PFMT_CMD,
1909831bc9e3SMatthew Dillon 		ahci_pread(ap, AHCI_PREG_TFD), AHCI_PFMT_TFD_STS,
1910831bc9e3SMatthew Dillon 		ahci_pread(ap, AHCI_PREG_SERR), AHCI_PFMT_SERR);
19115f8c1efdSMatthew Dillon 
1912258223a3SMatthew Dillon 	timeout_fn(ccb);
1913831bc9e3SMatthew Dillon 
1914258223a3SMatthew Dillon 	crit_exit();
1915258223a3SMatthew Dillon 
1916831bc9e3SMatthew Dillon 	return(ccb->ccb_xa.state);
1917831bc9e3SMatthew Dillon }
1918831bc9e3SMatthew Dillon 
1919831bc9e3SMatthew Dillon /*
1920831bc9e3SMatthew Dillon  * When polling we have to check if the currently active CCB(s)
1921831bc9e3SMatthew Dillon  * have timed out as the callout will be deadlocked while we
1922831bc9e3SMatthew Dillon  * hold the port lock.
1923831bc9e3SMatthew Dillon  */
1924831bc9e3SMatthew Dillon void
1925831bc9e3SMatthew Dillon ahci_check_active_timeouts(struct ahci_port *ap)
1926831bc9e3SMatthew Dillon {
1927831bc9e3SMatthew Dillon 	struct ahci_ccb *ccb;
1928831bc9e3SMatthew Dillon 	u_int32_t mask;
1929831bc9e3SMatthew Dillon 	int tag;
1930831bc9e3SMatthew Dillon 
1931831bc9e3SMatthew Dillon 	mask = ap->ap_active | ap->ap_sactive;
1932831bc9e3SMatthew Dillon 	while (mask) {
1933831bc9e3SMatthew Dillon 		tag = ffs(mask) - 1;
1934831bc9e3SMatthew Dillon 		mask &= ~(1 << tag);
1935831bc9e3SMatthew Dillon 		ccb = &ap->ap_ccbs[tag];
1936831bc9e3SMatthew Dillon 		if (ccb->ccb_xa.flags & ATA_F_TIMEOUT_EXPIRED) {
1937831bc9e3SMatthew Dillon 			ahci_ata_cmd_timeout(ccb);
1938831bc9e3SMatthew Dillon 		}
1939831bc9e3SMatthew Dillon 	}
1940258223a3SMatthew Dillon }
1941258223a3SMatthew Dillon 
19423209f581SMatthew Dillon static
19433209f581SMatthew Dillon __inline
19443209f581SMatthew Dillon void
19453209f581SMatthew Dillon ahci_start_timeout(struct ahci_ccb *ccb)
19463209f581SMatthew Dillon {
19473209f581SMatthew Dillon 	if (ccb->ccb_xa.flags & ATA_F_TIMEOUT_DESIRED) {
19483209f581SMatthew Dillon 		ccb->ccb_xa.flags |= ATA_F_TIMEOUT_RUNNING;
19493209f581SMatthew Dillon 		callout_reset(&ccb->ccb_timeout,
19503209f581SMatthew Dillon 			      (ccb->ccb_xa.timeout * hz + 999) / 1000,
19513209f581SMatthew Dillon 			      ahci_ata_cmd_timeout_unserialized, ccb);
19523209f581SMatthew Dillon 	}
19533209f581SMatthew Dillon }
19543209f581SMatthew Dillon 
1955258223a3SMatthew Dillon void
1956258223a3SMatthew Dillon ahci_start(struct ahci_ccb *ccb)
1957258223a3SMatthew Dillon {
1958258223a3SMatthew Dillon 	struct ahci_port		*ap = ccb->ccb_port;
1959258223a3SMatthew Dillon 	struct ahci_softc		*sc = ap->ap_sc;
1960258223a3SMatthew Dillon 
1961258223a3SMatthew Dillon 	KKASSERT(ccb->ccb_xa.state == ATA_S_PENDING);
1962258223a3SMatthew Dillon 
1963258223a3SMatthew Dillon 	/* Zero transferred byte count before transfer */
1964258223a3SMatthew Dillon 	ccb->ccb_cmd_hdr->prdbc = 0;
1965258223a3SMatthew Dillon 
1966258223a3SMatthew Dillon 	/* Sync command list entry and corresponding command table entry */
1967258223a3SMatthew Dillon 	bus_dmamap_sync(sc->sc_tag_cmdh,
1968258223a3SMatthew Dillon 			AHCI_DMA_MAP(ap->ap_dmamem_cmd_list),
1969258223a3SMatthew Dillon 			BUS_DMASYNC_PREWRITE);
1970258223a3SMatthew Dillon 	bus_dmamap_sync(sc->sc_tag_cmdt,
1971258223a3SMatthew Dillon 			AHCI_DMA_MAP(ap->ap_dmamem_cmd_table),
1972258223a3SMatthew Dillon 			BUS_DMASYNC_PREWRITE);
1973258223a3SMatthew Dillon 
1974258223a3SMatthew Dillon 	/* Prepare RFIS area for write by controller */
1975258223a3SMatthew Dillon 	bus_dmamap_sync(sc->sc_tag_rfis,
1976258223a3SMatthew Dillon 			AHCI_DMA_MAP(ap->ap_dmamem_rfis),
1977258223a3SMatthew Dillon 			BUS_DMASYNC_PREREAD);
1978258223a3SMatthew Dillon 
19791980eff3SMatthew Dillon 	/*
19804c339a5fSMatthew Dillon 	 * There's no point trying to optimize this, it only shaves a few
19814c339a5fSMatthew Dillon 	 * nanoseconds so just queue the command and call our generic issue.
19821980eff3SMatthew Dillon 	 */
19834c339a5fSMatthew Dillon 	ahci_issue_pending_commands(ap, ccb);
1984258223a3SMatthew Dillon }
1985258223a3SMatthew Dillon 
1986831bc9e3SMatthew Dillon /*
1987831bc9e3SMatthew Dillon  * While holding the port lock acquire exclusive access to the port.
1988831bc9e3SMatthew Dillon  *
1989831bc9e3SMatthew Dillon  * This is used when running the state machine to initialize and identify
1990831bc9e3SMatthew Dillon  * targets over a port multiplier.  Setting exclusive access prevents
1991831bc9e3SMatthew Dillon  * ahci_port_intr() from activating any requests sitting on the pending
1992831bc9e3SMatthew Dillon  * queue.
1993831bc9e3SMatthew Dillon  */
1994831bc9e3SMatthew Dillon void
1995831bc9e3SMatthew Dillon ahci_beg_exclusive_access(struct ahci_port *ap, struct ata_port *at)
1996831bc9e3SMatthew Dillon {
1997831bc9e3SMatthew Dillon 	KKASSERT((ap->ap_flags & AP_F_EXCLUSIVE_ACCESS) == 0);
1998831bc9e3SMatthew Dillon 	ap->ap_flags |= AP_F_EXCLUSIVE_ACCESS;
1999831bc9e3SMatthew Dillon 	while (ap->ap_active || ap->ap_sactive) {
2000831bc9e3SMatthew Dillon 		ahci_port_intr(ap, 1);
2001831bc9e3SMatthew Dillon 		ahci_os_softsleep();
2002831bc9e3SMatthew Dillon 	}
2003831bc9e3SMatthew Dillon }
2004831bc9e3SMatthew Dillon 
2005831bc9e3SMatthew Dillon void
2006831bc9e3SMatthew Dillon ahci_end_exclusive_access(struct ahci_port *ap, struct ata_port *at)
2007831bc9e3SMatthew Dillon {
2008831bc9e3SMatthew Dillon 	KKASSERT((ap->ap_flags & AP_F_EXCLUSIVE_ACCESS) != 0);
2009831bc9e3SMatthew Dillon 	ap->ap_flags &= ~AP_F_EXCLUSIVE_ACCESS;
20104c339a5fSMatthew Dillon 	ahci_issue_pending_commands(ap, NULL);
2011831bc9e3SMatthew Dillon }
2012831bc9e3SMatthew Dillon 
20131980eff3SMatthew Dillon /*
20144c339a5fSMatthew Dillon  * If ccb is not NULL enqueue and/or issue it.
20154c339a5fSMatthew Dillon  *
20164c339a5fSMatthew Dillon  * If ccb is NULL issue whatever we can from the queue.  However, nothing
20174c339a5fSMatthew Dillon  * new is issued if the exclusive access flag is set or expired ccb's are
20184c339a5fSMatthew Dillon  * present.
20194c339a5fSMatthew Dillon  *
20204c339a5fSMatthew Dillon  * If existing commands are still active (ap_active/ap_sactive) we can only
20214c339a5fSMatthew Dillon  * issue matching new commands.
20221980eff3SMatthew Dillon  */
20234c339a5fSMatthew Dillon void
20244c339a5fSMatthew Dillon ahci_issue_pending_commands(struct ahci_port *ap, struct ahci_ccb *ccb)
20254c339a5fSMatthew Dillon {
20264c339a5fSMatthew Dillon 	u_int32_t		mask;
20274c339a5fSMatthew Dillon 	int			limit;
2028258223a3SMatthew Dillon 
20291980eff3SMatthew Dillon 	/*
20304c339a5fSMatthew Dillon 	 * Enqueue the ccb.
20314c339a5fSMatthew Dillon 	 *
20324c339a5fSMatthew Dillon 	 * If just running the queue and in exclusive access mode we
20334c339a5fSMatthew Dillon 	 * just return.  Also in this case if there are any expired ccb's
20344c339a5fSMatthew Dillon 	 * we want to clear the queue so the port can be safely stopped.
20354c339a5fSMatthew Dillon 	 */
20364c339a5fSMatthew Dillon 	if (ccb) {
20374c339a5fSMatthew Dillon 		TAILQ_INSERT_TAIL(&ap->ap_ccb_pending, ccb, ccb_entry);
20384c339a5fSMatthew Dillon 	} else if ((ap->ap_flags & AP_F_EXCLUSIVE_ACCESS) || ap->ap_expired) {
20394c339a5fSMatthew Dillon 		return;
20404c339a5fSMatthew Dillon 	}
20414c339a5fSMatthew Dillon 
20424c339a5fSMatthew Dillon 	/*
20434c339a5fSMatthew Dillon 	 * Pull the next ccb off the queue and run it if possible.
20444c339a5fSMatthew Dillon 	 */
20454c339a5fSMatthew Dillon 	if ((ccb = TAILQ_FIRST(&ap->ap_ccb_pending)) == NULL)
20464c339a5fSMatthew Dillon 		return;
20474c339a5fSMatthew Dillon 
20484c339a5fSMatthew Dillon 	if (ccb->ccb_xa.flags & ATA_F_NCQ) {
20494c339a5fSMatthew Dillon 		/*
20504c339a5fSMatthew Dillon 		 * The next command is a NCQ command and can be issued as
20514c339a5fSMatthew Dillon 		 * long as currently active commands are not standard.
20524c339a5fSMatthew Dillon 		 */
20534c339a5fSMatthew Dillon 		if (ap->ap_active) {
20544c339a5fSMatthew Dillon 			KKASSERT(ap->ap_active_cnt > 0);
20554c339a5fSMatthew Dillon 			return;
20564c339a5fSMatthew Dillon 		}
20574c339a5fSMatthew Dillon 		KKASSERT(ap->ap_active_cnt == 0);
20584c339a5fSMatthew Dillon 
20594c339a5fSMatthew Dillon 		mask = 0;
20604c339a5fSMatthew Dillon 		do {
20614c339a5fSMatthew Dillon 			TAILQ_REMOVE(&ap->ap_ccb_pending, ccb, ccb_entry);
20624c339a5fSMatthew Dillon 			ahci_start_timeout(ccb);
20634c339a5fSMatthew Dillon 			mask |= 1 << ccb->ccb_slot;
20644c339a5fSMatthew Dillon 			ccb->ccb_xa.state = ATA_S_ONCHIP;
20654c339a5fSMatthew Dillon 			ccb = TAILQ_FIRST(&ap->ap_ccb_pending);
20664c339a5fSMatthew Dillon 		} while (ccb && (ccb->ccb_xa.flags & ATA_F_NCQ));
20674c339a5fSMatthew Dillon 
20684c339a5fSMatthew Dillon 		ap->ap_sactive |= mask;
20694c339a5fSMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SACT, mask);
20704c339a5fSMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CI, mask);
20714c339a5fSMatthew Dillon 	} else {
20724c339a5fSMatthew Dillon 		/*
20734c339a5fSMatthew Dillon 		 * The next command is a standard command and can be issued
20744c339a5fSMatthew Dillon 		 * as long as currently active commands are not NCQ.
20754c339a5fSMatthew Dillon 		 *
20764c339a5fSMatthew Dillon 		 * We limit ourself to 1 command if we have a port multiplier,
20774c339a5fSMatthew Dillon 		 * (at least without FBSS support), otherwise timeouts on
20784c339a5fSMatthew Dillon 		 * one port can race completions on other ports (see
20794c339a5fSMatthew Dillon 		 * ahci_ata_cmd_timeout() for more information).
20804c339a5fSMatthew Dillon 		 *
20814c339a5fSMatthew Dillon 		 * If not on a port multiplier generally allow up to 4
20824c339a5fSMatthew Dillon 		 * standard commands to be enqueued.  Remember that the
20834c339a5fSMatthew Dillon 		 * command processor will still process them sequentially.
20841980eff3SMatthew Dillon 		 */
20851980eff3SMatthew Dillon 		if (ap->ap_sactive)
2086258223a3SMatthew Dillon 			return;
20874c339a5fSMatthew Dillon 		if (ap->ap_type == ATA_PORT_T_PM)
20884c339a5fSMatthew Dillon 			limit = 1;
20894c339a5fSMatthew Dillon 		else if (ap->ap_sc->sc_ncmds > 4)
20904c339a5fSMatthew Dillon 			limit = 4;
20914c339a5fSMatthew Dillon 		else
20924c339a5fSMatthew Dillon 			limit = 2;
2093258223a3SMatthew Dillon 
20944c339a5fSMatthew Dillon 		while (ap->ap_active_cnt < limit && ccb &&
20954c339a5fSMatthew Dillon 		       (ccb->ccb_xa.flags & ATA_F_NCQ) == 0) {
20964c339a5fSMatthew Dillon 			TAILQ_REMOVE(&ap->ap_ccb_pending, ccb, ccb_entry);
20974c339a5fSMatthew Dillon 			ahci_start_timeout(ccb);
20984c339a5fSMatthew Dillon 			ap->ap_active |= 1 << ccb->ccb_slot;
2099258223a3SMatthew Dillon 			ap->ap_active_cnt++;
21004c339a5fSMatthew Dillon 			ccb->ccb_xa.state = ATA_S_ONCHIP;
21014c339a5fSMatthew Dillon 			ahci_pwrite(ap, AHCI_PREG_CI, 1 << ccb->ccb_slot);
21024c339a5fSMatthew Dillon 			ccb = TAILQ_FIRST(&ap->ap_ccb_pending);
21031980eff3SMatthew Dillon 		}
2104258223a3SMatthew Dillon 	}
2105258223a3SMatthew Dillon }
2106258223a3SMatthew Dillon 
2107258223a3SMatthew Dillon void
2108258223a3SMatthew Dillon ahci_intr(void *arg)
2109258223a3SMatthew Dillon {
2110258223a3SMatthew Dillon 	struct ahci_softc	*sc = arg;
2111f4553de1SMatthew Dillon 	struct ahci_port	*ap;
2112258223a3SMatthew Dillon 	u_int32_t		is, ack = 0;
2113258223a3SMatthew Dillon 	int			port;
2114258223a3SMatthew Dillon 
2115f4553de1SMatthew Dillon 	/*
2116f4553de1SMatthew Dillon 	 * Check if the master enable is up, and whether any interrupts are
2117f4553de1SMatthew Dillon 	 * pending.
2118f4553de1SMatthew Dillon 	 */
2119f4553de1SMatthew Dillon 	if ((sc->sc_flags & AHCI_F_INT_GOOD) == 0)
2120f4553de1SMatthew Dillon 		return;
2121258223a3SMatthew Dillon 	is = ahci_read(sc, AHCI_REG_IS);
2122258223a3SMatthew Dillon 	if (is == 0 || is == 0xffffffff)
2123258223a3SMatthew Dillon 		return;
2124258223a3SMatthew Dillon 	ack = is;
2125258223a3SMatthew Dillon 
2126258223a3SMatthew Dillon #ifdef AHCI_COALESCE
2127258223a3SMatthew Dillon 	/* Check coalescing interrupt first */
2128258223a3SMatthew Dillon 	if (is & sc->sc_ccc_mask) {
2129258223a3SMatthew Dillon 		DPRINTF(AHCI_D_INTR, "%s: command coalescing interrupt\n",
2130258223a3SMatthew Dillon 		    DEVNAME(sc));
2131258223a3SMatthew Dillon 		is &= ~sc->sc_ccc_mask;
2132258223a3SMatthew Dillon 		is |= sc->sc_ccc_ports_cur;
2133258223a3SMatthew Dillon 	}
2134258223a3SMatthew Dillon #endif
2135258223a3SMatthew Dillon 
2136f4553de1SMatthew Dillon 	/*
2137f4553de1SMatthew Dillon 	 * Process interrupts for each port in a non-blocking fashion.
2138f4553de1SMatthew Dillon 	 */
2139258223a3SMatthew Dillon 	while (is) {
2140258223a3SMatthew Dillon 		port = ffs(is) - 1;
2141f4553de1SMatthew Dillon 		ap = sc->sc_ports[port];
2142f4553de1SMatthew Dillon 		if (ap) {
2143f4553de1SMatthew Dillon 			if (ahci_os_lock_port_nb(ap) == 0) {
2144f4553de1SMatthew Dillon 				ahci_port_intr(ap, 0);
2145f4553de1SMatthew Dillon 				ahci_os_unlock_port(ap);
2146f4553de1SMatthew Dillon 			} else {
2147f4553de1SMatthew Dillon 				ahci_pwrite(ap, AHCI_PREG_IE, 0);
2148f4553de1SMatthew Dillon 				ahci_os_signal_port_thread(ap, AP_SIGF_PORTINT);
2149f4553de1SMatthew Dillon 			}
2150f4553de1SMatthew Dillon 		}
2151258223a3SMatthew Dillon 		is &= ~(1 << port);
2152258223a3SMatthew Dillon 	}
2153258223a3SMatthew Dillon 
2154258223a3SMatthew Dillon 	/* Finally, acknowledge global interrupt */
2155258223a3SMatthew Dillon 	ahci_write(sc, AHCI_REG_IS, ack);
2156258223a3SMatthew Dillon }
2157258223a3SMatthew Dillon 
2158f4553de1SMatthew Dillon /*
2159f4553de1SMatthew Dillon  * Core called from helper thread.
2160f4553de1SMatthew Dillon  */
21613209f581SMatthew Dillon void
2162f4553de1SMatthew Dillon ahci_port_thread_core(struct ahci_port *ap, int mask)
2163f4553de1SMatthew Dillon {
2164f4553de1SMatthew Dillon 	/*
2165f4553de1SMatthew Dillon 	 * Process any expired timedouts.
2166f4553de1SMatthew Dillon 	 */
2167f4553de1SMatthew Dillon 	ahci_os_lock_port(ap);
2168f4553de1SMatthew Dillon 	if (mask & AP_SIGF_TIMEOUT) {
2169831bc9e3SMatthew Dillon 		ahci_check_active_timeouts(ap);
2170f4553de1SMatthew Dillon 	}
2171f4553de1SMatthew Dillon 
2172f4553de1SMatthew Dillon 	/*
2173f4553de1SMatthew Dillon 	 * Process port interrupts which require a higher level of
2174f4553de1SMatthew Dillon 	 * intervention.
2175f4553de1SMatthew Dillon 	 */
2176f4553de1SMatthew Dillon 	if (mask & AP_SIGF_PORTINT) {
2177f4553de1SMatthew Dillon 		ahci_port_intr(ap, 1);
2178f4553de1SMatthew Dillon 		ahci_port_interrupt_enable(ap);
2179831bc9e3SMatthew Dillon 		ahci_os_unlock_port(ap);
2180f4553de1SMatthew Dillon 	} else {
2181f4553de1SMatthew Dillon 		ahci_os_unlock_port(ap);
2182f4553de1SMatthew Dillon 	}
2183f4553de1SMatthew Dillon }
2184f4553de1SMatthew Dillon 
2185f4553de1SMatthew Dillon /*
2186f4553de1SMatthew Dillon  * Core per-port interrupt handler.
2187f4553de1SMatthew Dillon  *
2188f4553de1SMatthew Dillon  * If blockable is 0 we cannot call ahci_os_sleep() at all and we can only
2189f4553de1SMatthew Dillon  * deal with normal command completions which do not require blocking.
2190f4553de1SMatthew Dillon  */
2191f4553de1SMatthew Dillon void
2192f4553de1SMatthew Dillon ahci_port_intr(struct ahci_port *ap, int blockable)
2193258223a3SMatthew Dillon {
2194258223a3SMatthew Dillon 	struct ahci_softc	*sc = ap->ap_sc;
21953209f581SMatthew Dillon 	u_int32_t		is, ci_saved, ci_masked;
219622181ab7SMatthew Dillon 	int			slot;
2197258223a3SMatthew Dillon 	struct ahci_ccb		*ccb = NULL;
21981980eff3SMatthew Dillon 	struct ata_port		*ccb_at = NULL;
2199258223a3SMatthew Dillon 	volatile u_int32_t	*active;
2200258223a3SMatthew Dillon #ifdef DIAGNOSTIC
2201258223a3SMatthew Dillon 	u_int32_t		tmp;
2202258223a3SMatthew Dillon #endif
2203f4553de1SMatthew Dillon 	const u_int32_t		blockable_mask = AHCI_PREG_IS_TFES |
2204f4553de1SMatthew Dillon 						 AHCI_PREG_IS_IFS |
2205f4553de1SMatthew Dillon 						 AHCI_PREG_IS_PCS |
2206f4553de1SMatthew Dillon 						 AHCI_PREG_IS_PRCS |
2207f4553de1SMatthew Dillon 						 AHCI_PREG_IS_HBFS |
2208f4553de1SMatthew Dillon 						 AHCI_PREG_IS_OFS |
2209f4553de1SMatthew Dillon 						 AHCI_PREG_IS_UFS;
2210f4553de1SMatthew Dillon 
221122181ab7SMatthew Dillon 	enum { NEED_NOTHING, NEED_RESTART, NEED_HOTPLUG_INSERT,
221222181ab7SMatthew Dillon 	       NEED_HOTPLUG_REMOVE } need = NEED_NOTHING;
2213258223a3SMatthew Dillon 
2214258223a3SMatthew Dillon 	is = ahci_pread(ap, AHCI_PREG_IS);
2215f4553de1SMatthew Dillon 
2216f4553de1SMatthew Dillon 	/*
2217f4553de1SMatthew Dillon 	 * All basic command completions are always processed.
2218f4553de1SMatthew Dillon 	 */
2219cec07d75SMatthew Dillon 	if (is & AHCI_PREG_IS_DPS)
2220cec07d75SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS, is & AHCI_PREG_IS_DPS);
2221258223a3SMatthew Dillon 
2222f4553de1SMatthew Dillon 	/*
2223f4553de1SMatthew Dillon 	 * If we can't block then we can't handle these here.  Disable
2224f4553de1SMatthew Dillon 	 * the interrupts in question so we don't live-lock, the helper
2225f4553de1SMatthew Dillon 	 * thread will re-enable them.
2226f4553de1SMatthew Dillon 	 *
2227f4553de1SMatthew Dillon 	 * If the port is in a completely failed state we do not want
2228dbef6246SMatthew Dillon 	 * to drop through to failed-command-processing if blockable is 0,
2229f4553de1SMatthew Dillon 	 * just let the thread deal with it all.
2230dbef6246SMatthew Dillon 	 *
2231dbef6246SMatthew Dillon 	 * Otherwise we fall through and still handle DHRS and any commands
2232dbef6246SMatthew Dillon 	 * which completed normally.  Even if we are errored we haven't
2233dbef6246SMatthew Dillon 	 * stopped the port yet so CI/SACT are still good.
2234f4553de1SMatthew Dillon 	 */
2235f4553de1SMatthew Dillon 	if (blockable == 0) {
2236f4553de1SMatthew Dillon 		if (ap->ap_state == AP_S_FATAL_ERROR) {
2237f4553de1SMatthew Dillon 			ahci_pwrite(ap, AHCI_PREG_IE,
2238f4553de1SMatthew Dillon 				    ahci_pread(ap, AHCI_PREG_IE) & ~is);
2239f4553de1SMatthew Dillon 			ahci_os_signal_port_thread(ap, AP_SIGF_PORTINT);
2240f4553de1SMatthew Dillon 			return;
2241f4553de1SMatthew Dillon 		}
2242f4553de1SMatthew Dillon 		if (is & blockable_mask) {
2243f4553de1SMatthew Dillon 			ahci_pwrite(ap, AHCI_PREG_IE,
2244dbef6246SMatthew Dillon 			    ahci_pread(ap, AHCI_PREG_IE) & ~blockable_mask);
2245dbef6246SMatthew Dillon 			is &= ~blockable_mask;
2246f4553de1SMatthew Dillon 			ahci_os_signal_port_thread(ap, AP_SIGF_PORTINT);
2247f4553de1SMatthew Dillon 		}
2248f4553de1SMatthew Dillon 	}
2249f4553de1SMatthew Dillon 
22501980eff3SMatthew Dillon #if 0
22511980eff3SMatthew Dillon 	kprintf("%s: INTERRUPT %b\n", PORTNAME(ap),
22521980eff3SMatthew Dillon 		is, AHCI_PFMT_IS);
22531980eff3SMatthew Dillon #endif
22541980eff3SMatthew Dillon 
22553209f581SMatthew Dillon 	/*
2256f4553de1SMatthew Dillon 	 * Either NCQ or non-NCQ commands will be active, never both.
22573209f581SMatthew Dillon 	 */
2258258223a3SMatthew Dillon 	if (ap->ap_sactive) {
2259258223a3SMatthew Dillon 		KKASSERT(ap->ap_active == 0);
2260258223a3SMatthew Dillon 		KKASSERT(ap->ap_active_cnt == 0);
2261258223a3SMatthew Dillon 		ci_saved = ahci_pread(ap, AHCI_PREG_SACT);
2262258223a3SMatthew Dillon 		active = &ap->ap_sactive;
2263258223a3SMatthew Dillon 	} else {
2264258223a3SMatthew Dillon 		ci_saved = ahci_pread(ap, AHCI_PREG_CI);
2265258223a3SMatthew Dillon 		active = &ap->ap_active;
2266258223a3SMatthew Dillon 	}
2267258223a3SMatthew Dillon 
22681980eff3SMatthew Dillon 	if (is & AHCI_PREG_IS_TFES) {
2269cf5f3a81SMatthew Dillon 		/*
2270f4553de1SMatthew Dillon 		 * Command failed (blockable).
2271f4553de1SMatthew Dillon 		 *
2272f4553de1SMatthew Dillon 		 * See AHCI 1.1 spec 6.2.2.1 and 6.2.2.2.
22731980eff3SMatthew Dillon 		 *
22741980eff3SMatthew Dillon 		 * This stops command processing.
2275cf5f3a81SMatthew Dillon 		 */
2276258223a3SMatthew Dillon 		u_int32_t tfd, serr;
2277258223a3SMatthew Dillon 		int	err_slot;
2278258223a3SMatthew Dillon 
2279258223a3SMatthew Dillon 		tfd = ahci_pread(ap, AHCI_PREG_TFD);
2280258223a3SMatthew Dillon 		serr = ahci_pread(ap, AHCI_PREG_SERR);
2281258223a3SMatthew Dillon 
2282cf5f3a81SMatthew Dillon 		/*
2283cf5f3a81SMatthew Dillon 		 * If no NCQ commands are active the error slot is easily
2284cf5f3a81SMatthew Dillon 		 * determined, otherwise we have to extract the error
2285cf5f3a81SMatthew Dillon 		 * from the log page.
2286cf5f3a81SMatthew Dillon 		 */
2287258223a3SMatthew Dillon 		if (ap->ap_sactive == 0) {
2288cf5f3a81SMatthew Dillon 			err_slot = AHCI_PREG_CMD_CCS(
2289cf5f3a81SMatthew Dillon 					ahci_pread(ap, AHCI_PREG_CMD));
2290258223a3SMatthew Dillon 			ccb = &ap->ap_ccbs[err_slot];
22911980eff3SMatthew Dillon 			ccb_at = ccb->ccb_xa.at;	/* can be NULL */
2292258223a3SMatthew Dillon 
2293258223a3SMatthew Dillon 			/* Preserve received taskfile data from the RFIS. */
2294258223a3SMatthew Dillon 			memcpy(&ccb->ccb_xa.rfis, ap->ap_rfis->rfis,
2295258223a3SMatthew Dillon 			       sizeof(struct ata_fis_d2h));
2296cf5f3a81SMatthew Dillon 		} else {
2297cf5f3a81SMatthew Dillon 			err_slot = -1;
2298cf5f3a81SMatthew Dillon 		}
2299258223a3SMatthew Dillon 
23001980eff3SMatthew Dillon 		DPRINTF(AHCI_D_VERBOSE, "%s: errd slot %d, TFD: %b, SERR: %b\n",
23011980eff3SMatthew Dillon 			PORTNAME(ap), err_slot,
23021980eff3SMatthew Dillon 			tfd, AHCI_PFMT_TFD_STS,
23031980eff3SMatthew Dillon 			serr, AHCI_PFMT_SERR);
2304258223a3SMatthew Dillon 
2305cf5f3a81SMatthew Dillon 		/* Stopping the port clears CI and SACT */
2306258223a3SMatthew Dillon 		ahci_port_stop(ap, 0);
230722181ab7SMatthew Dillon 		need = NEED_RESTART;
2308258223a3SMatthew Dillon 
2309cf5f3a81SMatthew Dillon 		/*
2310cf5f3a81SMatthew Dillon 		 * Clear SERR (primarily DIAG_X) to enable capturing of the
2311cf5f3a81SMatthew Dillon 		 * next error.
2312cf5f3a81SMatthew Dillon 		 */
2313258223a3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SERR, serr);
2314258223a3SMatthew Dillon 
2315258223a3SMatthew Dillon 		/* Acknowledge the interrupts we can recover from. */
2316cf5f3a81SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS,
2317cec07d75SMatthew Dillon 			    is & (AHCI_PREG_IS_TFES | AHCI_PREG_IS_IFS));
23181980eff3SMatthew Dillon 		is &= ~(AHCI_PREG_IS_TFES | AHCI_PREG_IS_IFS);
2319258223a3SMatthew Dillon 
2320258223a3SMatthew Dillon 		/* If device hasn't cleared its busy status, try to idle it. */
2321258223a3SMatthew Dillon 		if (tfd & (AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) {
2322baef7501SMatthew Dillon 			kprintf("%s: Attempting to idle device\n",
2323baef7501SMatthew Dillon 				ATANAME(ap, ccb_at));
23241980eff3SMatthew Dillon 			if (ap->ap_flags & AP_F_IN_RESET)
23251980eff3SMatthew Dillon 				goto fatal;
23261980eff3SMatthew Dillon 			/*
23271980eff3SMatthew Dillon 			 * XXX how do we unbrick a PM target (ccb_at != NULL).
23281980eff3SMatthew Dillon 			 *
23291980eff3SMatthew Dillon 			 * For now fail the target and use CLO to clear the
23301980eff3SMatthew Dillon 			 * busy condition and make the ahci port usable for
23311980eff3SMatthew Dillon 			 * the remaining devices.
23321980eff3SMatthew Dillon 			 */
23331980eff3SMatthew Dillon 			if (ccb_at) {
23341980eff3SMatthew Dillon 				ccb_at->at_probe = ATA_PROBE_FAILED;
23351980eff3SMatthew Dillon 				ahci_port_clo(ap);
23361980eff3SMatthew Dillon 			} else if (ahci_port_reset(ap, ccb_at, 0)) {
233717eab71eSMatthew Dillon 				kprintf("%s: Unable to idle device, port "
233817eab71eSMatthew Dillon 					"bricked on us\n",
2339258223a3SMatthew Dillon 					PORTNAME(ap));
2340258223a3SMatthew Dillon 				goto fatal;
2341258223a3SMatthew Dillon 			}
2342258223a3SMatthew Dillon 
2343258223a3SMatthew Dillon 			/* Had to reset device, can't gather extended info. */
2344258223a3SMatthew Dillon 		} else if (ap->ap_sactive) {
23451980eff3SMatthew Dillon 			/*
23461980eff3SMatthew Dillon 			 * Recover the NCQ error from log page 10h.
23471980eff3SMatthew Dillon 			 *
23481980eff3SMatthew Dillon 			 * XXX NCQ currently not supported with port
23491980eff3SMatthew Dillon 			 *     multiplier.
23501980eff3SMatthew Dillon 			 */
2351258223a3SMatthew Dillon 			ahci_port_read_ncq_error(ap, &err_slot);
2352cec07d75SMatthew Dillon 			kprintf("recover from NCQ error err_slot %d\n",
2353cec07d75SMatthew Dillon 				err_slot);
2354258223a3SMatthew Dillon 			if (err_slot < 0)
2355258223a3SMatthew Dillon 				goto failall;
2356258223a3SMatthew Dillon 
2357258223a3SMatthew Dillon 			DPRINTF(AHCI_D_VERBOSE, "%s: NCQ errored slot %d\n",
2358258223a3SMatthew Dillon 				PORTNAME(ap), err_slot);
2359258223a3SMatthew Dillon 
2360258223a3SMatthew Dillon 			ccb = &ap->ap_ccbs[err_slot];
2361258223a3SMatthew Dillon 		} else {
23624c339a5fSMatthew Dillon 			/*
23634c339a5fSMatthew Dillon 			 * Non-NCQ error.  We could gather extended info from
23644c339a5fSMatthew Dillon 			 * the log but for now just fall through.
23654c339a5fSMatthew Dillon 			 */
23664c339a5fSMatthew Dillon 			/* */
2367258223a3SMatthew Dillon 		}
2368258223a3SMatthew Dillon 
2369258223a3SMatthew Dillon 		/*
2370258223a3SMatthew Dillon 		 * If we couldn't determine the errored slot, reset the port
2371258223a3SMatthew Dillon 		 * and fail all the active slots.
2372258223a3SMatthew Dillon 		 */
2373258223a3SMatthew Dillon 		if (err_slot == -1) {
23741980eff3SMatthew Dillon 			if (ap->ap_flags & AP_F_IN_RESET)
23751980eff3SMatthew Dillon 				goto fatal;
23761980eff3SMatthew Dillon 			/*
23771980eff3SMatthew Dillon 			 * XXX how do we unbrick a PM target (ccb_at != NULL).
23781980eff3SMatthew Dillon 			 *
23791980eff3SMatthew Dillon 			 * For now fail the target and use CLO to clear the
23801980eff3SMatthew Dillon 			 * busy condition and make the ahci port usable for
23811980eff3SMatthew Dillon 			 * the remaining devices.
23821980eff3SMatthew Dillon 			 */
23831980eff3SMatthew Dillon 			if (ccb_at) {
23841980eff3SMatthew Dillon 				ccb_at->at_probe = ATA_PROBE_FAILED;
23851980eff3SMatthew Dillon 				ahci_port_clo(ap);
23861980eff3SMatthew Dillon 			} else if (ahci_port_reset(ap, ccb_at, 0)) {
238717eab71eSMatthew Dillon 				kprintf("%s: Unable to idle device after "
238817eab71eSMatthew Dillon 					"NCQ error, port bricked on us\n",
2389258223a3SMatthew Dillon 					PORTNAME(ap));
2390258223a3SMatthew Dillon 				goto fatal;
2391258223a3SMatthew Dillon 			}
2392258223a3SMatthew Dillon 			kprintf("%s: couldn't recover NCQ error, failing "
2393258223a3SMatthew Dillon 				"all outstanding commands.\n",
2394258223a3SMatthew Dillon 				PORTNAME(ap));
2395258223a3SMatthew Dillon 			goto failall;
2396258223a3SMatthew Dillon 		}
2397258223a3SMatthew Dillon 
2398258223a3SMatthew Dillon 		/* Clear the failed command in saved CI so completion runs. */
2399258223a3SMatthew Dillon 		ci_saved &= ~(1 << err_slot);
2400258223a3SMatthew Dillon 
2401258223a3SMatthew Dillon 		/* Note the error in the ata_xfer. */
2402258223a3SMatthew Dillon 		KKASSERT(ccb->ccb_xa.state == ATA_S_ONCHIP);
2403258223a3SMatthew Dillon 		ccb->ccb_xa.state = ATA_S_ERROR;
2404258223a3SMatthew Dillon 
2405258223a3SMatthew Dillon #ifdef DIAGNOSTIC
2406258223a3SMatthew Dillon 		/* There may only be one outstanding standard command now. */
2407258223a3SMatthew Dillon 		if (ap->ap_sactive == 0) {
2408258223a3SMatthew Dillon 			tmp = ci_saved;
2409258223a3SMatthew Dillon 			if (tmp) {
2410258223a3SMatthew Dillon 				slot = ffs(tmp) - 1;
2411258223a3SMatthew Dillon 				tmp &= ~(1 << slot);
2412258223a3SMatthew Dillon 				KKASSERT(tmp == 0);
2413258223a3SMatthew Dillon 			}
2414258223a3SMatthew Dillon 		}
2415258223a3SMatthew Dillon #endif
24161980eff3SMatthew Dillon 	} else if (is & AHCI_PREG_IS_DHRS) {
24171980eff3SMatthew Dillon 		/*
2418f4553de1SMatthew Dillon 		 * Command posted D2H register FIS to the rfis (non-blocking).
2419f4553de1SMatthew Dillon 		 *
24201980eff3SMatthew Dillon 		 * Command posted D2H register FIS to the rfis.  This
24218bf6a3ffSMatthew Dillon 		 * does NOT stop command processing and it is unclear
24228bf6a3ffSMatthew Dillon 		 * how we are supposed to deal with it other then using
24238bf6a3ffSMatthew Dillon 		 * only a queue of 1.
24248bf6a3ffSMatthew Dillon 		 *
24258bf6a3ffSMatthew Dillon 		 * We must copy the port rfis to the ccb and restart
24268bf6a3ffSMatthew Dillon 		 * command processing.  ahci_pm_read() does not function
24278bf6a3ffSMatthew Dillon 		 * without this support.
24281980eff3SMatthew Dillon 		 */
24291980eff3SMatthew Dillon 		int	err_slot;
24301980eff3SMatthew Dillon 
24311980eff3SMatthew Dillon 		if (ap->ap_sactive == 0) {
24321980eff3SMatthew Dillon 			err_slot = AHCI_PREG_CMD_CCS(
24331980eff3SMatthew Dillon 					ahci_pread(ap, AHCI_PREG_CMD));
24341980eff3SMatthew Dillon 			ccb = &ap->ap_ccbs[err_slot];
24351980eff3SMatthew Dillon 			ccb_at = ccb->ccb_xa.at;	/* can be NULL */
24361980eff3SMatthew Dillon 
24371980eff3SMatthew Dillon 			memcpy(&ccb->ccb_xa.rfis, ap->ap_rfis->rfis,
24381980eff3SMatthew Dillon 			       sizeof(struct ata_fis_d2h));
24391980eff3SMatthew Dillon 		} else {
24401980eff3SMatthew Dillon 			kprintf("%s: Unexpected DHRS posted while "
24411980eff3SMatthew Dillon 				"NCQ running\n", PORTNAME(ap));
24421980eff3SMatthew Dillon 			err_slot = -1;
2443258223a3SMatthew Dillon 		}
2444cec07d75SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_DHRS);
2445cec07d75SMatthew Dillon 		is &= ~AHCI_PREG_IS_DHRS;
24461980eff3SMatthew Dillon 	}
24471980eff3SMatthew Dillon 
24481980eff3SMatthew Dillon 	/*
2449f4553de1SMatthew Dillon 	 * Device notification to us (non-blocking)
24501980eff3SMatthew Dillon 	 *
2451cec07d75SMatthew Dillon 	 * NOTE!  On some parts notification bits can get set without
2452cec07d75SMatthew Dillon 	 *	  generating an interrupt.  It is unclear whether this is
2453cec07d75SMatthew Dillon 	 *	  a bug in the PM (sending a DTOH device setbits with 'N' set
2454cec07d75SMatthew Dillon 	 *	  and 'I' not set), or a bug in the host controller.
2455cec07d75SMatthew Dillon 	 *
2456cec07d75SMatthew Dillon 	 *	  It only seems to occur under load.
24571980eff3SMatthew Dillon 	 */
2458cec07d75SMatthew Dillon 	if (/*(is & AHCI_PREG_IS_SDBS) &&*/ (sc->sc_cap & AHCI_REG_CAP_SSNTF)) {
24591980eff3SMatthew Dillon 		u_int32_t data;
2460cec07d75SMatthew Dillon 		const char *xstr;
24611980eff3SMatthew Dillon 
24621980eff3SMatthew Dillon 		data = ahci_pread(ap, AHCI_PREG_SNTF);
2463cec07d75SMatthew Dillon 		if (is & AHCI_PREG_IS_SDBS) {
24641980eff3SMatthew Dillon 			ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_SDBS);
2465cec07d75SMatthew Dillon 			is &= ~AHCI_PREG_IS_SDBS;
2466cec07d75SMatthew Dillon 			xstr = " (no SDBS!)";
2467cec07d75SMatthew Dillon 		} else {
2468cec07d75SMatthew Dillon 			xstr = "";
2469cec07d75SMatthew Dillon 		}
2470cec07d75SMatthew Dillon 		if (data) {
2471cec07d75SMatthew Dillon 			ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_SDBS);
2472cec07d75SMatthew Dillon 
2473cec07d75SMatthew Dillon 			kprintf("%s: NOTIFY %08x%s\n",
2474cec07d75SMatthew Dillon 				PORTNAME(ap), data, xstr);
2475cec07d75SMatthew Dillon 			ahci_pwrite(ap, AHCI_PREG_SERR, AHCI_PREG_SERR_DIAG_N);
24763209f581SMatthew Dillon 			ahci_pwrite(ap, AHCI_PREG_SNTF, data);
24773209f581SMatthew Dillon 			ahci_cam_changed(ap, NULL, -1);
24781980eff3SMatthew Dillon 		}
24791980eff3SMatthew Dillon 	}
24803209f581SMatthew Dillon 
24813209f581SMatthew Dillon 	/*
2482f4553de1SMatthew Dillon 	 * Spurious IFS errors (blockable).
2483f4553de1SMatthew Dillon 	 *
24843209f581SMatthew Dillon 	 * Spurious IFS errors can occur while we are doing a reset
24853209f581SMatthew Dillon 	 * sequence through a PM.  Try to recover if we are being asked
24863209f581SMatthew Dillon 	 * to ignore IFS errors during these periods.
24873209f581SMatthew Dillon 	 */
24883209f581SMatthew Dillon 	if ((is & AHCI_PREG_IS_IFS) && (ap->ap_flags & AP_F_IGNORE_IFS)) {
24891980eff3SMatthew Dillon 		u_int32_t serr = ahci_pread(ap, AHCI_PREG_SERR);
24903209f581SMatthew Dillon 		if ((ap->ap_flags & AP_F_IFS_IGNORED) == 0) {
24911980eff3SMatthew Dillon 			kprintf("%s: Ignoring IFS (XXX) (IS: %b, SERR: %b)\n",
24921980eff3SMatthew Dillon 				PORTNAME(ap),
24931980eff3SMatthew Dillon 				is, AHCI_PFMT_IS,
24941980eff3SMatthew Dillon 				serr, AHCI_PFMT_SERR);
24953209f581SMatthew Dillon 			ap->ap_flags |= AP_F_IFS_IGNORED;
24963209f581SMatthew Dillon 		}
24973209f581SMatthew Dillon 		ap->ap_flags |= AP_F_IFS_OCCURED;
24981980eff3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SERR, -1);
24991980eff3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_IFS);
25001980eff3SMatthew Dillon 		is &= ~AHCI_PREG_IS_IFS;
25011980eff3SMatthew Dillon 		ahci_port_stop(ap, 0);
25021980eff3SMatthew Dillon 		ahci_port_start(ap);
25031980eff3SMatthew Dillon 		need = NEED_RESTART;
25041980eff3SMatthew Dillon 	}
2505258223a3SMatthew Dillon 
2506258223a3SMatthew Dillon 	/*
2507f4553de1SMatthew Dillon 	 * Port change (hot-plug) (blockable).
2508258223a3SMatthew Dillon 	 *
2509258223a3SMatthew Dillon 	 * A PCS interrupt will occur on hot-plug once communication is
2510258223a3SMatthew Dillon 	 * established.
2511258223a3SMatthew Dillon 	 *
2512258223a3SMatthew Dillon 	 * A PRCS interrupt will occur on hot-unplug (and possibly also
2513258223a3SMatthew Dillon 	 * on hot-plug).
2514258223a3SMatthew Dillon 	 *
251522181ab7SMatthew Dillon 	 * XXX We can then check the CPS (Cold Presence State) bit, if
251622181ab7SMatthew Dillon 	 * supported, to determine if a device is plugged in or not and do
251722181ab7SMatthew Dillon 	 * the right thing.
251822181ab7SMatthew Dillon 	 *
251922181ab7SMatthew Dillon 	 * WARNING:  A PCS interrupt is cleared by clearing DIAG_X, and
252022181ab7SMatthew Dillon 	 *	     can also occur if an unsolicited COMINIT is received.
252122181ab7SMatthew Dillon 	 *	     If this occurs command processing is automatically
252222181ab7SMatthew Dillon 	 *	     stopped (CR goes inactive) and the port must be stopped
252322181ab7SMatthew Dillon 	 *	     and restarted.
2524258223a3SMatthew Dillon 	 */
2525258223a3SMatthew Dillon 	if (is & (AHCI_PREG_IS_PCS | AHCI_PREG_IS_PRCS)) {
2526cec07d75SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS,
2527cec07d75SMatthew Dillon 			    is & (AHCI_PREG_IS_PCS | AHCI_PREG_IS_PRCS));
2528cec07d75SMatthew Dillon 		is &= ~(AHCI_PREG_IS_PCS | AHCI_PREG_IS_PRCS);
2529258223a3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SERR,
25301980eff3SMatthew Dillon 			(AHCI_PREG_SERR_DIAG_N | AHCI_PREG_SERR_DIAG_X));
253122181ab7SMatthew Dillon 		ahci_port_stop(ap, 0);
2532258223a3SMatthew Dillon 		switch (ahci_pread(ap, AHCI_PREG_SSTS) & AHCI_PREG_SSTS_DET) {
2533258223a3SMatthew Dillon 		case AHCI_PREG_SSTS_DET_DEV:
25341980eff3SMatthew Dillon 			if (ap->ap_type == ATA_PORT_T_NONE) {
253522181ab7SMatthew Dillon 				need = NEED_HOTPLUG_INSERT;
253622181ab7SMatthew Dillon 				goto fatal;
2537258223a3SMatthew Dillon 			}
253822181ab7SMatthew Dillon 			need = NEED_RESTART;
2539258223a3SMatthew Dillon 			break;
2540258223a3SMatthew Dillon 		default:
25411980eff3SMatthew Dillon 			if (ap->ap_type != ATA_PORT_T_NONE) {
254222181ab7SMatthew Dillon 				need = NEED_HOTPLUG_REMOVE;
254322181ab7SMatthew Dillon 				goto fatal;
2544258223a3SMatthew Dillon 			}
254522181ab7SMatthew Dillon 			need = NEED_RESTART;
2546258223a3SMatthew Dillon 			break;
2547258223a3SMatthew Dillon 		}
2548258223a3SMatthew Dillon 	}
2549258223a3SMatthew Dillon 
255022181ab7SMatthew Dillon 	/*
2551f4553de1SMatthew Dillon 	 * Check for remaining errors - they are fatal. (blockable)
255222181ab7SMatthew Dillon 	 */
2553258223a3SMatthew Dillon 	if (is & (AHCI_PREG_IS_TFES | AHCI_PREG_IS_HBFS | AHCI_PREG_IS_IFS |
2554258223a3SMatthew Dillon 		  AHCI_PREG_IS_OFS | AHCI_PREG_IS_UFS)) {
2555cec07d75SMatthew Dillon 		u_int32_t serr;
2556cec07d75SMatthew Dillon 
2557cec07d75SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS,
2558cec07d75SMatthew Dillon 			    is & (AHCI_PREG_IS_TFES | AHCI_PREG_IS_HBFS |
2559cec07d75SMatthew Dillon 				  AHCI_PREG_IS_IFS | AHCI_PREG_IS_OFS |
2560cec07d75SMatthew Dillon 				  AHCI_PREG_IS_UFS));
2561cec07d75SMatthew Dillon 		serr = ahci_pread(ap, AHCI_PREG_SERR);
2562831bc9e3SMatthew Dillon 		kprintf("%s: Unrecoverable errors (IS: %b, SERR: %b), "
25634444122dSMatthew Dillon 			"disabling port.\n",
25644444122dSMatthew Dillon 			PORTNAME(ap),
25654444122dSMatthew Dillon 			is, AHCI_PFMT_IS,
25661980eff3SMatthew Dillon 			serr, AHCI_PFMT_SERR
25674444122dSMatthew Dillon 		);
2568831bc9e3SMatthew Dillon 		is &= ~(AHCI_PREG_IS_TFES | AHCI_PREG_IS_HBFS |
2569831bc9e3SMatthew Dillon 			AHCI_PREG_IS_IFS | AHCI_PREG_IS_OFS |
2570831bc9e3SMatthew Dillon 		        AHCI_PREG_IS_UFS);
2571258223a3SMatthew Dillon 		/* XXX try recovery first */
2572258223a3SMatthew Dillon 		goto fatal;
2573258223a3SMatthew Dillon 	}
2574258223a3SMatthew Dillon 
257522181ab7SMatthew Dillon 	/*
257622181ab7SMatthew Dillon 	 * Fail all outstanding commands if we know the port won't recover.
25771980eff3SMatthew Dillon 	 *
25781980eff3SMatthew Dillon 	 * We may have a ccb_at if the failed command is known and was
25791980eff3SMatthew Dillon 	 * being sent to a device over a port multiplier (PM).  In this
25801980eff3SMatthew Dillon 	 * case if the port itself has not completely failed we fail just
25811980eff3SMatthew Dillon 	 * the commands related to that target.
258222181ab7SMatthew Dillon 	 */
2583258223a3SMatthew Dillon 	if (ap->ap_state == AP_S_FATAL_ERROR) {
2584258223a3SMatthew Dillon fatal:
2585258223a3SMatthew Dillon 		ap->ap_state = AP_S_FATAL_ERROR;
2586258223a3SMatthew Dillon failall:
2587258223a3SMatthew Dillon 
2588cf5f3a81SMatthew Dillon 		/* Stopping the port clears CI/SACT */
2589cf5f3a81SMatthew Dillon 		ahci_port_stop(ap, 0);
2590258223a3SMatthew Dillon 
25911980eff3SMatthew Dillon 		/*
25921980eff3SMatthew Dillon 		 * Error all the active slots.  If running across a PM
25931980eff3SMatthew Dillon 		 * try to error out just the slots related to the target.
25941980eff3SMatthew Dillon 		 */
2595258223a3SMatthew Dillon 		ci_masked = ci_saved & *active;
2596258223a3SMatthew Dillon 		while (ci_masked) {
2597258223a3SMatthew Dillon 			slot = ffs(ci_masked) - 1;
2598258223a3SMatthew Dillon 			ccb = &ap->ap_ccbs[slot];
25991980eff3SMatthew Dillon 			if (ccb_at == ccb->ccb_xa.at ||
26001980eff3SMatthew Dillon 			    ap->ap_state == AP_S_FATAL_ERROR) {
2601258223a3SMatthew Dillon 				ci_masked &= ~(1 << slot);
2602258223a3SMatthew Dillon 				ccb->ccb_xa.state = ATA_S_ERROR;
2603258223a3SMatthew Dillon 			}
26041980eff3SMatthew Dillon 		}
2605258223a3SMatthew Dillon 
2606258223a3SMatthew Dillon 		/* Run completion for all active slots. */
2607258223a3SMatthew Dillon 		ci_saved &= ~*active;
2608258223a3SMatthew Dillon 
2609258223a3SMatthew Dillon 		/*
2610258223a3SMatthew Dillon 		 * Don't restart the port if our problems were deemed fatal.
2611258223a3SMatthew Dillon 		 *
2612258223a3SMatthew Dillon 		 * Also acknowlege all fatal interrupt sources to prevent
2613258223a3SMatthew Dillon 		 * a livelock.
2614258223a3SMatthew Dillon 		 */
2615258223a3SMatthew Dillon 		if (ap->ap_state == AP_S_FATAL_ERROR) {
261622181ab7SMatthew Dillon 			if (need == NEED_RESTART)
261722181ab7SMatthew Dillon 				need = NEED_NOTHING;
2618258223a3SMatthew Dillon 			ahci_pwrite(ap, AHCI_PREG_IS,
2619258223a3SMatthew Dillon 				    AHCI_PREG_IS_TFES | AHCI_PREG_IS_HBFS |
2620258223a3SMatthew Dillon 				    AHCI_PREG_IS_IFS | AHCI_PREG_IS_OFS |
2621258223a3SMatthew Dillon 				    AHCI_PREG_IS_UFS);
2622258223a3SMatthew Dillon 		}
2623258223a3SMatthew Dillon 	}
2624258223a3SMatthew Dillon 
2625258223a3SMatthew Dillon 	/*
2626f4553de1SMatthew Dillon 	 * CCB completion (non blocking).
2627f4553de1SMatthew Dillon 	 *
2628258223a3SMatthew Dillon 	 * CCB completion is detected by noticing its slot's bit in CI has
2629258223a3SMatthew Dillon 	 * changed to zero some time after we activated it.
2630258223a3SMatthew Dillon 	 * If we are polling, we may only be interested in particular slot(s).
2631cf5f3a81SMatthew Dillon 	 *
2632cf5f3a81SMatthew Dillon 	 * Any active bits not saved are completed within the restrictions
2633cf5f3a81SMatthew Dillon 	 * imposed by the caller.
2634258223a3SMatthew Dillon 	 */
26353209f581SMatthew Dillon 	ci_masked = ~ci_saved & *active;
2636258223a3SMatthew Dillon 	while (ci_masked) {
2637258223a3SMatthew Dillon 		slot = ffs(ci_masked) - 1;
2638258223a3SMatthew Dillon 		ccb = &ap->ap_ccbs[slot];
2639258223a3SMatthew Dillon 		ci_masked &= ~(1 << slot);
2640258223a3SMatthew Dillon 
2641258223a3SMatthew Dillon 		DPRINTF(AHCI_D_INTR, "%s: slot %d is complete%s\n",
2642258223a3SMatthew Dillon 		    PORTNAME(ap), slot, ccb->ccb_xa.state == ATA_S_ERROR ?
2643258223a3SMatthew Dillon 		    " (error)" : "");
2644258223a3SMatthew Dillon 
2645258223a3SMatthew Dillon 		bus_dmamap_sync(sc->sc_tag_cmdh,
2646258223a3SMatthew Dillon 				AHCI_DMA_MAP(ap->ap_dmamem_cmd_list),
2647258223a3SMatthew Dillon 				BUS_DMASYNC_POSTWRITE);
2648258223a3SMatthew Dillon 
2649258223a3SMatthew Dillon 		bus_dmamap_sync(sc->sc_tag_cmdt,
2650258223a3SMatthew Dillon 				AHCI_DMA_MAP(ap->ap_dmamem_cmd_table),
2651258223a3SMatthew Dillon 				BUS_DMASYNC_POSTWRITE);
2652258223a3SMatthew Dillon 
2653258223a3SMatthew Dillon 		bus_dmamap_sync(sc->sc_tag_rfis,
2654258223a3SMatthew Dillon 				AHCI_DMA_MAP(ap->ap_dmamem_rfis),
2655258223a3SMatthew Dillon 				BUS_DMASYNC_POSTREAD);
2656258223a3SMatthew Dillon 
2657258223a3SMatthew Dillon 		*active &= ~(1 << ccb->ccb_slot);
26581980eff3SMatthew Dillon 		if (active == &ap->ap_active) {
26591980eff3SMatthew Dillon 			KKASSERT(ap->ap_active_cnt > 0);
26601980eff3SMatthew Dillon 			--ap->ap_active_cnt;
26611980eff3SMatthew Dillon 		}
26624c339a5fSMatthew Dillon 
26634c339a5fSMatthew Dillon 		/*
26644c339a5fSMatthew Dillon 		 * Complete the ccb.  If the ccb was marked expired it
26654c339a5fSMatthew Dillon 		 * was probably already removed from the command processor,
26664c339a5fSMatthew Dillon 		 * so don't take the clear ci_saved bit as meaning the
26674c339a5fSMatthew Dillon 		 * command actually succeeded, it didn't.
26684c339a5fSMatthew Dillon 		 */
26694c339a5fSMatthew Dillon 		if (ap->ap_expired & (1 << ccb->ccb_slot)) {
26704c339a5fSMatthew Dillon 			ccb->ccb_xa.state = ATA_S_TIMEOUT;
2671258223a3SMatthew Dillon 			ccb->ccb_done(ccb);
26724c339a5fSMatthew Dillon 			ccb->ccb_xa.complete(&ccb->ccb_xa);
26734c339a5fSMatthew Dillon 		} else {
26744c339a5fSMatthew Dillon 			if (ccb->ccb_xa.state == ATA_S_ONCHIP)
26754c339a5fSMatthew Dillon 				ccb->ccb_xa.state = ATA_S_COMPLETE;
26764c339a5fSMatthew Dillon 			ccb->ccb_done(ccb);
26774c339a5fSMatthew Dillon 		}
26784c339a5fSMatthew Dillon 		ahci_issue_pending_commands(ap, NULL);
2679258223a3SMatthew Dillon 	}
2680258223a3SMatthew Dillon 
2681f4553de1SMatthew Dillon 	/*
2682f4553de1SMatthew Dillon 	 * Cleanup.  Will not be set if non-blocking.
2683f4553de1SMatthew Dillon 	 */
268422181ab7SMatthew Dillon 	switch(need) {
268522181ab7SMatthew Dillon 	case NEED_RESTART:
268622181ab7SMatthew Dillon 		/*
268722181ab7SMatthew Dillon 		 * A recoverable error occured and we can restart outstanding
268822181ab7SMatthew Dillon 		 * commands on the port.
268922181ab7SMatthew Dillon 		 */
269017eab71eSMatthew Dillon 		ahci_port_start(ap);
2691258223a3SMatthew Dillon 
2692258223a3SMatthew Dillon 		if (ci_saved) {
2693258223a3SMatthew Dillon #ifdef DIAGNOSTIC
2694258223a3SMatthew Dillon 			tmp = ci_saved;
2695258223a3SMatthew Dillon 			while (tmp) {
2696258223a3SMatthew Dillon 				slot = ffs(tmp) - 1;
2697258223a3SMatthew Dillon 				tmp &= ~(1 << slot);
2698258223a3SMatthew Dillon 				ccb = &ap->ap_ccbs[slot];
2699258223a3SMatthew Dillon 				KKASSERT(ccb->ccb_xa.state == ATA_S_ONCHIP);
2700258223a3SMatthew Dillon 				KKASSERT((!!(ccb->ccb_xa.flags & ATA_F_NCQ)) ==
2701258223a3SMatthew Dillon 				    (!!ap->ap_sactive));
2702258223a3SMatthew Dillon 			}
2703258223a3SMatthew Dillon #endif
27044c339a5fSMatthew Dillon 			ahci_issue_saved_commands(ap, ci_saved);
2705258223a3SMatthew Dillon 		}
270622181ab7SMatthew Dillon 		break;
270722181ab7SMatthew Dillon 	case NEED_HOTPLUG_INSERT:
270822181ab7SMatthew Dillon 		/*
2709cf5f3a81SMatthew Dillon 		 * A hot-plug insertion event has occured and all
2710cf5f3a81SMatthew Dillon 		 * outstanding commands have already been revoked.
27111980eff3SMatthew Dillon 		 *
27121980eff3SMatthew Dillon 		 * Don't recurse if this occurs while we are
27131980eff3SMatthew Dillon 		 * resetting the port.
271422181ab7SMatthew Dillon 		 */
27151980eff3SMatthew Dillon 		if ((ap->ap_flags & AP_F_IN_RESET) == 0) {
271622181ab7SMatthew Dillon 			kprintf("%s: HOTPLUG - Device inserted\n",
271722181ab7SMatthew Dillon 				PORTNAME(ap));
27183209f581SMatthew Dillon 			ap->ap_probe = ATA_PROBE_NEED_INIT;
27193209f581SMatthew Dillon 			ahci_cam_changed(ap, NULL, -1);
27201980eff3SMatthew Dillon 		}
272122181ab7SMatthew Dillon 		break;
272222181ab7SMatthew Dillon 	case NEED_HOTPLUG_REMOVE:
2723cf5f3a81SMatthew Dillon 		/*
2724cf5f3a81SMatthew Dillon 		 * A hot-plug removal event has occured and all
2725cf5f3a81SMatthew Dillon 		 * outstanding commands have already been revoked.
27261980eff3SMatthew Dillon 		 *
27271980eff3SMatthew Dillon 		 * Don't recurse if this occurs while we are
27281980eff3SMatthew Dillon 		 * resetting the port.
2729cf5f3a81SMatthew Dillon 		 */
27301980eff3SMatthew Dillon 		if ((ap->ap_flags & AP_F_IN_RESET) == 0) {
273122181ab7SMatthew Dillon 			kprintf("%s: HOTPLUG - Device removed\n",
273222181ab7SMatthew Dillon 				PORTNAME(ap));
2733cf5f3a81SMatthew Dillon 			ahci_port_hardstop(ap);
27343209f581SMatthew Dillon 			/* ap_probe set to failed */
27353209f581SMatthew Dillon 			ahci_cam_changed(ap, NULL, -1);
27361980eff3SMatthew Dillon 		}
273722181ab7SMatthew Dillon 		break;
273822181ab7SMatthew Dillon 	default:
273922181ab7SMatthew Dillon 		break;
2740258223a3SMatthew Dillon 	}
2741258223a3SMatthew Dillon }
2742258223a3SMatthew Dillon 
2743258223a3SMatthew Dillon struct ahci_ccb *
2744258223a3SMatthew Dillon ahci_get_ccb(struct ahci_port *ap)
2745258223a3SMatthew Dillon {
2746258223a3SMatthew Dillon 	struct ahci_ccb			*ccb;
2747258223a3SMatthew Dillon 
2748258223a3SMatthew Dillon 	lockmgr(&ap->ap_ccb_lock, LK_EXCLUSIVE);
2749258223a3SMatthew Dillon 	ccb = TAILQ_FIRST(&ap->ap_ccb_free);
2750258223a3SMatthew Dillon 	if (ccb != NULL) {
2751258223a3SMatthew Dillon 		KKASSERT(ccb->ccb_xa.state == ATA_S_PUT);
2752258223a3SMatthew Dillon 		TAILQ_REMOVE(&ap->ap_ccb_free, ccb, ccb_entry);
2753258223a3SMatthew Dillon 		ccb->ccb_xa.state = ATA_S_SETUP;
27541980eff3SMatthew Dillon 		ccb->ccb_xa.at = NULL;
2755258223a3SMatthew Dillon 	}
2756258223a3SMatthew Dillon 	lockmgr(&ap->ap_ccb_lock, LK_RELEASE);
2757258223a3SMatthew Dillon 
2758258223a3SMatthew Dillon 	return (ccb);
2759258223a3SMatthew Dillon }
2760258223a3SMatthew Dillon 
2761258223a3SMatthew Dillon void
2762258223a3SMatthew Dillon ahci_put_ccb(struct ahci_ccb *ccb)
2763258223a3SMatthew Dillon {
2764258223a3SMatthew Dillon 	struct ahci_port		*ap = ccb->ccb_port;
2765258223a3SMatthew Dillon 
2766258223a3SMatthew Dillon #ifdef DIAGNOSTIC
2767258223a3SMatthew Dillon 	if (ccb->ccb_xa.state != ATA_S_COMPLETE &&
2768258223a3SMatthew Dillon 	    ccb->ccb_xa.state != ATA_S_TIMEOUT &&
2769258223a3SMatthew Dillon 	    ccb->ccb_xa.state != ATA_S_ERROR) {
2770258223a3SMatthew Dillon 		kprintf("%s: invalid ata_xfer state %02x in ahci_put_ccb, "
2771258223a3SMatthew Dillon 			"slot %d\n",
2772258223a3SMatthew Dillon 			PORTNAME(ccb->ccb_port), ccb->ccb_xa.state,
2773258223a3SMatthew Dillon 			ccb->ccb_slot);
2774258223a3SMatthew Dillon 	}
2775258223a3SMatthew Dillon #endif
2776258223a3SMatthew Dillon 
2777258223a3SMatthew Dillon 	ccb->ccb_xa.state = ATA_S_PUT;
2778258223a3SMatthew Dillon 	lockmgr(&ap->ap_ccb_lock, LK_EXCLUSIVE);
2779258223a3SMatthew Dillon 	TAILQ_INSERT_TAIL(&ap->ap_ccb_free, ccb, ccb_entry);
2780258223a3SMatthew Dillon 	lockmgr(&ap->ap_ccb_lock, LK_RELEASE);
2781258223a3SMatthew Dillon }
2782258223a3SMatthew Dillon 
2783258223a3SMatthew Dillon struct ahci_ccb *
2784258223a3SMatthew Dillon ahci_get_err_ccb(struct ahci_port *ap)
2785258223a3SMatthew Dillon {
2786258223a3SMatthew Dillon 	struct ahci_ccb *err_ccb;
2787258223a3SMatthew Dillon 	u_int32_t sact;
2788258223a3SMatthew Dillon 
2789258223a3SMatthew Dillon 	/* No commands may be active on the chip. */
2790258223a3SMatthew Dillon 	sact = ahci_pread(ap, AHCI_PREG_SACT);
2791258223a3SMatthew Dillon 	if (sact != 0)
2792258223a3SMatthew Dillon 		kprintf("ahci_get_err_ccb but SACT %08x != 0?\n", sact);
2793258223a3SMatthew Dillon 	KKASSERT(ahci_pread(ap, AHCI_PREG_CI) == 0);
2794baef7501SMatthew Dillon 	KKASSERT((ap->ap_flags & AP_F_ERR_CCB_RESERVED) == 0);
2795baef7501SMatthew Dillon 	ap->ap_flags |= AP_F_ERR_CCB_RESERVED;
2796258223a3SMatthew Dillon 
2797258223a3SMatthew Dillon #ifdef DIAGNOSTIC
2798258223a3SMatthew Dillon 	KKASSERT(ap->ap_err_busy == 0);
2799258223a3SMatthew Dillon 	ap->ap_err_busy = 1;
2800258223a3SMatthew Dillon #endif
2801258223a3SMatthew Dillon 	/* Save outstanding command state. */
2802258223a3SMatthew Dillon 	ap->ap_err_saved_active = ap->ap_active;
2803258223a3SMatthew Dillon 	ap->ap_err_saved_active_cnt = ap->ap_active_cnt;
2804258223a3SMatthew Dillon 	ap->ap_err_saved_sactive = ap->ap_sactive;
2805258223a3SMatthew Dillon 
2806258223a3SMatthew Dillon 	/*
2807258223a3SMatthew Dillon 	 * Pretend we have no commands outstanding, so that completions won't
2808258223a3SMatthew Dillon 	 * run prematurely.
2809258223a3SMatthew Dillon 	 */
2810258223a3SMatthew Dillon 	ap->ap_active = ap->ap_active_cnt = ap->ap_sactive = 0;
2811258223a3SMatthew Dillon 
2812258223a3SMatthew Dillon 	/*
2813258223a3SMatthew Dillon 	 * Grab a CCB to use for error recovery.  This should never fail, as
2814258223a3SMatthew Dillon 	 * we ask atascsi to reserve one for us at init time.
2815258223a3SMatthew Dillon 	 */
28161067474aSMatthew Dillon 	err_ccb = ap->ap_err_ccb;
2817258223a3SMatthew Dillon 	KKASSERT(err_ccb != NULL);
2818258223a3SMatthew Dillon 	err_ccb->ccb_xa.flags = 0;
2819258223a3SMatthew Dillon 	err_ccb->ccb_done = ahci_empty_done;
2820258223a3SMatthew Dillon 
2821258223a3SMatthew Dillon 	return err_ccb;
2822258223a3SMatthew Dillon }
2823258223a3SMatthew Dillon 
2824258223a3SMatthew Dillon void
2825258223a3SMatthew Dillon ahci_put_err_ccb(struct ahci_ccb *ccb)
2826258223a3SMatthew Dillon {
2827258223a3SMatthew Dillon 	struct ahci_port *ap = ccb->ccb_port;
2828258223a3SMatthew Dillon 	u_int32_t sact;
28295f8c1efdSMatthew Dillon 	u_int32_t ci;
2830258223a3SMatthew Dillon 
2831258223a3SMatthew Dillon #ifdef DIAGNOSTIC
2832258223a3SMatthew Dillon 	KKASSERT(ap->ap_err_busy);
2833258223a3SMatthew Dillon #endif
2834baef7501SMatthew Dillon 	KKASSERT((ap->ap_flags & AP_F_ERR_CCB_RESERVED) != 0);
2835baef7501SMatthew Dillon 
28365f8c1efdSMatthew Dillon 	/*
28375f8c1efdSMatthew Dillon 	 * No commands may be active on the chip
28385f8c1efdSMatthew Dillon 	 */
2839258223a3SMatthew Dillon 	sact = ahci_pread(ap, AHCI_PREG_SACT);
28405f8c1efdSMatthew Dillon 	if (sact) {
28415f8c1efdSMatthew Dillon 		panic("ahci_port_err_ccb(%d) but SACT %08x != 0\n",
28425f8c1efdSMatthew Dillon 		      ccb->ccb_slot, sact);
2843258223a3SMatthew Dillon 	}
28445f8c1efdSMatthew Dillon 	ci = ahci_pread(ap, AHCI_PREG_CI);
28455f8c1efdSMatthew Dillon 	if (ci) {
2846cf5f3a81SMatthew Dillon 		panic("ahci_put_err_ccb(%d) but CI %08x != 0 "
2847cf5f3a81SMatthew Dillon 		      "(act=%08x sact=%08x)\n",
2848cf5f3a81SMatthew Dillon 		      ccb->ccb_slot, ci,
2849cf5f3a81SMatthew Dillon 		      ap->ap_active, ap->ap_sactive);
28505f8c1efdSMatthew Dillon 	}
2851258223a3SMatthew Dillon 
28521067474aSMatthew Dillon 	KKASSERT(ccb == ap->ap_err_ccb);
2853258223a3SMatthew Dillon 
2854258223a3SMatthew Dillon 	/* Restore outstanding command state */
2855258223a3SMatthew Dillon 	ap->ap_sactive = ap->ap_err_saved_sactive;
2856258223a3SMatthew Dillon 	ap->ap_active_cnt = ap->ap_err_saved_active_cnt;
2857258223a3SMatthew Dillon 	ap->ap_active = ap->ap_err_saved_active;
2858258223a3SMatthew Dillon 
2859258223a3SMatthew Dillon #ifdef DIAGNOSTIC
2860258223a3SMatthew Dillon 	ap->ap_err_busy = 0;
2861258223a3SMatthew Dillon #endif
2862baef7501SMatthew Dillon 	ap->ap_flags &= ~AP_F_ERR_CCB_RESERVED;
2863258223a3SMatthew Dillon }
2864258223a3SMatthew Dillon 
28651980eff3SMatthew Dillon /*
28661980eff3SMatthew Dillon  * Read log page to get NCQ error.
28671980eff3SMatthew Dillon  *
28681980eff3SMatthew Dillon  * NOTE: NCQ not currently supported on port multipliers. XXX
28691980eff3SMatthew Dillon  */
2870258223a3SMatthew Dillon int
2871258223a3SMatthew Dillon ahci_port_read_ncq_error(struct ahci_port *ap, int *err_slotp)
2872258223a3SMatthew Dillon {
2873258223a3SMatthew Dillon 	struct ahci_ccb			*ccb;
2874258223a3SMatthew Dillon 	struct ahci_cmd_hdr		*cmd_slot;
2875258223a3SMatthew Dillon 	u_int32_t			cmd;
2876258223a3SMatthew Dillon 	struct ata_fis_h2d		*fis;
2877258223a3SMatthew Dillon 	int				rc = EIO;
2878258223a3SMatthew Dillon 
2879258223a3SMatthew Dillon 	DPRINTF(AHCI_D_VERBOSE, "%s: read log page\n", PORTNAME(ap));
2880258223a3SMatthew Dillon 
2881258223a3SMatthew Dillon 	/* Save command register state. */
2882258223a3SMatthew Dillon 	cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC;
2883258223a3SMatthew Dillon 
2884258223a3SMatthew Dillon 	/* Port should have been idled already.  Start it. */
2885258223a3SMatthew Dillon 	KKASSERT((cmd & AHCI_PREG_CMD_CR) == 0);
288617eab71eSMatthew Dillon 	ahci_port_start(ap);
2887258223a3SMatthew Dillon 
2888258223a3SMatthew Dillon 	/* Prep error CCB for READ LOG EXT, page 10h, 1 sector. */
2889258223a3SMatthew Dillon 	ccb = ahci_get_err_ccb(ap);
2890258223a3SMatthew Dillon 	ccb->ccb_xa.flags = ATA_F_NOWAIT | ATA_F_READ | ATA_F_POLL;
2891258223a3SMatthew Dillon 	ccb->ccb_xa.data = ap->ap_err_scratch;
2892258223a3SMatthew Dillon 	ccb->ccb_xa.datalen = 512;
2893258223a3SMatthew Dillon 	cmd_slot = ccb->ccb_cmd_hdr;
2894258223a3SMatthew Dillon 	bzero(ccb->ccb_cmd_table, sizeof(struct ahci_cmd_table));
2895258223a3SMatthew Dillon 
2896258223a3SMatthew Dillon 	fis = (struct ata_fis_h2d *)ccb->ccb_cmd_table->cfis;
2897258223a3SMatthew Dillon 	fis->type = ATA_FIS_TYPE_H2D;
2898258223a3SMatthew Dillon 	fis->flags = ATA_H2D_FLAGS_CMD;
2899258223a3SMatthew Dillon 	fis->command = ATA_C_READ_LOG_EXT;
2900258223a3SMatthew Dillon 	fis->lba_low = 0x10;		/* queued error log page (10h) */
2901258223a3SMatthew Dillon 	fis->sector_count = 1;		/* number of sectors (1) */
2902258223a3SMatthew Dillon 	fis->sector_count_exp = 0;
2903258223a3SMatthew Dillon 	fis->lba_mid = 0;		/* starting offset */
2904258223a3SMatthew Dillon 	fis->lba_mid_exp = 0;
2905258223a3SMatthew Dillon 	fis->device = 0;
2906258223a3SMatthew Dillon 
2907258223a3SMatthew Dillon 	cmd_slot->flags = htole16(5);	/* FIS length: 5 DWORDS */
2908258223a3SMatthew Dillon 
2909258223a3SMatthew Dillon 	if (ahci_load_prdt(ccb) != 0) {
2910258223a3SMatthew Dillon 		rc = ENOMEM;	/* XXX caller must abort all commands */
2911258223a3SMatthew Dillon 		goto err;
2912258223a3SMatthew Dillon 	}
2913258223a3SMatthew Dillon 
2914258223a3SMatthew Dillon 	ccb->ccb_xa.state = ATA_S_PENDING;
2915831bc9e3SMatthew Dillon 	if (ahci_poll(ccb, 1000, ahci_quick_timeout) != 0)
2916258223a3SMatthew Dillon 		goto err;
2917258223a3SMatthew Dillon 
2918258223a3SMatthew Dillon 	rc = 0;
2919258223a3SMatthew Dillon err:
2920258223a3SMatthew Dillon 	/* Abort our command, if it failed, by stopping command DMA. */
2921831bc9e3SMatthew Dillon 	if (rc) {
2922258223a3SMatthew Dillon 		kprintf("%s: log page read failed, slot %d was still active.\n",
2923258223a3SMatthew Dillon 			PORTNAME(ap), ccb->ccb_slot);
2924258223a3SMatthew Dillon 	}
2925258223a3SMatthew Dillon 
2926258223a3SMatthew Dillon 	/* Done with the error CCB now. */
2927258223a3SMatthew Dillon 	ahci_unload_prdt(ccb);
2928258223a3SMatthew Dillon 	ahci_put_err_ccb(ccb);
2929258223a3SMatthew Dillon 
2930258223a3SMatthew Dillon 	/* Extract failed register set and tags from the scratch space. */
2931258223a3SMatthew Dillon 	if (rc == 0) {
2932258223a3SMatthew Dillon 		struct ata_log_page_10h		*log;
2933258223a3SMatthew Dillon 		int				err_slot;
2934258223a3SMatthew Dillon 
2935258223a3SMatthew Dillon 		log = (struct ata_log_page_10h *)ap->ap_err_scratch;
2936258223a3SMatthew Dillon 		if (log->err_regs.type & ATA_LOG_10H_TYPE_NOTQUEUED) {
2937258223a3SMatthew Dillon 			/* Not queued bit was set - wasn't an NCQ error? */
2938258223a3SMatthew Dillon 			kprintf("%s: read NCQ error page, but not an NCQ "
2939258223a3SMatthew Dillon 				"error?\n",
2940258223a3SMatthew Dillon 				PORTNAME(ap));
2941258223a3SMatthew Dillon 			rc = ESRCH;
2942258223a3SMatthew Dillon 		} else {
2943258223a3SMatthew Dillon 			/* Copy back the log record as a D2H register FIS. */
2944258223a3SMatthew Dillon 			*err_slotp = err_slot = log->err_regs.type &
2945258223a3SMatthew Dillon 			    ATA_LOG_10H_TYPE_TAG_MASK;
2946258223a3SMatthew Dillon 
2947258223a3SMatthew Dillon 			ccb = &ap->ap_ccbs[err_slot];
2948258223a3SMatthew Dillon 			memcpy(&ccb->ccb_xa.rfis, &log->err_regs,
2949258223a3SMatthew Dillon 			    sizeof(struct ata_fis_d2h));
2950258223a3SMatthew Dillon 			ccb->ccb_xa.rfis.type = ATA_FIS_TYPE_D2H;
2951258223a3SMatthew Dillon 			ccb->ccb_xa.rfis.flags = 0;
2952258223a3SMatthew Dillon 		}
2953258223a3SMatthew Dillon 	}
2954258223a3SMatthew Dillon 
2955258223a3SMatthew Dillon 	/* Restore saved CMD register state */
2956258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_CMD, cmd);
2957258223a3SMatthew Dillon 
2958258223a3SMatthew Dillon 	return (rc);
2959258223a3SMatthew Dillon }
2960258223a3SMatthew Dillon 
2961258223a3SMatthew Dillon /*
2962258223a3SMatthew Dillon  * Allocate memory for various structures DMAd by hardware.  The maximum
2963258223a3SMatthew Dillon  * number of segments for these tags is 1 so the DMA memory will have a
2964258223a3SMatthew Dillon  * single physical base address.
2965258223a3SMatthew Dillon  */
2966258223a3SMatthew Dillon struct ahci_dmamem *
2967258223a3SMatthew Dillon ahci_dmamem_alloc(struct ahci_softc *sc, bus_dma_tag_t tag)
2968258223a3SMatthew Dillon {
2969258223a3SMatthew Dillon 	struct ahci_dmamem *adm;
2970258223a3SMatthew Dillon 	int	error;
2971258223a3SMatthew Dillon 
2972258223a3SMatthew Dillon 	adm = kmalloc(sizeof(*adm), M_DEVBUF, M_INTWAIT | M_ZERO);
2973258223a3SMatthew Dillon 
2974258223a3SMatthew Dillon 	error = bus_dmamem_alloc(tag, (void **)&adm->adm_kva,
2975258223a3SMatthew Dillon 				 BUS_DMA_ZERO, &adm->adm_map);
2976258223a3SMatthew Dillon 	if (error == 0) {
2977258223a3SMatthew Dillon 		adm->adm_tag = tag;
2978258223a3SMatthew Dillon 		error = bus_dmamap_load(tag, adm->adm_map,
2979258223a3SMatthew Dillon 					adm->adm_kva,
2980258223a3SMatthew Dillon 					bus_dma_tag_getmaxsize(tag),
2981258223a3SMatthew Dillon 					ahci_dmamem_saveseg, &adm->adm_busaddr,
2982258223a3SMatthew Dillon 					0);
2983258223a3SMatthew Dillon 	}
2984258223a3SMatthew Dillon 	if (error) {
2985258223a3SMatthew Dillon 		if (adm->adm_map) {
2986258223a3SMatthew Dillon 			bus_dmamap_destroy(tag, adm->adm_map);
2987258223a3SMatthew Dillon 			adm->adm_map = NULL;
2988258223a3SMatthew Dillon 			adm->adm_tag = NULL;
2989258223a3SMatthew Dillon 			adm->adm_kva = NULL;
2990258223a3SMatthew Dillon 		}
2991258223a3SMatthew Dillon 		kfree(adm, M_DEVBUF);
2992258223a3SMatthew Dillon 		adm = NULL;
2993258223a3SMatthew Dillon 	}
2994258223a3SMatthew Dillon 	return (adm);
2995258223a3SMatthew Dillon }
2996258223a3SMatthew Dillon 
2997258223a3SMatthew Dillon static
2998258223a3SMatthew Dillon void
2999258223a3SMatthew Dillon ahci_dmamem_saveseg(void *info, bus_dma_segment_t *segs, int nsegs, int error)
3000258223a3SMatthew Dillon {
3001258223a3SMatthew Dillon 	KKASSERT(error == 0);
3002258223a3SMatthew Dillon 	KKASSERT(nsegs == 1);
3003258223a3SMatthew Dillon 	*(bus_addr_t *)info = segs->ds_addr;
3004258223a3SMatthew Dillon }
3005258223a3SMatthew Dillon 
3006258223a3SMatthew Dillon 
3007258223a3SMatthew Dillon void
3008258223a3SMatthew Dillon ahci_dmamem_free(struct ahci_softc *sc, struct ahci_dmamem *adm)
3009258223a3SMatthew Dillon {
3010258223a3SMatthew Dillon 	if (adm->adm_map) {
3011258223a3SMatthew Dillon 		bus_dmamap_unload(adm->adm_tag, adm->adm_map);
3012258223a3SMatthew Dillon 		bus_dmamap_destroy(adm->adm_tag, adm->adm_map);
3013258223a3SMatthew Dillon 		adm->adm_map = NULL;
3014258223a3SMatthew Dillon 		adm->adm_tag = NULL;
3015258223a3SMatthew Dillon 		adm->adm_kva = NULL;
3016258223a3SMatthew Dillon 	}
3017258223a3SMatthew Dillon 	kfree(adm, M_DEVBUF);
3018258223a3SMatthew Dillon }
3019258223a3SMatthew Dillon 
3020258223a3SMatthew Dillon u_int32_t
3021258223a3SMatthew Dillon ahci_read(struct ahci_softc *sc, bus_size_t r)
3022258223a3SMatthew Dillon {
3023258223a3SMatthew Dillon 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
3024258223a3SMatthew Dillon 			  BUS_SPACE_BARRIER_READ);
3025258223a3SMatthew Dillon 	return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, r));
3026258223a3SMatthew Dillon }
3027258223a3SMatthew Dillon 
3028258223a3SMatthew Dillon void
3029258223a3SMatthew Dillon ahci_write(struct ahci_softc *sc, bus_size_t r, u_int32_t v)
3030258223a3SMatthew Dillon {
3031258223a3SMatthew Dillon 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v);
3032258223a3SMatthew Dillon 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
3033258223a3SMatthew Dillon 			  BUS_SPACE_BARRIER_WRITE);
3034258223a3SMatthew Dillon }
3035258223a3SMatthew Dillon 
3036258223a3SMatthew Dillon u_int32_t
3037258223a3SMatthew Dillon ahci_pread(struct ahci_port *ap, bus_size_t r)
3038258223a3SMatthew Dillon {
3039258223a3SMatthew Dillon 	bus_space_barrier(ap->ap_sc->sc_iot, ap->ap_ioh, r, 4,
3040258223a3SMatthew Dillon 			  BUS_SPACE_BARRIER_READ);
3041258223a3SMatthew Dillon 	return (bus_space_read_4(ap->ap_sc->sc_iot, ap->ap_ioh, r));
3042258223a3SMatthew Dillon }
3043258223a3SMatthew Dillon 
3044258223a3SMatthew Dillon void
3045258223a3SMatthew Dillon ahci_pwrite(struct ahci_port *ap, bus_size_t r, u_int32_t v)
3046258223a3SMatthew Dillon {
3047258223a3SMatthew Dillon 	bus_space_write_4(ap->ap_sc->sc_iot, ap->ap_ioh, r, v);
3048258223a3SMatthew Dillon 	bus_space_barrier(ap->ap_sc->sc_iot, ap->ap_ioh, r, 4,
3049258223a3SMatthew Dillon 			  BUS_SPACE_BARRIER_WRITE);
3050258223a3SMatthew Dillon }
3051258223a3SMatthew Dillon 
3052831bc9e3SMatthew Dillon /*
3053831bc9e3SMatthew Dillon  * Wait up to (timeout) milliseconds for the masked port register to
3054831bc9e3SMatthew Dillon  * match the target.
3055831bc9e3SMatthew Dillon  *
3056831bc9e3SMatthew Dillon  * Timeout is in milliseconds.
3057831bc9e3SMatthew Dillon  */
3058258223a3SMatthew Dillon int
3059cec85a37SMatthew Dillon ahci_pwait_eq(struct ahci_port *ap, int timeout,
3060cec85a37SMatthew Dillon 	      bus_size_t r, u_int32_t mask, u_int32_t target)
3061258223a3SMatthew Dillon {
3062831bc9e3SMatthew Dillon 	int	t;
3063258223a3SMatthew Dillon 
3064831bc9e3SMatthew Dillon 	/*
3065831bc9e3SMatthew Dillon 	 * Loop hard up to 100uS
3066831bc9e3SMatthew Dillon 	 */
3067831bc9e3SMatthew Dillon 	for (t = 0; t < 100; ++t) {
3068258223a3SMatthew Dillon 		if ((ahci_pread(ap, r) & mask) == target)
3069258223a3SMatthew Dillon 			return (0);
3070831bc9e3SMatthew Dillon 		ahci_os_hardsleep(1);	/* us */
3071258223a3SMatthew Dillon 	}
3072258223a3SMatthew Dillon 
3073831bc9e3SMatthew Dillon 	do {
3074831bc9e3SMatthew Dillon 		timeout -= ahci_os_softsleep();
3075831bc9e3SMatthew Dillon 		if ((ahci_pread(ap, r) & mask) == target)
3076831bc9e3SMatthew Dillon 			return (0);
3077831bc9e3SMatthew Dillon 	} while (timeout > 0);
3078831bc9e3SMatthew Dillon 	return (1);
3079831bc9e3SMatthew Dillon }
3080831bc9e3SMatthew Dillon 
3081831bc9e3SMatthew Dillon int
3082831bc9e3SMatthew Dillon ahci_wait_ne(struct ahci_softc *sc, bus_size_t r, u_int32_t mask,
3083831bc9e3SMatthew Dillon 	     u_int32_t target)
3084831bc9e3SMatthew Dillon {
3085831bc9e3SMatthew Dillon 	int	t;
3086831bc9e3SMatthew Dillon 
3087831bc9e3SMatthew Dillon 	/*
3088831bc9e3SMatthew Dillon 	 * Loop hard up to 100uS
3089831bc9e3SMatthew Dillon 	 */
3090831bc9e3SMatthew Dillon 	for (t = 0; t < 100; ++t) {
3091831bc9e3SMatthew Dillon 		if ((ahci_read(sc, r) & mask) != target)
3092831bc9e3SMatthew Dillon 			return (0);
3093831bc9e3SMatthew Dillon 		ahci_os_hardsleep(1);	/* us */
3094831bc9e3SMatthew Dillon 	}
3095831bc9e3SMatthew Dillon 
3096831bc9e3SMatthew Dillon 	/*
3097831bc9e3SMatthew Dillon 	 * And one millisecond the slow way
3098831bc9e3SMatthew Dillon 	 */
3099831bc9e3SMatthew Dillon 	t = 1000;
3100831bc9e3SMatthew Dillon 	do {
3101831bc9e3SMatthew Dillon 		t -= ahci_os_softsleep();
3102831bc9e3SMatthew Dillon 		if ((ahci_read(sc, r) & mask) != target)
3103831bc9e3SMatthew Dillon 			return (0);
3104831bc9e3SMatthew Dillon 	} while (t > 0);
3105831bc9e3SMatthew Dillon 
3106258223a3SMatthew Dillon 	return (1);
3107258223a3SMatthew Dillon }
3108258223a3SMatthew Dillon 
3109831bc9e3SMatthew Dillon 
31101980eff3SMatthew Dillon /*
31111980eff3SMatthew Dillon  * Acquire an ata transfer.
31121980eff3SMatthew Dillon  *
31131980eff3SMatthew Dillon  * Pass a NULL at for direct-attached transfers, and a non-NULL at for
31141980eff3SMatthew Dillon  * targets that go through the port multiplier.
31151980eff3SMatthew Dillon  */
3116258223a3SMatthew Dillon struct ata_xfer *
31171980eff3SMatthew Dillon ahci_ata_get_xfer(struct ahci_port *ap, struct ata_port *at)
3118258223a3SMatthew Dillon {
3119258223a3SMatthew Dillon 	struct ahci_ccb		*ccb;
3120258223a3SMatthew Dillon 
3121258223a3SMatthew Dillon 	ccb = ahci_get_ccb(ap);
3122258223a3SMatthew Dillon 	if (ccb == NULL) {
3123258223a3SMatthew Dillon 		DPRINTF(AHCI_D_XFER, "%s: ahci_ata_get_xfer: NULL ccb\n",
3124258223a3SMatthew Dillon 		    PORTNAME(ap));
3125258223a3SMatthew Dillon 		return (NULL);
3126258223a3SMatthew Dillon 	}
3127258223a3SMatthew Dillon 
3128258223a3SMatthew Dillon 	DPRINTF(AHCI_D_XFER, "%s: ahci_ata_get_xfer got slot %d\n",
3129258223a3SMatthew Dillon 	    PORTNAME(ap), ccb->ccb_slot);
3130258223a3SMatthew Dillon 
31311980eff3SMatthew Dillon 	ccb->ccb_xa.at = at;
3132258223a3SMatthew Dillon 	ccb->ccb_xa.fis->type = ATA_FIS_TYPE_H2D;
3133258223a3SMatthew Dillon 
3134258223a3SMatthew Dillon 	return (&ccb->ccb_xa);
3135258223a3SMatthew Dillon }
3136258223a3SMatthew Dillon 
3137258223a3SMatthew Dillon void
3138258223a3SMatthew Dillon ahci_ata_put_xfer(struct ata_xfer *xa)
3139258223a3SMatthew Dillon {
3140258223a3SMatthew Dillon 	struct ahci_ccb			*ccb = (struct ahci_ccb *)xa;
3141258223a3SMatthew Dillon 
3142258223a3SMatthew Dillon 	DPRINTF(AHCI_D_XFER, "ahci_ata_put_xfer slot %d\n", ccb->ccb_slot);
3143258223a3SMatthew Dillon 
3144258223a3SMatthew Dillon 	ahci_put_ccb(ccb);
3145258223a3SMatthew Dillon }
3146258223a3SMatthew Dillon 
3147258223a3SMatthew Dillon int
3148258223a3SMatthew Dillon ahci_ata_cmd(struct ata_xfer *xa)
3149258223a3SMatthew Dillon {
3150258223a3SMatthew Dillon 	struct ahci_ccb			*ccb = (struct ahci_ccb *)xa;
3151258223a3SMatthew Dillon 	struct ahci_cmd_hdr		*cmd_slot;
3152258223a3SMatthew Dillon 
3153258223a3SMatthew Dillon 	KKASSERT(xa->state == ATA_S_SETUP);
3154258223a3SMatthew Dillon 
3155258223a3SMatthew Dillon 	if (ccb->ccb_port->ap_state == AP_S_FATAL_ERROR)
3156258223a3SMatthew Dillon 		goto failcmd;
31571980eff3SMatthew Dillon #if 0
31581980eff3SMatthew Dillon 	kprintf("%s: started std command %b ccb %d ccb_at %p %d\n",
31591980eff3SMatthew Dillon 		ATANAME(ccb->ccb_port, ccb->ccb_xa.at),
31601980eff3SMatthew Dillon 		ahci_pread(ccb->ccb_port, AHCI_PREG_CMD), AHCI_PFMT_CMD,
31611980eff3SMatthew Dillon 		ccb->ccb_slot,
31621980eff3SMatthew Dillon 		ccb->ccb_xa.at,
31631980eff3SMatthew Dillon 		ccb->ccb_xa.at ? ccb->ccb_xa.at->at_target : -1);
31641980eff3SMatthew Dillon #endif
3165258223a3SMatthew Dillon 
3166258223a3SMatthew Dillon 	ccb->ccb_done = ahci_ata_cmd_done;
3167258223a3SMatthew Dillon 
3168258223a3SMatthew Dillon 	cmd_slot = ccb->ccb_cmd_hdr;
3169258223a3SMatthew Dillon 	cmd_slot->flags = htole16(5); /* FIS length (in DWORDs) */
31701980eff3SMatthew Dillon 	if (ccb->ccb_xa.at) {
31711980eff3SMatthew Dillon 		cmd_slot->flags |= htole16(ccb->ccb_xa.at->at_target <<
31721980eff3SMatthew Dillon 					   AHCI_CMD_LIST_FLAG_PMP_SHIFT);
31731980eff3SMatthew Dillon 	}
3174258223a3SMatthew Dillon 
3175258223a3SMatthew Dillon 	if (xa->flags & ATA_F_WRITE)
3176258223a3SMatthew Dillon 		cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_W);
3177258223a3SMatthew Dillon 
3178258223a3SMatthew Dillon 	if (xa->flags & ATA_F_PACKET)
3179258223a3SMatthew Dillon 		cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_A);
3180258223a3SMatthew Dillon 
3181258223a3SMatthew Dillon 	if (ahci_load_prdt(ccb) != 0)
3182258223a3SMatthew Dillon 		goto failcmd;
3183258223a3SMatthew Dillon 
3184258223a3SMatthew Dillon 	xa->state = ATA_S_PENDING;
3185258223a3SMatthew Dillon 
3186831bc9e3SMatthew Dillon 	if (xa->flags & ATA_F_POLL)
3187831bc9e3SMatthew Dillon 		return (ahci_poll(ccb, xa->timeout, ahci_ata_cmd_timeout));
3188258223a3SMatthew Dillon 
3189258223a3SMatthew Dillon 	crit_enter();
3190f4553de1SMatthew Dillon 	KKASSERT((xa->flags & ATA_F_TIMEOUT_EXPIRED) == 0);
31913209f581SMatthew Dillon 	xa->flags |= ATA_F_TIMEOUT_DESIRED;
3192258223a3SMatthew Dillon 	ahci_start(ccb);
3193258223a3SMatthew Dillon 	crit_exit();
3194831bc9e3SMatthew Dillon 	return (xa->state);
3195258223a3SMatthew Dillon 
3196258223a3SMatthew Dillon failcmd:
3197258223a3SMatthew Dillon 	crit_enter();
3198258223a3SMatthew Dillon 	xa->state = ATA_S_ERROR;
3199258223a3SMatthew Dillon 	xa->complete(xa);
3200258223a3SMatthew Dillon 	crit_exit();
3201831bc9e3SMatthew Dillon 	return (ATA_S_ERROR);
3202258223a3SMatthew Dillon }
3203258223a3SMatthew Dillon 
3204258223a3SMatthew Dillon void
3205258223a3SMatthew Dillon ahci_ata_cmd_done(struct ahci_ccb *ccb)
3206258223a3SMatthew Dillon {
3207258223a3SMatthew Dillon 	struct ata_xfer			*xa = &ccb->ccb_xa;
3208258223a3SMatthew Dillon 
3209831bc9e3SMatthew Dillon 	/*
3210831bc9e3SMatthew Dillon 	 * NOTE: callout does not lock port and may race us modifying
3211831bc9e3SMatthew Dillon 	 * the flags, so make sure its stopped.
3212831bc9e3SMatthew Dillon 	 */
3213258223a3SMatthew Dillon 	if (xa->flags & ATA_F_TIMEOUT_RUNNING) {
3214258223a3SMatthew Dillon 		callout_stop(&ccb->ccb_timeout);
3215831bc9e3SMatthew Dillon 		xa->flags &= ~ATA_F_TIMEOUT_RUNNING;
3216258223a3SMatthew Dillon 	}
3217f4553de1SMatthew Dillon 	xa->flags &= ~(ATA_F_TIMEOUT_DESIRED | ATA_F_TIMEOUT_EXPIRED);
3218258223a3SMatthew Dillon 
32194c339a5fSMatthew Dillon 	KKASSERT(xa->state != ATA_S_ONCHIP);
3220258223a3SMatthew Dillon 	ahci_unload_prdt(ccb);
3221258223a3SMatthew Dillon 
3222258223a3SMatthew Dillon #ifdef DIAGNOSTIC
3223258223a3SMatthew Dillon 	else if (xa->state != ATA_S_ERROR && xa->state != ATA_S_TIMEOUT)
3224258223a3SMatthew Dillon 		kprintf("%s: invalid ata_xfer state %02x in ahci_ata_cmd_done, "
3225258223a3SMatthew Dillon 			"slot %d\n",
3226258223a3SMatthew Dillon 			PORTNAME(ccb->ccb_port), xa->state, ccb->ccb_slot);
3227258223a3SMatthew Dillon #endif
3228258223a3SMatthew Dillon 	if (xa->state != ATA_S_TIMEOUT)
3229258223a3SMatthew Dillon 		xa->complete(xa);
3230258223a3SMatthew Dillon }
3231258223a3SMatthew Dillon 
3232f4553de1SMatthew Dillon /*
3233f4553de1SMatthew Dillon  * Timeout from callout, MPSAFE - nothing can mess with the CCB's flags
3234f4553de1SMatthew Dillon  * while the callout is runing.
3235f4553de1SMatthew Dillon  *
3236f4553de1SMatthew Dillon  * We can't safely get the port lock here or delay, we could block
3237f4553de1SMatthew Dillon  * the callout thread.
3238f4553de1SMatthew Dillon  */
3239258223a3SMatthew Dillon static void
3240258223a3SMatthew Dillon ahci_ata_cmd_timeout_unserialized(void *arg)
3241258223a3SMatthew Dillon {
3242258223a3SMatthew Dillon 	struct ahci_ccb		*ccb = arg;
3243258223a3SMatthew Dillon 	struct ahci_port	*ap = ccb->ccb_port;
3244258223a3SMatthew Dillon 
3245f4553de1SMatthew Dillon 	ccb->ccb_xa.flags &= ~ATA_F_TIMEOUT_RUNNING;
3246f4553de1SMatthew Dillon 	ccb->ccb_xa.flags |= ATA_F_TIMEOUT_EXPIRED;
3247f4553de1SMatthew Dillon 	ahci_os_signal_port_thread(ap, AP_SIGF_TIMEOUT);
3248258223a3SMatthew Dillon }
3249258223a3SMatthew Dillon 
32504c339a5fSMatthew Dillon /*
32514c339a5fSMatthew Dillon  * Timeout code, typically called when the port command processor is running.
32524c339a5fSMatthew Dillon  *
32534c339a5fSMatthew Dillon  * We have to be very very careful here.  We cannot stop the port unless
32544c339a5fSMatthew Dillon  * CR is already clear or the only active commands remaining are timed-out
32554c339a5fSMatthew Dillon  * ones.  Otherwise stopping the port will race the command processor and
32564c339a5fSMatthew Dillon  * we can lose events.  While we can theoretically just restart everything
32574c339a5fSMatthew Dillon  * that could result in a double-issue which will not work for ATAPI commands.
32584c339a5fSMatthew Dillon  */
32591980eff3SMatthew Dillon void
3260831bc9e3SMatthew Dillon ahci_ata_cmd_timeout(struct ahci_ccb *ccb)
3261258223a3SMatthew Dillon {
3262258223a3SMatthew Dillon 	struct ata_xfer		*xa = &ccb->ccb_xa;
3263258223a3SMatthew Dillon 	struct ahci_port	*ap = ccb->ccb_port;
32644c339a5fSMatthew Dillon 	struct ata_port		*at;
32654c339a5fSMatthew Dillon 	int			ci_saved;
32664c339a5fSMatthew Dillon 	int			slot;
3267258223a3SMatthew Dillon 
32684c339a5fSMatthew Dillon 	at = ccb->ccb_xa.at;
32694c339a5fSMatthew Dillon 
32704c339a5fSMatthew Dillon 	kprintf("%s: CMD TIMEOUT state=%d slot=%d\n"
32714c339a5fSMatthew Dillon 		"\tcmd-reg 0x%b\n"
32724c339a5fSMatthew Dillon 		"\tsactive=%08x active=%08x expired=%08x\n"
3273258223a3SMatthew Dillon 		"\t   sact=%08x     ci=%08x\n",
32744c339a5fSMatthew Dillon 		ATANAME(ap, at),
32754c339a5fSMatthew Dillon 		ccb->ccb_xa.state, ccb->ccb_slot,
3276258223a3SMatthew Dillon 		ahci_pread(ap, AHCI_PREG_CMD), AHCI_PFMT_CMD,
32774c339a5fSMatthew Dillon 		ap->ap_sactive, ap->ap_active, ap->ap_expired,
3278258223a3SMatthew Dillon 		ahci_pread(ap, AHCI_PREG_SACT),
3279258223a3SMatthew Dillon 		ahci_pread(ap, AHCI_PREG_CI));
3280258223a3SMatthew Dillon 
32819e145b23SMatthew Dillon 	/*
32829e145b23SMatthew Dillon 	 * NOTE: Timeout will not be running if the command was polled.
32833209f581SMatthew Dillon 	 *	 If we got here at least one of these flags should be set.
32849e145b23SMatthew Dillon 	 */
32853209f581SMatthew Dillon 	KKASSERT(xa->flags & (ATA_F_POLL | ATA_F_TIMEOUT_DESIRED |
32863209f581SMatthew Dillon 			      ATA_F_TIMEOUT_RUNNING));
3287f4553de1SMatthew Dillon 	xa->flags &= ~(ATA_F_TIMEOUT_RUNNING | ATA_F_TIMEOUT_EXPIRED);
3288258223a3SMatthew Dillon 
3289258223a3SMatthew Dillon 	if (ccb->ccb_xa.state == ATA_S_PENDING) {
3290258223a3SMatthew Dillon 		TAILQ_REMOVE(&ap->ap_ccb_pending, ccb, ccb_entry);
32914c339a5fSMatthew Dillon 		ccb->ccb_xa.state = ATA_S_TIMEOUT;
32924c339a5fSMatthew Dillon 		ccb->ccb_done(ccb);
32934c339a5fSMatthew Dillon 		xa->complete(xa);
32944c339a5fSMatthew Dillon 		ahci_issue_pending_commands(ap, NULL);
32954c339a5fSMatthew Dillon 		return;
32964c339a5fSMatthew Dillon 	}
32974c339a5fSMatthew Dillon 	if (ccb->ccb_xa.state != ATA_S_ONCHIP) {
32984c339a5fSMatthew Dillon 		kprintf("%s: Unexpected state during timeout: %d\n",
32994c339a5fSMatthew Dillon 			ATANAME(ap, at), ccb->ccb_xa.state);
33004c339a5fSMatthew Dillon 		return;
33014c339a5fSMatthew Dillon 	}
33024c339a5fSMatthew Dillon 
33034c339a5fSMatthew Dillon 	/*
33044c339a5fSMatthew Dillon 	 * Ok, we can only get this command off the chip if CR is inactive
33054c339a5fSMatthew Dillon 	 * or if the only commands running on the chip are all expired.
33064c339a5fSMatthew Dillon 	 * Otherwise we have to wait until the port is in a safe state.
33074c339a5fSMatthew Dillon 	 *
33084c339a5fSMatthew Dillon 	 * Do not set state here, it will cause polls to return when the
33094c339a5fSMatthew Dillon 	 * ccb is not yet off the chip.
33104c339a5fSMatthew Dillon 	 */
33114c339a5fSMatthew Dillon 	ap->ap_expired |= 1 << ccb->ccb_slot;
33124c339a5fSMatthew Dillon 
33134c339a5fSMatthew Dillon 	if ((ahci_pread(ap, AHCI_PREG_CMD) & AHCI_PREG_CMD_CR) &&
33144c339a5fSMatthew Dillon 	    (ap->ap_active | ap->ap_sactive) != ap->ap_expired) {
33154c339a5fSMatthew Dillon 		/*
33164c339a5fSMatthew Dillon 		 * If using FBSS or NCQ we can't safely stop the port
33174c339a5fSMatthew Dillon 		 * right now.
33184c339a5fSMatthew Dillon 		 */
33194c339a5fSMatthew Dillon 		kprintf("%s: Deferred timeout until its safe, slot %d\n",
33204c339a5fSMatthew Dillon 			ATANAME(ap, at), ccb->ccb_slot);
33214c339a5fSMatthew Dillon 		return;
33224c339a5fSMatthew Dillon 	}
33234c339a5fSMatthew Dillon 
33244c339a5fSMatthew Dillon 	/*
33254c339a5fSMatthew Dillon 	 * We can safely stop the port and process all expired ccb's,
33264c339a5fSMatthew Dillon 	 * which will include our current ccb.
33274c339a5fSMatthew Dillon 	 */
33284c339a5fSMatthew Dillon 	ci_saved = (ap->ap_sactive) ? ahci_pread(ap, AHCI_PREG_SACT) :
33294c339a5fSMatthew Dillon 				      ahci_pread(ap, AHCI_PREG_CI);
33304c339a5fSMatthew Dillon 	ahci_port_stop(ap, 0);
33314c339a5fSMatthew Dillon 
33324c339a5fSMatthew Dillon 	while (ap->ap_expired) {
33334c339a5fSMatthew Dillon 		slot = ffs(ap->ap_expired) - 1;
33344c339a5fSMatthew Dillon 		ap->ap_expired &= ~(1 << slot);
33354c339a5fSMatthew Dillon 		ci_saved &= ~(1 << slot);
33364c339a5fSMatthew Dillon 		ccb = &ap->ap_ccbs[slot];
33374c339a5fSMatthew Dillon 		ccb->ccb_xa.state = ATA_S_TIMEOUT;
33384c339a5fSMatthew Dillon 		if (ccb->ccb_xa.flags & ATA_F_NCQ) {
33394c339a5fSMatthew Dillon 			KKASSERT(ap->ap_sactive & (1 << slot));
33404c339a5fSMatthew Dillon 			ap->ap_sactive &= ~(1 << slot);
33414c339a5fSMatthew Dillon 		} else {
33424c339a5fSMatthew Dillon 			KKASSERT(ap->ap_active & (1 << slot));
33434c339a5fSMatthew Dillon 			ap->ap_active &= ~(1 << slot);
33441980eff3SMatthew Dillon 			--ap->ap_active_cnt;
33451980eff3SMatthew Dillon 		}
3346258223a3SMatthew Dillon 		ccb->ccb_done(ccb);
33474c339a5fSMatthew Dillon 		ccb->ccb_xa.complete(&ccb->ccb_xa);
3348258223a3SMatthew Dillon 	}
33494c339a5fSMatthew Dillon 	/* ccb invalid now */
3350258223a3SMatthew Dillon 
33514c339a5fSMatthew Dillon 	/*
33524c339a5fSMatthew Dillon 	 * We can safely CLO the port to clear any BSY/DRQ, a case which
33534c339a5fSMatthew Dillon 	 * can occur with port multipliers.  This will unbrick the port
33544c339a5fSMatthew Dillon 	 * and allow commands to other targets behind the PM continue.
33554c339a5fSMatthew Dillon 	 * (FBSS).
33564c339a5fSMatthew Dillon 	 *
33574c339a5fSMatthew Dillon 	 * Finally, once the port has been restarted we can issue any
33584c339a5fSMatthew Dillon 	 * previously saved pending commands, and run the port interrupt
33594c339a5fSMatthew Dillon 	 * code to handle any completions which may have occured when
33604c339a5fSMatthew Dillon 	 * we saved CI.
33614c339a5fSMatthew Dillon 	 */
33624c339a5fSMatthew Dillon 	if (ahci_pread(ap, AHCI_PREG_TFD) &
33634c339a5fSMatthew Dillon 		   (AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) {
33644c339a5fSMatthew Dillon 		kprintf("%s: Warning, issuing CLO after timeout\n",
33654c339a5fSMatthew Dillon 			ATANAME(ap, at));
3366131be210SMatthew Dillon 		ahci_port_clo(ap);
33674c339a5fSMatthew Dillon 	}
3368131be210SMatthew Dillon 	ahci_port_start(ap);
33694c339a5fSMatthew Dillon 	ahci_issue_saved_commands(ap, ci_saved & ~ap->ap_expired);
33704c339a5fSMatthew Dillon 	ahci_issue_pending_commands(ap, NULL);
33714c339a5fSMatthew Dillon 	ahci_port_intr(ap, 0);
33724c339a5fSMatthew Dillon }
33734c339a5fSMatthew Dillon 
3374cf5f3a81SMatthew Dillon /*
33754c339a5fSMatthew Dillon  * Issue a previously saved set of commands
3376cf5f3a81SMatthew Dillon  */
33774c339a5fSMatthew Dillon void
33784c339a5fSMatthew Dillon ahci_issue_saved_commands(struct ahci_port *ap, u_int32_t ci_saved)
33794c339a5fSMatthew Dillon {
33804c339a5fSMatthew Dillon 	if (ci_saved) {
33814c339a5fSMatthew Dillon 		KKASSERT(!((ap->ap_active & ci_saved) &&
33824c339a5fSMatthew Dillon 			   (ap->ap_sactive & ci_saved)));
33834c339a5fSMatthew Dillon 		KKASSERT((ci_saved & ap->ap_expired) == 0);
33844c339a5fSMatthew Dillon 		if (ap->ap_sactive & ci_saved)
33854c339a5fSMatthew Dillon 			ahci_pwrite(ap, AHCI_PREG_SACT, ci_saved);
33864c339a5fSMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CI, ci_saved);
3387131be210SMatthew Dillon 	}
3388258223a3SMatthew Dillon }
3389258223a3SMatthew Dillon 
3390831bc9e3SMatthew Dillon /*
3391831bc9e3SMatthew Dillon  * Used by the softreset, pmprobe, and read_ncq_error only, in very
3392831bc9e3SMatthew Dillon  * specialized, controlled circumstances.
3393831bc9e3SMatthew Dillon  *
3394831bc9e3SMatthew Dillon  * Only one command may be pending.
3395831bc9e3SMatthew Dillon  */
3396831bc9e3SMatthew Dillon void
3397831bc9e3SMatthew Dillon ahci_quick_timeout(struct ahci_ccb *ccb)
3398831bc9e3SMatthew Dillon {
3399831bc9e3SMatthew Dillon 	struct ahci_port *ap = ccb->ccb_port;
3400831bc9e3SMatthew Dillon 
3401831bc9e3SMatthew Dillon 	switch (ccb->ccb_xa.state) {
3402831bc9e3SMatthew Dillon 	case ATA_S_PENDING:
3403831bc9e3SMatthew Dillon 		TAILQ_REMOVE(&ap->ap_ccb_pending, ccb, ccb_entry);
3404831bc9e3SMatthew Dillon 		ccb->ccb_xa.state = ATA_S_TIMEOUT;
3405831bc9e3SMatthew Dillon 		break;
3406831bc9e3SMatthew Dillon 	case ATA_S_ONCHIP:
3407831bc9e3SMatthew Dillon 		KKASSERT(ap->ap_active == (1 << ccb->ccb_slot) &&
3408831bc9e3SMatthew Dillon 			 ap->ap_sactive == 0);
3409831bc9e3SMatthew Dillon 		ahci_port_stop(ap, 0);
3410831bc9e3SMatthew Dillon 		ahci_port_start(ap);
3411831bc9e3SMatthew Dillon 
3412831bc9e3SMatthew Dillon 		ccb->ccb_xa.state = ATA_S_TIMEOUT;
3413831bc9e3SMatthew Dillon 		ap->ap_active &= ~(1 << ccb->ccb_slot);
3414831bc9e3SMatthew Dillon 		KKASSERT(ap->ap_active_cnt > 0);
3415831bc9e3SMatthew Dillon 		--ap->ap_active_cnt;
3416831bc9e3SMatthew Dillon 		break;
3417831bc9e3SMatthew Dillon 	default:
3418831bc9e3SMatthew Dillon 		panic("%s: ahci_quick_timeout: ccb in bad state %d",
3419831bc9e3SMatthew Dillon 		      ATANAME(ap, ccb->ccb_xa.at), ccb->ccb_xa.state);
3420831bc9e3SMatthew Dillon 	}
3421831bc9e3SMatthew Dillon }
3422831bc9e3SMatthew Dillon 
3423258223a3SMatthew Dillon void
3424258223a3SMatthew Dillon ahci_empty_done(struct ahci_ccb *ccb)
3425258223a3SMatthew Dillon {
3426258223a3SMatthew Dillon }
3427