xref: /dflybsd-src/sys/dev/disk/ahci/ahci.c (revision 22726f69823a465916a320f3689f671bcd6180e7)
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 void	ahci_port_interrupt_enable(struct ahci_port *ap);
55258223a3SMatthew Dillon 
56258223a3SMatthew Dillon int	ahci_load_prdt(struct ahci_ccb *);
57258223a3SMatthew Dillon void	ahci_unload_prdt(struct ahci_ccb *);
58258223a3SMatthew Dillon static void ahci_load_prdt_callback(void *info, bus_dma_segment_t *segs,
59258223a3SMatthew Dillon 				    int nsegs, int error);
60258223a3SMatthew Dillon void	ahci_start(struct ahci_ccb *);
6117eab71eSMatthew Dillon int	ahci_port_softreset(struct ahci_port *ap);
621980eff3SMatthew Dillon int	ahci_port_hardreset(struct ahci_port *ap, int hard);
63cf5f3a81SMatthew Dillon void	ahci_port_hardstop(struct ahci_port *ap);
64258223a3SMatthew Dillon 
65831bc9e3SMatthew Dillon static void ahci_ata_cmd_timeout_unserialized(void *);
66831bc9e3SMatthew Dillon void	ahci_check_active_timeouts(struct ahci_port *ap);
67258223a3SMatthew Dillon 
68831bc9e3SMatthew Dillon void	ahci_beg_exclusive_access(struct ahci_port *ap, struct ata_port *at);
69831bc9e3SMatthew Dillon void	ahci_end_exclusive_access(struct ahci_port *ap, struct ata_port *at);
704c339a5fSMatthew Dillon void	ahci_issue_pending_commands(struct ahci_port *ap, struct ahci_ccb *ccb);
714c339a5fSMatthew Dillon void	ahci_issue_saved_commands(struct ahci_port *ap, u_int32_t mask);
72258223a3SMatthew Dillon 
7312feb904SMatthew Dillon int	ahci_port_read_ncq_error(struct ahci_port *, int);
74258223a3SMatthew Dillon 
75258223a3SMatthew Dillon struct ahci_dmamem *ahci_dmamem_alloc(struct ahci_softc *, bus_dma_tag_t tag);
76258223a3SMatthew Dillon void	ahci_dmamem_free(struct ahci_softc *, struct ahci_dmamem *);
77258223a3SMatthew Dillon static void ahci_dmamem_saveseg(void *info, bus_dma_segment_t *segs, int nsegs, int error);
78258223a3SMatthew Dillon 
7912feb904SMatthew Dillon static void ahci_dummy_done(struct ata_xfer *xa);
8012feb904SMatthew Dillon static void ahci_empty_done(struct ahci_ccb *ccb);
8112feb904SMatthew Dillon static void ahci_ata_cmd_done(struct ahci_ccb *ccb);
82258223a3SMatthew Dillon 
83fd8bd957SMatthew Dillon /*
84fd8bd957SMatthew Dillon  * Initialize the global AHCI hardware.  This code does not set up any of
85fd8bd957SMatthew Dillon  * its ports.
86fd8bd957SMatthew Dillon  */
87258223a3SMatthew Dillon int
88258223a3SMatthew Dillon ahci_init(struct ahci_softc *sc)
89258223a3SMatthew Dillon {
9012feb904SMatthew Dillon 	u_int32_t	cap, pi, pleft;
91831bc9e3SMatthew Dillon 	int		i;
92831bc9e3SMatthew Dillon 	struct ahci_port *ap;
93258223a3SMatthew Dillon 
94258223a3SMatthew Dillon 	DPRINTF(AHCI_D_VERBOSE, " GHC 0x%b",
95258223a3SMatthew Dillon 		ahci_read(sc, AHCI_REG_GHC), AHCI_FMT_GHC);
96258223a3SMatthew Dillon 
97b012a2caSMatthew Dillon 	/*
98b012a2caSMatthew Dillon 	 * save BIOS initialised parameters, enable staggered spin up
99b012a2caSMatthew Dillon 	 */
100258223a3SMatthew Dillon 	cap = ahci_read(sc, AHCI_REG_CAP);
101258223a3SMatthew Dillon 	cap &= AHCI_REG_CAP_SMPS;
102258223a3SMatthew Dillon 	cap |= AHCI_REG_CAP_SSS;
103258223a3SMatthew Dillon 	pi = ahci_read(sc, AHCI_REG_PI);
104258223a3SMatthew Dillon 
105831bc9e3SMatthew Dillon 	/*
106b012a2caSMatthew Dillon 	 * Unconditionally reset the controller, do not conditionalize on
107b012a2caSMatthew Dillon 	 * trying to figure it if it was previously active or not.
108b012a2caSMatthew Dillon 	 *
109b012a2caSMatthew Dillon 	 * NOTE: On AE before HR.  The AHCI-1.1 spec has a note in section
110b012a2caSMatthew Dillon 	 *	 5.2.2.1 regarding this.  HR should be set to 1 only after
111b012a2caSMatthew Dillon 	 *	 AE is set to 1.  The reset sequence will clear HR when
112b012a2caSMatthew Dillon 	 *	 it completes, and will also clear AE if SAM is 0.  AE must
113b012a2caSMatthew Dillon 	 *	 then be set again.  When SAM is 1 the AE bit typically reads
114b012a2caSMatthew Dillon 	 *	 as 1 (and is read-only).
115b012a2caSMatthew Dillon 	 *
116b012a2caSMatthew Dillon 	 * NOTE: Avoid PCI[e] transaction burst by issuing dummy reads,
117b012a2caSMatthew Dillon 	 *	 otherwise the writes will only be separated by a few
118b012a2caSMatthew Dillon 	 *	 nanoseconds.
119b012a2caSMatthew Dillon 	 *
120b012a2caSMatthew Dillon 	 * NOTE BRICKS (1)
121b012a2caSMatthew Dillon 	 *
122b012a2caSMatthew Dillon 	 *	If you have a port multiplier and it does not have a device
123b012a2caSMatthew Dillon 	 *	in target 0, and it probes normally, but a later operation
124b012a2caSMatthew Dillon 	 *	mis-probes a target behind that PM, it is possible for the
125b012a2caSMatthew Dillon 	 *	port to brick such that only (a) a power cycle of the host
126b012a2caSMatthew Dillon 	 *	or (b) placing a device in target 0 will fix the problem.
127b012a2caSMatthew Dillon 	 *	Power cycling the PM has no effect (it works fine on another
128b012a2caSMatthew Dillon 	 *	host port).  This issue is unrelated to CLO.
129b012a2caSMatthew Dillon 	 */
1304e21f4daSMatthew Dillon 	/*
1314e21f4daSMatthew Dillon 	 * Wait for any prior reset sequence to complete
1324e21f4daSMatthew Dillon 	 */
1334e21f4daSMatthew Dillon 	if (ahci_wait_ne(sc, AHCI_REG_GHC,
1344e21f4daSMatthew Dillon 			 AHCI_REG_GHC_HR, AHCI_REG_GHC_HR) != 0) {
1354e21f4daSMatthew Dillon 		device_printf(sc->sc_dev, "Controller is stuck in reset\n");
1364e21f4daSMatthew Dillon 		return (1);
1374e21f4daSMatthew Dillon 	}
138b012a2caSMatthew Dillon 	ahci_write(sc, AHCI_REG_GHC, AHCI_REG_GHC_AE);
1394e21f4daSMatthew Dillon 	ahci_os_sleep(500);
140b012a2caSMatthew Dillon 	ahci_read(sc, AHCI_REG_GHC);		/* flush */
141b012a2caSMatthew Dillon 	ahci_write(sc, AHCI_REG_GHC, AHCI_REG_GHC_AE | AHCI_REG_GHC_HR);
1424e21f4daSMatthew Dillon 	ahci_os_sleep(500);
143b012a2caSMatthew Dillon 	ahci_read(sc, AHCI_REG_GHC);		/* flush */
144b012a2caSMatthew Dillon 	if (ahci_wait_ne(sc, AHCI_REG_GHC,
145b012a2caSMatthew Dillon 			 AHCI_REG_GHC_HR, AHCI_REG_GHC_HR) != 0) {
1464e21f4daSMatthew Dillon 		device_printf(sc->sc_dev, "unable to reset controller\n");
147b012a2caSMatthew Dillon 		return (1);
148b012a2caSMatthew Dillon 	}
1494e21f4daSMatthew Dillon 	if (ahci_read(sc, AHCI_REG_GHC) & AHCI_REG_GHC_AE) {
1504e21f4daSMatthew Dillon 		device_printf(sc->sc_dev, "AE did not auto-clear!\n");
1514e21f4daSMatthew Dillon 		ahci_write(sc, AHCI_REG_GHC, 0);
1524e21f4daSMatthew Dillon 		ahci_os_sleep(500);
1534e21f4daSMatthew Dillon 	}
154b012a2caSMatthew Dillon 
155b012a2caSMatthew Dillon 	/*
156b012a2caSMatthew Dillon 	 * Enable ahci (global interrupts disabled)
157b012a2caSMatthew Dillon 	 *
158b012a2caSMatthew Dillon 	 * Restore saved parameters.  Avoid pci transaction burst write
159b012a2caSMatthew Dillon 	 * by issuing dummy reads.
160b012a2caSMatthew Dillon 	 */
1614e21f4daSMatthew Dillon 	ahci_os_sleep(500);
162b012a2caSMatthew Dillon 	ahci_write(sc, AHCI_REG_GHC, AHCI_REG_GHC_AE);
163b012a2caSMatthew Dillon 	ahci_os_sleep(500);
164b012a2caSMatthew Dillon 
165b012a2caSMatthew Dillon 	ahci_read(sc, AHCI_REG_GHC);		/* flush */
166b012a2caSMatthew Dillon 	ahci_write(sc, AHCI_REG_CAP, cap);
167b012a2caSMatthew Dillon 	ahci_write(sc, AHCI_REG_PI, pi);
168b012a2caSMatthew Dillon 	ahci_read(sc, AHCI_REG_GHC);		/* flush */
169b012a2caSMatthew Dillon 
170b012a2caSMatthew Dillon 	/*
171b012a2caSMatthew Dillon 	 * Intel hocus pocus in case the BIOS has not set the chip up
172b012a2caSMatthew Dillon 	 * properly for AHCI operation.
173b012a2caSMatthew Dillon 	 */
174b012a2caSMatthew Dillon 	if (pci_get_vendor(sc->sc_dev) == PCI_VENDOR_INTEL) {
175b012a2caSMatthew Dillon 	        if ((pci_read_config(sc->sc_dev, 0x92, 2) & 0x0F) != 0x0F)
176b012a2caSMatthew Dillon 			device_printf(sc->sc_dev, "Intel hocus pocus\n");
177b012a2caSMatthew Dillon 		pci_write_config(sc->sc_dev, 0x92,
178b012a2caSMatthew Dillon 			     pci_read_config(sc->sc_dev, 0x92, 2) | 0x0F, 2);
179b012a2caSMatthew Dillon 	}
180b012a2caSMatthew Dillon 
181b012a2caSMatthew Dillon 	/*
182831bc9e3SMatthew Dillon 	 * This is a hack that currently does not appear to have
183831bc9e3SMatthew Dillon 	 * a significant effect, but I noticed the port registers
184831bc9e3SMatthew Dillon 	 * do not appear to be completely cleared after the host
185831bc9e3SMatthew Dillon 	 * controller is reset.
18612feb904SMatthew Dillon 	 *
18712feb904SMatthew Dillon 	 * Use a temporary ap structure so we can call ahci_pwrite().
1884e21f4daSMatthew Dillon 	 *
1894e21f4daSMatthew Dillon 	 * We must be sure to stop the port
190831bc9e3SMatthew Dillon 	 */
191831bc9e3SMatthew Dillon 	ap = kmalloc(sizeof(*ap), M_DEVBUF, M_WAITOK | M_ZERO);
192831bc9e3SMatthew Dillon 	ap->ap_sc = sc;
19312feb904SMatthew Dillon 	pleft = pi;
19412feb904SMatthew Dillon 	for (i = 0; i < AHCI_MAX_PORTS; ++i) {
19512feb904SMatthew Dillon 		if (pleft == 0)
19612feb904SMatthew Dillon 			break;
197831bc9e3SMatthew Dillon 		if ((pi & (1 << i)) == 0)
198831bc9e3SMatthew Dillon 			continue;
199831bc9e3SMatthew Dillon 		if (bus_space_subregion(sc->sc_iot, sc->sc_ioh,
200831bc9e3SMatthew Dillon 		    AHCI_PORT_REGION(i), AHCI_PORT_SIZE, &ap->ap_ioh) != 0) {
201831bc9e3SMatthew Dillon 			device_printf(sc->sc_dev, "can't map port\n");
202831bc9e3SMatthew Dillon 			return (1);
203831bc9e3SMatthew Dillon 		}
2044e21f4daSMatthew Dillon 		/*
2054e21f4daSMatthew Dillon 		 * NOTE!  Setting AHCI_PREG_SCTL_DET_DISABLE on AHCI1.0 or
2064e21f4daSMatthew Dillon 		 *	  AHCI1.1 can brick the chipset.  Not only brick it,
2074e21f4daSMatthew Dillon 		 *	  but also crash the PC.  The bit seems unreliable
2084e21f4daSMatthew Dillon 		 *	  on AHCI1.2 as well.
2094e21f4daSMatthew Dillon 		 */
2104e21f4daSMatthew Dillon 		ahci_port_stop(ap, 1);
2114e21f4daSMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SCTL, AHCI_PREG_SCTL_IPM_DISABLED);
212831bc9e3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SERR, -1);
213831bc9e3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IE, 0);
21412feb904SMatthew Dillon 		ahci_write(ap->ap_sc, AHCI_REG_IS, 1 << i);
215831bc9e3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CMD, 0);
21612feb904SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS, -1);
21712feb904SMatthew Dillon 		sc->sc_portmask |= (1 << i);
21812feb904SMatthew Dillon 		pleft &= ~(1 << i);
219831bc9e3SMatthew Dillon 	}
22012feb904SMatthew Dillon 	sc->sc_numports = i;
221831bc9e3SMatthew Dillon 	kfree(ap, M_DEVBUF);
222831bc9e3SMatthew Dillon 
223258223a3SMatthew Dillon 	return (0);
224258223a3SMatthew Dillon }
225258223a3SMatthew Dillon 
226fd8bd957SMatthew Dillon /*
227fd8bd957SMatthew Dillon  * Allocate and initialize an AHCI port.
228fd8bd957SMatthew Dillon  */
229258223a3SMatthew Dillon int
230258223a3SMatthew Dillon ahci_port_alloc(struct ahci_softc *sc, u_int port)
231258223a3SMatthew Dillon {
232258223a3SMatthew Dillon 	struct ahci_port	*ap;
2331980eff3SMatthew Dillon 	struct ata_port		*at;
234258223a3SMatthew Dillon 	struct ahci_ccb		*ccb;
235258223a3SMatthew Dillon 	u_int64_t		dva;
236258223a3SMatthew Dillon 	u_int32_t		cmd;
23712feb904SMatthew Dillon 	u_int32_t		data;
238258223a3SMatthew Dillon 	struct ahci_cmd_hdr	*hdr;
239258223a3SMatthew Dillon 	struct ahci_cmd_table	*table;
240258223a3SMatthew Dillon 	int	rc = ENOMEM;
241258223a3SMatthew Dillon 	int	error;
242258223a3SMatthew Dillon 	int	i;
243258223a3SMatthew Dillon 
244258223a3SMatthew Dillon 	ap = kmalloc(sizeof(*ap), M_DEVBUF, M_WAITOK | M_ZERO);
24512feb904SMatthew Dillon 	ap->ap_err_scratch = kmalloc(512, M_DEVBUF, M_WAITOK | M_ZERO);
246258223a3SMatthew Dillon 
247258223a3SMatthew Dillon 	ksnprintf(ap->ap_name, sizeof(ap->ap_name), "%s%d.%d",
248258223a3SMatthew Dillon 		  device_get_name(sc->sc_dev),
249258223a3SMatthew Dillon 		  device_get_unit(sc->sc_dev),
250258223a3SMatthew Dillon 		  port);
251258223a3SMatthew Dillon 	sc->sc_ports[port] = ap;
252258223a3SMatthew Dillon 
2531980eff3SMatthew Dillon 	/*
2541980eff3SMatthew Dillon 	 * Allocate enough so we never have to reallocate, it makes
2551980eff3SMatthew Dillon 	 * it easier.
2561980eff3SMatthew Dillon 	 *
2571980eff3SMatthew Dillon 	 * ap_pmcount will be reduced by the scan if we encounter the
2581980eff3SMatthew Dillon 	 * port multiplier port prior to target 15.
259b012a2caSMatthew Dillon 	 *
260b012a2caSMatthew Dillon 	 * kmalloc power-of-2 allocations are guaranteed not to cross
261b012a2caSMatthew Dillon 	 * a page boundary.  Make sure the identify sub-structure in the
262b012a2caSMatthew Dillon 	 * at structure does not cross a page boundary, just in case the
263b012a2caSMatthew Dillon 	 * part is AHCI-1.1 and can't handle multiple DRQ blocks.
2641980eff3SMatthew Dillon 	 */
265b012a2caSMatthew Dillon 	if (ap->ap_ata[0] == NULL) {
266b012a2caSMatthew Dillon 		int pw2;
267b012a2caSMatthew Dillon 
268b012a2caSMatthew Dillon 		for (pw2 = 1; pw2 < sizeof(*at); pw2 <<= 1)
269b012a2caSMatthew Dillon 			;
2701980eff3SMatthew Dillon 		for (i = 0; i < AHCI_MAX_PMPORTS; ++i) {
271b012a2caSMatthew Dillon 			at = kmalloc(pw2, M_DEVBUF, M_INTWAIT | M_ZERO);
272b012a2caSMatthew Dillon 			ap->ap_ata[i] = at;
2731980eff3SMatthew Dillon 			at->at_ahci_port = ap;
2741980eff3SMatthew Dillon 			at->at_target = i;
2753209f581SMatthew Dillon 			at->at_probe = ATA_PROBE_NEED_INIT;
276831bc9e3SMatthew Dillon 			at->at_features |= ATA_PORT_F_RESCAN;
2771980eff3SMatthew Dillon 			ksnprintf(at->at_name, sizeof(at->at_name),
2781980eff3SMatthew Dillon 				  "%s.%d", ap->ap_name, i);
2791980eff3SMatthew Dillon 		}
2801980eff3SMatthew Dillon 	}
281258223a3SMatthew Dillon 	if (bus_space_subregion(sc->sc_iot, sc->sc_ioh,
282258223a3SMatthew Dillon 	    AHCI_PORT_REGION(port), AHCI_PORT_SIZE, &ap->ap_ioh) != 0) {
283258223a3SMatthew Dillon 		device_printf(sc->sc_dev,
284258223a3SMatthew Dillon 			      "unable to create register window for port %d\n",
285258223a3SMatthew Dillon 			      port);
286258223a3SMatthew Dillon 		goto freeport;
287258223a3SMatthew Dillon 	}
288258223a3SMatthew Dillon 
289258223a3SMatthew Dillon 	ap->ap_sc = sc;
290258223a3SMatthew Dillon 	ap->ap_num = port;
2913209f581SMatthew Dillon 	ap->ap_probe = ATA_PROBE_NEED_INIT;
292f17a0cedSMatthew Dillon 	ap->link_pwr_mgmt = AHCI_LINK_PWR_MGMT_NONE;
293f17a0cedSMatthew Dillon 	ap->sysctl_tree = NULL;
294258223a3SMatthew Dillon 	TAILQ_INIT(&ap->ap_ccb_free);
295258223a3SMatthew Dillon 	TAILQ_INIT(&ap->ap_ccb_pending);
296258223a3SMatthew Dillon 	lockinit(&ap->ap_ccb_lock, "ahcipo", 0, 0);
297258223a3SMatthew Dillon 
298258223a3SMatthew Dillon 	/* Disable port interrupts */
299258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_IE, 0);
300831bc9e3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SERR, -1);
301258223a3SMatthew Dillon 
30217eab71eSMatthew Dillon 	/*
30317eab71eSMatthew Dillon 	 * Sec 10.1.2 - deinitialise port if it is already running
30417eab71eSMatthew Dillon 	 */
305258223a3SMatthew Dillon 	cmd = ahci_pread(ap, AHCI_PREG_CMD);
3060be9576aSMatthew Dillon 	kprintf("%s: Caps %b\n", PORTNAME(ap), cmd, AHCI_PFMT_CMD);
3070be9576aSMatthew Dillon 
308258223a3SMatthew Dillon 	if ((cmd & (AHCI_PREG_CMD_ST | AHCI_PREG_CMD_CR |
309258223a3SMatthew Dillon 		    AHCI_PREG_CMD_FRE | AHCI_PREG_CMD_FR)) ||
310258223a3SMatthew Dillon 	    (ahci_pread(ap, AHCI_PREG_SCTL) & AHCI_PREG_SCTL_DET)) {
311258223a3SMatthew Dillon 		int r;
312258223a3SMatthew Dillon 
313258223a3SMatthew Dillon 		r = ahci_port_stop(ap, 1);
314258223a3SMatthew Dillon 		if (r) {
315258223a3SMatthew Dillon 			device_printf(sc->sc_dev,
316258223a3SMatthew Dillon 				  "unable to disable %s, ignoring port %d\n",
317258223a3SMatthew Dillon 				  ((r == 2) ? "CR" : "FR"), port);
318258223a3SMatthew Dillon 			rc = ENXIO;
319258223a3SMatthew Dillon 			goto freeport;
320258223a3SMatthew Dillon 		}
321258223a3SMatthew Dillon 
322258223a3SMatthew Dillon 		/* Write DET to zero */
323cf5f3a81SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SCTL, AHCI_PREG_SCTL_IPM_DISABLED);
324258223a3SMatthew Dillon 	}
325258223a3SMatthew Dillon 
326258223a3SMatthew Dillon 	/* Allocate RFIS */
327258223a3SMatthew Dillon 	ap->ap_dmamem_rfis = ahci_dmamem_alloc(sc, sc->sc_tag_rfis);
328258223a3SMatthew Dillon 	if (ap->ap_dmamem_rfis == NULL) {
329cf5f3a81SMatthew Dillon 		kprintf("%s: NORFIS\n", PORTNAME(ap));
330258223a3SMatthew Dillon 		goto nomem;
331258223a3SMatthew Dillon 	}
332258223a3SMatthew Dillon 
333258223a3SMatthew Dillon 	/* Setup RFIS base address */
334258223a3SMatthew Dillon 	ap->ap_rfis = (struct ahci_rfis *) AHCI_DMA_KVA(ap->ap_dmamem_rfis);
335258223a3SMatthew Dillon 	dva = AHCI_DMA_DVA(ap->ap_dmamem_rfis);
336258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_FBU, (u_int32_t)(dva >> 32));
337258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_FB, (u_int32_t)dva);
338258223a3SMatthew Dillon 
339831bc9e3SMatthew Dillon 	/* Clear SERR before starting FIS reception or ST or anything */
340831bc9e3SMatthew Dillon 	ahci_flush_tfd(ap);
341831bc9e3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SERR, -1);
342831bc9e3SMatthew Dillon 
343258223a3SMatthew Dillon 	/* Enable FIS reception and activate port. */
344258223a3SMatthew Dillon 	cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC;
3451980eff3SMatthew Dillon 	cmd &= ~(AHCI_PREG_CMD_CLO | AHCI_PREG_CMD_PMA);
346258223a3SMatthew Dillon 	cmd |= AHCI_PREG_CMD_FRE | AHCI_PREG_CMD_POD | AHCI_PREG_CMD_SUD;
347258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_CMD, cmd | AHCI_PREG_CMD_ICC_ACTIVE);
348258223a3SMatthew Dillon 
349258223a3SMatthew Dillon 	/* Check whether port activated.  Skip it if not. */
350258223a3SMatthew Dillon 	cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC;
351258223a3SMatthew Dillon 	if ((cmd & AHCI_PREG_CMD_FRE) == 0) {
352cf5f3a81SMatthew Dillon 		kprintf("%s: NOT-ACTIVATED\n", PORTNAME(ap));
353258223a3SMatthew Dillon 		rc = ENXIO;
354258223a3SMatthew Dillon 		goto freeport;
355258223a3SMatthew Dillon 	}
356258223a3SMatthew Dillon 
357258223a3SMatthew Dillon 	/* Allocate a CCB for each command slot */
358258223a3SMatthew Dillon 	ap->ap_ccbs = kmalloc(sizeof(struct ahci_ccb) * sc->sc_ncmds, M_DEVBUF,
359258223a3SMatthew Dillon 			      M_WAITOK | M_ZERO);
360258223a3SMatthew Dillon 	if (ap->ap_ccbs == NULL) {
361258223a3SMatthew Dillon 		device_printf(sc->sc_dev,
362258223a3SMatthew Dillon 			      "unable to allocate command list for port %d\n",
363258223a3SMatthew Dillon 			      port);
364258223a3SMatthew Dillon 		goto freeport;
365258223a3SMatthew Dillon 	}
366258223a3SMatthew Dillon 
367258223a3SMatthew Dillon 	/* Command List Structures and Command Tables */
368258223a3SMatthew Dillon 	ap->ap_dmamem_cmd_list = ahci_dmamem_alloc(sc, sc->sc_tag_cmdh);
369258223a3SMatthew Dillon 	ap->ap_dmamem_cmd_table = ahci_dmamem_alloc(sc, sc->sc_tag_cmdt);
370258223a3SMatthew Dillon 	if (ap->ap_dmamem_cmd_table == NULL ||
371258223a3SMatthew Dillon 	    ap->ap_dmamem_cmd_list == NULL) {
372258223a3SMatthew Dillon nomem:
373258223a3SMatthew Dillon 		device_printf(sc->sc_dev,
374258223a3SMatthew Dillon 			      "unable to allocate DMA memory for port %d\n",
375258223a3SMatthew Dillon 			      port);
376258223a3SMatthew Dillon 		goto freeport;
377258223a3SMatthew Dillon 	}
378258223a3SMatthew Dillon 
379258223a3SMatthew Dillon 	/* Setup command list base address */
380258223a3SMatthew Dillon 	dva = AHCI_DMA_DVA(ap->ap_dmamem_cmd_list);
381258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_CLBU, (u_int32_t)(dva >> 32));
382258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_CLB, (u_int32_t)dva);
383258223a3SMatthew Dillon 
384258223a3SMatthew Dillon 	/* Split CCB allocation into CCBs and assign to command header/table */
385258223a3SMatthew Dillon 	hdr = AHCI_DMA_KVA(ap->ap_dmamem_cmd_list);
386258223a3SMatthew Dillon 	table = AHCI_DMA_KVA(ap->ap_dmamem_cmd_table);
387258223a3SMatthew Dillon 	for (i = 0; i < sc->sc_ncmds; i++) {
388258223a3SMatthew Dillon 		ccb = &ap->ap_ccbs[i];
389258223a3SMatthew Dillon 
390258223a3SMatthew Dillon 		error = bus_dmamap_create(sc->sc_tag_data, BUS_DMA_ALLOCNOW,
391258223a3SMatthew Dillon 					  &ccb->ccb_dmamap);
392258223a3SMatthew Dillon 		if (error) {
393258223a3SMatthew Dillon 			device_printf(sc->sc_dev,
394258223a3SMatthew Dillon 				      "unable to create dmamap for port %d "
395258223a3SMatthew Dillon 				      "ccb %d\n", port, i);
396258223a3SMatthew Dillon 			goto freeport;
397258223a3SMatthew Dillon 		}
398258223a3SMatthew Dillon 
399258223a3SMatthew Dillon 		callout_init(&ccb->ccb_timeout);
400258223a3SMatthew Dillon 		ccb->ccb_slot = i;
401258223a3SMatthew Dillon 		ccb->ccb_port = ap;
402258223a3SMatthew Dillon 		ccb->ccb_cmd_hdr = &hdr[i];
403258223a3SMatthew Dillon 		ccb->ccb_cmd_table = &table[i];
404258223a3SMatthew Dillon 		dva = AHCI_DMA_DVA(ap->ap_dmamem_cmd_table) +
405258223a3SMatthew Dillon 		    ccb->ccb_slot * sizeof(struct ahci_cmd_table);
406258223a3SMatthew Dillon 		ccb->ccb_cmd_hdr->ctba_hi = htole32((u_int32_t)(dva >> 32));
407258223a3SMatthew Dillon 		ccb->ccb_cmd_hdr->ctba_lo = htole32((u_int32_t)dva);
408258223a3SMatthew Dillon 
409258223a3SMatthew Dillon 		ccb->ccb_xa.fis =
410258223a3SMatthew Dillon 		    (struct ata_fis_h2d *)ccb->ccb_cmd_table->cfis;
411258223a3SMatthew Dillon 		ccb->ccb_xa.packetcmd = ccb->ccb_cmd_table->acmd;
412258223a3SMatthew Dillon 		ccb->ccb_xa.tag = i;
413258223a3SMatthew Dillon 
414258223a3SMatthew Dillon 		ccb->ccb_xa.state = ATA_S_COMPLETE;
4151067474aSMatthew Dillon 
4161067474aSMatthew Dillon 		/*
4171067474aSMatthew Dillon 		 * CCB[1] is the error CCB and is not get or put.  It is
4181067474aSMatthew Dillon 		 * also used for probing.  Numerous HBAs only load the
4191067474aSMatthew Dillon 		 * signature from CCB[1] so it MUST be used for the second
4201067474aSMatthew Dillon 		 * FIS.
4211067474aSMatthew Dillon 		 */
4221067474aSMatthew Dillon 		if (i == 1)
4231067474aSMatthew Dillon 			ap->ap_err_ccb = ccb;
4241067474aSMatthew Dillon 		else
425258223a3SMatthew Dillon 			ahci_put_ccb(ccb);
426258223a3SMatthew Dillon 	}
427258223a3SMatthew Dillon 
42812feb904SMatthew Dillon 	/*
42912feb904SMatthew Dillon 	 * Wait for ICC change to complete
43012feb904SMatthew Dillon 	 */
431258223a3SMatthew Dillon 	ahci_pwait_clr(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_ICC);
432258223a3SMatthew Dillon 
433fd8bd957SMatthew Dillon 	/*
43412feb904SMatthew Dillon 	 * Calculate the interrupt mask
43512feb904SMatthew Dillon 	 */
43612feb904SMatthew Dillon 	data = AHCI_PREG_IE_TFEE | AHCI_PREG_IE_HBFE |
43712feb904SMatthew Dillon 	       AHCI_PREG_IE_IFE | AHCI_PREG_IE_OFE |
43812feb904SMatthew Dillon 	       AHCI_PREG_IE_DPE | AHCI_PREG_IE_UFE |
43912feb904SMatthew Dillon 	       AHCI_PREG_IE_PCE | AHCI_PREG_IE_PRCE |
44012feb904SMatthew Dillon 	       AHCI_PREG_IE_DHRE | AHCI_PREG_IE_SDBE;
44112feb904SMatthew Dillon 	if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SSNTF)
44212feb904SMatthew Dillon 		data |= AHCI_PREG_IE_IPME;
44312feb904SMatthew Dillon #ifdef AHCI_COALESCE
44412feb904SMatthew Dillon 	if (sc->sc_ccc_ports & (1 << port)
44512feb904SMatthew Dillon 		data &= ~(AHCI_PREG_IE_SDBE | AHCI_PREG_IE_DHRE);
44612feb904SMatthew Dillon #endif
44712feb904SMatthew Dillon 	ap->ap_intmask = data;
44812feb904SMatthew Dillon 
44912feb904SMatthew Dillon 	/*
450e8cf3f55SMatthew Dillon 	 * Start the port helper thread.  The helper thread will call
451e8cf3f55SMatthew Dillon 	 * ahci_port_init() so the ports can all be started in parallel.
452e8cf3f55SMatthew Dillon 	 * A failure by ahci_port_init() does not deallocate the port
453e8cf3f55SMatthew Dillon 	 * since we still want hot-plug events.
454fd8bd957SMatthew Dillon 	 */
455f4553de1SMatthew Dillon 	ahci_os_start_port(ap);
456fd8bd957SMatthew Dillon 	return(0);
457fd8bd957SMatthew Dillon freeport:
458fd8bd957SMatthew Dillon 	ahci_port_free(sc, port);
459fd8bd957SMatthew Dillon 	return (rc);
460fd8bd957SMatthew Dillon }
461fd8bd957SMatthew Dillon 
462fd8bd957SMatthew Dillon /*
463fd8bd957SMatthew Dillon  * [re]initialize an idle port.  No CCBs should be active.
464fd8bd957SMatthew Dillon  *
465fd8bd957SMatthew Dillon  * This function is called during the initial port allocation sequence
466fd8bd957SMatthew Dillon  * and is also called on hot-plug insertion.  We take no chances and
467fd8bd957SMatthew Dillon  * use a portreset instead of a softreset.
468fd8bd957SMatthew Dillon  *
46922181ab7SMatthew Dillon  * This function is the only way to move a failed port back to active
47022181ab7SMatthew Dillon  * status.
47122181ab7SMatthew Dillon  *
472fd8bd957SMatthew Dillon  * Returns 0 if a device is successfully detected.
473fd8bd957SMatthew Dillon  */
474fd8bd957SMatthew Dillon int
47512feb904SMatthew Dillon ahci_port_init(struct ahci_port *ap)
476fd8bd957SMatthew Dillon {
477fd8bd957SMatthew Dillon 	/*
47812feb904SMatthew Dillon 	 * Register [re]initialization
479fd8bd957SMatthew Dillon 	 */
48012feb904SMatthew Dillon 	if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SSNTF)
4811980eff3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SNTF, -1);
4821980eff3SMatthew Dillon 	ap->ap_probe = ATA_PROBE_NEED_HARD_RESET;
4831980eff3SMatthew Dillon 	ap->ap_pmcount = 0;
484e8cf3f55SMatthew Dillon 
485e8cf3f55SMatthew Dillon 	/*
486f17a0cedSMatthew Dillon 	 * Flush the TFD and SERR and make sure the port is stopped before
487f17a0cedSMatthew Dillon 	 * enabling its interrupt.  We no longer cycle the port start as
488f17a0cedSMatthew Dillon 	 * the port should not be started unless a device is present.
489f17a0cedSMatthew Dillon 	 *
490f17a0cedSMatthew Dillon 	 * XXX should we enable FIS reception? (FRE)?
491e8cf3f55SMatthew Dillon 	 */
492f17a0cedSMatthew Dillon 	ahci_flush_tfd(ap);
493f17a0cedSMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SERR, -1);
494e8cf3f55SMatthew Dillon 	ahci_port_stop(ap, 0);
495f4553de1SMatthew Dillon 	ahci_port_interrupt_enable(ap);
49612feb904SMatthew Dillon 	return (0);
497f4553de1SMatthew Dillon }
498f4553de1SMatthew Dillon 
499f4553de1SMatthew Dillon /*
500f4553de1SMatthew Dillon  * Enable or re-enable interrupts on a port.
501f4553de1SMatthew Dillon  *
502f4553de1SMatthew Dillon  * This routine is called from the port initialization code or from the
503f4553de1SMatthew Dillon  * helper thread as the real interrupt may be forced to turn off certain
504f4553de1SMatthew Dillon  * interrupt sources.
505f4553de1SMatthew Dillon  */
506f4553de1SMatthew Dillon void
507f4553de1SMatthew Dillon ahci_port_interrupt_enable(struct ahci_port *ap)
508f4553de1SMatthew Dillon {
50912feb904SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_IE, ap->ap_intmask);
5101980eff3SMatthew Dillon }
511258223a3SMatthew Dillon 
512fd8bd957SMatthew Dillon /*
513f5caeaa0SMatthew Dillon  * Manage the agressive link power management capability.
514f17a0cedSMatthew Dillon  */
515f17a0cedSMatthew Dillon void
516f17a0cedSMatthew Dillon ahci_port_link_pwr_mgmt(struct ahci_port *ap, int link_pwr_mgmt)
517f17a0cedSMatthew Dillon {
518f17a0cedSMatthew Dillon 	u_int32_t cmd, sctl;
519f17a0cedSMatthew Dillon 
520f17a0cedSMatthew Dillon 	if (link_pwr_mgmt == ap->link_pwr_mgmt)
521f17a0cedSMatthew Dillon 		return;
522f17a0cedSMatthew Dillon 
523f17a0cedSMatthew Dillon 	if ((ap->ap_sc->sc_cap & AHCI_REG_CAP_SALP) == 0) {
524f17a0cedSMatthew Dillon 		kprintf("%s: link power management not supported.\n",
525f17a0cedSMatthew Dillon 			PORTNAME(ap));
526f17a0cedSMatthew Dillon 		return;
527f17a0cedSMatthew Dillon 	}
528f17a0cedSMatthew Dillon 
529f17a0cedSMatthew Dillon 	ahci_os_lock_port(ap);
530f17a0cedSMatthew Dillon 
531f17a0cedSMatthew Dillon 	if (link_pwr_mgmt == AHCI_LINK_PWR_MGMT_AGGR &&
532f17a0cedSMatthew Dillon 	    (ap->ap_sc->sc_cap & AHCI_REG_CAP_SSC)) {
533f17a0cedSMatthew Dillon 		kprintf("%s: enabling aggressive link power management.\n",
534f17a0cedSMatthew Dillon 			PORTNAME(ap));
535f17a0cedSMatthew Dillon 
536f17a0cedSMatthew Dillon 		ap->ap_intmask &= ~AHCI_PREG_IE_PRCE;
537f17a0cedSMatthew Dillon 		ahci_port_interrupt_enable(ap);
538f17a0cedSMatthew Dillon 
539f17a0cedSMatthew Dillon 		sctl = ahci_pread(ap, AHCI_PREG_SCTL);
540f17a0cedSMatthew Dillon 		sctl &= ~(AHCI_PREG_SCTL_IPM_DISABLED);
541f17a0cedSMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SCTL, sctl);
542f17a0cedSMatthew Dillon 
543f17a0cedSMatthew Dillon 		cmd = ahci_pread(ap, AHCI_PREG_CMD);
544f17a0cedSMatthew Dillon 		cmd |= AHCI_PREG_CMD_ASP;
545f17a0cedSMatthew Dillon 		cmd |= AHCI_PREG_CMD_ALPE;
546f17a0cedSMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CMD, cmd);
547f17a0cedSMatthew Dillon 
548f17a0cedSMatthew Dillon 		ap->link_pwr_mgmt = link_pwr_mgmt;
549f17a0cedSMatthew Dillon 
550f17a0cedSMatthew Dillon 	} else if (link_pwr_mgmt == AHCI_LINK_PWR_MGMT_MEDIUM &&
551f17a0cedSMatthew Dillon 	           (ap->ap_sc->sc_cap & AHCI_REG_CAP_PSC)) {
552f17a0cedSMatthew Dillon 		kprintf("%s: enabling medium link power management.\n",
553f17a0cedSMatthew Dillon 			PORTNAME(ap));
554f17a0cedSMatthew Dillon 
555f17a0cedSMatthew Dillon 		ap->ap_intmask &= ~AHCI_PREG_IE_PRCE;
556f17a0cedSMatthew Dillon 		ahci_port_interrupt_enable(ap);
557f17a0cedSMatthew Dillon 
558f17a0cedSMatthew Dillon 		sctl = ahci_pread(ap, AHCI_PREG_SCTL);
559f17a0cedSMatthew Dillon 		sctl &= ~(AHCI_PREG_SCTL_IPM_DISABLED);
560f17a0cedSMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SCTL, sctl);
561f17a0cedSMatthew Dillon 
562f17a0cedSMatthew Dillon 		cmd = ahci_pread(ap, AHCI_PREG_CMD);
563f17a0cedSMatthew Dillon 		cmd &= ~AHCI_PREG_CMD_ASP;
564f17a0cedSMatthew Dillon 		cmd |= AHCI_PREG_CMD_ALPE;
565f17a0cedSMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CMD, cmd);
566f17a0cedSMatthew Dillon 
567f17a0cedSMatthew Dillon 		ap->link_pwr_mgmt = link_pwr_mgmt;
568f17a0cedSMatthew Dillon 
569f17a0cedSMatthew Dillon 	} else if (link_pwr_mgmt == AHCI_LINK_PWR_MGMT_NONE) {
570f17a0cedSMatthew Dillon 		kprintf("%s: disabling link power management.\n",
571f17a0cedSMatthew Dillon 			PORTNAME(ap));
572f17a0cedSMatthew Dillon 
573f17a0cedSMatthew Dillon 		cmd = ahci_pread(ap, AHCI_PREG_CMD);
574f17a0cedSMatthew Dillon 		cmd |= AHCI_PREG_CMD_ASP;
575f17a0cedSMatthew Dillon 		cmd &= ~(AHCI_PREG_CMD_ALPE | AHCI_PREG_CMD_ASP);
576f17a0cedSMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CMD, cmd);
577f17a0cedSMatthew Dillon 
578f17a0cedSMatthew Dillon 		sctl = ahci_pread(ap, AHCI_PREG_SCTL);
579f17a0cedSMatthew Dillon 		sctl |= AHCI_PREG_SCTL_IPM_DISABLED;
580f17a0cedSMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SCTL, sctl);
581f17a0cedSMatthew Dillon 
582f17a0cedSMatthew Dillon 		/* let the drive come back to avoid PRCS interrupts later */
583f17a0cedSMatthew Dillon 		ahci_os_unlock_port(ap);
584f17a0cedSMatthew Dillon 		ahci_os_sleep(1000);
585f17a0cedSMatthew Dillon 		ahci_os_lock_port(ap);
586f17a0cedSMatthew Dillon 
587f17a0cedSMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SERR, AHCI_PREG_SERR_DIAG_N);
588f17a0cedSMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_PRCS);
589f17a0cedSMatthew Dillon 
590f17a0cedSMatthew Dillon 		ap->ap_intmask |= AHCI_PREG_IE_PRCE;
591f17a0cedSMatthew Dillon 		ahci_port_interrupt_enable(ap);
592f17a0cedSMatthew Dillon 
593f17a0cedSMatthew Dillon 		ap->link_pwr_mgmt = link_pwr_mgmt;
594f17a0cedSMatthew Dillon 	} else {
595f17a0cedSMatthew Dillon 		kprintf("%s: unsupported link power management state %d.\n",
596f17a0cedSMatthew Dillon 			PORTNAME(ap), link_pwr_mgmt);
597f17a0cedSMatthew Dillon 	}
598f17a0cedSMatthew Dillon 
599f17a0cedSMatthew Dillon 	ahci_os_unlock_port(ap);
600f17a0cedSMatthew Dillon }
601f17a0cedSMatthew Dillon 
602f17a0cedSMatthew Dillon 
603f17a0cedSMatthew Dillon /*
6043209f581SMatthew Dillon  * Run the port / target state machine from a main context.
6053209f581SMatthew Dillon  *
6063209f581SMatthew Dillon  * The state machine for the port is always run.
6073209f581SMatthew Dillon  *
6083209f581SMatthew Dillon  * If atx is non-NULL run the state machine for a particular target.
6093209f581SMatthew Dillon  * If atx is NULL run the state machine for all targets.
6103209f581SMatthew Dillon  */
6113209f581SMatthew Dillon void
612831bc9e3SMatthew Dillon ahci_port_state_machine(struct ahci_port *ap, int initial)
6133209f581SMatthew Dillon {
6143209f581SMatthew Dillon 	struct ata_port *at;
6153209f581SMatthew Dillon 	u_int32_t data;
6163209f581SMatthew Dillon 	int target;
6173209f581SMatthew Dillon 	int didsleep;
618831bc9e3SMatthew Dillon 	int loop;
6193209f581SMatthew Dillon 
620831bc9e3SMatthew Dillon 	/*
621831bc9e3SMatthew Dillon 	 * State machine for port.  Note that CAM is not yet associated
622831bc9e3SMatthew Dillon 	 * during the initial parallel probe and the port's probe state
623831bc9e3SMatthew Dillon 	 * will not get past ATA_PROBE_NEED_IDENT.
624831bc9e3SMatthew Dillon 	 */
625c408a8b3SMatthew Dillon 	{
6261067474aSMatthew Dillon 		if (initial == 0 && ap->ap_probe <= ATA_PROBE_NEED_HARD_RESET) {
6271067474aSMatthew Dillon 			kprintf("%s: Waiting 10 seconds on insertion\n",
6281067474aSMatthew Dillon 				PORTNAME(ap));
6291067474aSMatthew Dillon 			ahci_os_sleep(10000);
6301067474aSMatthew Dillon 			initial = 1;
6313209f581SMatthew Dillon 		}
6321067474aSMatthew Dillon 		if (ap->ap_probe == ATA_PROBE_NEED_INIT)
63312feb904SMatthew Dillon 			ahci_port_init(ap);
6343209f581SMatthew Dillon 		if (ap->ap_probe == ATA_PROBE_NEED_HARD_RESET)
6353209f581SMatthew Dillon 			ahci_port_reset(ap, NULL, 1);
6363209f581SMatthew Dillon 		if (ap->ap_probe == ATA_PROBE_NEED_SOFT_RESET)
6373209f581SMatthew Dillon 			ahci_port_reset(ap, NULL, 0);
6383209f581SMatthew Dillon 		if (ap->ap_probe == ATA_PROBE_NEED_IDENT)
6393209f581SMatthew Dillon 			ahci_cam_probe(ap, NULL);
6403209f581SMatthew Dillon 	}
6413209f581SMatthew Dillon 	if (ap->ap_type != ATA_PORT_T_PM) {
6423209f581SMatthew Dillon 		if (ap->ap_probe == ATA_PROBE_FAILED) {
6433209f581SMatthew Dillon 			ahci_cam_changed(ap, NULL, 0);
644f4553de1SMatthew Dillon 		} else if (ap->ap_probe >= ATA_PROBE_NEED_IDENT) {
6453209f581SMatthew Dillon 			ahci_cam_changed(ap, NULL, 1);
6463209f581SMatthew Dillon 		}
6473209f581SMatthew Dillon 		return;
6483209f581SMatthew Dillon 	}
6493209f581SMatthew Dillon 
650831bc9e3SMatthew Dillon 	/*
651831bc9e3SMatthew Dillon 	 * Port Multiplier state machine.
652831bc9e3SMatthew Dillon 	 *
653831bc9e3SMatthew Dillon 	 * Get a mask of changed targets and combine with any runnable
654831bc9e3SMatthew Dillon 	 * states already present.
655831bc9e3SMatthew Dillon 	 */
656831bc9e3SMatthew Dillon 	for (loop = 0; ;++loop) {
6572cc2e845SMatthew Dillon 		if (ahci_pm_read(ap, 15, SATA_PMREG_EINFO, &data)) {
6583209f581SMatthew Dillon 			kprintf("%s: PM unable to read hot-plug bitmap\n",
6593209f581SMatthew Dillon 				PORTNAME(ap));
6603209f581SMatthew Dillon 			break;
6613209f581SMatthew Dillon 		}
6623209f581SMatthew Dillon 
6633209f581SMatthew Dillon 		/*
664831bc9e3SMatthew Dillon 		 * Do at least one loop, then stop if no more state changes
665831bc9e3SMatthew Dillon 		 * have occured.  The PM might not generate a new
666831bc9e3SMatthew Dillon 		 * notification until we clear the entire bitmap.
6673209f581SMatthew Dillon 		 */
668831bc9e3SMatthew Dillon 		if (loop && data == 0)
6693209f581SMatthew Dillon 			break;
6703209f581SMatthew Dillon 
6713209f581SMatthew Dillon 		/*
6723209f581SMatthew Dillon 		 * New devices showing up in the bitmap require some spin-up
6733209f581SMatthew Dillon 		 * time before we start probing them.  Reset didsleep.  The
6743209f581SMatthew Dillon 		 * first new device we detect will sleep before probing.
675831bc9e3SMatthew Dillon 		 *
676831bc9e3SMatthew Dillon 		 * This only applies to devices whos change bit is set in
677831bc9e3SMatthew Dillon 		 * the data, and does not apply to the initial boot-time
678831bc9e3SMatthew Dillon 		 * probe.
6793209f581SMatthew Dillon 		 */
6803209f581SMatthew Dillon 		didsleep = 0;
6813209f581SMatthew Dillon 
6823209f581SMatthew Dillon 		for (target = 0; target < ap->ap_pmcount; ++target) {
683b012a2caSMatthew Dillon 			at = ap->ap_ata[target];
6843209f581SMatthew Dillon 
6853209f581SMatthew Dillon 			/*
6863209f581SMatthew Dillon 			 * Check the target state for targets behind the PM
6873209f581SMatthew Dillon 			 * which have changed state.  This will adjust
6883209f581SMatthew Dillon 			 * at_probe and set ATA_PORT_F_RESCAN
6893209f581SMatthew Dillon 			 *
6901067474aSMatthew Dillon 			 * We want to wait at least 10 seconds before probing
6913209f581SMatthew Dillon 			 * a newly inserted device.  If the check status
6923209f581SMatthew Dillon 			 * indicates a device is present and in need of a
6933209f581SMatthew Dillon 			 * hard reset, we make sure we have slept before
6943209f581SMatthew Dillon 			 * continuing.
695831bc9e3SMatthew Dillon 			 *
6961067474aSMatthew Dillon 			 * We also need to wait at least 1 second for the
6971067474aSMatthew Dillon 			 * PHY state to change after insertion, if we
6981067474aSMatthew Dillon 			 * haven't already waited the 10 seconds.
6991067474aSMatthew Dillon 			 *
700831bc9e3SMatthew Dillon 			 * NOTE: When pm_check_good finds a good port it
701831bc9e3SMatthew Dillon 			 *	 typically starts us in probe state
702831bc9e3SMatthew Dillon 			 *	 NEED_HARD_RESET rather than INIT.
7033209f581SMatthew Dillon 			 */
7043209f581SMatthew Dillon 			if (data & (1 << target)) {
7051067474aSMatthew Dillon 				if (initial == 0 && didsleep == 0)
7061067474aSMatthew Dillon 					ahci_os_sleep(1000);
7073209f581SMatthew Dillon 				ahci_pm_check_good(ap, target);
708831bc9e3SMatthew Dillon 				if (initial == 0 && didsleep == 0 &&
709831bc9e3SMatthew Dillon 				    at->at_probe <= ATA_PROBE_NEED_HARD_RESET
710831bc9e3SMatthew Dillon 				) {
7113209f581SMatthew Dillon 					didsleep = 1;
712121d8e75SMatthew Dillon 					kprintf("%s: Waiting 10 seconds on insertion\n", PORTNAME(ap));
713121d8e75SMatthew Dillon 					ahci_os_sleep(10000);
7143209f581SMatthew Dillon 				}
7153209f581SMatthew Dillon 			}
716831bc9e3SMatthew Dillon 
717831bc9e3SMatthew Dillon 			/*
718831bc9e3SMatthew Dillon 			 * Report hot-plug events before the probe state
719831bc9e3SMatthew Dillon 			 * really gets hot.  Only actual events are reported
720831bc9e3SMatthew Dillon 			 * here to reduce spew.
721831bc9e3SMatthew Dillon 			 */
722831bc9e3SMatthew Dillon 			if (data & (1 << target)) {
723831bc9e3SMatthew Dillon 				kprintf("%s: HOTPLUG (PM) - ", ATANAME(ap, at));
724831bc9e3SMatthew Dillon 				switch(at->at_probe) {
725831bc9e3SMatthew Dillon 				case ATA_PROBE_NEED_INIT:
726831bc9e3SMatthew Dillon 				case ATA_PROBE_NEED_HARD_RESET:
727831bc9e3SMatthew Dillon 					kprintf("Device inserted\n");
728831bc9e3SMatthew Dillon 					break;
729831bc9e3SMatthew Dillon 				case ATA_PROBE_FAILED:
730831bc9e3SMatthew Dillon 					kprintf("Device removed\n");
731831bc9e3SMatthew Dillon 					break;
732831bc9e3SMatthew Dillon 				default:
733831bc9e3SMatthew Dillon 					kprintf("Device probe in progress\n");
734831bc9e3SMatthew Dillon 					break;
735831bc9e3SMatthew Dillon 				}
7363209f581SMatthew Dillon 			}
7373209f581SMatthew Dillon 
7383209f581SMatthew Dillon 			/*
739831bc9e3SMatthew Dillon 			 * Run through the state machine as necessary if
740831bc9e3SMatthew Dillon 			 * the port is not marked failed.
741831bc9e3SMatthew Dillon 			 *
742831bc9e3SMatthew Dillon 			 * The state machine may stop at NEED_IDENT if
743831bc9e3SMatthew Dillon 			 * CAM is not yet attached.
744831bc9e3SMatthew Dillon 			 *
745831bc9e3SMatthew Dillon 			 * Acquire exclusive access to the port while we
746831bc9e3SMatthew Dillon 			 * are doing this.  This prevents command-completion
747831bc9e3SMatthew Dillon 			 * from queueing commands for non-polled targets
748831bc9e3SMatthew Dillon 			 * inbetween our probe steps.  We need to do this
749831bc9e3SMatthew Dillon 			 * because the reset probes can generate severe PHY
750831bc9e3SMatthew Dillon 			 * and protocol errors and soft-brick the port.
7513209f581SMatthew Dillon 			 */
752831bc9e3SMatthew Dillon 			if (at->at_probe != ATA_PROBE_FAILED &&
753831bc9e3SMatthew Dillon 			    at->at_probe != ATA_PROBE_GOOD) {
754831bc9e3SMatthew Dillon 				ahci_beg_exclusive_access(ap, at);
7553209f581SMatthew Dillon 				if (at->at_probe == ATA_PROBE_NEED_INIT)
75612feb904SMatthew Dillon 					ahci_pm_port_init(ap, at);
7573209f581SMatthew Dillon 				if (at->at_probe == ATA_PROBE_NEED_HARD_RESET)
7583209f581SMatthew Dillon 					ahci_port_reset(ap, at, 1);
7593209f581SMatthew Dillon 				if (at->at_probe == ATA_PROBE_NEED_SOFT_RESET)
7603209f581SMatthew Dillon 					ahci_port_reset(ap, at, 0);
7613209f581SMatthew Dillon 				if (at->at_probe == ATA_PROBE_NEED_IDENT)
7623209f581SMatthew Dillon 					ahci_cam_probe(ap, at);
763831bc9e3SMatthew Dillon 				ahci_end_exclusive_access(ap, at);
7643209f581SMatthew Dillon 			}
7653209f581SMatthew Dillon 
7663209f581SMatthew Dillon 			/*
767831bc9e3SMatthew Dillon 			 * Add or remove from CAM
7683209f581SMatthew Dillon 			 */
7693209f581SMatthew Dillon 			if (at->at_features & ATA_PORT_F_RESCAN) {
7703209f581SMatthew Dillon 				at->at_features &= ~ATA_PORT_F_RESCAN;
7713209f581SMatthew Dillon 				if (at->at_probe == ATA_PROBE_FAILED) {
7723209f581SMatthew Dillon 					ahci_cam_changed(ap, at, 0);
773f4553de1SMatthew Dillon 				} else if (at->at_probe >= ATA_PROBE_NEED_IDENT) {
7743209f581SMatthew Dillon 					ahci_cam_changed(ap, at, 1);
7753209f581SMatthew Dillon 				}
7763209f581SMatthew Dillon 			}
7773560ed94SMatthew Dillon 			data &= ~(1 << target);
7783560ed94SMatthew Dillon 		}
7793560ed94SMatthew Dillon 		if (data) {
7803560ed94SMatthew Dillon 			kprintf("%s: WARNING (PM): extra bits set in "
7813560ed94SMatthew Dillon 				"EINFO: %08x\n", PORTNAME(ap), data);
7823560ed94SMatthew Dillon 			while (target < AHCI_MAX_PMPORTS) {
7833560ed94SMatthew Dillon 				ahci_pm_check_good(ap, target);
7843560ed94SMatthew Dillon 				++target;
7853560ed94SMatthew Dillon 			}
7863209f581SMatthew Dillon 		}
7873209f581SMatthew Dillon 	}
7883209f581SMatthew Dillon }
7893209f581SMatthew Dillon 
7903209f581SMatthew Dillon 
7913209f581SMatthew Dillon /*
792fd8bd957SMatthew Dillon  * De-initialize and detach a port.
793fd8bd957SMatthew Dillon  */
794258223a3SMatthew Dillon void
795258223a3SMatthew Dillon ahci_port_free(struct ahci_softc *sc, u_int port)
796258223a3SMatthew Dillon {
797258223a3SMatthew Dillon 	struct ahci_port	*ap = sc->sc_ports[port];
798258223a3SMatthew Dillon 	struct ahci_ccb		*ccb;
799b012a2caSMatthew Dillon 	int i;
800258223a3SMatthew Dillon 
80117eab71eSMatthew Dillon 	/*
80217eab71eSMatthew Dillon 	 * Ensure port is disabled and its interrupts are all flushed.
80317eab71eSMatthew Dillon 	 */
804258223a3SMatthew Dillon 	if (ap->ap_sc) {
80517eab71eSMatthew Dillon 		ahci_port_stop(ap, 1);
806f4553de1SMatthew Dillon 		ahci_os_stop_port(ap);
807258223a3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CMD, 0);
808258223a3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IE, 0);
809258223a3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS, ahci_pread(ap, AHCI_PREG_IS));
810258223a3SMatthew Dillon 		ahci_write(sc, AHCI_REG_IS, 1 << port);
811258223a3SMatthew Dillon 	}
812258223a3SMatthew Dillon 
813258223a3SMatthew Dillon 	if (ap->ap_ccbs) {
814258223a3SMatthew Dillon 		while ((ccb = ahci_get_ccb(ap)) != NULL) {
815258223a3SMatthew Dillon 			if (ccb->ccb_dmamap) {
816258223a3SMatthew Dillon 				bus_dmamap_destroy(sc->sc_tag_data,
817258223a3SMatthew Dillon 						   ccb->ccb_dmamap);
818258223a3SMatthew Dillon 				ccb->ccb_dmamap = NULL;
819258223a3SMatthew Dillon 			}
820258223a3SMatthew Dillon 		}
8211067474aSMatthew Dillon 		if ((ccb = ap->ap_err_ccb) != NULL) {
8221067474aSMatthew Dillon 			if (ccb->ccb_dmamap) {
8231067474aSMatthew Dillon 				bus_dmamap_destroy(sc->sc_tag_data,
8241067474aSMatthew Dillon 						   ccb->ccb_dmamap);
8251067474aSMatthew Dillon 				ccb->ccb_dmamap = NULL;
8261067474aSMatthew Dillon 			}
8271067474aSMatthew Dillon 			ap->ap_err_ccb = NULL;
8281067474aSMatthew Dillon 		}
829258223a3SMatthew Dillon 		kfree(ap->ap_ccbs, M_DEVBUF);
830258223a3SMatthew Dillon 		ap->ap_ccbs = NULL;
831258223a3SMatthew Dillon 	}
832258223a3SMatthew Dillon 
833258223a3SMatthew Dillon 	if (ap->ap_dmamem_cmd_list) {
834258223a3SMatthew Dillon 		ahci_dmamem_free(sc, ap->ap_dmamem_cmd_list);
835258223a3SMatthew Dillon 		ap->ap_dmamem_cmd_list = NULL;
836258223a3SMatthew Dillon 	}
837258223a3SMatthew Dillon 	if (ap->ap_dmamem_rfis) {
838258223a3SMatthew Dillon 		ahci_dmamem_free(sc, ap->ap_dmamem_rfis);
839258223a3SMatthew Dillon 		ap->ap_dmamem_rfis = NULL;
840258223a3SMatthew Dillon 	}
841258223a3SMatthew Dillon 	if (ap->ap_dmamem_cmd_table) {
842258223a3SMatthew Dillon 		ahci_dmamem_free(sc, ap->ap_dmamem_cmd_table);
843258223a3SMatthew Dillon 		ap->ap_dmamem_cmd_table = NULL;
844258223a3SMatthew Dillon 	}
8451980eff3SMatthew Dillon 	if (ap->ap_ata) {
846b012a2caSMatthew Dillon 		for (i = 0; i < AHCI_MAX_PMPORTS; ++i) {
847b012a2caSMatthew Dillon 			if (ap->ap_ata[i]) {
848b012a2caSMatthew Dillon 				kfree(ap->ap_ata[i], M_DEVBUF);
849b012a2caSMatthew Dillon 				ap->ap_ata[i] = NULL;
850b012a2caSMatthew Dillon 			}
851b012a2caSMatthew Dillon 		}
8521980eff3SMatthew Dillon 	}
85312feb904SMatthew Dillon 	if (ap->ap_err_scratch) {
85412feb904SMatthew Dillon 		kfree(ap->ap_err_scratch, M_DEVBUF);
85512feb904SMatthew Dillon 		ap->ap_err_scratch = NULL;
85612feb904SMatthew Dillon 	}
857258223a3SMatthew Dillon 
858258223a3SMatthew Dillon 	/* bus_space(9) says we dont free the subregions handle */
859258223a3SMatthew Dillon 
860258223a3SMatthew Dillon 	kfree(ap, M_DEVBUF);
861258223a3SMatthew Dillon 	sc->sc_ports[port] = NULL;
862258223a3SMatthew Dillon }
863258223a3SMatthew Dillon 
864fd8bd957SMatthew Dillon /*
865fd8bd957SMatthew Dillon  * Start high-level command processing on the port
866fd8bd957SMatthew Dillon  */
867258223a3SMatthew Dillon int
86817eab71eSMatthew Dillon ahci_port_start(struct ahci_port *ap)
869258223a3SMatthew Dillon {
87012feb904SMatthew Dillon 	u_int32_t	r, s, is, tfd;
871258223a3SMatthew Dillon 
87217eab71eSMatthew Dillon 	/*
87317eab71eSMatthew Dillon 	 * FRE must be turned on before ST.  Wait for FR to go active
87417eab71eSMatthew Dillon 	 * before turning on ST.  The spec doesn't seem to think this
87517eab71eSMatthew Dillon 	 * is necessary but waiting here avoids an on-off race in the
87617eab71eSMatthew Dillon 	 * ahci_port_stop() code.
87717eab71eSMatthew Dillon 	 */
87812feb904SMatthew Dillon 	r = ahci_pread(ap, AHCI_PREG_CMD);
87917eab71eSMatthew Dillon 	if ((r & AHCI_PREG_CMD_FRE) == 0) {
880258223a3SMatthew Dillon 		r |= AHCI_PREG_CMD_FRE;
88117eab71eSMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CMD, r);
88217eab71eSMatthew Dillon 	}
88317eab71eSMatthew Dillon 	if ((ap->ap_sc->sc_flags & AHCI_F_IGN_FR) == 0) {
88417eab71eSMatthew Dillon 		if (ahci_pwait_set(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_FR)) {
88517eab71eSMatthew Dillon 			kprintf("%s: Cannot start FIS reception\n",
88617eab71eSMatthew Dillon 				PORTNAME(ap));
88717eab71eSMatthew Dillon 			return (2);
88817eab71eSMatthew Dillon 		}
889f17a0cedSMatthew Dillon 	} else {
890f17a0cedSMatthew Dillon 		ahci_os_sleep(10);
89117eab71eSMatthew Dillon 	}
89217eab71eSMatthew Dillon 
89317eab71eSMatthew Dillon 	/*
89417eab71eSMatthew Dillon 	 * Turn on ST, wait for CR to come up.
89517eab71eSMatthew Dillon 	 */
896258223a3SMatthew Dillon 	r |= AHCI_PREG_CMD_ST;
897258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_CMD, r);
898f17a0cedSMatthew Dillon 	if (ahci_pwait_set_to(ap, 2000, AHCI_PREG_CMD, AHCI_PREG_CMD_CR)) {
8998bf6a3ffSMatthew Dillon 		s = ahci_pread(ap, AHCI_PREG_SERR);
9008bf6a3ffSMatthew Dillon 		is = ahci_pread(ap, AHCI_PREG_IS);
9018bf6a3ffSMatthew Dillon 		tfd = ahci_pread(ap, AHCI_PREG_TFD);
9021980eff3SMatthew Dillon 		kprintf("%s: Cannot start command DMA\n"
9031980eff3SMatthew Dillon 			"NCMP=%b NSERR=%b\n"
90412feb904SMatthew Dillon 			"NEWIS=%b\n"
90512feb904SMatthew Dillon 			"NEWTFD=%b\n",
9061980eff3SMatthew Dillon 			PORTNAME(ap),
9071980eff3SMatthew Dillon 			r, AHCI_PFMT_CMD, s, AHCI_PFMT_SERR,
90812feb904SMatthew Dillon 			is, AHCI_PFMT_IS,
90912feb904SMatthew Dillon 			tfd, AHCI_PFMT_TFD_STS);
91017eab71eSMatthew Dillon 		return (1);
91117eab71eSMatthew Dillon 	}
912258223a3SMatthew Dillon 
913258223a3SMatthew Dillon #ifdef AHCI_COALESCE
91417eab71eSMatthew Dillon 	/*
91517eab71eSMatthew Dillon 	 * (Re-)enable coalescing on the port.
91617eab71eSMatthew Dillon 	 */
917258223a3SMatthew Dillon 	if (ap->ap_sc->sc_ccc_ports & (1 << ap->ap_num)) {
918258223a3SMatthew Dillon 		ap->ap_sc->sc_ccc_ports_cur |= (1 << ap->ap_num);
919258223a3SMatthew Dillon 		ahci_write(ap->ap_sc, AHCI_REG_CCC_PORTS,
920258223a3SMatthew Dillon 		    ap->ap_sc->sc_ccc_ports_cur);
921258223a3SMatthew Dillon 	}
922258223a3SMatthew Dillon #endif
923258223a3SMatthew Dillon 
924258223a3SMatthew Dillon 	return (0);
925258223a3SMatthew Dillon }
926258223a3SMatthew Dillon 
927fd8bd957SMatthew Dillon /*
928fd8bd957SMatthew Dillon  * Stop high-level command processing on a port
9294c339a5fSMatthew Dillon  *
9304c339a5fSMatthew Dillon  * WARNING!  If the port is stopped while CR is still active our saved
9314c339a5fSMatthew Dillon  *	     CI/SACT will race any commands completed by the command
9324c339a5fSMatthew Dillon  *	     processor prior to being able to stop.  Thus we never call
9334c339a5fSMatthew Dillon  *	     this function unless we intend to dispose of any remaining
9344c339a5fSMatthew Dillon  *	     active commands.  In particular, this complicates the timeout
9354c339a5fSMatthew Dillon  *	     code.
936fd8bd957SMatthew Dillon  */
937258223a3SMatthew Dillon int
938258223a3SMatthew Dillon ahci_port_stop(struct ahci_port *ap, int stop_fis_rx)
939258223a3SMatthew Dillon {
940258223a3SMatthew Dillon 	u_int32_t	r;
941258223a3SMatthew Dillon 
942258223a3SMatthew Dillon #ifdef AHCI_COALESCE
94317eab71eSMatthew Dillon 	/*
94417eab71eSMatthew Dillon 	 * Disable coalescing on the port while it is stopped.
94517eab71eSMatthew Dillon 	 */
946258223a3SMatthew Dillon 	if (ap->ap_sc->sc_ccc_ports & (1 << ap->ap_num)) {
947258223a3SMatthew Dillon 		ap->ap_sc->sc_ccc_ports_cur &= ~(1 << ap->ap_num);
948258223a3SMatthew Dillon 		ahci_write(ap->ap_sc, AHCI_REG_CCC_PORTS,
949258223a3SMatthew Dillon 		    ap->ap_sc->sc_ccc_ports_cur);
950258223a3SMatthew Dillon 	}
951258223a3SMatthew Dillon #endif
952258223a3SMatthew Dillon 
95317eab71eSMatthew Dillon 	/*
95417eab71eSMatthew Dillon 	 * Turn off ST, then wait for CR to go off.
95517eab71eSMatthew Dillon 	 */
956258223a3SMatthew Dillon 	r = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC;
957258223a3SMatthew Dillon 	r &= ~AHCI_PREG_CMD_ST;
958258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_CMD, r);
959258223a3SMatthew Dillon 
96017eab71eSMatthew Dillon 	if (ahci_pwait_clr(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_CR)) {
96117eab71eSMatthew Dillon 		kprintf("%s: Port bricked, unable to stop (ST)\n",
96217eab71eSMatthew Dillon 			PORTNAME(ap));
963258223a3SMatthew Dillon 		return (1);
96417eab71eSMatthew Dillon 	}
965258223a3SMatthew Dillon 
9661980eff3SMatthew Dillon #if 0
96717eab71eSMatthew Dillon 	/*
96817eab71eSMatthew Dillon 	 * Turn off FRE, then wait for FR to go off.  FRE cannot
96917eab71eSMatthew Dillon 	 * be turned off until CR transitions to 0.
97017eab71eSMatthew Dillon 	 */
9711980eff3SMatthew Dillon 	if ((r & AHCI_PREG_CMD_FR) == 0) {
9721980eff3SMatthew Dillon 		kprintf("%s: FR stopped, clear FRE for next start\n",
9731980eff3SMatthew Dillon 			PORTNAME(ap));
9741980eff3SMatthew Dillon 		stop_fis_rx = 2;
9751980eff3SMatthew Dillon 	}
9761980eff3SMatthew Dillon #endif
97717eab71eSMatthew Dillon 	if (stop_fis_rx) {
97817eab71eSMatthew Dillon 		r &= ~AHCI_PREG_CMD_FRE;
97917eab71eSMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CMD, r);
98017eab71eSMatthew Dillon 		if (ahci_pwait_clr(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_FR)) {
98117eab71eSMatthew Dillon 			kprintf("%s: Port bricked, unable to stop (FRE)\n",
98217eab71eSMatthew Dillon 				PORTNAME(ap));
983258223a3SMatthew Dillon 			return (2);
98417eab71eSMatthew Dillon 		}
98517eab71eSMatthew Dillon 	}
986258223a3SMatthew Dillon 
987258223a3SMatthew Dillon 	return (0);
988258223a3SMatthew Dillon }
989258223a3SMatthew Dillon 
990fd8bd957SMatthew Dillon /*
991fd8bd957SMatthew Dillon  * AHCI command list override -> forcibly clear TFD.STS.{BSY,DRQ}
992fd8bd957SMatthew Dillon  */
993258223a3SMatthew Dillon int
994258223a3SMatthew Dillon ahci_port_clo(struct ahci_port *ap)
995258223a3SMatthew Dillon {
996258223a3SMatthew Dillon 	struct ahci_softc		*sc = ap->ap_sc;
997258223a3SMatthew Dillon 	u_int32_t			cmd;
998258223a3SMatthew Dillon 
999258223a3SMatthew Dillon 	/* Only attempt CLO if supported by controller */
1000258223a3SMatthew Dillon 	if ((ahci_read(sc, AHCI_REG_CAP) & AHCI_REG_CAP_SCLO) == 0)
1001258223a3SMatthew Dillon 		return (1);
1002258223a3SMatthew Dillon 
1003258223a3SMatthew Dillon 	/* Issue CLO */
1004258223a3SMatthew Dillon 	cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC;
1005258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_CMD, cmd | AHCI_PREG_CMD_CLO);
1006258223a3SMatthew Dillon 
1007258223a3SMatthew Dillon 	/* Wait for completion */
1008258223a3SMatthew Dillon 	if (ahci_pwait_clr(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_CLO)) {
1009258223a3SMatthew Dillon 		kprintf("%s: CLO did not complete\n", PORTNAME(ap));
1010258223a3SMatthew Dillon 		return (1);
1011258223a3SMatthew Dillon 	}
1012258223a3SMatthew Dillon 
1013258223a3SMatthew Dillon 	return (0);
1014258223a3SMatthew Dillon }
1015258223a3SMatthew Dillon 
1016fd8bd957SMatthew Dillon /*
10171980eff3SMatthew Dillon  * Reset a port.
101817eab71eSMatthew Dillon  *
10191980eff3SMatthew Dillon  * If hard is 0 perform a softreset of the port.
102017eab71eSMatthew Dillon  * If hard is 1 perform a hard reset of the port.
10211980eff3SMatthew Dillon  *
10221980eff3SMatthew Dillon  * If at is non-NULL an indirect port via a port-multiplier is being
10231980eff3SMatthew Dillon  * reset, otherwise a direct port is being reset.
10241980eff3SMatthew Dillon  *
10251980eff3SMatthew Dillon  * NOTE: Indirect ports can only be soft-reset.
102617eab71eSMatthew Dillon  */
102717eab71eSMatthew Dillon int
10281980eff3SMatthew Dillon ahci_port_reset(struct ahci_port *ap, struct ata_port *at, int hard)
102917eab71eSMatthew Dillon {
103017eab71eSMatthew Dillon 	int rc;
103117eab71eSMatthew Dillon 
103217eab71eSMatthew Dillon 	if (hard) {
10331980eff3SMatthew Dillon 		if (at)
10341980eff3SMatthew Dillon 			rc = ahci_pm_hardreset(ap, at->at_target, hard);
10351980eff3SMatthew Dillon 		else
10361980eff3SMatthew Dillon 			rc = ahci_port_hardreset(ap, hard);
103717eab71eSMatthew Dillon 	} else {
10381980eff3SMatthew Dillon 		if (at)
10391980eff3SMatthew Dillon 			rc = ahci_pm_softreset(ap, at->at_target);
10401980eff3SMatthew Dillon 		else
104117eab71eSMatthew Dillon 			rc = ahci_port_softreset(ap);
104217eab71eSMatthew Dillon 	}
104317eab71eSMatthew Dillon 	return(rc);
104417eab71eSMatthew Dillon }
104517eab71eSMatthew Dillon 
104617eab71eSMatthew Dillon /*
1047fd8bd957SMatthew Dillon  * AHCI soft reset, Section 10.4.1
1048fd8bd957SMatthew Dillon  *
10491980eff3SMatthew Dillon  * (at) will be NULL when soft-resetting a directly-attached device, and
10501980eff3SMatthew Dillon  * non-NULL when soft-resetting a device through a port multiplier.
10511980eff3SMatthew Dillon  *
1052fd8bd957SMatthew Dillon  * This function keeps port communications intact and attempts to generate
10531980eff3SMatthew Dillon  * a reset to the connected device using device commands.
1054fd8bd957SMatthew Dillon  */
1055258223a3SMatthew Dillon int
1056258223a3SMatthew Dillon ahci_port_softreset(struct ahci_port *ap)
1057258223a3SMatthew Dillon {
1058258223a3SMatthew Dillon 	struct ahci_ccb		*ccb = NULL;
1059258223a3SMatthew Dillon 	struct ahci_cmd_hdr	*cmd_slot;
1060258223a3SMatthew Dillon 	u_int8_t		*fis;
10613209f581SMatthew Dillon 	int			error;
1062258223a3SMatthew Dillon 
10633209f581SMatthew Dillon 	error = EIO;
10641980eff3SMatthew Dillon 
1065074579dfSMatthew Dillon 	if (bootverbose) {
10661980eff3SMatthew Dillon 		kprintf("%s: START SOFTRESET %b\n", PORTNAME(ap),
10671980eff3SMatthew Dillon 			ahci_pread(ap, AHCI_PREG_CMD), AHCI_PFMT_CMD);
1068074579dfSMatthew Dillon 	}
10691980eff3SMatthew Dillon 
1070258223a3SMatthew Dillon 	DPRINTF(AHCI_D_VERBOSE, "%s: soft reset\n", PORTNAME(ap));
1071258223a3SMatthew Dillon 
1072258223a3SMatthew Dillon 	crit_enter();
10731980eff3SMatthew Dillon 	ap->ap_flags |= AP_F_IN_RESET;
10741980eff3SMatthew Dillon 	ap->ap_state = AP_S_NORMAL;
1075258223a3SMatthew Dillon 
10761980eff3SMatthew Dillon 	/*
10771980eff3SMatthew Dillon 	 * Remember port state in cmd (main to restore start/stop)
10781980eff3SMatthew Dillon 	 *
10791980eff3SMatthew Dillon 	 * Idle port.
10801980eff3SMatthew Dillon 	 */
1081258223a3SMatthew Dillon 	if (ahci_port_stop(ap, 0)) {
1082258223a3SMatthew Dillon 		kprintf("%s: failed to stop port, cannot softreset\n",
1083258223a3SMatthew Dillon 			PORTNAME(ap));
1084258223a3SMatthew Dillon 		goto err;
1085258223a3SMatthew Dillon 	}
1086cf5f3a81SMatthew Dillon 
1087cf5f3a81SMatthew Dillon 	/*
10881980eff3SMatthew Dillon 	 * Request CLO if device appears hung.
1089cf5f3a81SMatthew Dillon 	 */
1090258223a3SMatthew Dillon 	if (ahci_pread(ap, AHCI_PREG_TFD) &
1091258223a3SMatthew Dillon 		   (AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) {
1092258223a3SMatthew Dillon 		ahci_port_clo(ap);
1093258223a3SMatthew Dillon 	}
1094258223a3SMatthew Dillon 
10951980eff3SMatthew Dillon 	/*
10961980eff3SMatthew Dillon 	 * This is an attempt to clear errors so a new signature will
10971980eff3SMatthew Dillon 	 * be latched.  It isn't working properly.  XXX
10981980eff3SMatthew Dillon 	 */
1099cf5f3a81SMatthew Dillon 	ahci_flush_tfd(ap);
11001980eff3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SERR, -1);
1101258223a3SMatthew Dillon 
1102258223a3SMatthew Dillon 	/* Restart port */
110317eab71eSMatthew Dillon 	if (ahci_port_start(ap)) {
1104258223a3SMatthew Dillon 		kprintf("%s: failed to start port, cannot softreset\n",
1105258223a3SMatthew Dillon 		        PORTNAME(ap));
1106258223a3SMatthew Dillon 		goto err;
1107258223a3SMatthew Dillon 	}
1108258223a3SMatthew Dillon 
1109258223a3SMatthew Dillon 	/* Check whether CLO worked */
1110258223a3SMatthew Dillon 	if (ahci_pwait_clr(ap, AHCI_PREG_TFD,
1111258223a3SMatthew Dillon 			       AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) {
1112258223a3SMatthew Dillon 		kprintf("%s: CLO %s, need port reset\n",
1113258223a3SMatthew Dillon 			PORTNAME(ap),
1114258223a3SMatthew Dillon 			(ahci_read(ap->ap_sc, AHCI_REG_CAP) & AHCI_REG_CAP_SCLO)
1115258223a3SMatthew Dillon 			? "failed" : "unsupported");
11163209f581SMatthew Dillon 		error = EBUSY;
1117258223a3SMatthew Dillon 		goto err;
1118258223a3SMatthew Dillon 	}
1119258223a3SMatthew Dillon 
1120cec85a37SMatthew Dillon 	/*
1121cec85a37SMatthew Dillon 	 * Prep first D2H command with SRST feature & clear busy/reset flags
1122cec85a37SMatthew Dillon 	 *
1123cec85a37SMatthew Dillon 	 * It is unclear which other fields in the FIS are used.  Just zero
1124cec85a37SMatthew Dillon 	 * everything.
11251067474aSMatthew Dillon 	 *
11261067474aSMatthew Dillon 	 * NOTE!  This CCB is used for both the first and second commands.
11271067474aSMatthew Dillon 	 *	  The second command must use CCB slot 1 to properly load
11281067474aSMatthew Dillon 	 *	  the signature.
1129cec85a37SMatthew Dillon 	 */
1130258223a3SMatthew Dillon 	ccb = ahci_get_err_ccb(ap);
113112feb904SMatthew Dillon 	ccb->ccb_xa.complete = ahci_dummy_done;
113212feb904SMatthew Dillon 	ccb->ccb_xa.flags = ATA_F_POLL | ATA_F_EXCLUSIVE;
11331067474aSMatthew Dillon 	KKASSERT(ccb->ccb_slot == 1);
11341980eff3SMatthew Dillon 	ccb->ccb_xa.at = NULL;
1135258223a3SMatthew Dillon 	cmd_slot = ccb->ccb_cmd_hdr;
1136258223a3SMatthew Dillon 
1137258223a3SMatthew Dillon 	fis = ccb->ccb_cmd_table->cfis;
1138cec85a37SMatthew Dillon 	bzero(fis, sizeof(ccb->ccb_cmd_table->cfis));
11391980eff3SMatthew Dillon 	fis[0] = ATA_FIS_TYPE_H2D;
11401980eff3SMatthew Dillon 	fis[15] = ATA_FIS_CONTROL_SRST|ATA_FIS_CONTROL_4BIT;
1141258223a3SMatthew Dillon 
1142258223a3SMatthew Dillon 	cmd_slot->prdtl = 0;
1143258223a3SMatthew Dillon 	cmd_slot->flags = htole16(5);	/* FIS length: 5 DWORDS */
1144258223a3SMatthew Dillon 	cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_C); /* Clear busy on OK */
1145258223a3SMatthew Dillon 	cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_R); /* Reset */
1146258223a3SMatthew Dillon 
1147258223a3SMatthew Dillon 	ccb->ccb_xa.state = ATA_S_PENDING;
114812feb904SMatthew Dillon 
1149831bc9e3SMatthew Dillon 	if (ahci_poll(ccb, 1000, ahci_quick_timeout) != ATA_S_COMPLETE) {
11505f8c1efdSMatthew Dillon 		kprintf("%s: First FIS failed\n", PORTNAME(ap));
1151258223a3SMatthew Dillon 		goto err;
1152cec85a37SMatthew Dillon 	}
1153258223a3SMatthew Dillon 
1154cec85a37SMatthew Dillon 	/*
1155831bc9e3SMatthew Dillon 	 * WARNING!	TIME SENSITIVE SPACE!	WARNING!
1156831bc9e3SMatthew Dillon 	 *
1157831bc9e3SMatthew Dillon 	 * The two FISes are supposed to be back to back.  Don't issue other
1158831bc9e3SMatthew Dillon 	 * commands or even delay if we can help it.
11591980eff3SMatthew Dillon 	 */
11601980eff3SMatthew Dillon 
11611980eff3SMatthew Dillon 	/*
1162cec85a37SMatthew Dillon 	 * Prep second D2H command to read status and complete reset sequence
1163cec85a37SMatthew Dillon 	 * AHCI 10.4.1 and "Serial ATA Revision 2.6".  I can't find the ATA
1164cec85a37SMatthew Dillon 	 * Rev 2.6 and it is unclear how the second FIS should be set up
1165cec85a37SMatthew Dillon 	 * from the AHCI document.
1166cec85a37SMatthew Dillon 	 *
1167b089d0bfSMatthew Dillon 	 * Give the device 3ms before sending the second FIS.
1168cec85a37SMatthew Dillon 	 *
1169cec85a37SMatthew Dillon 	 * It is unclear which other fields in the FIS are used.  Just zero
1170cec85a37SMatthew Dillon 	 * everything.
1171cec85a37SMatthew Dillon 	 */
117212feb904SMatthew Dillon 	ccb->ccb_xa.flags = ATA_F_POLL | ATA_F_AUTOSENSE | ATA_F_EXCLUSIVE;
117312feb904SMatthew Dillon 
1174cec85a37SMatthew Dillon 	bzero(fis, sizeof(ccb->ccb_cmd_table->cfis));
11751980eff3SMatthew Dillon 	fis[0] = ATA_FIS_TYPE_H2D;
11761980eff3SMatthew Dillon 	fis[15] = ATA_FIS_CONTROL_4BIT;
1177258223a3SMatthew Dillon 
1178258223a3SMatthew Dillon 	cmd_slot->prdtl = 0;
1179258223a3SMatthew Dillon 	cmd_slot->flags = htole16(5);	/* FIS length: 5 DWORDS */
1180258223a3SMatthew Dillon 
1181258223a3SMatthew Dillon 	ccb->ccb_xa.state = ATA_S_PENDING;
1182831bc9e3SMatthew Dillon 	if (ahci_poll(ccb, 1000, ahci_quick_timeout) != ATA_S_COMPLETE) {
11835f8c1efdSMatthew Dillon 		kprintf("%s: Second FIS failed\n", PORTNAME(ap));
1184258223a3SMatthew Dillon 		goto err;
1185cec85a37SMatthew Dillon 	}
1186258223a3SMatthew Dillon 
11871980eff3SMatthew Dillon 	if (ahci_pwait_clr(ap, AHCI_PREG_TFD,
11881980eff3SMatthew Dillon 			    AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) {
1189258223a3SMatthew Dillon 		kprintf("%s: device didn't come ready after reset, TFD: 0x%b\n",
1190258223a3SMatthew Dillon 			PORTNAME(ap),
1191258223a3SMatthew Dillon 			ahci_pread(ap, AHCI_PREG_TFD), AHCI_PFMT_TFD_STS);
11923209f581SMatthew Dillon 		error = EBUSY;
1193258223a3SMatthew Dillon 		goto err;
1194258223a3SMatthew Dillon 	}
11953209f581SMatthew Dillon 	ahci_os_sleep(10);
1196258223a3SMatthew Dillon 
1197fd8bd957SMatthew Dillon 	/*
1198fd8bd957SMatthew Dillon 	 * If the softreset is trying to clear a BSY condition after a
1199fd8bd957SMatthew Dillon 	 * normal portreset we assign the port type.
1200fd8bd957SMatthew Dillon 	 *
1201fd8bd957SMatthew Dillon 	 * If the softreset is being run first as part of the ccb error
1202fd8bd957SMatthew Dillon 	 * processing code then report if the device signature changed
1203fd8bd957SMatthew Dillon 	 * unexpectedly.
1204fd8bd957SMatthew Dillon 	 */
12051980eff3SMatthew Dillon 	if (ap->ap_type == ATA_PORT_T_NONE) {
12061980eff3SMatthew Dillon 		ap->ap_type = ahci_port_signature_detect(ap, NULL);
1207fd8bd957SMatthew Dillon 	} else {
12081980eff3SMatthew Dillon 		if (ahci_port_signature_detect(ap, NULL) != ap->ap_type) {
12091980eff3SMatthew Dillon 			kprintf("%s: device signature unexpectedly "
12101980eff3SMatthew Dillon 				"changed\n", PORTNAME(ap));
12113209f581SMatthew Dillon 			error = EBUSY; /* XXX */
1212fd8bd957SMatthew Dillon 		}
1213fd8bd957SMatthew Dillon 	}
12143209f581SMatthew Dillon 	error = 0;
12151980eff3SMatthew Dillon 
12163209f581SMatthew Dillon 	ahci_os_sleep(3);
1217258223a3SMatthew Dillon err:
1218258223a3SMatthew Dillon 	if (ccb != NULL) {
1219258223a3SMatthew Dillon 		ahci_put_err_ccb(ccb);
12201980eff3SMatthew Dillon 
12211980eff3SMatthew Dillon 		/*
12221980eff3SMatthew Dillon 		 * If the target is busy use CLO to clear the busy
12231980eff3SMatthew Dillon 		 * condition.  The BSY should be cleared on the next
12241980eff3SMatthew Dillon 		 * start.
12251980eff3SMatthew Dillon 		 */
12261980eff3SMatthew Dillon 		if (ahci_pread(ap, AHCI_PREG_TFD) &
12271980eff3SMatthew Dillon 		    (AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) {
12281980eff3SMatthew Dillon 			ahci_port_clo(ap);
12291980eff3SMatthew Dillon 		}
1230258223a3SMatthew Dillon 	}
1231258223a3SMatthew Dillon 
1232cf5f3a81SMatthew Dillon 	/*
1233cf5f3a81SMatthew Dillon 	 * If we failed to softreset make the port quiescent, otherwise
1234cf5f3a81SMatthew Dillon 	 * make sure the port's start/stop state matches what it was on
1235cf5f3a81SMatthew Dillon 	 * entry.
12361980eff3SMatthew Dillon 	 *
12371980eff3SMatthew Dillon 	 * Don't kill the port if the softreset is on a port multiplier
12381980eff3SMatthew Dillon 	 * target, that would kill all the targets!
1239cf5f3a81SMatthew Dillon 	 */
12403209f581SMatthew Dillon 	if (error) {
1241cf5f3a81SMatthew Dillon 		ahci_port_hardstop(ap);
12423209f581SMatthew Dillon 		/* ap_probe set to failed */
1243cf5f3a81SMatthew Dillon 	} else {
12443209f581SMatthew Dillon 		ap->ap_probe = ATA_PROBE_NEED_IDENT;
124512feb904SMatthew Dillon 		ap->ap_pmcount = 1;
12464c339a5fSMatthew Dillon 		ahci_port_start(ap);
1247cf5f3a81SMatthew Dillon 	}
12483209f581SMatthew Dillon 	ap->ap_flags &= ~AP_F_IN_RESET;
1249258223a3SMatthew Dillon 	crit_exit();
1250258223a3SMatthew Dillon 
1251074579dfSMatthew Dillon 	if (bootverbose)
12521980eff3SMatthew Dillon 		kprintf("%s: END SOFTRESET\n", PORTNAME(ap));
12531980eff3SMatthew Dillon 
12543209f581SMatthew Dillon 	return (error);
1255258223a3SMatthew Dillon }
1256258223a3SMatthew Dillon 
1257fd8bd957SMatthew Dillon /*
1258fd8bd957SMatthew Dillon  * AHCI port reset, Section 10.4.2
1259fd8bd957SMatthew Dillon  *
1260fd8bd957SMatthew Dillon  * This function does a hard reset of the port.  Note that the device
1261fd8bd957SMatthew Dillon  * connected to the port could still end-up hung.
1262fd8bd957SMatthew Dillon  */
1263258223a3SMatthew Dillon int
12641980eff3SMatthew Dillon ahci_port_hardreset(struct ahci_port *ap, int hard)
1265258223a3SMatthew Dillon {
1266258223a3SMatthew Dillon 	u_int32_t cmd, r;
126712feb904SMatthew Dillon 	u_int32_t data;
12683209f581SMatthew Dillon 	int	error;
12691980eff3SMatthew Dillon 	int	loop;
1270258223a3SMatthew Dillon 
127112feb904SMatthew Dillon 	if (bootverbose)
127212feb904SMatthew Dillon 		kprintf("%s: START HARDRESET\n", PORTNAME(ap));
12731980eff3SMatthew Dillon 	ap->ap_flags |= AP_F_IN_RESET;
1274cf5f3a81SMatthew Dillon 
1275cf5f3a81SMatthew Dillon 	/*
12761980eff3SMatthew Dillon 	 * Idle the port,
12771980eff3SMatthew Dillon 	 */
12781980eff3SMatthew Dillon 	ahci_port_stop(ap, 0);
12791980eff3SMatthew Dillon 	ap->ap_state = AP_S_NORMAL;
12801980eff3SMatthew Dillon 
12811980eff3SMatthew Dillon 	/*
12821980eff3SMatthew Dillon 	 * The port may have been quiescent with its SUD bit cleared, so
12831980eff3SMatthew Dillon 	 * set the SUD (spin up device).
1284cf5f3a81SMatthew Dillon 	 */
1285cf5f3a81SMatthew Dillon 	cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC;
1286cf5f3a81SMatthew Dillon 	cmd |= AHCI_PREG_CMD_SUD;
1287cf5f3a81SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_CMD, cmd);
1288258223a3SMatthew Dillon 
12891980eff3SMatthew Dillon 	/*
12904e21f4daSMatthew Dillon 	 * Perform device detection.
12911067474aSMatthew Dillon 	 *
12924e21f4daSMatthew Dillon 	 * NOTE!  AHCi_PREG_SCTL_DET_DISABLE seems to be highly unreliable
12934e21f4daSMatthew Dillon 	 *	  on multiple chipsets and can brick the chipset or even
12944e21f4daSMatthew Dillon 	 *	  the whole PC.  Never use it.
12951980eff3SMatthew Dillon 	 */
12961980eff3SMatthew Dillon 	ap->ap_type = ATA_PORT_T_NONE;
1297258223a3SMatthew Dillon 
12981980eff3SMatthew Dillon 	r = AHCI_PREG_SCTL_IPM_DISABLED;
12991980eff3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SCTL, r);
13003209f581SMatthew Dillon 	ahci_os_sleep(10);
13011980eff3SMatthew Dillon 
13021980eff3SMatthew Dillon 	/*
13031980eff3SMatthew Dillon 	 * Start transmitting COMRESET.  COMRESET must be sent for at
13041980eff3SMatthew Dillon 	 * least 1ms.
13051980eff3SMatthew Dillon 	 */
13061980eff3SMatthew Dillon 	r = AHCI_PREG_SCTL_IPM_DISABLED | AHCI_PREG_SCTL_DET_INIT;
1307074579dfSMatthew Dillon 	if (AhciForceGen1 & (1 << ap->ap_num))
1308258223a3SMatthew Dillon 		r |= AHCI_PREG_SCTL_SPD_GEN1;
1309074579dfSMatthew Dillon 	else
1310258223a3SMatthew Dillon 		r |= AHCI_PREG_SCTL_SPD_ANY;
1311258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SCTL, r);
1312831bc9e3SMatthew Dillon 
1313831bc9e3SMatthew Dillon 	/*
1314831bc9e3SMatthew Dillon 	 * Through trial and error it seems to take around 100ms
1315831bc9e3SMatthew Dillon 	 * for the detect logic to settle down.  If this is too
1316831bc9e3SMatthew Dillon 	 * short the softreset code will fail.
1317831bc9e3SMatthew Dillon 	 */
1318831bc9e3SMatthew Dillon 	ahci_os_sleep(100);
1319cf5f3a81SMatthew Dillon 
1320cf5f3a81SMatthew Dillon 	/*
1321cf5f3a81SMatthew Dillon 	 * Only SERR_DIAG_X needs to be cleared for TFD updates, but
1322cf5f3a81SMatthew Dillon 	 * since we are hard-resetting the port we might as well clear
1323cf5f3a81SMatthew Dillon 	 * the whole enchillada
1324cf5f3a81SMatthew Dillon 	 */
1325cf5f3a81SMatthew Dillon 	ahci_flush_tfd(ap);
1326cf5f3a81SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SERR, -1);
1327258223a3SMatthew Dillon 	r &= ~AHCI_PREG_SCTL_DET_INIT;
1328258223a3SMatthew Dillon 	r |= AHCI_PREG_SCTL_DET_NONE;
1329258223a3SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SCTL, r);
1330258223a3SMatthew Dillon 
13311980eff3SMatthew Dillon 	/*
13321980eff3SMatthew Dillon 	 * Try to determine if there is a device on the port.
13331980eff3SMatthew Dillon 	 *
13341980eff3SMatthew Dillon 	 * Give the device 3/10 second to at least be detected.
13351980eff3SMatthew Dillon 	 * If we fail clear PRCS (phy detect) since we may cycled
13361980eff3SMatthew Dillon 	 * the phy and probably caused another PRCS interrupt.
13371980eff3SMatthew Dillon 	 */
133876497a9cSMatthew Dillon 	loop = 300;
133976497a9cSMatthew Dillon 	while (loop > 0) {
13401980eff3SMatthew Dillon 		r = ahci_pread(ap, AHCI_PREG_SSTS);
13411980eff3SMatthew Dillon 		if (r & AHCI_PREG_SSTS_DET)
13421980eff3SMatthew Dillon 			break;
134376497a9cSMatthew Dillon 		loop -= ahci_os_softsleep();
13441980eff3SMatthew Dillon 	}
13451980eff3SMatthew Dillon 	if (loop == 0) {
13461980eff3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_PRCS);
1347074579dfSMatthew Dillon 		if (bootverbose) {
13481980eff3SMatthew Dillon 			kprintf("%s: Port appears to be unplugged\n",
13491980eff3SMatthew Dillon 				PORTNAME(ap));
1350074579dfSMatthew Dillon 		}
13513209f581SMatthew Dillon 		error = ENODEV;
135212feb904SMatthew Dillon 		goto done;
1353258223a3SMatthew Dillon 	}
1354258223a3SMatthew Dillon 
1355cec85a37SMatthew Dillon 	/*
13561980eff3SMatthew Dillon 	 * There is something on the port.  Give the device 3 seconds
13571980eff3SMatthew Dillon 	 * to fully negotiate.
13581980eff3SMatthew Dillon 	 */
135912feb904SMatthew Dillon 	if (ahci_pwait_eq(ap, 3000, AHCI_PREG_SSTS,
13601980eff3SMatthew Dillon 			  AHCI_PREG_SSTS_DET, AHCI_PREG_SSTS_DET_DEV)) {
1361074579dfSMatthew Dillon 		if (bootverbose) {
13621980eff3SMatthew Dillon 			kprintf("%s: Device may be powered down\n",
13631980eff3SMatthew Dillon 				PORTNAME(ap));
1364074579dfSMatthew Dillon 		}
13653209f581SMatthew Dillon 		error = ENODEV;
136612feb904SMatthew Dillon 		goto pmdetect;
13671980eff3SMatthew Dillon 	}
13681980eff3SMatthew Dillon 
136912feb904SMatthew Dillon 	/*
137012feb904SMatthew Dillon 	 * We got something that definitely looks like a device.  Give
137112feb904SMatthew Dillon 	 * the device time to send us its first D2H FIS.  Waiting for
137212feb904SMatthew Dillon 	 * BSY to clear accomplishes this.
137312feb904SMatthew Dillon 	 *
137412feb904SMatthew Dillon 	 * NOTE that a port multiplier may or may not clear BSY here,
137512feb904SMatthew Dillon 	 * depending on what is sitting in target 0 behind it.
137612feb904SMatthew Dillon 	 */
1377c408a8b3SMatthew Dillon 	ahci_flush_tfd(ap);
1378c408a8b3SMatthew Dillon 
137912feb904SMatthew Dillon 	if (ahci_pwait_clr_to(ap, 3000, AHCI_PREG_TFD,
13801980eff3SMatthew Dillon 			    AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) {
138112feb904SMatthew Dillon 		error = EBUSY;
13821980eff3SMatthew Dillon 	} else {
13833209f581SMatthew Dillon 		error = 0;
13841980eff3SMatthew Dillon 	}
1385258223a3SMatthew Dillon 
138612feb904SMatthew Dillon pmdetect:
1387cf5f3a81SMatthew Dillon 	/*
138812feb904SMatthew Dillon 	 * Do the PM port probe regardless of how things turned out on
138912feb904SMatthew Dillon 	 * the BSY check.
1390cf5f3a81SMatthew Dillon 	 */
139112feb904SMatthew Dillon 	if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SPM)
139212feb904SMatthew Dillon 		error = ahci_pm_port_probe(ap, error);
139312feb904SMatthew Dillon 
139412feb904SMatthew Dillon done:
139512feb904SMatthew Dillon 	/*
139612feb904SMatthew Dillon 	 * Finish up.
139712feb904SMatthew Dillon 	 */
139812feb904SMatthew Dillon 	switch(error) {
139912feb904SMatthew Dillon 	case 0:
140012feb904SMatthew Dillon 		/*
140112feb904SMatthew Dillon 		 * All good, make sure the port is running and set the
140212feb904SMatthew Dillon 		 * probe state.  Ignore the signature junk (it's unreliable)
140312feb904SMatthew Dillon 		 * until we get to the softreset code.
140412feb904SMatthew Dillon 		 */
140512feb904SMatthew Dillon 		if (ahci_port_start(ap)) {
140612feb904SMatthew Dillon 			kprintf("%s: failed to start command DMA on port, "
140712feb904SMatthew Dillon 			        "disabling\n", PORTNAME(ap));
140812feb904SMatthew Dillon 			error = EBUSY;
140912feb904SMatthew Dillon 			goto done;
141012feb904SMatthew Dillon 		}
1411f4553de1SMatthew Dillon 		if (ap->ap_type == ATA_PORT_T_PM)
1412f4553de1SMatthew Dillon 			ap->ap_probe = ATA_PROBE_GOOD;
1413f4553de1SMatthew Dillon 		else
1414f4553de1SMatthew Dillon 			ap->ap_probe = ATA_PROBE_NEED_SOFT_RESET;
141512feb904SMatthew Dillon 		break;
141612feb904SMatthew Dillon 	case ENODEV:
1417fd8bd957SMatthew Dillon 		/*
141812feb904SMatthew Dillon 		 * Normal device probe failure
14191980eff3SMatthew Dillon 		 */
142012feb904SMatthew Dillon 		data = ahci_pread(ap, AHCI_PREG_SSTS);
14211980eff3SMatthew Dillon 
142212feb904SMatthew Dillon 		switch(data & AHCI_PREG_SSTS_DET) {
142312feb904SMatthew Dillon 		case AHCI_PREG_SSTS_DET_DEV_NE:
142412feb904SMatthew Dillon 			kprintf("%s: Device not communicating\n",
14251980eff3SMatthew Dillon 				PORTNAME(ap));
142612feb904SMatthew Dillon 			break;
142712feb904SMatthew Dillon 		case AHCI_PREG_SSTS_DET_PHYOFFLINE:
142812feb904SMatthew Dillon 			kprintf("%s: PHY offline\n",
142912feb904SMatthew Dillon 				PORTNAME(ap));
143012feb904SMatthew Dillon 			break;
143112feb904SMatthew Dillon 		default:
143212feb904SMatthew Dillon 			kprintf("%s: No device detected\n",
143312feb904SMatthew Dillon 				PORTNAME(ap));
143412feb904SMatthew Dillon 			break;
14351980eff3SMatthew Dillon 		}
143612feb904SMatthew Dillon 		ahci_port_hardstop(ap);
143712feb904SMatthew Dillon 		break;
143812feb904SMatthew Dillon 	default:
14391980eff3SMatthew Dillon 		/*
144012feb904SMatthew Dillon 		 * Abnormal probe (EBUSY)
14411980eff3SMatthew Dillon 		 */
144212feb904SMatthew Dillon 		kprintf("%s: Device on port is bricked\n",
144312feb904SMatthew Dillon 			PORTNAME(ap));
144412feb904SMatthew Dillon 		ahci_port_hardstop(ap);
144512feb904SMatthew Dillon #if 0
144612feb904SMatthew Dillon 		rc = ahci_port_reset(ap, atx, 0);
144712feb904SMatthew Dillon 		if (rc) {
144812feb904SMatthew Dillon 			kprintf("%s: Unable unbrick device\n",
144912feb904SMatthew Dillon 				PORTNAME(ap));
14501980eff3SMatthew Dillon 		} else {
145112feb904SMatthew Dillon 			kprintf("%s: Successfully unbricked\n",
14523209f581SMatthew Dillon 				PORTNAME(ap));
145312feb904SMatthew Dillon 		}
145412feb904SMatthew Dillon #endif
145512feb904SMatthew Dillon 		break;
14563209f581SMatthew Dillon 	}
14571067474aSMatthew Dillon 
14581067474aSMatthew Dillon 	/*
145912feb904SMatthew Dillon 	 * Clean up
14601067474aSMatthew Dillon 	 */
146112feb904SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SERR, -1);
146212feb904SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_PCS | AHCI_PREG_IS_PRCS);
14633209f581SMatthew Dillon 
146412feb904SMatthew Dillon 	ap->ap_flags &= ~AP_F_IN_RESET;
14651980eff3SMatthew Dillon 
146612feb904SMatthew Dillon 	if (bootverbose)
146712feb904SMatthew Dillon 		kprintf("%s: END HARDRESET %d\n", PORTNAME(ap), error);
1468831bc9e3SMatthew Dillon 	return (error);
14691980eff3SMatthew Dillon }
14701980eff3SMatthew Dillon 
14711980eff3SMatthew Dillon /*
1472cf5f3a81SMatthew Dillon  * Hard-stop on hot-swap device removal.  See 10.10.1
1473cf5f3a81SMatthew Dillon  *
1474cf5f3a81SMatthew Dillon  * Place the port in a mode that will allow it to detect hot-swap insertions.
1475cf5f3a81SMatthew Dillon  * This is a bit imprecise because just setting-up SCTL to DET_INIT doesn't
1476cf5f3a81SMatthew Dillon  * seem to do the job.
1477f17a0cedSMatthew Dillon  *
1478f17a0cedSMatthew Dillon  * FIS reception is left enabled but command processing is disabled.
1479f17a0cedSMatthew Dillon  * Cycling FIS reception (FRE) can brick ports.
1480cf5f3a81SMatthew Dillon  */
1481cf5f3a81SMatthew Dillon void
1482cf5f3a81SMatthew Dillon ahci_port_hardstop(struct ahci_port *ap)
1483cf5f3a81SMatthew Dillon {
148476497a9cSMatthew Dillon 	struct ahci_ccb *ccb;
14851980eff3SMatthew Dillon 	struct ata_port *at;
1486cf5f3a81SMatthew Dillon 	u_int32_t r;
1487cf5f3a81SMatthew Dillon 	u_int32_t cmd;
148876497a9cSMatthew Dillon 	int slot;
14891980eff3SMatthew Dillon 	int i;
1490cf5f3a81SMatthew Dillon 
1491cf5f3a81SMatthew Dillon 	/*
1492cf5f3a81SMatthew Dillon 	 * Stop the port.  We can't modify things like SUD if the port
1493cf5f3a81SMatthew Dillon 	 * is running.
1494cf5f3a81SMatthew Dillon 	 */
1495cf5f3a81SMatthew Dillon 	ap->ap_state = AP_S_FATAL_ERROR;
14961980eff3SMatthew Dillon 	ap->ap_probe = ATA_PROBE_FAILED;
14971980eff3SMatthew Dillon 	ap->ap_type = ATA_PORT_T_NONE;
1498cf5f3a81SMatthew Dillon 	ahci_port_stop(ap, 0);
1499cf5f3a81SMatthew Dillon 	cmd = ahci_pread(ap, AHCI_PREG_CMD);
1500cf5f3a81SMatthew Dillon 
1501cf5f3a81SMatthew Dillon 	/*
15021980eff3SMatthew Dillon 	 * Clean up AT sub-ports on SATA port.
15031980eff3SMatthew Dillon 	 */
15041980eff3SMatthew Dillon 	for (i = 0; ap->ap_ata && i < AHCI_MAX_PMPORTS; ++i) {
1505b012a2caSMatthew Dillon 		at = ap->ap_ata[i];
15061980eff3SMatthew Dillon 		at->at_type = ATA_PORT_T_NONE;
15073209f581SMatthew Dillon 		at->at_probe = ATA_PROBE_FAILED;
15081980eff3SMatthew Dillon 	}
15091980eff3SMatthew Dillon 
15101980eff3SMatthew Dillon 	/*
15111980eff3SMatthew Dillon 	 * Turn off port-multiplier control bit
15121980eff3SMatthew Dillon 	 */
15131980eff3SMatthew Dillon 	if (cmd & AHCI_PREG_CMD_PMA) {
15141980eff3SMatthew Dillon 		cmd &= ~AHCI_PREG_CMD_PMA;
15151980eff3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CMD, cmd);
15161980eff3SMatthew Dillon 	}
15171980eff3SMatthew Dillon 
15181980eff3SMatthew Dillon 	/*
1519cf5f3a81SMatthew Dillon 	 * Make sure FRE is active.  There isn't anything we can do if it
1520cf5f3a81SMatthew Dillon 	 * fails so just ignore errors.
1521cf5f3a81SMatthew Dillon 	 */
1522cf5f3a81SMatthew Dillon 	if ((cmd & AHCI_PREG_CMD_FRE) == 0) {
1523cf5f3a81SMatthew Dillon 		cmd |= AHCI_PREG_CMD_FRE;
1524cf5f3a81SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CMD, cmd);
1525cf5f3a81SMatthew Dillon 		if ((ap->ap_sc->sc_flags & AHCI_F_IGN_FR) == 0)
1526cf5f3a81SMatthew Dillon 			ahci_pwait_set(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_FR);
1527cf5f3a81SMatthew Dillon 	}
1528cf5f3a81SMatthew Dillon 
1529cf5f3a81SMatthew Dillon 	/*
1530cf5f3a81SMatthew Dillon 	 * 10.10.3 DET must be set to 0 before setting SUD to 0.
1531cf5f3a81SMatthew Dillon 	 * 10.10.1 place us in the Listen state.
1532cf5f3a81SMatthew Dillon 	 *
1533cf5f3a81SMatthew Dillon 	 * Deactivating SUD only applies if the controller supports SUD.
1534cf5f3a81SMatthew Dillon 	 */
1535cf5f3a81SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SCTL, AHCI_PREG_SCTL_IPM_DISABLED);
15363209f581SMatthew Dillon 	ahci_os_sleep(1);
1537cf5f3a81SMatthew Dillon 	if (cmd & AHCI_PREG_CMD_SUD) {
1538cf5f3a81SMatthew Dillon 		cmd &= ~AHCI_PREG_CMD_SUD;
1539cf5f3a81SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CMD, cmd);
1540cf5f3a81SMatthew Dillon 	}
15413209f581SMatthew Dillon 	ahci_os_sleep(1);
1542cf5f3a81SMatthew Dillon 
1543cf5f3a81SMatthew Dillon 	/*
1544cf5f3a81SMatthew Dillon 	 * Transition su to the spin-up state.  HVA shall send COMRESET and
1545cf5f3a81SMatthew Dillon 	 * begin initialization sequence (whatever that means).
1546cf5f3a81SMatthew Dillon 	 *
1547cf5f3a81SMatthew Dillon 	 * This only applies if the controller supports SUD.
15484e21f4daSMatthew Dillon 	 * NEVER use AHCI_PREG_DET_DISABLE.
1549cf5f3a81SMatthew Dillon 	 */
1550cf5f3a81SMatthew Dillon 	cmd |= AHCI_PREG_CMD_SUD;
1551cf5f3a81SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_CMD, cmd);
15523209f581SMatthew Dillon 	ahci_os_sleep(1);
1553cf5f3a81SMatthew Dillon 
1554cf5f3a81SMatthew Dillon 	/*
1555cf5f3a81SMatthew Dillon 	 * Transition us to the Reset state.  Theoretically we send a
1556cf5f3a81SMatthew Dillon 	 * continuous stream of COMRESETs in this state.
1557cf5f3a81SMatthew Dillon 	 */
1558cf5f3a81SMatthew Dillon 	r = AHCI_PREG_SCTL_IPM_DISABLED | AHCI_PREG_SCTL_DET_INIT;
1559cf5f3a81SMatthew Dillon 	if (AhciForceGen1 & (1 << ap->ap_num)) {
1560cf5f3a81SMatthew Dillon 		kprintf("%s: Force 1.5Gbits\n", PORTNAME(ap));
1561cf5f3a81SMatthew Dillon 		r |= AHCI_PREG_SCTL_SPD_GEN1;
1562cf5f3a81SMatthew Dillon 	} else {
1563cf5f3a81SMatthew Dillon 		r |= AHCI_PREG_SCTL_SPD_ANY;
1564cf5f3a81SMatthew Dillon 	}
1565cf5f3a81SMatthew Dillon 	ahci_pwrite(ap, AHCI_PREG_SCTL, r);
15663209f581SMatthew Dillon 	ahci_os_sleep(1);
1567cf5f3a81SMatthew Dillon 
1568cf5f3a81SMatthew Dillon 	/*
1569cf5f3a81SMatthew Dillon 	 * Flush SERR_DIAG_X so the TFD can update.
1570cf5f3a81SMatthew Dillon 	 */
1571cf5f3a81SMatthew Dillon 	ahci_flush_tfd(ap);
1572cf5f3a81SMatthew Dillon 
1573cf5f3a81SMatthew Dillon 	/*
157476497a9cSMatthew Dillon 	 * Clean out pending ccbs
157576497a9cSMatthew Dillon 	 */
157676497a9cSMatthew Dillon 	while (ap->ap_active) {
157776497a9cSMatthew Dillon 		slot = ffs(ap->ap_active) - 1;
157876497a9cSMatthew Dillon 		ap->ap_active &= ~(1 << slot);
157976497a9cSMatthew Dillon 		ap->ap_expired &= ~(1 << slot);
158076497a9cSMatthew Dillon 		--ap->ap_active_cnt;
158176497a9cSMatthew Dillon 		ccb = &ap->ap_ccbs[slot];
158276497a9cSMatthew Dillon 		if (ccb->ccb_xa.flags & ATA_F_TIMEOUT_RUNNING) {
158376497a9cSMatthew Dillon 			callout_stop(&ccb->ccb_timeout);
158476497a9cSMatthew Dillon 			ccb->ccb_xa.flags &= ~ATA_F_TIMEOUT_RUNNING;
158576497a9cSMatthew Dillon 		}
158676497a9cSMatthew Dillon 		ccb->ccb_xa.flags &= ~(ATA_F_TIMEOUT_DESIRED |
158776497a9cSMatthew Dillon 				       ATA_F_TIMEOUT_EXPIRED);
158876497a9cSMatthew Dillon 		ccb->ccb_xa.state = ATA_S_TIMEOUT;
158976497a9cSMatthew Dillon 		ccb->ccb_done(ccb);
159076497a9cSMatthew Dillon 		ccb->ccb_xa.complete(&ccb->ccb_xa);
159176497a9cSMatthew Dillon 	}
159276497a9cSMatthew Dillon 	while (ap->ap_sactive) {
159376497a9cSMatthew Dillon 		slot = ffs(ap->ap_sactive) - 1;
159476497a9cSMatthew Dillon 		ap->ap_sactive &= ~(1 << slot);
159576497a9cSMatthew Dillon 		ap->ap_expired &= ~(1 << slot);
159676497a9cSMatthew Dillon 		ccb = &ap->ap_ccbs[slot];
159776497a9cSMatthew Dillon 		if (ccb->ccb_xa.flags & ATA_F_TIMEOUT_RUNNING) {
159876497a9cSMatthew Dillon 			callout_stop(&ccb->ccb_timeout);
159976497a9cSMatthew Dillon 			ccb->ccb_xa.flags &= ~ATA_F_TIMEOUT_RUNNING;
160076497a9cSMatthew Dillon 		}
160176497a9cSMatthew Dillon 		ccb->ccb_xa.flags &= ~(ATA_F_TIMEOUT_DESIRED |
160276497a9cSMatthew Dillon 				       ATA_F_TIMEOUT_EXPIRED);
160376497a9cSMatthew Dillon 		ccb->ccb_xa.state = ATA_S_TIMEOUT;
160476497a9cSMatthew Dillon 		ccb->ccb_done(ccb);
160576497a9cSMatthew Dillon 		ccb->ccb_xa.complete(&ccb->ccb_xa);
160676497a9cSMatthew Dillon 	}
160776497a9cSMatthew Dillon 	KKASSERT(ap->ap_active_cnt == 0);
160876497a9cSMatthew Dillon 
160976497a9cSMatthew Dillon 	while ((ccb = TAILQ_FIRST(&ap->ap_ccb_pending)) != NULL) {
161076497a9cSMatthew Dillon 		TAILQ_REMOVE(&ap->ap_ccb_pending, ccb, ccb_entry);
161176497a9cSMatthew Dillon 		ccb->ccb_xa.state = ATA_S_TIMEOUT;
161276497a9cSMatthew Dillon 		ccb->ccb_xa.flags &= ~ATA_F_TIMEOUT_DESIRED;
161376497a9cSMatthew Dillon 		ccb->ccb_done(ccb);
161476497a9cSMatthew Dillon 		ccb->ccb_xa.complete(&ccb->ccb_xa);
161576497a9cSMatthew Dillon 	}
161676497a9cSMatthew Dillon 
161776497a9cSMatthew Dillon 	/*
1618cf5f3a81SMatthew Dillon 	 * Leave us in COMRESET (both SUD and INIT active), the HBA should
1619cf5f3a81SMatthew Dillon 	 * hopefully send us a DIAG_X-related interrupt if it receives
1620cf5f3a81SMatthew Dillon 	 * a COMINIT, and if not that then at least a Phy transition
1621cf5f3a81SMatthew Dillon 	 * interrupt.
1622cf5f3a81SMatthew Dillon 	 *
1623cf5f3a81SMatthew Dillon 	 * If we transition INIT from 1->0 to begin the initalization
1624cf5f3a81SMatthew Dillon 	 * sequence it is unclear if that sequence will remain active
1625cf5f3a81SMatthew Dillon 	 * until the next device insertion.
1626cf5f3a81SMatthew Dillon 	 *
1627cf5f3a81SMatthew Dillon 	 * If we go back to the listen state it is unclear if the
1628cf5f3a81SMatthew Dillon 	 * device will actually send us a COMINIT, since we aren't
1629cf5f3a81SMatthew Dillon 	 * sending any COMRESET's
1630cf5f3a81SMatthew Dillon 	 */
1631cf5f3a81SMatthew Dillon 	/* NOP */
1632cf5f3a81SMatthew Dillon }
1633cf5f3a81SMatthew Dillon 
1634cf5f3a81SMatthew Dillon /*
1635c408a8b3SMatthew Dillon  * We can't loop on the X bit, a continuous COMINIT received will make
1636c408a8b3SMatthew Dillon  * it loop forever.  Just assume one event has built up and clear X
1637c408a8b3SMatthew Dillon  * so the task file descriptor can update.
1638cf5f3a81SMatthew Dillon  */
1639cf5f3a81SMatthew Dillon void
1640cf5f3a81SMatthew Dillon ahci_flush_tfd(struct ahci_port *ap)
1641cf5f3a81SMatthew Dillon {
1642cf5f3a81SMatthew Dillon 	u_int32_t r;
1643cf5f3a81SMatthew Dillon 
1644cf5f3a81SMatthew Dillon 	r = ahci_pread(ap, AHCI_PREG_SERR);
1645c408a8b3SMatthew Dillon 	if (r & AHCI_PREG_SERR_DIAG_X)
16461980eff3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SERR, AHCI_PREG_SERR_DIAG_X);
1647cf5f3a81SMatthew Dillon }
1648cf5f3a81SMatthew Dillon 
1649cf5f3a81SMatthew Dillon /*
1650fd8bd957SMatthew Dillon  * Figure out what type of device is connected to the port, ATAPI or
1651fd8bd957SMatthew Dillon  * DISK.
1652fd8bd957SMatthew Dillon  */
1653fd8bd957SMatthew Dillon int
16541980eff3SMatthew Dillon ahci_port_signature_detect(struct ahci_port *ap, struct ata_port *at)
1655fd8bd957SMatthew Dillon {
1656fd8bd957SMatthew Dillon 	u_int32_t sig;
1657fd8bd957SMatthew Dillon 
1658fd8bd957SMatthew Dillon 	sig = ahci_pread(ap, AHCI_PREG_SIG);
1659074579dfSMatthew Dillon 	if (bootverbose)
16601980eff3SMatthew Dillon 		kprintf("%s: sig %08x\n", ATANAME(ap, at), sig);
1661fd8bd957SMatthew Dillon 	if ((sig & 0xffff0000) == (SATA_SIGNATURE_ATAPI & 0xffff0000)) {
1662fd8bd957SMatthew Dillon 		return(ATA_PORT_T_ATAPI);
16631980eff3SMatthew Dillon 	} else if ((sig & 0xffff0000) ==
16641980eff3SMatthew Dillon 		 (SATA_SIGNATURE_PORT_MULTIPLIER & 0xffff0000)) {
16651980eff3SMatthew Dillon 		return(ATA_PORT_T_PM);
1666fd8bd957SMatthew Dillon 	} else {
1667fd8bd957SMatthew Dillon 		return(ATA_PORT_T_DISK);
1668fd8bd957SMatthew Dillon 	}
1669fd8bd957SMatthew Dillon }
1670fd8bd957SMatthew Dillon 
1671fd8bd957SMatthew Dillon /*
1672fd8bd957SMatthew Dillon  * Load the DMA descriptor table for a CCB's buffer.
1673fd8bd957SMatthew Dillon  */
1674258223a3SMatthew Dillon int
1675258223a3SMatthew Dillon ahci_load_prdt(struct ahci_ccb *ccb)
1676258223a3SMatthew Dillon {
1677258223a3SMatthew Dillon 	struct ahci_port		*ap = ccb->ccb_port;
1678258223a3SMatthew Dillon 	struct ahci_softc		*sc = ap->ap_sc;
1679258223a3SMatthew Dillon 	struct ata_xfer			*xa = &ccb->ccb_xa;
1680258223a3SMatthew Dillon 	struct ahci_prdt		*prdt = ccb->ccb_cmd_table->prdt;
1681258223a3SMatthew Dillon 	bus_dmamap_t			dmap = ccb->ccb_dmamap;
1682258223a3SMatthew Dillon 	struct ahci_cmd_hdr		*cmd_slot = ccb->ccb_cmd_hdr;
1683258223a3SMatthew Dillon 	int				error;
1684258223a3SMatthew Dillon 
1685258223a3SMatthew Dillon 	if (xa->datalen == 0) {
1686258223a3SMatthew Dillon 		ccb->ccb_cmd_hdr->prdtl = 0;
1687258223a3SMatthew Dillon 		return (0);
1688258223a3SMatthew Dillon 	}
1689258223a3SMatthew Dillon 
1690258223a3SMatthew Dillon 	error = bus_dmamap_load(sc->sc_tag_data, dmap,
1691258223a3SMatthew Dillon 				xa->data, xa->datalen,
1692258223a3SMatthew Dillon 				ahci_load_prdt_callback,
1693258223a3SMatthew Dillon 				&prdt,
1694258223a3SMatthew Dillon 				((xa->flags & ATA_F_NOWAIT) ?
1695258223a3SMatthew Dillon 				    BUS_DMA_NOWAIT : BUS_DMA_WAITOK));
1696258223a3SMatthew Dillon 	if (error != 0) {
1697258223a3SMatthew Dillon 		kprintf("%s: error %d loading dmamap\n", PORTNAME(ap), error);
1698258223a3SMatthew Dillon 		return (1);
1699258223a3SMatthew Dillon 	}
170012feb904SMatthew Dillon #if 0
1701258223a3SMatthew Dillon 	if (xa->flags & ATA_F_PIO)
1702258223a3SMatthew Dillon 		prdt->flags |= htole32(AHCI_PRDT_FLAG_INTR);
170312feb904SMatthew Dillon #endif
1704258223a3SMatthew Dillon 
1705258223a3SMatthew Dillon 	cmd_slot->prdtl = htole16(prdt - ccb->ccb_cmd_table->prdt + 1);
1706258223a3SMatthew Dillon 
1707b012a2caSMatthew Dillon 	if (xa->flags & ATA_F_READ)
1708b012a2caSMatthew Dillon 		bus_dmamap_sync(sc->sc_tag_data, dmap, BUS_DMASYNC_PREREAD);
1709b012a2caSMatthew Dillon 	if (xa->flags & ATA_F_WRITE)
1710b012a2caSMatthew Dillon 		bus_dmamap_sync(sc->sc_tag_data, dmap, BUS_DMASYNC_PREWRITE);
1711258223a3SMatthew Dillon 
1712258223a3SMatthew Dillon 	return (0);
1713258223a3SMatthew Dillon }
1714258223a3SMatthew Dillon 
1715258223a3SMatthew Dillon /*
1716258223a3SMatthew Dillon  * Callback from BUSDMA system to load the segment list.  The passed segment
1717258223a3SMatthew Dillon  * list is a temporary structure.
1718258223a3SMatthew Dillon  */
1719258223a3SMatthew Dillon static
1720258223a3SMatthew Dillon void
1721258223a3SMatthew Dillon ahci_load_prdt_callback(void *info, bus_dma_segment_t *segs, int nsegs,
1722258223a3SMatthew Dillon 			int error)
1723258223a3SMatthew Dillon {
1724258223a3SMatthew Dillon 	struct ahci_prdt *prd = *(void **)info;
1725258223a3SMatthew Dillon 	u_int64_t addr;
1726258223a3SMatthew Dillon 
1727258223a3SMatthew Dillon 	KKASSERT(nsegs <= AHCI_MAX_PRDT);
1728258223a3SMatthew Dillon 
1729258223a3SMatthew Dillon 	while (nsegs) {
1730258223a3SMatthew Dillon 		addr = segs->ds_addr;
1731258223a3SMatthew Dillon 		prd->dba_hi = htole32((u_int32_t)(addr >> 32));
1732258223a3SMatthew Dillon 		prd->dba_lo = htole32((u_int32_t)addr);
1733258223a3SMatthew Dillon 		prd->flags = htole32(segs->ds_len - 1);
1734258223a3SMatthew Dillon 		--nsegs;
1735258223a3SMatthew Dillon 		if (nsegs)
1736258223a3SMatthew Dillon 			++prd;
1737258223a3SMatthew Dillon 		++segs;
1738258223a3SMatthew Dillon 	}
1739258223a3SMatthew Dillon 	*(void **)info = prd;	/* return last valid segment */
1740258223a3SMatthew Dillon }
1741258223a3SMatthew Dillon 
1742258223a3SMatthew Dillon void
1743258223a3SMatthew Dillon ahci_unload_prdt(struct ahci_ccb *ccb)
1744258223a3SMatthew Dillon {
1745258223a3SMatthew Dillon 	struct ahci_port		*ap = ccb->ccb_port;
1746258223a3SMatthew Dillon 	struct ahci_softc		*sc = ap->ap_sc;
1747258223a3SMatthew Dillon 	struct ata_xfer			*xa = &ccb->ccb_xa;
1748258223a3SMatthew Dillon 	bus_dmamap_t			dmap = ccb->ccb_dmamap;
1749258223a3SMatthew Dillon 
1750258223a3SMatthew Dillon 	if (xa->datalen != 0) {
1751b012a2caSMatthew Dillon 		if (xa->flags & ATA_F_READ) {
1752258223a3SMatthew Dillon 			bus_dmamap_sync(sc->sc_tag_data, dmap,
1753b012a2caSMatthew Dillon 					BUS_DMASYNC_POSTREAD);
1754b012a2caSMatthew Dillon 		}
1755b012a2caSMatthew Dillon 		if (xa->flags & ATA_F_WRITE) {
1756b012a2caSMatthew Dillon 			bus_dmamap_sync(sc->sc_tag_data, dmap,
1757b012a2caSMatthew Dillon 					BUS_DMASYNC_POSTWRITE);
1758b012a2caSMatthew Dillon 		}
1759258223a3SMatthew Dillon 		bus_dmamap_unload(sc->sc_tag_data, dmap);
1760258223a3SMatthew Dillon 
1761f7d09f74SMatthew Dillon 		/*
1762f7d09f74SMatthew Dillon 		 * prdbc is only updated by hardware for non-NCQ commands.
1763f7d09f74SMatthew Dillon 		 */
1764f7d09f74SMatthew Dillon 		if (ccb->ccb_xa.flags & ATA_F_NCQ) {
1765f7d09f74SMatthew Dillon 			xa->resid = 0;
1766f7d09f74SMatthew Dillon 		} else {
176750a3ecb6SMatthew Dillon 			if (ccb->ccb_cmd_hdr->prdbc == 0 &&
176850a3ecb6SMatthew Dillon 			    ccb->ccb_xa.state == ATA_S_COMPLETE) {
1769f7d09f74SMatthew Dillon 				kprintf("%s: WARNING!  Unload prdbc resid "
1770f7d09f74SMatthew Dillon 					"was zero! tag=%d\n",
177112feb904SMatthew Dillon 					ATANAME(ap, xa->at), ccb->ccb_slot);
177212feb904SMatthew Dillon 			}
1773258223a3SMatthew Dillon 			xa->resid = xa->datalen -
1774258223a3SMatthew Dillon 			    le32toh(ccb->ccb_cmd_hdr->prdbc);
1775258223a3SMatthew Dillon 		}
1776258223a3SMatthew Dillon 	}
1777f7d09f74SMatthew Dillon }
1778258223a3SMatthew Dillon 
17795f8c1efdSMatthew Dillon /*
17805f8c1efdSMatthew Dillon  * Start a command and poll for completion.
17815f8c1efdSMatthew Dillon  *
17823209f581SMatthew Dillon  * timeout is in ms and only counts once the command gets on-chip.
17833209f581SMatthew Dillon  *
1784831bc9e3SMatthew Dillon  * Returns ATA_S_* state, compare against ATA_S_COMPLETE to determine
1785831bc9e3SMatthew Dillon  * that no error occured.
1786831bc9e3SMatthew Dillon  *
17875f8c1efdSMatthew Dillon  * NOTE: If the caller specifies a NULL timeout function the caller is
17885f8c1efdSMatthew Dillon  *	 responsible for clearing hardware state on failure, but we will
17895f8c1efdSMatthew Dillon  *	 deal with removing the ccb from any pending queue.
17905f8c1efdSMatthew Dillon  *
17915f8c1efdSMatthew Dillon  * NOTE: NCQ should never be used with this function.
1792cf5f3a81SMatthew Dillon  *
1793cf5f3a81SMatthew Dillon  * NOTE: If the port is in a failed state and stopped we do not try
1794cf5f3a81SMatthew Dillon  *	 to activate the ccb.
17955f8c1efdSMatthew Dillon  */
1796258223a3SMatthew Dillon int
1797831bc9e3SMatthew Dillon ahci_poll(struct ahci_ccb *ccb, int timeout,
1798831bc9e3SMatthew Dillon 	  void (*timeout_fn)(struct ahci_ccb *))
1799258223a3SMatthew Dillon {
1800258223a3SMatthew Dillon 	struct ahci_port *ap = ccb->ccb_port;
1801258223a3SMatthew Dillon 
1802cf5f3a81SMatthew Dillon 	if (ccb->ccb_port->ap_state == AP_S_FATAL_ERROR) {
1803cf5f3a81SMatthew Dillon 		ccb->ccb_xa.state = ATA_S_ERROR;
1804831bc9e3SMatthew Dillon 		return(ccb->ccb_xa.state);
1805cf5f3a81SMatthew Dillon 	}
1806258223a3SMatthew Dillon 	crit_enter();
180712feb904SMatthew Dillon #if 0
180812feb904SMatthew Dillon 	kprintf("%s: Start command %02x tag=%d\n",
180912feb904SMatthew Dillon 		ATANAME(ccb->ccb_port, ccb->ccb_xa.at),
181012feb904SMatthew Dillon 		ccb->ccb_xa.fis->command, ccb->ccb_slot);
181112feb904SMatthew Dillon #endif
1812258223a3SMatthew Dillon 	ahci_start(ccb);
18131980eff3SMatthew Dillon 
1814258223a3SMatthew Dillon 	do {
1815f4553de1SMatthew Dillon 		ahci_port_intr(ap, 1);
1816831bc9e3SMatthew Dillon 		switch(ccb->ccb_xa.state) {
1817831bc9e3SMatthew Dillon 		case ATA_S_ONCHIP:
1818831bc9e3SMatthew Dillon 			timeout -= ahci_os_softsleep();
1819f4553de1SMatthew Dillon 			break;
1820831bc9e3SMatthew Dillon 		case ATA_S_PENDING:
1821831bc9e3SMatthew Dillon 			ahci_os_softsleep();
1822831bc9e3SMatthew Dillon 			ahci_check_active_timeouts(ap);
1823831bc9e3SMatthew Dillon 			break;
1824831bc9e3SMatthew Dillon 		default:
1825831bc9e3SMatthew Dillon 			crit_exit();
1826831bc9e3SMatthew Dillon 			return (ccb->ccb_xa.state);
1827f4553de1SMatthew Dillon 		}
18283209f581SMatthew Dillon 	} while (timeout > 0);
18295f8c1efdSMatthew Dillon 
1830831bc9e3SMatthew Dillon 	kprintf("%s: Poll timeout slot %d CMD: %b TFD: 0x%b SERR: %b\n",
1831831bc9e3SMatthew Dillon 		ATANAME(ap, ccb->ccb_xa.at), ccb->ccb_slot,
1832831bc9e3SMatthew Dillon 		ahci_pread(ap, AHCI_PREG_CMD), AHCI_PFMT_CMD,
1833831bc9e3SMatthew Dillon 		ahci_pread(ap, AHCI_PREG_TFD), AHCI_PFMT_TFD_STS,
1834831bc9e3SMatthew Dillon 		ahci_pread(ap, AHCI_PREG_SERR), AHCI_PFMT_SERR);
18355f8c1efdSMatthew Dillon 
1836258223a3SMatthew Dillon 	timeout_fn(ccb);
1837831bc9e3SMatthew Dillon 
1838258223a3SMatthew Dillon 	crit_exit();
1839258223a3SMatthew Dillon 
1840831bc9e3SMatthew Dillon 	return(ccb->ccb_xa.state);
1841831bc9e3SMatthew Dillon }
1842831bc9e3SMatthew Dillon 
1843831bc9e3SMatthew Dillon /*
1844831bc9e3SMatthew Dillon  * When polling we have to check if the currently active CCB(s)
1845831bc9e3SMatthew Dillon  * have timed out as the callout will be deadlocked while we
1846831bc9e3SMatthew Dillon  * hold the port lock.
1847831bc9e3SMatthew Dillon  */
1848831bc9e3SMatthew Dillon void
1849831bc9e3SMatthew Dillon ahci_check_active_timeouts(struct ahci_port *ap)
1850831bc9e3SMatthew Dillon {
1851831bc9e3SMatthew Dillon 	struct ahci_ccb *ccb;
1852831bc9e3SMatthew Dillon 	u_int32_t mask;
1853831bc9e3SMatthew Dillon 	int tag;
1854831bc9e3SMatthew Dillon 
1855831bc9e3SMatthew Dillon 	mask = ap->ap_active | ap->ap_sactive;
1856831bc9e3SMatthew Dillon 	while (mask) {
1857831bc9e3SMatthew Dillon 		tag = ffs(mask) - 1;
1858831bc9e3SMatthew Dillon 		mask &= ~(1 << tag);
1859831bc9e3SMatthew Dillon 		ccb = &ap->ap_ccbs[tag];
1860831bc9e3SMatthew Dillon 		if (ccb->ccb_xa.flags & ATA_F_TIMEOUT_EXPIRED) {
1861831bc9e3SMatthew Dillon 			ahci_ata_cmd_timeout(ccb);
1862831bc9e3SMatthew Dillon 		}
1863831bc9e3SMatthew Dillon 	}
1864258223a3SMatthew Dillon }
1865258223a3SMatthew Dillon 
18663209f581SMatthew Dillon static
18673209f581SMatthew Dillon __inline
18683209f581SMatthew Dillon void
18693209f581SMatthew Dillon ahci_start_timeout(struct ahci_ccb *ccb)
18703209f581SMatthew Dillon {
18713209f581SMatthew Dillon 	if (ccb->ccb_xa.flags & ATA_F_TIMEOUT_DESIRED) {
18723209f581SMatthew Dillon 		ccb->ccb_xa.flags |= ATA_F_TIMEOUT_RUNNING;
18733209f581SMatthew Dillon 		callout_reset(&ccb->ccb_timeout,
18743209f581SMatthew Dillon 			      (ccb->ccb_xa.timeout * hz + 999) / 1000,
18753209f581SMatthew Dillon 			      ahci_ata_cmd_timeout_unserialized, ccb);
18763209f581SMatthew Dillon 	}
18773209f581SMatthew Dillon }
18783209f581SMatthew Dillon 
1879258223a3SMatthew Dillon void
1880258223a3SMatthew Dillon ahci_start(struct ahci_ccb *ccb)
1881258223a3SMatthew Dillon {
1882258223a3SMatthew Dillon 	struct ahci_port		*ap = ccb->ccb_port;
1883258223a3SMatthew Dillon 	struct ahci_softc		*sc = ap->ap_sc;
1884258223a3SMatthew Dillon 
1885258223a3SMatthew Dillon 	KKASSERT(ccb->ccb_xa.state == ATA_S_PENDING);
1886258223a3SMatthew Dillon 
1887258223a3SMatthew Dillon 	/* Zero transferred byte count before transfer */
1888258223a3SMatthew Dillon 	ccb->ccb_cmd_hdr->prdbc = 0;
1889258223a3SMatthew Dillon 
1890258223a3SMatthew Dillon 	/* Sync command list entry and corresponding command table entry */
1891258223a3SMatthew Dillon 	bus_dmamap_sync(sc->sc_tag_cmdh,
1892258223a3SMatthew Dillon 			AHCI_DMA_MAP(ap->ap_dmamem_cmd_list),
1893258223a3SMatthew Dillon 			BUS_DMASYNC_PREWRITE);
1894258223a3SMatthew Dillon 	bus_dmamap_sync(sc->sc_tag_cmdt,
1895258223a3SMatthew Dillon 			AHCI_DMA_MAP(ap->ap_dmamem_cmd_table),
1896258223a3SMatthew Dillon 			BUS_DMASYNC_PREWRITE);
1897258223a3SMatthew Dillon 
1898258223a3SMatthew Dillon 	/* Prepare RFIS area for write by controller */
1899258223a3SMatthew Dillon 	bus_dmamap_sync(sc->sc_tag_rfis,
1900258223a3SMatthew Dillon 			AHCI_DMA_MAP(ap->ap_dmamem_rfis),
1901258223a3SMatthew Dillon 			BUS_DMASYNC_PREREAD);
1902258223a3SMatthew Dillon 
19031980eff3SMatthew Dillon 	/*
19044c339a5fSMatthew Dillon 	 * There's no point trying to optimize this, it only shaves a few
19054c339a5fSMatthew Dillon 	 * nanoseconds so just queue the command and call our generic issue.
19061980eff3SMatthew Dillon 	 */
19074c339a5fSMatthew Dillon 	ahci_issue_pending_commands(ap, ccb);
1908258223a3SMatthew Dillon }
1909258223a3SMatthew Dillon 
1910831bc9e3SMatthew Dillon /*
1911831bc9e3SMatthew Dillon  * While holding the port lock acquire exclusive access to the port.
1912831bc9e3SMatthew Dillon  *
1913831bc9e3SMatthew Dillon  * This is used when running the state machine to initialize and identify
1914831bc9e3SMatthew Dillon  * targets over a port multiplier.  Setting exclusive access prevents
1915831bc9e3SMatthew Dillon  * ahci_port_intr() from activating any requests sitting on the pending
1916831bc9e3SMatthew Dillon  * queue.
1917831bc9e3SMatthew Dillon  */
1918831bc9e3SMatthew Dillon void
1919831bc9e3SMatthew Dillon ahci_beg_exclusive_access(struct ahci_port *ap, struct ata_port *at)
1920831bc9e3SMatthew Dillon {
1921831bc9e3SMatthew Dillon 	KKASSERT((ap->ap_flags & AP_F_EXCLUSIVE_ACCESS) == 0);
1922831bc9e3SMatthew Dillon 	ap->ap_flags |= AP_F_EXCLUSIVE_ACCESS;
1923831bc9e3SMatthew Dillon 	while (ap->ap_active || ap->ap_sactive) {
1924831bc9e3SMatthew Dillon 		ahci_port_intr(ap, 1);
1925831bc9e3SMatthew Dillon 		ahci_os_softsleep();
1926831bc9e3SMatthew Dillon 	}
1927831bc9e3SMatthew Dillon }
1928831bc9e3SMatthew Dillon 
1929831bc9e3SMatthew Dillon void
1930831bc9e3SMatthew Dillon ahci_end_exclusive_access(struct ahci_port *ap, struct ata_port *at)
1931831bc9e3SMatthew Dillon {
1932831bc9e3SMatthew Dillon 	KKASSERT((ap->ap_flags & AP_F_EXCLUSIVE_ACCESS) != 0);
1933831bc9e3SMatthew Dillon 	ap->ap_flags &= ~AP_F_EXCLUSIVE_ACCESS;
19344c339a5fSMatthew Dillon 	ahci_issue_pending_commands(ap, NULL);
1935831bc9e3SMatthew Dillon }
1936831bc9e3SMatthew Dillon 
193712feb904SMatthew Dillon #if 0
193812feb904SMatthew Dillon 
193912feb904SMatthew Dillon static void
194012feb904SMatthew Dillon fubar(struct ahci_ccb *ccb)
194112feb904SMatthew Dillon {
194212feb904SMatthew Dillon 	struct ahci_port *ap = ccb->ccb_port;
194312feb904SMatthew Dillon 	struct ahci_cmd_hdr	*cmd;
194412feb904SMatthew Dillon 	struct ahci_cmd_table	*tab;
194512feb904SMatthew Dillon 	struct ahci_prdt	*prdt;
194612feb904SMatthew Dillon 	int i;
194712feb904SMatthew Dillon 
194812feb904SMatthew Dillon 	kprintf("%s: ISSUE %02x\n",
194912feb904SMatthew Dillon 		ATANAME(ap, ccb->ccb_xa.at),
195012feb904SMatthew Dillon 		ccb->ccb_xa.fis->command);
195112feb904SMatthew Dillon 	cmd = ccb->ccb_cmd_hdr;
195212feb904SMatthew Dillon 	tab = ccb->ccb_cmd_table;
195312feb904SMatthew Dillon 	prdt = ccb->ccb_cmd_table->prdt;
195412feb904SMatthew Dillon 	kprintf("cmd flags=%04x prdtl=%d prdbc=%d ctba=%08x%08x\n",
195512feb904SMatthew Dillon 		cmd->flags, cmd->prdtl, cmd->prdbc,
195612feb904SMatthew Dillon 		cmd->ctba_hi, cmd->ctba_lo);
195712feb904SMatthew Dillon 	for (i = 0; i < cmd->prdtl; ++i) {
195812feb904SMatthew Dillon 		kprintf("\t%d dba=%08x%08x res=%08x flags=%08x\n",
195912feb904SMatthew Dillon 			i, prdt->dba_hi, prdt->dba_lo, prdt->reserved,
196012feb904SMatthew Dillon 			prdt->flags);
196112feb904SMatthew Dillon 	}
196212feb904SMatthew Dillon 	kprintf("tab\n");
196312feb904SMatthew Dillon }
196412feb904SMatthew Dillon 
196512feb904SMatthew Dillon #endif
196612feb904SMatthew Dillon 
19671980eff3SMatthew Dillon /*
19684c339a5fSMatthew Dillon  * If ccb is not NULL enqueue and/or issue it.
19694c339a5fSMatthew Dillon  *
19704c339a5fSMatthew Dillon  * If ccb is NULL issue whatever we can from the queue.  However, nothing
19714c339a5fSMatthew Dillon  * new is issued if the exclusive access flag is set or expired ccb's are
19724c339a5fSMatthew Dillon  * present.
19734c339a5fSMatthew Dillon  *
19744c339a5fSMatthew Dillon  * If existing commands are still active (ap_active/ap_sactive) we can only
19754c339a5fSMatthew Dillon  * issue matching new commands.
19761980eff3SMatthew Dillon  */
19774c339a5fSMatthew Dillon void
19784c339a5fSMatthew Dillon ahci_issue_pending_commands(struct ahci_port *ap, struct ahci_ccb *ccb)
19794c339a5fSMatthew Dillon {
19804c339a5fSMatthew Dillon 	u_int32_t		mask;
19814c339a5fSMatthew Dillon 	int			limit;
1982258223a3SMatthew Dillon 
19831980eff3SMatthew Dillon 	/*
19844c339a5fSMatthew Dillon 	 * Enqueue the ccb.
19854c339a5fSMatthew Dillon 	 *
19864c339a5fSMatthew Dillon 	 * If just running the queue and in exclusive access mode we
19874c339a5fSMatthew Dillon 	 * just return.  Also in this case if there are any expired ccb's
19884c339a5fSMatthew Dillon 	 * we want to clear the queue so the port can be safely stopped.
19894c339a5fSMatthew Dillon 	 */
19904c339a5fSMatthew Dillon 	if (ccb) {
19914c339a5fSMatthew Dillon 		TAILQ_INSERT_TAIL(&ap->ap_ccb_pending, ccb, ccb_entry);
19924c339a5fSMatthew Dillon 	} else if ((ap->ap_flags & AP_F_EXCLUSIVE_ACCESS) || ap->ap_expired) {
19934c339a5fSMatthew Dillon 		return;
19944c339a5fSMatthew Dillon 	}
19954c339a5fSMatthew Dillon 
19964c339a5fSMatthew Dillon 	/*
19974c339a5fSMatthew Dillon 	 * Pull the next ccb off the queue and run it if possible.
19984c339a5fSMatthew Dillon 	 */
19994c339a5fSMatthew Dillon 	if ((ccb = TAILQ_FIRST(&ap->ap_ccb_pending)) == NULL)
20004c339a5fSMatthew Dillon 		return;
20014c339a5fSMatthew Dillon 
200212feb904SMatthew Dillon 	/*
200312feb904SMatthew Dillon 	 * Handle exclusivity requirements.
200412feb904SMatthew Dillon 	 *
200512feb904SMatthew Dillon 	 * ATA_F_EXCLUSIVE is used when we want to be the only command
200612feb904SMatthew Dillon 	 * running.
200712feb904SMatthew Dillon 	 *
200812feb904SMatthew Dillon 	 * ATA_F_AUTOSENSE is used when we want the D2H rfis loaded
200912feb904SMatthew Dillon 	 * back into the ccb on a normal (non-errored) command completion.
201012feb904SMatthew Dillon 	 * For example, for PM requests to target 15.  Because the AHCI
201112feb904SMatthew Dillon 	 * spec does not stop the command processor and has only one rfis
201212feb904SMatthew Dillon 	 * area (for non-FBSS anyway), AUTOSENSE currently implies EXCLUSIVE.
201312feb904SMatthew Dillon 	 * Otherwise multiple completions can destroy the rfis data before
201412feb904SMatthew Dillon 	 * we have a chance to copy it.
201512feb904SMatthew Dillon 	 */
201612feb904SMatthew Dillon 	if (ap->ap_active & ~ap->ap_expired) {
201712feb904SMatthew Dillon 		/*
201812feb904SMatthew Dillon 		 * There may be multiple ccb's already running,
201912feb904SMatthew Dillon 		 * if any are running and ap_run_flags sets
202012feb904SMatthew Dillon 		 * one of these flags then we know only one is
202112feb904SMatthew Dillon 		 * running.
202212feb904SMatthew Dillon 		 *
202312feb904SMatthew Dillon 		 * XXX Current AUTOSENSE code forces exclusivity
202412feb904SMatthew Dillon 		 *     to simplify the code.
202512feb904SMatthew Dillon 		 */
202612feb904SMatthew Dillon 		if (ap->ap_run_flags &
202712feb904SMatthew Dillon 		    (ATA_F_EXCLUSIVE | ATA_F_AUTOSENSE)) {
202812feb904SMatthew Dillon 			return;
202912feb904SMatthew Dillon 		}
203012feb904SMatthew Dillon 
203112feb904SMatthew Dillon 		if (ccb->ccb_xa.flags &
203212feb904SMatthew Dillon 		    (ATA_F_EXCLUSIVE | ATA_F_AUTOSENSE)) {
203312feb904SMatthew Dillon 			return;
203412feb904SMatthew Dillon 		}
203512feb904SMatthew Dillon 	}
203612feb904SMatthew Dillon 
20374c339a5fSMatthew Dillon 	if (ccb->ccb_xa.flags & ATA_F_NCQ) {
20384c339a5fSMatthew Dillon 		/*
20394c339a5fSMatthew Dillon 		 * The next command is a NCQ command and can be issued as
20404c339a5fSMatthew Dillon 		 * long as currently active commands are not standard.
20414c339a5fSMatthew Dillon 		 */
20424c339a5fSMatthew Dillon 		if (ap->ap_active) {
20434c339a5fSMatthew Dillon 			KKASSERT(ap->ap_active_cnt > 0);
20444c339a5fSMatthew Dillon 			return;
20454c339a5fSMatthew Dillon 		}
20464c339a5fSMatthew Dillon 		KKASSERT(ap->ap_active_cnt == 0);
20474c339a5fSMatthew Dillon 
20484c339a5fSMatthew Dillon 		mask = 0;
20494c339a5fSMatthew Dillon 		do {
20504c339a5fSMatthew Dillon 			TAILQ_REMOVE(&ap->ap_ccb_pending, ccb, ccb_entry);
20514c339a5fSMatthew Dillon 			mask |= 1 << ccb->ccb_slot;
20524c339a5fSMatthew Dillon 			ccb->ccb_xa.state = ATA_S_ONCHIP;
205312feb904SMatthew Dillon 			ahci_start_timeout(ccb);
205412feb904SMatthew Dillon 			ap->ap_run_flags = ccb->ccb_xa.flags;
20554c339a5fSMatthew Dillon 			ccb = TAILQ_FIRST(&ap->ap_ccb_pending);
205612feb904SMatthew Dillon 		} while (ccb && (ccb->ccb_xa.flags & ATA_F_NCQ) &&
205712feb904SMatthew Dillon 			 (ap->ap_run_flags &
205812feb904SMatthew Dillon 			     (ATA_F_EXCLUSIVE | ATA_F_AUTOSENSE)) == 0);
20594c339a5fSMatthew Dillon 
20604c339a5fSMatthew Dillon 		ap->ap_sactive |= mask;
20614c339a5fSMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SACT, mask);
20624c339a5fSMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CI, mask);
20634c339a5fSMatthew Dillon 	} else {
20644c339a5fSMatthew Dillon 		/*
20654c339a5fSMatthew Dillon 		 * The next command is a standard command and can be issued
20664c339a5fSMatthew Dillon 		 * as long as currently active commands are not NCQ.
20674c339a5fSMatthew Dillon 		 *
20684c339a5fSMatthew Dillon 		 * We limit ourself to 1 command if we have a port multiplier,
20694c339a5fSMatthew Dillon 		 * (at least without FBSS support), otherwise timeouts on
20704c339a5fSMatthew Dillon 		 * one port can race completions on other ports (see
20714c339a5fSMatthew Dillon 		 * ahci_ata_cmd_timeout() for more information).
20724c339a5fSMatthew Dillon 		 *
20734c339a5fSMatthew Dillon 		 * If not on a port multiplier generally allow up to 4
20744c339a5fSMatthew Dillon 		 * standard commands to be enqueued.  Remember that the
20754c339a5fSMatthew Dillon 		 * command processor will still process them sequentially.
20761980eff3SMatthew Dillon 		 */
20771980eff3SMatthew Dillon 		if (ap->ap_sactive)
2078258223a3SMatthew Dillon 			return;
20794c339a5fSMatthew Dillon 		if (ap->ap_type == ATA_PORT_T_PM)
20804c339a5fSMatthew Dillon 			limit = 1;
20814c339a5fSMatthew Dillon 		else if (ap->ap_sc->sc_ncmds > 4)
20824c339a5fSMatthew Dillon 			limit = 4;
20834c339a5fSMatthew Dillon 		else
20844c339a5fSMatthew Dillon 			limit = 2;
2085258223a3SMatthew Dillon 
20864c339a5fSMatthew Dillon 		while (ap->ap_active_cnt < limit && ccb &&
20874c339a5fSMatthew Dillon 		       (ccb->ccb_xa.flags & ATA_F_NCQ) == 0) {
20884c339a5fSMatthew Dillon 			TAILQ_REMOVE(&ap->ap_ccb_pending, ccb, ccb_entry);
208912feb904SMatthew Dillon #if 0
209012feb904SMatthew Dillon 			fubar(ccb);
209112feb904SMatthew Dillon #endif
20924c339a5fSMatthew Dillon 			ap->ap_active |= 1 << ccb->ccb_slot;
2093258223a3SMatthew Dillon 			ap->ap_active_cnt++;
209412feb904SMatthew Dillon 			ap->ap_run_flags = ccb->ccb_xa.flags;
20954c339a5fSMatthew Dillon 			ccb->ccb_xa.state = ATA_S_ONCHIP;
20964c339a5fSMatthew Dillon 			ahci_pwrite(ap, AHCI_PREG_CI, 1 << ccb->ccb_slot);
209712feb904SMatthew Dillon 			ahci_start_timeout(ccb);
2098*22726f69SMatthew Dillon 			if ((ap->ap_run_flags &
2099*22726f69SMatthew Dillon 			    (ATA_F_EXCLUSIVE | ATA_F_AUTOSENSE)) == 0) {
2100*22726f69SMatthew Dillon 				break;
2101*22726f69SMatthew Dillon 			}
21024c339a5fSMatthew Dillon 			ccb = TAILQ_FIRST(&ap->ap_ccb_pending);
210312feb904SMatthew Dillon 			if (ccb && (ccb->ccb_xa.flags &
210412feb904SMatthew Dillon 				    (ATA_F_EXCLUSIVE | ATA_F_AUTOSENSE))) {
210512feb904SMatthew Dillon 				break;
210612feb904SMatthew Dillon 			}
21071980eff3SMatthew Dillon 		}
2108258223a3SMatthew Dillon 	}
2109258223a3SMatthew Dillon }
2110258223a3SMatthew Dillon 
2111258223a3SMatthew Dillon void
2112258223a3SMatthew Dillon ahci_intr(void *arg)
2113258223a3SMatthew Dillon {
2114258223a3SMatthew Dillon 	struct ahci_softc	*sc = arg;
2115f4553de1SMatthew Dillon 	struct ahci_port	*ap;
211612feb904SMatthew Dillon 	u_int32_t		is;
211712feb904SMatthew Dillon 	u_int32_t		ack;
2118258223a3SMatthew Dillon 	int			port;
2119258223a3SMatthew Dillon 
2120f4553de1SMatthew Dillon 	/*
2121f4553de1SMatthew Dillon 	 * Check if the master enable is up, and whether any interrupts are
2122f4553de1SMatthew Dillon 	 * pending.
2123f4553de1SMatthew Dillon 	 */
2124f4553de1SMatthew Dillon 	if ((sc->sc_flags & AHCI_F_INT_GOOD) == 0)
2125f4553de1SMatthew Dillon 		return;
2126258223a3SMatthew Dillon 	is = ahci_read(sc, AHCI_REG_IS);
212712feb904SMatthew Dillon 	if (is == 0 || is == 0xffffffff) {
2128258223a3SMatthew Dillon 		return;
212912feb904SMatthew Dillon 	}
213012feb904SMatthew Dillon 	is &= sc->sc_portmask;
2131258223a3SMatthew Dillon 
2132258223a3SMatthew Dillon #ifdef AHCI_COALESCE
2133258223a3SMatthew Dillon 	/* Check coalescing interrupt first */
2134258223a3SMatthew Dillon 	if (is & sc->sc_ccc_mask) {
2135258223a3SMatthew Dillon 		DPRINTF(AHCI_D_INTR, "%s: command coalescing interrupt\n",
2136258223a3SMatthew Dillon 		    DEVNAME(sc));
2137258223a3SMatthew Dillon 		is &= ~sc->sc_ccc_mask;
2138258223a3SMatthew Dillon 		is |= sc->sc_ccc_ports_cur;
2139258223a3SMatthew Dillon 	}
2140258223a3SMatthew Dillon #endif
2141258223a3SMatthew Dillon 
2142f4553de1SMatthew Dillon 	/*
2143f4553de1SMatthew Dillon 	 * Process interrupts for each port in a non-blocking fashion.
214412feb904SMatthew Dillon 	 *
214512feb904SMatthew Dillon 	 * The global IS bit is forced on if any unmasked port interrupts
214612feb904SMatthew Dillon 	 * are pending, even if we clear.
2147f4553de1SMatthew Dillon 	 */
214812feb904SMatthew Dillon 	for (ack = 0; is; is &= ~(1 << port)) {
2149258223a3SMatthew Dillon 		port = ffs(is) - 1;
215012feb904SMatthew Dillon 		ack |= 1 << port;
215112feb904SMatthew Dillon 
2152f4553de1SMatthew Dillon 		ap = sc->sc_ports[port];
215312feb904SMatthew Dillon 		if (ap == NULL)
215412feb904SMatthew Dillon 			continue;
215512feb904SMatthew Dillon 
2156f4553de1SMatthew Dillon 		if (ahci_os_lock_port_nb(ap) == 0) {
2157f4553de1SMatthew Dillon 			ahci_port_intr(ap, 0);
2158f4553de1SMatthew Dillon 			ahci_os_unlock_port(ap);
2159f4553de1SMatthew Dillon 		} else {
2160f4553de1SMatthew Dillon 			ahci_pwrite(ap, AHCI_PREG_IE, 0);
2161f4553de1SMatthew Dillon 			ahci_os_signal_port_thread(ap, AP_SIGF_PORTINT);
2162f4553de1SMatthew Dillon 		}
2163f4553de1SMatthew Dillon 	}
2164258223a3SMatthew Dillon 	ahci_write(sc, AHCI_REG_IS, ack);
2165258223a3SMatthew Dillon }
2166258223a3SMatthew Dillon 
2167f4553de1SMatthew Dillon /*
2168f4553de1SMatthew Dillon  * Core called from helper thread.
2169f4553de1SMatthew Dillon  */
21703209f581SMatthew Dillon void
2171f4553de1SMatthew Dillon ahci_port_thread_core(struct ahci_port *ap, int mask)
2172f4553de1SMatthew Dillon {
2173f4553de1SMatthew Dillon 	/*
2174f4553de1SMatthew Dillon 	 * Process any expired timedouts.
2175f4553de1SMatthew Dillon 	 */
2176f4553de1SMatthew Dillon 	ahci_os_lock_port(ap);
2177f4553de1SMatthew Dillon 	if (mask & AP_SIGF_TIMEOUT) {
2178831bc9e3SMatthew Dillon 		ahci_check_active_timeouts(ap);
2179f4553de1SMatthew Dillon 	}
2180f4553de1SMatthew Dillon 
2181f4553de1SMatthew Dillon 	/*
2182f4553de1SMatthew Dillon 	 * Process port interrupts which require a higher level of
2183f4553de1SMatthew Dillon 	 * intervention.
2184f4553de1SMatthew Dillon 	 */
2185f4553de1SMatthew Dillon 	if (mask & AP_SIGF_PORTINT) {
2186f4553de1SMatthew Dillon 		ahci_port_intr(ap, 1);
2187f4553de1SMatthew Dillon 		ahci_port_interrupt_enable(ap);
2188831bc9e3SMatthew Dillon 		ahci_os_unlock_port(ap);
218912feb904SMatthew Dillon 	} else if (ap->ap_probe != ATA_PROBE_FAILED) {
219012feb904SMatthew Dillon 		ahci_port_intr(ap, 1);
219112feb904SMatthew Dillon 		ahci_port_interrupt_enable(ap);
219212feb904SMatthew Dillon 		ahci_os_unlock_port(ap);
2193f4553de1SMatthew Dillon 	} else {
2194f4553de1SMatthew Dillon 		ahci_os_unlock_port(ap);
2195f4553de1SMatthew Dillon 	}
2196f4553de1SMatthew Dillon }
2197f4553de1SMatthew Dillon 
2198f4553de1SMatthew Dillon /*
2199f4553de1SMatthew Dillon  * Core per-port interrupt handler.
2200f4553de1SMatthew Dillon  *
2201f4553de1SMatthew Dillon  * If blockable is 0 we cannot call ahci_os_sleep() at all and we can only
2202f4553de1SMatthew Dillon  * deal with normal command completions which do not require blocking.
2203f4553de1SMatthew Dillon  */
2204f4553de1SMatthew Dillon void
2205f4553de1SMatthew Dillon ahci_port_intr(struct ahci_port *ap, int blockable)
2206258223a3SMatthew Dillon {
2207258223a3SMatthew Dillon 	struct ahci_softc	*sc = ap->ap_sc;
22083209f581SMatthew Dillon 	u_int32_t		is, ci_saved, ci_masked;
220922181ab7SMatthew Dillon 	int			slot;
2210258223a3SMatthew Dillon 	struct ahci_ccb		*ccb = NULL;
22111980eff3SMatthew Dillon 	struct ata_port		*ccb_at = NULL;
2212258223a3SMatthew Dillon 	volatile u_int32_t	*active;
2213f4553de1SMatthew Dillon 	const u_int32_t		blockable_mask = AHCI_PREG_IS_TFES |
2214f4553de1SMatthew Dillon 						 AHCI_PREG_IS_IFS |
2215f4553de1SMatthew Dillon 						 AHCI_PREG_IS_PCS |
2216f4553de1SMatthew Dillon 						 AHCI_PREG_IS_PRCS |
2217f4553de1SMatthew Dillon 						 AHCI_PREG_IS_HBFS |
2218f4553de1SMatthew Dillon 						 AHCI_PREG_IS_OFS |
2219f4553de1SMatthew Dillon 						 AHCI_PREG_IS_UFS;
2220f4553de1SMatthew Dillon 
222122181ab7SMatthew Dillon 	enum { NEED_NOTHING, NEED_RESTART, NEED_HOTPLUG_INSERT,
222222181ab7SMatthew Dillon 	       NEED_HOTPLUG_REMOVE } need = NEED_NOTHING;
2223258223a3SMatthew Dillon 
2224f4553de1SMatthew Dillon 	/*
2225f4553de1SMatthew Dillon 	 * All basic command completions are always processed.
2226f4553de1SMatthew Dillon 	 */
222712feb904SMatthew Dillon 	is = ahci_pread(ap, AHCI_PREG_IS);
2228cec07d75SMatthew Dillon 	if (is & AHCI_PREG_IS_DPS)
2229cec07d75SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS, is & AHCI_PREG_IS_DPS);
2230258223a3SMatthew Dillon 
2231f4553de1SMatthew Dillon 	/*
2232f4553de1SMatthew Dillon 	 * If we can't block then we can't handle these here.  Disable
2233f4553de1SMatthew Dillon 	 * the interrupts in question so we don't live-lock, the helper
2234f4553de1SMatthew Dillon 	 * thread will re-enable them.
2235f4553de1SMatthew Dillon 	 *
2236f4553de1SMatthew Dillon 	 * If the port is in a completely failed state we do not want
2237dbef6246SMatthew Dillon 	 * to drop through to failed-command-processing if blockable is 0,
2238f4553de1SMatthew Dillon 	 * just let the thread deal with it all.
2239dbef6246SMatthew Dillon 	 *
2240dbef6246SMatthew Dillon 	 * Otherwise we fall through and still handle DHRS and any commands
2241dbef6246SMatthew Dillon 	 * which completed normally.  Even if we are errored we haven't
2242dbef6246SMatthew Dillon 	 * stopped the port yet so CI/SACT are still good.
2243f4553de1SMatthew Dillon 	 */
2244f4553de1SMatthew Dillon 	if (blockable == 0) {
2245f4553de1SMatthew Dillon 		if (ap->ap_state == AP_S_FATAL_ERROR) {
224612feb904SMatthew Dillon 			ahci_pwrite(ap, AHCI_PREG_IE, 0);
2247f4553de1SMatthew Dillon 			ahci_os_signal_port_thread(ap, AP_SIGF_PORTINT);
2248f4553de1SMatthew Dillon 			return;
2249f4553de1SMatthew Dillon 		}
2250f4553de1SMatthew Dillon 		if (is & blockable_mask) {
225112feb904SMatthew Dillon 			ahci_pwrite(ap, AHCI_PREG_IE, 0);
2252f4553de1SMatthew Dillon 			ahci_os_signal_port_thread(ap, AP_SIGF_PORTINT);
225312feb904SMatthew Dillon 			return;
2254f4553de1SMatthew Dillon 		}
2255f4553de1SMatthew Dillon 	}
2256f4553de1SMatthew Dillon 
22573209f581SMatthew Dillon 	/*
2258f4553de1SMatthew Dillon 	 * Either NCQ or non-NCQ commands will be active, never both.
22593209f581SMatthew Dillon 	 */
2260258223a3SMatthew Dillon 	if (ap->ap_sactive) {
2261258223a3SMatthew Dillon 		KKASSERT(ap->ap_active == 0);
2262258223a3SMatthew Dillon 		KKASSERT(ap->ap_active_cnt == 0);
2263258223a3SMatthew Dillon 		ci_saved = ahci_pread(ap, AHCI_PREG_SACT);
2264258223a3SMatthew Dillon 		active = &ap->ap_sactive;
2265258223a3SMatthew Dillon 	} else {
2266258223a3SMatthew Dillon 		ci_saved = ahci_pread(ap, AHCI_PREG_CI);
2267258223a3SMatthew Dillon 		active = &ap->ap_active;
2268258223a3SMatthew Dillon 	}
226912feb904SMatthew Dillon 	KKASSERT(!(ap->ap_sactive && ap->ap_active));
227012feb904SMatthew Dillon #if 0
227112feb904SMatthew Dillon 	kprintf("CHECK act=%08x/%08x sact=%08x/%08x\n",
227212feb904SMatthew Dillon 		ap->ap_active, ahci_pread(ap, AHCI_PREG_CI),
227312feb904SMatthew Dillon 		ap->ap_sactive, ahci_pread(ap, AHCI_PREG_SACT));
227412feb904SMatthew Dillon #endif
2275258223a3SMatthew Dillon 
22761980eff3SMatthew Dillon 	if (is & AHCI_PREG_IS_TFES) {
2277cf5f3a81SMatthew Dillon 		/*
2278f4553de1SMatthew Dillon 		 * Command failed (blockable).
2279f4553de1SMatthew Dillon 		 *
2280f4553de1SMatthew Dillon 		 * See AHCI 1.1 spec 6.2.2.1 and 6.2.2.2.
22811980eff3SMatthew Dillon 		 *
22821980eff3SMatthew Dillon 		 * This stops command processing.
2283cf5f3a81SMatthew Dillon 		 */
2284258223a3SMatthew Dillon 		u_int32_t tfd, serr;
2285258223a3SMatthew Dillon 		int	err_slot;
2286258223a3SMatthew Dillon 
228712feb904SMatthew Dillon process_error:
2288258223a3SMatthew Dillon 		tfd = ahci_pread(ap, AHCI_PREG_TFD);
2289258223a3SMatthew Dillon 		serr = ahci_pread(ap, AHCI_PREG_SERR);
2290258223a3SMatthew Dillon 
2291cf5f3a81SMatthew Dillon 		/*
229212feb904SMatthew Dillon 		 * Load the error slot and restart command processing.
229312feb904SMatthew Dillon 		 * CLO if we need to.  The error slot may not be valid.
229412feb904SMatthew Dillon 		 * MUST BE DONE BEFORE CLEARING ST!
229512feb904SMatthew Dillon 		 *
229612feb904SMatthew Dillon 		 * Cycle ST.
229712feb904SMatthew Dillon 		 *
229812feb904SMatthew Dillon 		 * It is unclear but we may have to clear SERR to reenable
229912feb904SMatthew Dillon 		 * error processing.
2300cf5f3a81SMatthew Dillon 		 */
230112feb904SMatthew Dillon 		err_slot = AHCI_PREG_CMD_CCS(ahci_pread(ap, AHCI_PREG_CMD));
230212feb904SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_TFES |
230312feb904SMatthew Dillon 					      AHCI_PREG_IS_PSS |
230412feb904SMatthew Dillon 					      AHCI_PREG_IS_DHRS |
230512feb904SMatthew Dillon 					      AHCI_PREG_IS_SDBS);
230612feb904SMatthew Dillon 		is &= ~(AHCI_PREG_IS_TFES | AHCI_PREG_IS_PSS |
230712feb904SMatthew Dillon 			AHCI_PREG_IS_DHRS | AHCI_PREG_IS_SDBS);
230812feb904SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SERR, serr);
2309258223a3SMatthew Dillon 		ahci_port_stop(ap, 0);
231012feb904SMatthew Dillon 		ahci_os_hardsleep(10);
231112feb904SMatthew Dillon 		if (tfd & (AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) {
231212feb904SMatthew Dillon 			kprintf("%s: Issuing CLO\n", PORTNAME(ap));
231312feb904SMatthew Dillon 			ahci_port_clo(ap);
231412feb904SMatthew Dillon 		}
231512feb904SMatthew Dillon 		ahci_port_start(ap);
231622181ab7SMatthew Dillon 		need = NEED_RESTART;
2317258223a3SMatthew Dillon 
231850a3ecb6SMatthew Dillon 		/*
231950a3ecb6SMatthew Dillon 		 * ATAPI errors are fairly common from probing, just
232050a3ecb6SMatthew Dillon 		 * report disk errors or if bootverbose is on.
232150a3ecb6SMatthew Dillon 		 */
232250a3ecb6SMatthew Dillon 		if (bootverbose || ap->ap_type != ATA_PORT_T_ATAPI) {
232312feb904SMatthew Dillon 			kprintf("%s: TFES slot %d ci_saved = %08x\n",
232412feb904SMatthew Dillon 				PORTNAME(ap), err_slot, ci_saved);
232550a3ecb6SMatthew Dillon 		}
2326258223a3SMatthew Dillon 
23271980eff3SMatthew Dillon 		/*
232812feb904SMatthew Dillon 		 * If we got an error on an error CCB just complete it
232912feb904SMatthew Dillon 		 * with an error.  ci_saved has the mask to restart
233012feb904SMatthew Dillon 		 * (the err_ccb will be removed from it by finish_error).
23311980eff3SMatthew Dillon 		 */
233212feb904SMatthew Dillon 		if (ap->ap_flags & AP_F_ERR_CCB_RESERVED) {
233312feb904SMatthew Dillon 			err_slot = ap->ap_err_ccb->ccb_slot;
233412feb904SMatthew Dillon 			goto finish_error;
2335258223a3SMatthew Dillon 		}
2336258223a3SMatthew Dillon 
23371980eff3SMatthew Dillon 		/*
233812feb904SMatthew Dillon 		 * If NCQ commands were active get the error slot from
233912feb904SMatthew Dillon 		 * the log page.  NCQ is not supported for PM's so this
234012feb904SMatthew Dillon 		 * is a direct-attached target.
23411980eff3SMatthew Dillon 		 *
234212feb904SMatthew Dillon 		 * Otherwise if no commands were active we have a problem.
234312feb904SMatthew Dillon 		 *
234412feb904SMatthew Dillon 		 * Otherwise if the error slot is bad we have a problem.
234512feb904SMatthew Dillon 		 *
234612feb904SMatthew Dillon 		 * Otherwise process the error for the slot.
23471980eff3SMatthew Dillon 		 */
234812feb904SMatthew Dillon 		if (ap->ap_sactive) {
234912feb904SMatthew Dillon 			err_slot = ahci_port_read_ncq_error(ap, 0);
235012feb904SMatthew Dillon 		} else if (ap->ap_active == 0) {
235112feb904SMatthew Dillon 			kprintf("%s: TFES with no commands pending\n",
235212feb904SMatthew Dillon 				PORTNAME(ap));
235312feb904SMatthew Dillon 			err_slot = -1;
235412feb904SMatthew Dillon 		} else if (err_slot < 0 || err_slot >= ap->ap_sc->sc_ncmds) {
235512feb904SMatthew Dillon 			kprintf("%s: bad error slot %d\n",
2356258223a3SMatthew Dillon 				PORTNAME(ap), err_slot);
235712feb904SMatthew Dillon 			err_slot = -1;
2358258223a3SMatthew Dillon 		} else {
235912feb904SMatthew Dillon 			ccb = &ap->ap_ccbs[err_slot];
236012feb904SMatthew Dillon 
23614c339a5fSMatthew Dillon 			/*
236212feb904SMatthew Dillon 			 * Validate the errored ccb.  Note that ccb_at can
236312feb904SMatthew Dillon 			 * be NULL for direct-attached ccb's.
236412feb904SMatthew Dillon 			 *
236512feb904SMatthew Dillon 			 * Copy received taskfile data from the RFIS.
23664c339a5fSMatthew Dillon 			 */
236712feb904SMatthew Dillon 			if (ccb->ccb_xa.state == ATA_S_ONCHIP) {
236812feb904SMatthew Dillon 				ccb_at = ccb->ccb_xa.at;
236912feb904SMatthew Dillon 				memcpy(&ccb->ccb_xa.rfis, ap->ap_rfis->rfis,
237012feb904SMatthew Dillon 				       sizeof(struct ata_fis_d2h));
237150a3ecb6SMatthew Dillon 				if (bootverbose) {
237250a3ecb6SMatthew Dillon 					kprintf("%s: Copying rfis slot %d\n",
237312feb904SMatthew Dillon 						ATANAME(ap, ccb_at), err_slot);
237450a3ecb6SMatthew Dillon 				}
237512feb904SMatthew Dillon 			} else {
237612feb904SMatthew Dillon 				kprintf("%s: Cannot copy rfis, CCB slot "
237712feb904SMatthew Dillon 					"%d is not on-chip (state=%d)\n",
237812feb904SMatthew Dillon 					ATANAME(ap, ccb->ccb_xa.at),
237912feb904SMatthew Dillon 					err_slot, ccb->ccb_xa.state);
238012feb904SMatthew Dillon 				err_slot = -1;
238112feb904SMatthew Dillon 			}
2382258223a3SMatthew Dillon 		}
2383258223a3SMatthew Dillon 
2384258223a3SMatthew Dillon 		/*
238512feb904SMatthew Dillon 		 * If we could not determine the errored slot then
238612feb904SMatthew Dillon 		 * reset the port.
2387258223a3SMatthew Dillon 		 */
238812feb904SMatthew Dillon 		if (err_slot < 0) {
238912feb904SMatthew Dillon 			kprintf("%s: TFES: Unable to determine errored slot\n",
239012feb904SMatthew Dillon 				PORTNAME(ap));
23911980eff3SMatthew Dillon 			if (ap->ap_flags & AP_F_IN_RESET)
23921980eff3SMatthew Dillon 				goto fatal;
2393258223a3SMatthew Dillon 			goto failall;
2394258223a3SMatthew Dillon 		}
2395258223a3SMatthew Dillon 
239612feb904SMatthew Dillon 		/*
239712feb904SMatthew Dillon 		 * Finish error on slot.  We will restart ci_saved
239812feb904SMatthew Dillon 		 * commands except the errored slot which we generate
239912feb904SMatthew Dillon 		 * a failure for.
240012feb904SMatthew Dillon 		 */
240112feb904SMatthew Dillon finish_error:
240212feb904SMatthew Dillon 		ccb = &ap->ap_ccbs[err_slot];
2403258223a3SMatthew Dillon 		ci_saved &= ~(1 << err_slot);
2404258223a3SMatthew Dillon 		KKASSERT(ccb->ccb_xa.state == ATA_S_ONCHIP);
2405258223a3SMatthew Dillon 		ccb->ccb_xa.state = ATA_S_ERROR;
24061980eff3SMatthew Dillon 	} else if (is & AHCI_PREG_IS_DHRS) {
24071980eff3SMatthew Dillon 		/*
2408f4553de1SMatthew Dillon 		 * Command posted D2H register FIS to the rfis (non-blocking).
2409f4553de1SMatthew Dillon 		 *
241012feb904SMatthew Dillon 		 * A normal completion with an error may set DHRS instead
241112feb904SMatthew Dillon 		 * of TFES.  The CCS bits are only valid if ERR was set.
241212feb904SMatthew Dillon 		 * If ERR is set command processing was probably stopped.
24138bf6a3ffSMatthew Dillon 		 *
241412feb904SMatthew Dillon 		 * If ERR was not set we can only copy-back data for
241512feb904SMatthew Dillon 		 * exclusive-mode commands because otherwise we won't know
241612feb904SMatthew Dillon 		 * which tag the rfis belonged to.
241712feb904SMatthew Dillon 		 *
241812feb904SMatthew Dillon 		 * err_slot must be read from the CCS before any other port
241912feb904SMatthew Dillon 		 * action, such as stopping the port.
242012feb904SMatthew Dillon 		 *
242112feb904SMatthew Dillon 		 * WARNING!	This is not well documented in the AHCI spec.
242212feb904SMatthew Dillon 		 *		It can be found in the state machine tables
242312feb904SMatthew Dillon 		 *		but not in the explanations.
24241980eff3SMatthew Dillon 		 */
242512feb904SMatthew Dillon 		u_int32_t tfd;
242612feb904SMatthew Dillon 		u_int32_t cmd;
24271980eff3SMatthew Dillon 		int err_slot;
24281980eff3SMatthew Dillon 
242912feb904SMatthew Dillon 		tfd = ahci_pread(ap, AHCI_PREG_TFD);
243012feb904SMatthew Dillon 		cmd = ahci_pread(ap, AHCI_PREG_CMD);
243112feb904SMatthew Dillon 
243212feb904SMatthew Dillon 		if ((tfd & AHCI_PREG_TFD_STS_ERR) &&
243312feb904SMatthew Dillon 		    (cmd & AHCI_PREG_CMD_CR) == 0) {
24341980eff3SMatthew Dillon 			err_slot = AHCI_PREG_CMD_CCS(
24351980eff3SMatthew Dillon 						ahci_pread(ap, AHCI_PREG_CMD));
24361980eff3SMatthew Dillon 			ccb = &ap->ap_ccbs[err_slot];
243712feb904SMatthew Dillon 			kprintf("%s: DHRS tfd=%b err_slot=%d cmd=%02x\n",
243812feb904SMatthew Dillon 				PORTNAME(ap),
243912feb904SMatthew Dillon 				tfd, AHCI_PFMT_TFD_STS,
244012feb904SMatthew Dillon 				err_slot, ccb->ccb_xa.fis->command);
244112feb904SMatthew Dillon 			goto process_error;
2442258223a3SMatthew Dillon 		}
244312feb904SMatthew Dillon 		/*
244412feb904SMatthew Dillon 		 * NO ELSE... copy back is in the normal command completion
244512feb904SMatthew Dillon 		 * code and only if no error occured and ATA_F_AUTOSENSE
244612feb904SMatthew Dillon 		 * was set.
244712feb904SMatthew Dillon 		 */
2448cec07d75SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_DHRS);
24491980eff3SMatthew Dillon 	}
24501980eff3SMatthew Dillon 
24511980eff3SMatthew Dillon 	/*
2452f4553de1SMatthew Dillon 	 * Device notification to us (non-blocking)
24531980eff3SMatthew Dillon 	 *
245412feb904SMatthew Dillon 	 * NOTE!  On some parts notification bits can cause an IPMS
245512feb904SMatthew Dillon 	 *	  interrupt instead of a SDBS interrupt.
2456cec07d75SMatthew Dillon 	 *
245712feb904SMatthew Dillon 	 * NOTE!  On some parts (e.g. VBOX, probably intel ICHx),
245812feb904SMatthew Dillon 	 *	  SDBS notifies us of the completion of a NCQ command
245912feb904SMatthew Dillon 	 *	  and DBS does not.
24601980eff3SMatthew Dillon 	 */
246112feb904SMatthew Dillon 	if (is & (AHCI_PREG_IS_SDBS | AHCI_PREG_IS_IPMS)) {
24621980eff3SMatthew Dillon 		u_int32_t data;
24631980eff3SMatthew Dillon 
246412feb904SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS,
246512feb904SMatthew Dillon 				AHCI_PREG_IS_SDBS | AHCI_PREG_IS_IPMS);
246612feb904SMatthew Dillon 		if (sc->sc_cap & AHCI_REG_CAP_SSNTF) {
24671980eff3SMatthew Dillon 			data = ahci_pread(ap, AHCI_PREG_SNTF);
2468cec07d75SMatthew Dillon 			if (data) {
246912feb904SMatthew Dillon 				ahci_pwrite(ap, AHCI_PREG_IS,
247012feb904SMatthew Dillon 						AHCI_PREG_IS_SDBS);
247112feb904SMatthew Dillon 				kprintf("%s: NOTIFY %08x\n",
247212feb904SMatthew Dillon 					PORTNAME(ap), data);
247312feb904SMatthew Dillon 				ahci_pwrite(ap, AHCI_PREG_SERR,
247412feb904SMatthew Dillon 						AHCI_PREG_SERR_DIAG_N);
24753209f581SMatthew Dillon 				ahci_pwrite(ap, AHCI_PREG_SNTF, data);
24763209f581SMatthew Dillon 				ahci_cam_changed(ap, NULL, -1);
24771980eff3SMatthew Dillon 			}
24781980eff3SMatthew Dillon 		}
247912feb904SMatthew Dillon 		is &= ~(AHCI_PREG_IS_SDBS | AHCI_PREG_IS_IPMS);
248012feb904SMatthew Dillon 	}
24813209f581SMatthew Dillon 
24823209f581SMatthew Dillon 	/*
2483f4553de1SMatthew Dillon 	 * Spurious IFS errors (blockable).
2484f4553de1SMatthew Dillon 	 *
24853209f581SMatthew Dillon 	 * Spurious IFS errors can occur while we are doing a reset
24863209f581SMatthew Dillon 	 * sequence through a PM.  Try to recover if we are being asked
24873209f581SMatthew Dillon 	 * to ignore IFS errors during these periods.
24883209f581SMatthew Dillon 	 */
24893209f581SMatthew Dillon 	if ((is & AHCI_PREG_IS_IFS) && (ap->ap_flags & AP_F_IGNORE_IFS)) {
24901980eff3SMatthew Dillon 		u_int32_t serr = ahci_pread(ap, AHCI_PREG_SERR);
24913209f581SMatthew Dillon 		if ((ap->ap_flags & AP_F_IFS_IGNORED) == 0) {
24921980eff3SMatthew Dillon 			kprintf("%s: Ignoring IFS (XXX) (IS: %b, SERR: %b)\n",
24931980eff3SMatthew Dillon 				PORTNAME(ap),
24941980eff3SMatthew Dillon 				is, AHCI_PFMT_IS,
24951980eff3SMatthew Dillon 				serr, AHCI_PFMT_SERR);
24963209f581SMatthew Dillon 			ap->ap_flags |= AP_F_IFS_IGNORED;
24973209f581SMatthew Dillon 		}
24983209f581SMatthew Dillon 		ap->ap_flags |= AP_F_IFS_OCCURED;
24991980eff3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SERR, -1);
25001980eff3SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_IFS);
25011980eff3SMatthew Dillon 		is &= ~AHCI_PREG_IS_IFS;
25021980eff3SMatthew Dillon 		ahci_port_stop(ap, 0);
25031980eff3SMatthew Dillon 		ahci_port_start(ap);
250412feb904SMatthew Dillon 		kprintf("%s: Spurious IFS error\n", PORTNAME(ap));
250512feb904SMatthew Dillon 		goto failall;
250612feb904SMatthew Dillon 		/* need = NEED_RESTART; */
25071980eff3SMatthew Dillon 	}
2508258223a3SMatthew Dillon 
2509258223a3SMatthew Dillon 	/*
2510f4553de1SMatthew Dillon 	 * Port change (hot-plug) (blockable).
2511258223a3SMatthew Dillon 	 *
2512258223a3SMatthew Dillon 	 * A PCS interrupt will occur on hot-plug once communication is
2513258223a3SMatthew Dillon 	 * established.
2514258223a3SMatthew Dillon 	 *
2515258223a3SMatthew Dillon 	 * A PRCS interrupt will occur on hot-unplug (and possibly also
2516258223a3SMatthew Dillon 	 * on hot-plug).
2517258223a3SMatthew Dillon 	 *
251822181ab7SMatthew Dillon 	 * XXX We can then check the CPS (Cold Presence State) bit, if
251922181ab7SMatthew Dillon 	 * supported, to determine if a device is plugged in or not and do
252022181ab7SMatthew Dillon 	 * the right thing.
252122181ab7SMatthew Dillon 	 *
252222181ab7SMatthew Dillon 	 * WARNING:  A PCS interrupt is cleared by clearing DIAG_X, and
252322181ab7SMatthew Dillon 	 *	     can also occur if an unsolicited COMINIT is received.
252422181ab7SMatthew Dillon 	 *	     If this occurs command processing is automatically
252522181ab7SMatthew Dillon 	 *	     stopped (CR goes inactive) and the port must be stopped
252622181ab7SMatthew Dillon 	 *	     and restarted.
2527258223a3SMatthew Dillon 	 */
2528f17a0cedSMatthew Dillon 
2529f17a0cedSMatthew Dillon 	/* ignore AHCI_PREG_IS_PRCS when link power management is on */
2530f17a0cedSMatthew Dillon 	if (ap->link_pwr_mgmt != AHCI_LINK_PWR_MGMT_NONE) {
2531f17a0cedSMatthew Dillon 		is &= ~AHCI_PREG_IS_PRCS;
2532f17a0cedSMatthew Dillon 	}
2533f17a0cedSMatthew Dillon 
2534258223a3SMatthew Dillon 	if (is & (AHCI_PREG_IS_PCS | AHCI_PREG_IS_PRCS)) {
253512feb904SMatthew Dillon 		kprintf("%s: Transient Errors: %b\n",
253612feb904SMatthew Dillon 			PORTNAME(ap), is, AHCI_PFMT_IS);
253712feb904SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_SERR,
253812feb904SMatthew Dillon 			(AHCI_PREG_SERR_DIAG_N | AHCI_PREG_SERR_DIAG_X));
2539cec07d75SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS,
2540cec07d75SMatthew Dillon 			    is & (AHCI_PREG_IS_PCS | AHCI_PREG_IS_PRCS));
2541cec07d75SMatthew Dillon 		is &= ~(AHCI_PREG_IS_PCS | AHCI_PREG_IS_PRCS);
254222181ab7SMatthew Dillon 		ahci_port_stop(ap, 0);
25430be9576aSMatthew Dillon 
2544258223a3SMatthew Dillon 		switch (ahci_pread(ap, AHCI_PREG_SSTS) & AHCI_PREG_SSTS_DET) {
2545258223a3SMatthew Dillon 		case AHCI_PREG_SSTS_DET_DEV:
254612feb904SMatthew Dillon 			if (ap->ap_probe == ATA_PROBE_FAILED) {
254722181ab7SMatthew Dillon 				need = NEED_HOTPLUG_INSERT;
254822181ab7SMatthew Dillon 				goto fatal;
2549258223a3SMatthew Dillon 			}
255022181ab7SMatthew Dillon 			need = NEED_RESTART;
2551258223a3SMatthew Dillon 			break;
2552258223a3SMatthew Dillon 		default:
25530be9576aSMatthew Dillon 			if (ap->ap_probe != ATA_PROBE_FAILED) {
255422181ab7SMatthew Dillon 				need = NEED_HOTPLUG_REMOVE;
255522181ab7SMatthew Dillon 				goto fatal;
2556258223a3SMatthew Dillon 			}
255722181ab7SMatthew Dillon 			need = NEED_RESTART;
2558258223a3SMatthew Dillon 			break;
2559258223a3SMatthew Dillon 		}
2560258223a3SMatthew Dillon 	}
2561258223a3SMatthew Dillon 
256222181ab7SMatthew Dillon 	/*
2563f4553de1SMatthew Dillon 	 * Check for remaining errors - they are fatal. (blockable)
256422181ab7SMatthew Dillon 	 */
2565258223a3SMatthew Dillon 	if (is & (AHCI_PREG_IS_TFES | AHCI_PREG_IS_HBFS | AHCI_PREG_IS_IFS |
2566258223a3SMatthew Dillon 		  AHCI_PREG_IS_OFS | AHCI_PREG_IS_UFS)) {
2567cec07d75SMatthew Dillon 		u_int32_t serr;
2568cec07d75SMatthew Dillon 
2569cec07d75SMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_IS,
2570cec07d75SMatthew Dillon 			    is & (AHCI_PREG_IS_TFES | AHCI_PREG_IS_HBFS |
2571cec07d75SMatthew Dillon 				  AHCI_PREG_IS_IFS | AHCI_PREG_IS_OFS |
2572cec07d75SMatthew Dillon 				  AHCI_PREG_IS_UFS));
2573cec07d75SMatthew Dillon 		serr = ahci_pread(ap, AHCI_PREG_SERR);
2574831bc9e3SMatthew Dillon 		kprintf("%s: Unrecoverable errors (IS: %b, SERR: %b), "
25754444122dSMatthew Dillon 			"disabling port.\n",
25764444122dSMatthew Dillon 			PORTNAME(ap),
25774444122dSMatthew Dillon 			is, AHCI_PFMT_IS,
25781980eff3SMatthew Dillon 			serr, AHCI_PFMT_SERR
25794444122dSMatthew Dillon 		);
2580831bc9e3SMatthew Dillon 		is &= ~(AHCI_PREG_IS_TFES | AHCI_PREG_IS_HBFS |
2581831bc9e3SMatthew Dillon 			AHCI_PREG_IS_IFS | AHCI_PREG_IS_OFS |
2582831bc9e3SMatthew Dillon 		        AHCI_PREG_IS_UFS);
2583258223a3SMatthew Dillon 		/* XXX try recovery first */
2584258223a3SMatthew Dillon 		goto fatal;
2585258223a3SMatthew Dillon 	}
2586258223a3SMatthew Dillon 
258722181ab7SMatthew Dillon 	/*
258822181ab7SMatthew Dillon 	 * Fail all outstanding commands if we know the port won't recover.
25891980eff3SMatthew Dillon 	 *
25901980eff3SMatthew Dillon 	 * We may have a ccb_at if the failed command is known and was
25911980eff3SMatthew Dillon 	 * being sent to a device over a port multiplier (PM).  In this
25921980eff3SMatthew Dillon 	 * case if the port itself has not completely failed we fail just
25931980eff3SMatthew Dillon 	 * the commands related to that target.
259412feb904SMatthew Dillon 	 *
259512feb904SMatthew Dillon 	 * ci_saved contains the mask of active commands as of when the
259612feb904SMatthew Dillon 	 * error occured, prior to any port stops.
259722181ab7SMatthew Dillon 	 */
2598258223a3SMatthew Dillon 	if (ap->ap_state == AP_S_FATAL_ERROR) {
2599258223a3SMatthew Dillon fatal:
2600258223a3SMatthew Dillon 		ap->ap_state = AP_S_FATAL_ERROR;
2601cf5f3a81SMatthew Dillon 		ahci_port_stop(ap, 0);
260212feb904SMatthew Dillon failall:
260312feb904SMatthew Dillon 		kprintf("%s: Failing all commands\n", PORTNAME(ap));
2604258223a3SMatthew Dillon 
26051980eff3SMatthew Dillon 		/*
260612feb904SMatthew Dillon 		 * Error all the active slots not already errored.  If
260712feb904SMatthew Dillon 		 * running across a PM try to error out just the slots
260812feb904SMatthew Dillon 		 * related to the target.
26091980eff3SMatthew Dillon 		 */
261012feb904SMatthew Dillon 		ci_masked = ci_saved & *active & ~ap->ap_expired;
2611258223a3SMatthew Dillon 		while (ci_masked) {
2612258223a3SMatthew Dillon 			slot = ffs(ci_masked) - 1;
2613258223a3SMatthew Dillon 			ccb = &ap->ap_ccbs[slot];
26141980eff3SMatthew Dillon 			if (ccb_at == ccb->ccb_xa.at ||
26151980eff3SMatthew Dillon 			    ap->ap_state == AP_S_FATAL_ERROR) {
261612feb904SMatthew Dillon 				ccb->ccb_xa.state = ATA_S_TIMEOUT;
261712feb904SMatthew Dillon 				ap->ap_expired |= 1 << slot;
261812feb904SMatthew Dillon 				ci_saved &= ~(1 << slot);
2619258223a3SMatthew Dillon 			}
262012feb904SMatthew Dillon 			ci_masked &= ~(1 << slot);
26211980eff3SMatthew Dillon 		}
2622258223a3SMatthew Dillon 
262312feb904SMatthew Dillon 		/*
262412feb904SMatthew Dillon 		 * Clear bits in ci_saved (cause completions to be run)
262512feb904SMatthew Dillon 		 * for all slots which are not active.
262612feb904SMatthew Dillon 		 */
2627258223a3SMatthew Dillon 		ci_saved &= ~*active;
2628258223a3SMatthew Dillon 
2629258223a3SMatthew Dillon 		/*
2630258223a3SMatthew Dillon 		 * Don't restart the port if our problems were deemed fatal.
2631258223a3SMatthew Dillon 		 *
2632258223a3SMatthew Dillon 		 * Also acknowlege all fatal interrupt sources to prevent
2633258223a3SMatthew Dillon 		 * a livelock.
2634258223a3SMatthew Dillon 		 */
2635258223a3SMatthew Dillon 		if (ap->ap_state == AP_S_FATAL_ERROR) {
263622181ab7SMatthew Dillon 			if (need == NEED_RESTART)
263722181ab7SMatthew Dillon 				need = NEED_NOTHING;
2638258223a3SMatthew Dillon 			ahci_pwrite(ap, AHCI_PREG_IS,
2639258223a3SMatthew Dillon 				    AHCI_PREG_IS_TFES | AHCI_PREG_IS_HBFS |
2640258223a3SMatthew Dillon 				    AHCI_PREG_IS_IFS | AHCI_PREG_IS_OFS |
2641258223a3SMatthew Dillon 				    AHCI_PREG_IS_UFS);
2642258223a3SMatthew Dillon 		}
2643258223a3SMatthew Dillon 	}
2644258223a3SMatthew Dillon 
2645258223a3SMatthew Dillon 	/*
2646f4553de1SMatthew Dillon 	 * CCB completion (non blocking).
2647f4553de1SMatthew Dillon 	 *
2648258223a3SMatthew Dillon 	 * CCB completion is detected by noticing its slot's bit in CI has
2649258223a3SMatthew Dillon 	 * changed to zero some time after we activated it.
2650258223a3SMatthew Dillon 	 * If we are polling, we may only be interested in particular slot(s).
2651cf5f3a81SMatthew Dillon 	 *
2652cf5f3a81SMatthew Dillon 	 * Any active bits not saved are completed within the restrictions
2653cf5f3a81SMatthew Dillon 	 * imposed by the caller.
2654258223a3SMatthew Dillon 	 */
26553209f581SMatthew Dillon 	ci_masked = ~ci_saved & *active;
2656258223a3SMatthew Dillon 	while (ci_masked) {
2657258223a3SMatthew Dillon 		slot = ffs(ci_masked) - 1;
2658258223a3SMatthew Dillon 		ccb = &ap->ap_ccbs[slot];
2659258223a3SMatthew Dillon 		ci_masked &= ~(1 << slot);
2660258223a3SMatthew Dillon 
2661258223a3SMatthew Dillon 		DPRINTF(AHCI_D_INTR, "%s: slot %d is complete%s\n",
2662258223a3SMatthew Dillon 		    PORTNAME(ap), slot, ccb->ccb_xa.state == ATA_S_ERROR ?
2663258223a3SMatthew Dillon 		    " (error)" : "");
2664258223a3SMatthew Dillon 
2665258223a3SMatthew Dillon 		bus_dmamap_sync(sc->sc_tag_cmdh,
2666258223a3SMatthew Dillon 				AHCI_DMA_MAP(ap->ap_dmamem_cmd_list),
2667258223a3SMatthew Dillon 				BUS_DMASYNC_POSTWRITE);
2668258223a3SMatthew Dillon 
2669258223a3SMatthew Dillon 		bus_dmamap_sync(sc->sc_tag_cmdt,
2670258223a3SMatthew Dillon 				AHCI_DMA_MAP(ap->ap_dmamem_cmd_table),
2671258223a3SMatthew Dillon 				BUS_DMASYNC_POSTWRITE);
2672258223a3SMatthew Dillon 
2673258223a3SMatthew Dillon 		bus_dmamap_sync(sc->sc_tag_rfis,
2674258223a3SMatthew Dillon 				AHCI_DMA_MAP(ap->ap_dmamem_rfis),
2675258223a3SMatthew Dillon 				BUS_DMASYNC_POSTREAD);
2676258223a3SMatthew Dillon 
2677258223a3SMatthew Dillon 		*active &= ~(1 << ccb->ccb_slot);
26781980eff3SMatthew Dillon 		if (active == &ap->ap_active) {
26791980eff3SMatthew Dillon 			KKASSERT(ap->ap_active_cnt > 0);
26801980eff3SMatthew Dillon 			--ap->ap_active_cnt;
26811980eff3SMatthew Dillon 		}
26824c339a5fSMatthew Dillon 
26834c339a5fSMatthew Dillon 		/*
26844c339a5fSMatthew Dillon 		 * Complete the ccb.  If the ccb was marked expired it
26854c339a5fSMatthew Dillon 		 * was probably already removed from the command processor,
26864c339a5fSMatthew Dillon 		 * so don't take the clear ci_saved bit as meaning the
26874c339a5fSMatthew Dillon 		 * command actually succeeded, it didn't.
26884c339a5fSMatthew Dillon 		 */
26894c339a5fSMatthew Dillon 		if (ap->ap_expired & (1 << ccb->ccb_slot)) {
269076497a9cSMatthew Dillon 			ap->ap_expired &= ~(1 << ccb->ccb_slot);
26914c339a5fSMatthew Dillon 			ccb->ccb_xa.state = ATA_S_TIMEOUT;
2692258223a3SMatthew Dillon 			ccb->ccb_done(ccb);
26934c339a5fSMatthew Dillon 			ccb->ccb_xa.complete(&ccb->ccb_xa);
26944c339a5fSMatthew Dillon 		} else {
269512feb904SMatthew Dillon 			if (ccb->ccb_xa.state == ATA_S_ONCHIP) {
26964c339a5fSMatthew Dillon 				ccb->ccb_xa.state = ATA_S_COMPLETE;
269712feb904SMatthew Dillon 				if (ccb->ccb_xa.flags & ATA_F_AUTOSENSE) {
269812feb904SMatthew Dillon 					memcpy(&ccb->ccb_xa.rfis,
269912feb904SMatthew Dillon 					    ap->ap_rfis->rfis,
270012feb904SMatthew Dillon 					    sizeof(struct ata_fis_d2h));
270112feb904SMatthew Dillon 					if (ccb->ccb_xa.state == ATA_S_TIMEOUT)
270212feb904SMatthew Dillon 						ccb->ccb_xa.state = ATA_S_ERROR;
270312feb904SMatthew Dillon 				}
270412feb904SMatthew Dillon 			}
27054c339a5fSMatthew Dillon 			ccb->ccb_done(ccb);
27064c339a5fSMatthew Dillon 		}
2707258223a3SMatthew Dillon 	}
270812feb904SMatthew Dillon 	ahci_issue_pending_commands(ap, NULL);
2709258223a3SMatthew Dillon 
2710f4553de1SMatthew Dillon 	/*
2711f4553de1SMatthew Dillon 	 * Cleanup.  Will not be set if non-blocking.
2712f4553de1SMatthew Dillon 	 */
271322181ab7SMatthew Dillon 	switch(need) {
271422181ab7SMatthew Dillon 	case NEED_RESTART:
271522181ab7SMatthew Dillon 		/*
271622181ab7SMatthew Dillon 		 * A recoverable error occured and we can restart outstanding
271722181ab7SMatthew Dillon 		 * commands on the port.
271822181ab7SMatthew Dillon 		 */
271912feb904SMatthew Dillon 		ci_saved &= ~ap->ap_expired;
2720258223a3SMatthew Dillon 		if (ci_saved) {
272112feb904SMatthew Dillon 			kprintf("%s: Restart %08x\n", PORTNAME(ap), ci_saved);
27224c339a5fSMatthew Dillon 			ahci_issue_saved_commands(ap, ci_saved);
2723258223a3SMatthew Dillon 		}
272422181ab7SMatthew Dillon 		break;
272522181ab7SMatthew Dillon 	case NEED_HOTPLUG_INSERT:
272622181ab7SMatthew Dillon 		/*
2727cf5f3a81SMatthew Dillon 		 * A hot-plug insertion event has occured and all
2728cf5f3a81SMatthew Dillon 		 * outstanding commands have already been revoked.
27291980eff3SMatthew Dillon 		 *
27301980eff3SMatthew Dillon 		 * Don't recurse if this occurs while we are
27311980eff3SMatthew Dillon 		 * resetting the port.
273222181ab7SMatthew Dillon 		 */
27331980eff3SMatthew Dillon 		if ((ap->ap_flags & AP_F_IN_RESET) == 0) {
273422181ab7SMatthew Dillon 			kprintf("%s: HOTPLUG - Device inserted\n",
273522181ab7SMatthew Dillon 				PORTNAME(ap));
27363209f581SMatthew Dillon 			ap->ap_probe = ATA_PROBE_NEED_INIT;
27373209f581SMatthew Dillon 			ahci_cam_changed(ap, NULL, -1);
27381980eff3SMatthew Dillon 		}
273922181ab7SMatthew Dillon 		break;
274022181ab7SMatthew Dillon 	case NEED_HOTPLUG_REMOVE:
2741cf5f3a81SMatthew Dillon 		/*
2742cf5f3a81SMatthew Dillon 		 * A hot-plug removal event has occured and all
2743cf5f3a81SMatthew Dillon 		 * outstanding commands have already been revoked.
27441980eff3SMatthew Dillon 		 *
27451980eff3SMatthew Dillon 		 * Don't recurse if this occurs while we are
27461980eff3SMatthew Dillon 		 * resetting the port.
2747cf5f3a81SMatthew Dillon 		 */
27481980eff3SMatthew Dillon 		if ((ap->ap_flags & AP_F_IN_RESET) == 0) {
274922181ab7SMatthew Dillon 			kprintf("%s: HOTPLUG - Device removed\n",
275022181ab7SMatthew Dillon 				PORTNAME(ap));
2751cf5f3a81SMatthew Dillon 			ahci_port_hardstop(ap);
27523209f581SMatthew Dillon 			/* ap_probe set to failed */
27533209f581SMatthew Dillon 			ahci_cam_changed(ap, NULL, -1);
27541980eff3SMatthew Dillon 		}
275522181ab7SMatthew Dillon 		break;
275622181ab7SMatthew Dillon 	default:
275722181ab7SMatthew Dillon 		break;
2758258223a3SMatthew Dillon 	}
2759258223a3SMatthew Dillon }
2760258223a3SMatthew Dillon 
2761258223a3SMatthew Dillon struct ahci_ccb *
2762258223a3SMatthew Dillon ahci_get_ccb(struct ahci_port *ap)
2763258223a3SMatthew Dillon {
2764258223a3SMatthew Dillon 	struct ahci_ccb			*ccb;
2765258223a3SMatthew Dillon 
2766258223a3SMatthew Dillon 	lockmgr(&ap->ap_ccb_lock, LK_EXCLUSIVE);
2767258223a3SMatthew Dillon 	ccb = TAILQ_FIRST(&ap->ap_ccb_free);
2768258223a3SMatthew Dillon 	if (ccb != NULL) {
2769258223a3SMatthew Dillon 		KKASSERT(ccb->ccb_xa.state == ATA_S_PUT);
2770258223a3SMatthew Dillon 		TAILQ_REMOVE(&ap->ap_ccb_free, ccb, ccb_entry);
2771258223a3SMatthew Dillon 		ccb->ccb_xa.state = ATA_S_SETUP;
27721980eff3SMatthew Dillon 		ccb->ccb_xa.at = NULL;
2773258223a3SMatthew Dillon 	}
2774258223a3SMatthew Dillon 	lockmgr(&ap->ap_ccb_lock, LK_RELEASE);
2775258223a3SMatthew Dillon 
2776258223a3SMatthew Dillon 	return (ccb);
2777258223a3SMatthew Dillon }
2778258223a3SMatthew Dillon 
2779258223a3SMatthew Dillon void
2780258223a3SMatthew Dillon ahci_put_ccb(struct ahci_ccb *ccb)
2781258223a3SMatthew Dillon {
2782258223a3SMatthew Dillon 	struct ahci_port		*ap = ccb->ccb_port;
2783258223a3SMatthew Dillon 
2784258223a3SMatthew Dillon 	ccb->ccb_xa.state = ATA_S_PUT;
2785258223a3SMatthew Dillon 	lockmgr(&ap->ap_ccb_lock, LK_EXCLUSIVE);
2786258223a3SMatthew Dillon 	TAILQ_INSERT_TAIL(&ap->ap_ccb_free, ccb, ccb_entry);
2787258223a3SMatthew Dillon 	lockmgr(&ap->ap_ccb_lock, LK_RELEASE);
2788258223a3SMatthew Dillon }
2789258223a3SMatthew Dillon 
2790258223a3SMatthew Dillon struct ahci_ccb *
2791258223a3SMatthew Dillon ahci_get_err_ccb(struct ahci_port *ap)
2792258223a3SMatthew Dillon {
2793258223a3SMatthew Dillon 	struct ahci_ccb *err_ccb;
2794258223a3SMatthew Dillon 	u_int32_t sact;
2795b012a2caSMatthew Dillon 	u_int32_t ci;
2796258223a3SMatthew Dillon 
2797258223a3SMatthew Dillon 	/* No commands may be active on the chip. */
2798b012a2caSMatthew Dillon 
2799b012a2caSMatthew Dillon 	if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SNCQ) {
2800258223a3SMatthew Dillon 		sact = ahci_pread(ap, AHCI_PREG_SACT);
2801192ee1d0SMatthew Dillon 		if (sact != 0) {
2802192ee1d0SMatthew Dillon 			kprintf("%s: ahci_get_err_ccb but SACT %08x != 0?\n",
2803192ee1d0SMatthew Dillon 				PORTNAME(ap), sact);
2804192ee1d0SMatthew Dillon 		}
2805b012a2caSMatthew Dillon 	}
2806b012a2caSMatthew Dillon 	ci = ahci_pread(ap, AHCI_PREG_CI);
2807b012a2caSMatthew Dillon 	if (ci) {
2808b012a2caSMatthew Dillon 		kprintf("%s: ahci_get_err_ccb: ci not 0 (%08x)\n",
2809b012a2caSMatthew Dillon 			ap->ap_name, ci);
2810b012a2caSMatthew Dillon 	}
2811b012a2caSMatthew Dillon 	KKASSERT(ci == 0);
2812baef7501SMatthew Dillon 	KKASSERT((ap->ap_flags & AP_F_ERR_CCB_RESERVED) == 0);
2813baef7501SMatthew Dillon 	ap->ap_flags |= AP_F_ERR_CCB_RESERVED;
2814258223a3SMatthew Dillon 
2815258223a3SMatthew Dillon 	/* Save outstanding command state. */
2816258223a3SMatthew Dillon 	ap->ap_err_saved_active = ap->ap_active;
2817258223a3SMatthew Dillon 	ap->ap_err_saved_active_cnt = ap->ap_active_cnt;
2818258223a3SMatthew Dillon 	ap->ap_err_saved_sactive = ap->ap_sactive;
2819258223a3SMatthew Dillon 
2820258223a3SMatthew Dillon 	/*
2821258223a3SMatthew Dillon 	 * Pretend we have no commands outstanding, so that completions won't
2822258223a3SMatthew Dillon 	 * run prematurely.
2823258223a3SMatthew Dillon 	 */
2824258223a3SMatthew Dillon 	ap->ap_active = ap->ap_active_cnt = ap->ap_sactive = 0;
2825258223a3SMatthew Dillon 
2826258223a3SMatthew Dillon 	/*
2827258223a3SMatthew Dillon 	 * Grab a CCB to use for error recovery.  This should never fail, as
2828258223a3SMatthew Dillon 	 * we ask atascsi to reserve one for us at init time.
2829258223a3SMatthew Dillon 	 */
28301067474aSMatthew Dillon 	err_ccb = ap->ap_err_ccb;
2831258223a3SMatthew Dillon 	KKASSERT(err_ccb != NULL);
2832258223a3SMatthew Dillon 	err_ccb->ccb_xa.flags = 0;
2833258223a3SMatthew Dillon 	err_ccb->ccb_done = ahci_empty_done;
2834258223a3SMatthew Dillon 
2835258223a3SMatthew Dillon 	return err_ccb;
2836258223a3SMatthew Dillon }
2837258223a3SMatthew Dillon 
2838258223a3SMatthew Dillon void
2839258223a3SMatthew Dillon ahci_put_err_ccb(struct ahci_ccb *ccb)
2840258223a3SMatthew Dillon {
2841258223a3SMatthew Dillon 	struct ahci_port *ap = ccb->ccb_port;
2842258223a3SMatthew Dillon 	u_int32_t sact;
28435f8c1efdSMatthew Dillon 	u_int32_t ci;
2844258223a3SMatthew Dillon 
2845baef7501SMatthew Dillon 	KKASSERT((ap->ap_flags & AP_F_ERR_CCB_RESERVED) != 0);
2846baef7501SMatthew Dillon 
28475f8c1efdSMatthew Dillon 	/*
28485f8c1efdSMatthew Dillon 	 * No commands may be active on the chip
28495f8c1efdSMatthew Dillon 	 */
2850b012a2caSMatthew Dillon 	if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SNCQ) {
2851258223a3SMatthew Dillon 		sact = ahci_pread(ap, AHCI_PREG_SACT);
28525f8c1efdSMatthew Dillon 		if (sact) {
28535f8c1efdSMatthew Dillon 			panic("ahci_port_err_ccb(%d) but SACT %08x != 0\n",
28545f8c1efdSMatthew Dillon 			      ccb->ccb_slot, sact);
2855258223a3SMatthew Dillon 		}
2856b012a2caSMatthew Dillon 	}
28575f8c1efdSMatthew Dillon 	ci = ahci_pread(ap, AHCI_PREG_CI);
28585f8c1efdSMatthew Dillon 	if (ci) {
2859cf5f3a81SMatthew Dillon 		panic("ahci_put_err_ccb(%d) but CI %08x != 0 "
2860cf5f3a81SMatthew Dillon 		      "(act=%08x sact=%08x)\n",
2861cf5f3a81SMatthew Dillon 		      ccb->ccb_slot, ci,
2862cf5f3a81SMatthew Dillon 		      ap->ap_active, ap->ap_sactive);
28635f8c1efdSMatthew Dillon 	}
2864258223a3SMatthew Dillon 
28651067474aSMatthew Dillon 	KKASSERT(ccb == ap->ap_err_ccb);
2866258223a3SMatthew Dillon 
2867258223a3SMatthew Dillon 	/* Restore outstanding command state */
2868258223a3SMatthew Dillon 	ap->ap_sactive = ap->ap_err_saved_sactive;
2869258223a3SMatthew Dillon 	ap->ap_active_cnt = ap->ap_err_saved_active_cnt;
2870258223a3SMatthew Dillon 	ap->ap_active = ap->ap_err_saved_active;
2871258223a3SMatthew Dillon 
2872baef7501SMatthew Dillon 	ap->ap_flags &= ~AP_F_ERR_CCB_RESERVED;
2873258223a3SMatthew Dillon }
2874258223a3SMatthew Dillon 
28751980eff3SMatthew Dillon /*
28761980eff3SMatthew Dillon  * Read log page to get NCQ error.
28771980eff3SMatthew Dillon  *
28781980eff3SMatthew Dillon  * NOTE: NCQ not currently supported on port multipliers. XXX
28791980eff3SMatthew Dillon  */
2880258223a3SMatthew Dillon int
288112feb904SMatthew Dillon ahci_port_read_ncq_error(struct ahci_port *ap, int target)
2882258223a3SMatthew Dillon {
288312feb904SMatthew Dillon 	struct ata_log_page_10h	*log;
2884258223a3SMatthew Dillon 	struct ahci_ccb		*ccb;
2885258223a3SMatthew Dillon 	struct ahci_cmd_hdr	*cmd_slot;
2886258223a3SMatthew Dillon 	struct ata_fis_h2d	*fis;
288712feb904SMatthew Dillon 	int			err_slot;
2888258223a3SMatthew Dillon 
288912feb904SMatthew Dillon 	if (bootverbose) {
289012feb904SMatthew Dillon 		kprintf("%s: READ LOG PAGE target %d\n", PORTNAME(ap),
289112feb904SMatthew Dillon 			target);
289212feb904SMatthew Dillon 	}
2893258223a3SMatthew Dillon 
289412feb904SMatthew Dillon 	/*
289512feb904SMatthew Dillon 	 * Prep error CCB for READ LOG EXT, page 10h, 1 sector.
289612feb904SMatthew Dillon 	 *
289712feb904SMatthew Dillon 	 * Getting err_ccb clears active/sactive/active_cnt, putting
289812feb904SMatthew Dillon 	 * it back restores the fields.
289912feb904SMatthew Dillon 	 */
2900258223a3SMatthew Dillon 	ccb = ahci_get_err_ccb(ap);
290112feb904SMatthew Dillon 	ccb->ccb_xa.flags = ATA_F_READ | ATA_F_POLL;
2902258223a3SMatthew Dillon 	ccb->ccb_xa.data = ap->ap_err_scratch;
2903258223a3SMatthew Dillon 	ccb->ccb_xa.datalen = 512;
290412feb904SMatthew Dillon 	ccb->ccb_xa.complete = ahci_dummy_done;
2905b012a2caSMatthew Dillon 	ccb->ccb_xa.at = ap->ap_ata[target];
2906258223a3SMatthew Dillon 
2907258223a3SMatthew Dillon 	fis = (struct ata_fis_h2d *)ccb->ccb_cmd_table->cfis;
290812feb904SMatthew Dillon 	bzero(fis, sizeof(*fis));
2909258223a3SMatthew Dillon 	fis->type = ATA_FIS_TYPE_H2D;
291012feb904SMatthew Dillon 	fis->flags = ATA_H2D_FLAGS_CMD | target;
2911258223a3SMatthew Dillon 	fis->command = ATA_C_READ_LOG_EXT;
2912258223a3SMatthew Dillon 	fis->lba_low = 0x10;		/* queued error log page (10h) */
2913258223a3SMatthew Dillon 	fis->sector_count = 1;		/* number of sectors (1) */
2914258223a3SMatthew Dillon 	fis->sector_count_exp = 0;
2915258223a3SMatthew Dillon 	fis->lba_mid = 0;		/* starting offset */
2916258223a3SMatthew Dillon 	fis->lba_mid_exp = 0;
2917258223a3SMatthew Dillon 	fis->device = 0;
2918258223a3SMatthew Dillon 
291912feb904SMatthew Dillon 	cmd_slot = ccb->ccb_cmd_hdr;
2920258223a3SMatthew Dillon 	cmd_slot->flags = htole16(5);	/* FIS length: 5 DWORDS */
2921258223a3SMatthew Dillon 
2922258223a3SMatthew Dillon 	if (ahci_load_prdt(ccb) != 0) {
292312feb904SMatthew Dillon 		err_slot = -1;
2924258223a3SMatthew Dillon 		goto err;
2925258223a3SMatthew Dillon 	}
2926258223a3SMatthew Dillon 
2927258223a3SMatthew Dillon 	ccb->ccb_xa.state = ATA_S_PENDING;
292812feb904SMatthew Dillon 	if (ahci_poll(ccb, 1000, ahci_quick_timeout) != ATA_S_COMPLETE) {
292912feb904SMatthew Dillon 		err_slot = -1;
2930258223a3SMatthew Dillon 		ahci_unload_prdt(ccb);
293112feb904SMatthew Dillon 		goto err;
293212feb904SMatthew Dillon 	}
293312feb904SMatthew Dillon 	ahci_unload_prdt(ccb);
2934258223a3SMatthew Dillon 
293512feb904SMatthew Dillon 	/*
293612feb904SMatthew Dillon 	 * Success, extract failed register set and tags from the scratch
293712feb904SMatthew Dillon 	 * space.
293812feb904SMatthew Dillon 	 */
2939258223a3SMatthew Dillon 	log = (struct ata_log_page_10h *)ap->ap_err_scratch;
2940258223a3SMatthew Dillon 	if (log->err_regs.type & ATA_LOG_10H_TYPE_NOTQUEUED) {
2941258223a3SMatthew Dillon 		/* Not queued bit was set - wasn't an NCQ error? */
294212feb904SMatthew Dillon 		kprintf("%s: read NCQ error page, but not an NCQ error?\n",
2943258223a3SMatthew Dillon 			PORTNAME(ap));
294412feb904SMatthew Dillon 		err_slot = -1;
2945258223a3SMatthew Dillon 	} else {
2946258223a3SMatthew Dillon 		/* Copy back the log record as a D2H register FIS. */
294712feb904SMatthew Dillon 		err_slot = log->err_regs.type & ATA_LOG_10H_TYPE_TAG_MASK;
2948258223a3SMatthew Dillon 
2949258223a3SMatthew Dillon 		ccb = &ap->ap_ccbs[err_slot];
295012feb904SMatthew Dillon 		if (ccb->ccb_xa.state == ATA_S_ONCHIP) {
295112feb904SMatthew Dillon 			kprintf("%s: read NCQ error page slot=%d\n",
295212feb904SMatthew Dillon 				ATANAME(ap, ccb->ccb_xa.at),
295312feb904SMatthew Dillon 				err_slot);
2954258223a3SMatthew Dillon 			memcpy(&ccb->ccb_xa.rfis, &log->err_regs,
2955258223a3SMatthew Dillon 				sizeof(struct ata_fis_d2h));
2956258223a3SMatthew Dillon 			ccb->ccb_xa.rfis.type = ATA_FIS_TYPE_D2H;
2957258223a3SMatthew Dillon 			ccb->ccb_xa.rfis.flags = 0;
295812feb904SMatthew Dillon 		} else {
295912feb904SMatthew Dillon 			kprintf("%s: read NCQ error page slot=%d, "
296012feb904SMatthew Dillon 				"slot does not match any cmds\n",
296112feb904SMatthew Dillon 				ATANAME(ccb->ccb_port, ccb->ccb_xa.at),
296212feb904SMatthew Dillon 				err_slot);
296312feb904SMatthew Dillon 			err_slot = -1;
2964258223a3SMatthew Dillon 		}
2965258223a3SMatthew Dillon 	}
296612feb904SMatthew Dillon err:
296712feb904SMatthew Dillon 	ahci_put_err_ccb(ccb);
296812feb904SMatthew Dillon 	kprintf("%s: DONE log page target %d err_slot=%d\n",
296912feb904SMatthew Dillon 		PORTNAME(ap), target, err_slot);
297012feb904SMatthew Dillon 	return (err_slot);
2971258223a3SMatthew Dillon }
2972258223a3SMatthew Dillon 
2973258223a3SMatthew Dillon /*
2974258223a3SMatthew Dillon  * Allocate memory for various structures DMAd by hardware.  The maximum
2975258223a3SMatthew Dillon  * number of segments for these tags is 1 so the DMA memory will have a
2976258223a3SMatthew Dillon  * single physical base address.
2977258223a3SMatthew Dillon  */
2978258223a3SMatthew Dillon struct ahci_dmamem *
2979258223a3SMatthew Dillon ahci_dmamem_alloc(struct ahci_softc *sc, bus_dma_tag_t tag)
2980258223a3SMatthew Dillon {
2981258223a3SMatthew Dillon 	struct ahci_dmamem *adm;
2982258223a3SMatthew Dillon 	int	error;
2983258223a3SMatthew Dillon 
2984258223a3SMatthew Dillon 	adm = kmalloc(sizeof(*adm), M_DEVBUF, M_INTWAIT | M_ZERO);
2985258223a3SMatthew Dillon 
2986258223a3SMatthew Dillon 	error = bus_dmamem_alloc(tag, (void **)&adm->adm_kva,
2987258223a3SMatthew Dillon 				 BUS_DMA_ZERO, &adm->adm_map);
2988258223a3SMatthew Dillon 	if (error == 0) {
2989258223a3SMatthew Dillon 		adm->adm_tag = tag;
2990258223a3SMatthew Dillon 		error = bus_dmamap_load(tag, adm->adm_map,
2991258223a3SMatthew Dillon 					adm->adm_kva,
2992258223a3SMatthew Dillon 					bus_dma_tag_getmaxsize(tag),
2993258223a3SMatthew Dillon 					ahci_dmamem_saveseg, &adm->adm_busaddr,
2994258223a3SMatthew Dillon 					0);
2995258223a3SMatthew Dillon 	}
2996258223a3SMatthew Dillon 	if (error) {
2997258223a3SMatthew Dillon 		if (adm->adm_map) {
2998258223a3SMatthew Dillon 			bus_dmamap_destroy(tag, adm->adm_map);
2999258223a3SMatthew Dillon 			adm->adm_map = NULL;
3000258223a3SMatthew Dillon 			adm->adm_tag = NULL;
3001258223a3SMatthew Dillon 			adm->adm_kva = NULL;
3002258223a3SMatthew Dillon 		}
3003258223a3SMatthew Dillon 		kfree(adm, M_DEVBUF);
3004258223a3SMatthew Dillon 		adm = NULL;
3005258223a3SMatthew Dillon 	}
3006258223a3SMatthew Dillon 	return (adm);
3007258223a3SMatthew Dillon }
3008258223a3SMatthew Dillon 
3009258223a3SMatthew Dillon static
3010258223a3SMatthew Dillon void
3011258223a3SMatthew Dillon ahci_dmamem_saveseg(void *info, bus_dma_segment_t *segs, int nsegs, int error)
3012258223a3SMatthew Dillon {
3013258223a3SMatthew Dillon 	KKASSERT(error == 0);
3014258223a3SMatthew Dillon 	KKASSERT(nsegs == 1);
3015258223a3SMatthew Dillon 	*(bus_addr_t *)info = segs->ds_addr;
3016258223a3SMatthew Dillon }
3017258223a3SMatthew Dillon 
3018258223a3SMatthew Dillon 
3019258223a3SMatthew Dillon void
3020258223a3SMatthew Dillon ahci_dmamem_free(struct ahci_softc *sc, struct ahci_dmamem *adm)
3021258223a3SMatthew Dillon {
3022258223a3SMatthew Dillon 	if (adm->adm_map) {
3023258223a3SMatthew Dillon 		bus_dmamap_unload(adm->adm_tag, adm->adm_map);
3024258223a3SMatthew Dillon 		bus_dmamap_destroy(adm->adm_tag, adm->adm_map);
3025258223a3SMatthew Dillon 		adm->adm_map = NULL;
3026258223a3SMatthew Dillon 		adm->adm_tag = NULL;
3027258223a3SMatthew Dillon 		adm->adm_kva = NULL;
3028258223a3SMatthew Dillon 	}
3029258223a3SMatthew Dillon 	kfree(adm, M_DEVBUF);
3030258223a3SMatthew Dillon }
3031258223a3SMatthew Dillon 
3032258223a3SMatthew Dillon u_int32_t
3033258223a3SMatthew Dillon ahci_read(struct ahci_softc *sc, bus_size_t r)
3034258223a3SMatthew Dillon {
3035258223a3SMatthew Dillon 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
3036258223a3SMatthew Dillon 			  BUS_SPACE_BARRIER_READ);
3037258223a3SMatthew Dillon 	return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, r));
3038258223a3SMatthew Dillon }
3039258223a3SMatthew Dillon 
3040258223a3SMatthew Dillon void
3041258223a3SMatthew Dillon ahci_write(struct ahci_softc *sc, bus_size_t r, u_int32_t v)
3042258223a3SMatthew Dillon {
3043258223a3SMatthew Dillon 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v);
3044258223a3SMatthew Dillon 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4,
3045258223a3SMatthew Dillon 			  BUS_SPACE_BARRIER_WRITE);
3046258223a3SMatthew Dillon }
3047258223a3SMatthew Dillon 
3048258223a3SMatthew Dillon u_int32_t
3049258223a3SMatthew Dillon ahci_pread(struct ahci_port *ap, bus_size_t r)
3050258223a3SMatthew Dillon {
3051258223a3SMatthew Dillon 	bus_space_barrier(ap->ap_sc->sc_iot, ap->ap_ioh, r, 4,
3052258223a3SMatthew Dillon 			  BUS_SPACE_BARRIER_READ);
3053258223a3SMatthew Dillon 	return (bus_space_read_4(ap->ap_sc->sc_iot, ap->ap_ioh, r));
3054258223a3SMatthew Dillon }
3055258223a3SMatthew Dillon 
3056258223a3SMatthew Dillon void
3057258223a3SMatthew Dillon ahci_pwrite(struct ahci_port *ap, bus_size_t r, u_int32_t v)
3058258223a3SMatthew Dillon {
3059258223a3SMatthew Dillon 	bus_space_write_4(ap->ap_sc->sc_iot, ap->ap_ioh, r, v);
3060258223a3SMatthew Dillon 	bus_space_barrier(ap->ap_sc->sc_iot, ap->ap_ioh, r, 4,
3061258223a3SMatthew Dillon 			  BUS_SPACE_BARRIER_WRITE);
3062258223a3SMatthew Dillon }
3063258223a3SMatthew Dillon 
3064831bc9e3SMatthew Dillon /*
3065831bc9e3SMatthew Dillon  * Wait up to (timeout) milliseconds for the masked port register to
3066831bc9e3SMatthew Dillon  * match the target.
3067831bc9e3SMatthew Dillon  *
3068831bc9e3SMatthew Dillon  * Timeout is in milliseconds.
3069831bc9e3SMatthew Dillon  */
3070258223a3SMatthew Dillon int
3071cec85a37SMatthew Dillon ahci_pwait_eq(struct ahci_port *ap, int timeout,
3072cec85a37SMatthew Dillon 	      bus_size_t r, u_int32_t mask, u_int32_t target)
3073258223a3SMatthew Dillon {
3074831bc9e3SMatthew Dillon 	int	t;
3075258223a3SMatthew Dillon 
3076831bc9e3SMatthew Dillon 	/*
3077831bc9e3SMatthew Dillon 	 * Loop hard up to 100uS
3078831bc9e3SMatthew Dillon 	 */
3079831bc9e3SMatthew Dillon 	for (t = 0; t < 100; ++t) {
3080258223a3SMatthew Dillon 		if ((ahci_pread(ap, r) & mask) == target)
3081258223a3SMatthew Dillon 			return (0);
3082831bc9e3SMatthew Dillon 		ahci_os_hardsleep(1);	/* us */
3083258223a3SMatthew Dillon 	}
3084258223a3SMatthew Dillon 
3085831bc9e3SMatthew Dillon 	do {
3086831bc9e3SMatthew Dillon 		timeout -= ahci_os_softsleep();
3087831bc9e3SMatthew Dillon 		if ((ahci_pread(ap, r) & mask) == target)
3088831bc9e3SMatthew Dillon 			return (0);
3089831bc9e3SMatthew Dillon 	} while (timeout > 0);
3090831bc9e3SMatthew Dillon 	return (1);
3091831bc9e3SMatthew Dillon }
3092831bc9e3SMatthew Dillon 
3093831bc9e3SMatthew Dillon int
3094831bc9e3SMatthew Dillon ahci_wait_ne(struct ahci_softc *sc, bus_size_t r, u_int32_t mask,
3095831bc9e3SMatthew Dillon 	     u_int32_t target)
3096831bc9e3SMatthew Dillon {
3097831bc9e3SMatthew Dillon 	int	t;
3098831bc9e3SMatthew Dillon 
3099831bc9e3SMatthew Dillon 	/*
3100831bc9e3SMatthew Dillon 	 * Loop hard up to 100uS
3101831bc9e3SMatthew Dillon 	 */
3102831bc9e3SMatthew Dillon 	for (t = 0; t < 100; ++t) {
3103831bc9e3SMatthew Dillon 		if ((ahci_read(sc, r) & mask) != target)
3104831bc9e3SMatthew Dillon 			return (0);
3105831bc9e3SMatthew Dillon 		ahci_os_hardsleep(1);	/* us */
3106831bc9e3SMatthew Dillon 	}
3107831bc9e3SMatthew Dillon 
3108831bc9e3SMatthew Dillon 	/*
3109831bc9e3SMatthew Dillon 	 * And one millisecond the slow way
3110831bc9e3SMatthew Dillon 	 */
3111831bc9e3SMatthew Dillon 	t = 1000;
3112831bc9e3SMatthew Dillon 	do {
3113831bc9e3SMatthew Dillon 		t -= ahci_os_softsleep();
3114831bc9e3SMatthew Dillon 		if ((ahci_read(sc, r) & mask) != target)
3115831bc9e3SMatthew Dillon 			return (0);
3116831bc9e3SMatthew Dillon 	} while (t > 0);
3117831bc9e3SMatthew Dillon 
3118258223a3SMatthew Dillon 	return (1);
3119258223a3SMatthew Dillon }
3120258223a3SMatthew Dillon 
3121831bc9e3SMatthew Dillon 
31221980eff3SMatthew Dillon /*
31231980eff3SMatthew Dillon  * Acquire an ata transfer.
31241980eff3SMatthew Dillon  *
31251980eff3SMatthew Dillon  * Pass a NULL at for direct-attached transfers, and a non-NULL at for
31261980eff3SMatthew Dillon  * targets that go through the port multiplier.
31271980eff3SMatthew Dillon  */
3128258223a3SMatthew Dillon struct ata_xfer *
31291980eff3SMatthew Dillon ahci_ata_get_xfer(struct ahci_port *ap, struct ata_port *at)
3130258223a3SMatthew Dillon {
3131258223a3SMatthew Dillon 	struct ahci_ccb		*ccb;
3132258223a3SMatthew Dillon 
3133258223a3SMatthew Dillon 	ccb = ahci_get_ccb(ap);
3134258223a3SMatthew Dillon 	if (ccb == NULL) {
3135258223a3SMatthew Dillon 		DPRINTF(AHCI_D_XFER, "%s: ahci_ata_get_xfer: NULL ccb\n",
3136258223a3SMatthew Dillon 		    PORTNAME(ap));
3137258223a3SMatthew Dillon 		return (NULL);
3138258223a3SMatthew Dillon 	}
3139258223a3SMatthew Dillon 
3140258223a3SMatthew Dillon 	DPRINTF(AHCI_D_XFER, "%s: ahci_ata_get_xfer got slot %d\n",
3141258223a3SMatthew Dillon 	    PORTNAME(ap), ccb->ccb_slot);
3142258223a3SMatthew Dillon 
31432cc2e845SMatthew Dillon 	bzero(ccb->ccb_xa.fis, sizeof(*ccb->ccb_xa.fis));
31441980eff3SMatthew Dillon 	ccb->ccb_xa.at = at;
3145258223a3SMatthew Dillon 	ccb->ccb_xa.fis->type = ATA_FIS_TYPE_H2D;
3146258223a3SMatthew Dillon 
3147258223a3SMatthew Dillon 	return (&ccb->ccb_xa);
3148258223a3SMatthew Dillon }
3149258223a3SMatthew Dillon 
3150258223a3SMatthew Dillon void
3151258223a3SMatthew Dillon ahci_ata_put_xfer(struct ata_xfer *xa)
3152258223a3SMatthew Dillon {
3153258223a3SMatthew Dillon 	struct ahci_ccb			*ccb = (struct ahci_ccb *)xa;
3154258223a3SMatthew Dillon 
3155258223a3SMatthew Dillon 	DPRINTF(AHCI_D_XFER, "ahci_ata_put_xfer slot %d\n", ccb->ccb_slot);
3156258223a3SMatthew Dillon 
3157258223a3SMatthew Dillon 	ahci_put_ccb(ccb);
3158258223a3SMatthew Dillon }
3159258223a3SMatthew Dillon 
3160258223a3SMatthew Dillon int
3161258223a3SMatthew Dillon ahci_ata_cmd(struct ata_xfer *xa)
3162258223a3SMatthew Dillon {
3163258223a3SMatthew Dillon 	struct ahci_ccb			*ccb = (struct ahci_ccb *)xa;
3164258223a3SMatthew Dillon 	struct ahci_cmd_hdr		*cmd_slot;
3165258223a3SMatthew Dillon 
3166258223a3SMatthew Dillon 	KKASSERT(xa->state == ATA_S_SETUP);
3167258223a3SMatthew Dillon 
3168258223a3SMatthew Dillon 	if (ccb->ccb_port->ap_state == AP_S_FATAL_ERROR)
3169258223a3SMatthew Dillon 		goto failcmd;
3170258223a3SMatthew Dillon 	ccb->ccb_done = ahci_ata_cmd_done;
3171258223a3SMatthew Dillon 
3172258223a3SMatthew Dillon 	cmd_slot = ccb->ccb_cmd_hdr;
3173258223a3SMatthew Dillon 	cmd_slot->flags = htole16(5); /* FIS length (in DWORDs) */
31741980eff3SMatthew Dillon 	if (ccb->ccb_xa.at) {
31751980eff3SMatthew Dillon 		cmd_slot->flags |= htole16(ccb->ccb_xa.at->at_target <<
31761980eff3SMatthew Dillon 					   AHCI_CMD_LIST_FLAG_PMP_SHIFT);
31771980eff3SMatthew Dillon 	}
3178258223a3SMatthew Dillon 
3179258223a3SMatthew Dillon 	if (xa->flags & ATA_F_WRITE)
3180258223a3SMatthew Dillon 		cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_W);
3181258223a3SMatthew Dillon 
3182258223a3SMatthew Dillon 	if (xa->flags & ATA_F_PACKET)
3183258223a3SMatthew Dillon 		cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_A);
3184258223a3SMatthew Dillon 
3185258223a3SMatthew Dillon 	if (ahci_load_prdt(ccb) != 0)
3186258223a3SMatthew Dillon 		goto failcmd;
3187258223a3SMatthew Dillon 
3188258223a3SMatthew Dillon 	xa->state = ATA_S_PENDING;
3189258223a3SMatthew Dillon 
3190831bc9e3SMatthew Dillon 	if (xa->flags & ATA_F_POLL)
3191831bc9e3SMatthew Dillon 		return (ahci_poll(ccb, xa->timeout, ahci_ata_cmd_timeout));
3192258223a3SMatthew Dillon 
3193258223a3SMatthew Dillon 	crit_enter();
3194f4553de1SMatthew Dillon 	KKASSERT((xa->flags & ATA_F_TIMEOUT_EXPIRED) == 0);
31953209f581SMatthew Dillon 	xa->flags |= ATA_F_TIMEOUT_DESIRED;
3196258223a3SMatthew Dillon 	ahci_start(ccb);
3197258223a3SMatthew Dillon 	crit_exit();
3198831bc9e3SMatthew Dillon 	return (xa->state);
3199258223a3SMatthew Dillon 
3200258223a3SMatthew Dillon failcmd:
3201258223a3SMatthew Dillon 	crit_enter();
3202258223a3SMatthew Dillon 	xa->state = ATA_S_ERROR;
3203258223a3SMatthew Dillon 	xa->complete(xa);
3204258223a3SMatthew Dillon 	crit_exit();
3205831bc9e3SMatthew Dillon 	return (ATA_S_ERROR);
3206258223a3SMatthew Dillon }
3207258223a3SMatthew Dillon 
3208258223a3SMatthew Dillon void
3209258223a3SMatthew Dillon ahci_ata_cmd_done(struct ahci_ccb *ccb)
3210258223a3SMatthew Dillon {
3211258223a3SMatthew Dillon 	struct ata_xfer			*xa = &ccb->ccb_xa;
3212258223a3SMatthew Dillon 
3213831bc9e3SMatthew Dillon 	/*
3214831bc9e3SMatthew Dillon 	 * NOTE: callout does not lock port and may race us modifying
3215831bc9e3SMatthew Dillon 	 * the flags, so make sure its stopped.
3216831bc9e3SMatthew Dillon 	 */
3217258223a3SMatthew Dillon 	if (xa->flags & ATA_F_TIMEOUT_RUNNING) {
3218258223a3SMatthew Dillon 		callout_stop(&ccb->ccb_timeout);
3219831bc9e3SMatthew Dillon 		xa->flags &= ~ATA_F_TIMEOUT_RUNNING;
3220258223a3SMatthew Dillon 	}
3221f4553de1SMatthew Dillon 	xa->flags &= ~(ATA_F_TIMEOUT_DESIRED | ATA_F_TIMEOUT_EXPIRED);
3222258223a3SMatthew Dillon 
32234c339a5fSMatthew Dillon 	KKASSERT(xa->state != ATA_S_ONCHIP);
3224258223a3SMatthew Dillon 	ahci_unload_prdt(ccb);
3225258223a3SMatthew Dillon 
3226258223a3SMatthew Dillon 	if (xa->state != ATA_S_TIMEOUT)
3227258223a3SMatthew Dillon 		xa->complete(xa);
3228258223a3SMatthew Dillon }
3229258223a3SMatthew Dillon 
3230f4553de1SMatthew Dillon /*
3231f4553de1SMatthew Dillon  * Timeout from callout, MPSAFE - nothing can mess with the CCB's flags
3232f4553de1SMatthew Dillon  * while the callout is runing.
3233f4553de1SMatthew Dillon  *
3234f4553de1SMatthew Dillon  * We can't safely get the port lock here or delay, we could block
3235f4553de1SMatthew Dillon  * the callout thread.
3236f4553de1SMatthew Dillon  */
3237258223a3SMatthew Dillon static void
3238258223a3SMatthew Dillon ahci_ata_cmd_timeout_unserialized(void *arg)
3239258223a3SMatthew Dillon {
3240258223a3SMatthew Dillon 	struct ahci_ccb		*ccb = arg;
3241258223a3SMatthew Dillon 	struct ahci_port	*ap = ccb->ccb_port;
3242258223a3SMatthew Dillon 
3243f4553de1SMatthew Dillon 	ccb->ccb_xa.flags &= ~ATA_F_TIMEOUT_RUNNING;
3244f4553de1SMatthew Dillon 	ccb->ccb_xa.flags |= ATA_F_TIMEOUT_EXPIRED;
3245f4553de1SMatthew Dillon 	ahci_os_signal_port_thread(ap, AP_SIGF_TIMEOUT);
3246258223a3SMatthew Dillon }
3247258223a3SMatthew Dillon 
32484c339a5fSMatthew Dillon /*
32494c339a5fSMatthew Dillon  * Timeout code, typically called when the port command processor is running.
32504c339a5fSMatthew Dillon  *
32514c339a5fSMatthew Dillon  * We have to be very very careful here.  We cannot stop the port unless
32524c339a5fSMatthew Dillon  * CR is already clear or the only active commands remaining are timed-out
32534c339a5fSMatthew Dillon  * ones.  Otherwise stopping the port will race the command processor and
32544c339a5fSMatthew Dillon  * we can lose events.  While we can theoretically just restart everything
32554c339a5fSMatthew Dillon  * that could result in a double-issue which will not work for ATAPI commands.
32564c339a5fSMatthew Dillon  */
32571980eff3SMatthew Dillon void
3258831bc9e3SMatthew Dillon ahci_ata_cmd_timeout(struct ahci_ccb *ccb)
3259258223a3SMatthew Dillon {
3260258223a3SMatthew Dillon 	struct ata_xfer		*xa = &ccb->ccb_xa;
3261258223a3SMatthew Dillon 	struct ahci_port	*ap = ccb->ccb_port;
32624c339a5fSMatthew Dillon 	struct ata_port		*at;
32634c339a5fSMatthew Dillon 	int			ci_saved;
32644c339a5fSMatthew Dillon 	int			slot;
3265258223a3SMatthew Dillon 
32664c339a5fSMatthew Dillon 	at = ccb->ccb_xa.at;
32674c339a5fSMatthew Dillon 
32684c339a5fSMatthew Dillon 	kprintf("%s: CMD TIMEOUT state=%d slot=%d\n"
32694c339a5fSMatthew Dillon 		"\tcmd-reg 0x%b\n"
32704c339a5fSMatthew Dillon 		"\tsactive=%08x active=%08x expired=%08x\n"
327108fb24a7SMatthew Dillon 		"\t   sact=%08x     ci=%08x\n"
327208fb24a7SMatthew Dillon 		"\t    STS=%b\n",
32734c339a5fSMatthew Dillon 		ATANAME(ap, at),
32744c339a5fSMatthew Dillon 		ccb->ccb_xa.state, ccb->ccb_slot,
3275258223a3SMatthew Dillon 		ahci_pread(ap, AHCI_PREG_CMD), AHCI_PFMT_CMD,
32764c339a5fSMatthew Dillon 		ap->ap_sactive, ap->ap_active, ap->ap_expired,
3277258223a3SMatthew Dillon 		ahci_pread(ap, AHCI_PREG_SACT),
327808fb24a7SMatthew Dillon 		ahci_pread(ap, AHCI_PREG_CI),
327908fb24a7SMatthew Dillon 		ahci_pread(ap, AHCI_PREG_TFD), AHCI_PFMT_TFD_STS
328008fb24a7SMatthew Dillon 	);
328108fb24a7SMatthew Dillon 
3282258223a3SMatthew Dillon 
32839e145b23SMatthew Dillon 	/*
32849e145b23SMatthew Dillon 	 * NOTE: Timeout will not be running if the command was polled.
32853209f581SMatthew Dillon 	 *	 If we got here at least one of these flags should be set.
32869e145b23SMatthew Dillon 	 */
32873209f581SMatthew Dillon 	KKASSERT(xa->flags & (ATA_F_POLL | ATA_F_TIMEOUT_DESIRED |
32883209f581SMatthew Dillon 			      ATA_F_TIMEOUT_RUNNING));
3289f4553de1SMatthew Dillon 	xa->flags &= ~(ATA_F_TIMEOUT_RUNNING | ATA_F_TIMEOUT_EXPIRED);
3290258223a3SMatthew Dillon 
3291258223a3SMatthew Dillon 	if (ccb->ccb_xa.state == ATA_S_PENDING) {
3292258223a3SMatthew Dillon 		TAILQ_REMOVE(&ap->ap_ccb_pending, ccb, ccb_entry);
32934c339a5fSMatthew Dillon 		ccb->ccb_xa.state = ATA_S_TIMEOUT;
32944c339a5fSMatthew Dillon 		ccb->ccb_done(ccb);
32954c339a5fSMatthew Dillon 		xa->complete(xa);
32964c339a5fSMatthew Dillon 		ahci_issue_pending_commands(ap, NULL);
32974c339a5fSMatthew Dillon 		return;
32984c339a5fSMatthew Dillon 	}
32994c339a5fSMatthew Dillon 	if (ccb->ccb_xa.state != ATA_S_ONCHIP) {
33004c339a5fSMatthew Dillon 		kprintf("%s: Unexpected state during timeout: %d\n",
33014c339a5fSMatthew Dillon 			ATANAME(ap, at), ccb->ccb_xa.state);
33024c339a5fSMatthew Dillon 		return;
33034c339a5fSMatthew Dillon 	}
33044c339a5fSMatthew Dillon 
33054c339a5fSMatthew Dillon 	/*
33064c339a5fSMatthew Dillon 	 * Ok, we can only get this command off the chip if CR is inactive
33074c339a5fSMatthew Dillon 	 * or if the only commands running on the chip are all expired.
33084c339a5fSMatthew Dillon 	 * Otherwise we have to wait until the port is in a safe state.
33094c339a5fSMatthew Dillon 	 *
33104c339a5fSMatthew Dillon 	 * Do not set state here, it will cause polls to return when the
33114c339a5fSMatthew Dillon 	 * ccb is not yet off the chip.
33124c339a5fSMatthew Dillon 	 */
33134c339a5fSMatthew Dillon 	ap->ap_expired |= 1 << ccb->ccb_slot;
33144c339a5fSMatthew Dillon 
33154c339a5fSMatthew Dillon 	if ((ahci_pread(ap, AHCI_PREG_CMD) & AHCI_PREG_CMD_CR) &&
33164c339a5fSMatthew Dillon 	    (ap->ap_active | ap->ap_sactive) != ap->ap_expired) {
33174c339a5fSMatthew Dillon 		/*
33184c339a5fSMatthew Dillon 		 * If using FBSS or NCQ we can't safely stop the port
33194c339a5fSMatthew Dillon 		 * right now.
33204c339a5fSMatthew Dillon 		 */
33214c339a5fSMatthew Dillon 		kprintf("%s: Deferred timeout until its safe, slot %d\n",
33224c339a5fSMatthew Dillon 			ATANAME(ap, at), ccb->ccb_slot);
33234c339a5fSMatthew Dillon 		return;
33244c339a5fSMatthew Dillon 	}
33254c339a5fSMatthew Dillon 
33264c339a5fSMatthew Dillon 	/*
33274c339a5fSMatthew Dillon 	 * We can safely stop the port and process all expired ccb's,
33284c339a5fSMatthew Dillon 	 * which will include our current ccb.
33294c339a5fSMatthew Dillon 	 */
33304c339a5fSMatthew Dillon 	ci_saved = (ap->ap_sactive) ? ahci_pread(ap, AHCI_PREG_SACT) :
33314c339a5fSMatthew Dillon 				      ahci_pread(ap, AHCI_PREG_CI);
33324c339a5fSMatthew Dillon 	ahci_port_stop(ap, 0);
33334c339a5fSMatthew Dillon 
33344c339a5fSMatthew Dillon 	while (ap->ap_expired) {
33354c339a5fSMatthew Dillon 		slot = ffs(ap->ap_expired) - 1;
33364c339a5fSMatthew Dillon 		ap->ap_expired &= ~(1 << slot);
33374c339a5fSMatthew Dillon 		ci_saved &= ~(1 << slot);
33384c339a5fSMatthew Dillon 		ccb = &ap->ap_ccbs[slot];
33394c339a5fSMatthew Dillon 		ccb->ccb_xa.state = ATA_S_TIMEOUT;
33404c339a5fSMatthew Dillon 		if (ccb->ccb_xa.flags & ATA_F_NCQ) {
33414c339a5fSMatthew Dillon 			KKASSERT(ap->ap_sactive & (1 << slot));
33424c339a5fSMatthew Dillon 			ap->ap_sactive &= ~(1 << slot);
33434c339a5fSMatthew Dillon 		} else {
33444c339a5fSMatthew Dillon 			KKASSERT(ap->ap_active & (1 << slot));
33454c339a5fSMatthew Dillon 			ap->ap_active &= ~(1 << slot);
33461980eff3SMatthew Dillon 			--ap->ap_active_cnt;
33471980eff3SMatthew Dillon 		}
3348258223a3SMatthew Dillon 		ccb->ccb_done(ccb);
33494c339a5fSMatthew Dillon 		ccb->ccb_xa.complete(&ccb->ccb_xa);
3350258223a3SMatthew Dillon 	}
33514c339a5fSMatthew Dillon 	/* ccb invalid now */
3352258223a3SMatthew Dillon 
33534c339a5fSMatthew Dillon 	/*
33544c339a5fSMatthew Dillon 	 * We can safely CLO the port to clear any BSY/DRQ, a case which
33554c339a5fSMatthew Dillon 	 * can occur with port multipliers.  This will unbrick the port
33564c339a5fSMatthew Dillon 	 * and allow commands to other targets behind the PM continue.
33574c339a5fSMatthew Dillon 	 * (FBSS).
33584c339a5fSMatthew Dillon 	 *
33594c339a5fSMatthew Dillon 	 * Finally, once the port has been restarted we can issue any
33604c339a5fSMatthew Dillon 	 * previously saved pending commands, and run the port interrupt
33614c339a5fSMatthew Dillon 	 * code to handle any completions which may have occured when
33624c339a5fSMatthew Dillon 	 * we saved CI.
33634c339a5fSMatthew Dillon 	 */
33644c339a5fSMatthew Dillon 	if (ahci_pread(ap, AHCI_PREG_TFD) &
33654c339a5fSMatthew Dillon 		   (AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) {
33664c339a5fSMatthew Dillon 		kprintf("%s: Warning, issuing CLO after timeout\n",
33674c339a5fSMatthew Dillon 			ATANAME(ap, at));
3368131be210SMatthew Dillon 		ahci_port_clo(ap);
33694c339a5fSMatthew Dillon 	}
3370131be210SMatthew Dillon 	ahci_port_start(ap);
33714c339a5fSMatthew Dillon 	ahci_issue_saved_commands(ap, ci_saved & ~ap->ap_expired);
33724c339a5fSMatthew Dillon 	ahci_issue_pending_commands(ap, NULL);
33734c339a5fSMatthew Dillon 	ahci_port_intr(ap, 0);
33744c339a5fSMatthew Dillon }
33754c339a5fSMatthew Dillon 
3376cf5f3a81SMatthew Dillon /*
33774c339a5fSMatthew Dillon  * Issue a previously saved set of commands
3378cf5f3a81SMatthew Dillon  */
33794c339a5fSMatthew Dillon void
33804c339a5fSMatthew Dillon ahci_issue_saved_commands(struct ahci_port *ap, u_int32_t ci_saved)
33814c339a5fSMatthew Dillon {
33824c339a5fSMatthew Dillon 	if (ci_saved) {
33834c339a5fSMatthew Dillon 		KKASSERT(!((ap->ap_active & ci_saved) &&
33844c339a5fSMatthew Dillon 			   (ap->ap_sactive & ci_saved)));
33854c339a5fSMatthew Dillon 		KKASSERT((ci_saved & ap->ap_expired) == 0);
33864c339a5fSMatthew Dillon 		if (ap->ap_sactive & ci_saved)
33874c339a5fSMatthew Dillon 			ahci_pwrite(ap, AHCI_PREG_SACT, ci_saved);
33884c339a5fSMatthew Dillon 		ahci_pwrite(ap, AHCI_PREG_CI, ci_saved);
3389131be210SMatthew Dillon 	}
3390258223a3SMatthew Dillon }
3391258223a3SMatthew Dillon 
3392831bc9e3SMatthew Dillon /*
3393831bc9e3SMatthew Dillon  * Used by the softreset, pmprobe, and read_ncq_error only, in very
3394831bc9e3SMatthew Dillon  * specialized, controlled circumstances.
3395831bc9e3SMatthew Dillon  *
3396831bc9e3SMatthew Dillon  * Only one command may be pending.
3397831bc9e3SMatthew Dillon  */
3398831bc9e3SMatthew Dillon void
3399831bc9e3SMatthew Dillon ahci_quick_timeout(struct ahci_ccb *ccb)
3400831bc9e3SMatthew Dillon {
3401831bc9e3SMatthew Dillon 	struct ahci_port *ap = ccb->ccb_port;
3402831bc9e3SMatthew Dillon 
3403831bc9e3SMatthew Dillon 	switch (ccb->ccb_xa.state) {
3404831bc9e3SMatthew Dillon 	case ATA_S_PENDING:
3405831bc9e3SMatthew Dillon 		TAILQ_REMOVE(&ap->ap_ccb_pending, ccb, ccb_entry);
3406831bc9e3SMatthew Dillon 		ccb->ccb_xa.state = ATA_S_TIMEOUT;
3407831bc9e3SMatthew Dillon 		break;
3408831bc9e3SMatthew Dillon 	case ATA_S_ONCHIP:
3409831bc9e3SMatthew Dillon 		KKASSERT(ap->ap_active == (1 << ccb->ccb_slot) &&
3410831bc9e3SMatthew Dillon 			 ap->ap_sactive == 0);
3411831bc9e3SMatthew Dillon 		ahci_port_stop(ap, 0);
3412831bc9e3SMatthew Dillon 		ahci_port_start(ap);
3413831bc9e3SMatthew Dillon 
3414831bc9e3SMatthew Dillon 		ccb->ccb_xa.state = ATA_S_TIMEOUT;
3415831bc9e3SMatthew Dillon 		ap->ap_active &= ~(1 << ccb->ccb_slot);
3416831bc9e3SMatthew Dillon 		KKASSERT(ap->ap_active_cnt > 0);
3417831bc9e3SMatthew Dillon 		--ap->ap_active_cnt;
3418831bc9e3SMatthew Dillon 		break;
3419831bc9e3SMatthew Dillon 	default:
3420831bc9e3SMatthew Dillon 		panic("%s: ahci_quick_timeout: ccb in bad state %d",
3421831bc9e3SMatthew Dillon 		      ATANAME(ap, ccb->ccb_xa.at), ccb->ccb_xa.state);
3422831bc9e3SMatthew Dillon 	}
3423831bc9e3SMatthew Dillon }
3424831bc9e3SMatthew Dillon 
342512feb904SMatthew Dillon static void
342612feb904SMatthew Dillon ahci_dummy_done(struct ata_xfer *xa)
342712feb904SMatthew Dillon {
342812feb904SMatthew Dillon }
342912feb904SMatthew Dillon 
343012feb904SMatthew Dillon static void
3431258223a3SMatthew Dillon ahci_empty_done(struct ahci_ccb *ccb)
3432258223a3SMatthew Dillon {
3433258223a3SMatthew Dillon }
3434