1258223a3SMatthew Dillon /* 2fb00c6edSMatthew Dillon * (MPSAFE) 3fb00c6edSMatthew Dillon * 4258223a3SMatthew Dillon * Copyright (c) 2006 David Gwynne <dlg@openbsd.org> 5258223a3SMatthew Dillon * 6258223a3SMatthew Dillon * Permission to use, copy, modify, and distribute this software for any 7258223a3SMatthew Dillon * purpose with or without fee is hereby granted, provided that the above 8258223a3SMatthew Dillon * copyright notice and this permission notice appear in all copies. 9258223a3SMatthew Dillon * 10258223a3SMatthew Dillon * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11258223a3SMatthew Dillon * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12258223a3SMatthew Dillon * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13258223a3SMatthew Dillon * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14258223a3SMatthew Dillon * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15258223a3SMatthew Dillon * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16258223a3SMatthew Dillon * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17258223a3SMatthew Dillon * 18258223a3SMatthew Dillon * 19258223a3SMatthew Dillon * Copyright (c) 2009 The DragonFly Project. All rights reserved. 20258223a3SMatthew Dillon * 21258223a3SMatthew Dillon * This code is derived from software contributed to The DragonFly Project 22258223a3SMatthew Dillon * by Matthew Dillon <dillon@backplane.com> 23258223a3SMatthew Dillon * 24258223a3SMatthew Dillon * Redistribution and use in source and binary forms, with or without 25258223a3SMatthew Dillon * modification, are permitted provided that the following conditions 26258223a3SMatthew Dillon * are met: 27258223a3SMatthew Dillon * 28258223a3SMatthew Dillon * 1. Redistributions of source code must retain the above copyright 29258223a3SMatthew Dillon * notice, this list of conditions and the following disclaimer. 30258223a3SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright 31258223a3SMatthew Dillon * notice, this list of conditions and the following disclaimer in 32258223a3SMatthew Dillon * the documentation and/or other materials provided with the 33258223a3SMatthew Dillon * distribution. 34258223a3SMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its 35258223a3SMatthew Dillon * contributors may be used to endorse or promote products derived 36258223a3SMatthew Dillon * from this software without specific, prior written permission. 37258223a3SMatthew Dillon * 38258223a3SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 39258223a3SMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 40258223a3SMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 41258223a3SMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 42258223a3SMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 43258223a3SMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 44258223a3SMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 45258223a3SMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 46258223a3SMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 47258223a3SMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 48258223a3SMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 49258223a3SMatthew Dillon * SUCH DAMAGE. 50258223a3SMatthew Dillon * 51258223a3SMatthew Dillon * $OpenBSD: ahci.c,v 1.147 2009/02/16 21:19:07 miod Exp $ 52258223a3SMatthew Dillon */ 53258223a3SMatthew Dillon 54258223a3SMatthew Dillon #include "ahci.h" 55258223a3SMatthew Dillon 56f4553de1SMatthew Dillon void ahci_port_interrupt_enable(struct ahci_port *ap); 57258223a3SMatthew Dillon 58258223a3SMatthew Dillon int ahci_load_prdt(struct ahci_ccb *); 59258223a3SMatthew Dillon void ahci_unload_prdt(struct ahci_ccb *); 60258223a3SMatthew Dillon static void ahci_load_prdt_callback(void *info, bus_dma_segment_t *segs, 61258223a3SMatthew Dillon int nsegs, int error); 62258223a3SMatthew Dillon void ahci_start(struct ahci_ccb *); 6317eab71eSMatthew Dillon int ahci_port_softreset(struct ahci_port *ap); 641980eff3SMatthew Dillon int ahci_port_hardreset(struct ahci_port *ap, int hard); 65cf5f3a81SMatthew Dillon void ahci_port_hardstop(struct ahci_port *ap); 66258223a3SMatthew Dillon 67831bc9e3SMatthew Dillon static void ahci_ata_cmd_timeout_unserialized(void *); 68831bc9e3SMatthew Dillon void ahci_check_active_timeouts(struct ahci_port *ap); 69258223a3SMatthew Dillon 70831bc9e3SMatthew Dillon void ahci_beg_exclusive_access(struct ahci_port *ap, struct ata_port *at); 71831bc9e3SMatthew Dillon void ahci_end_exclusive_access(struct ahci_port *ap, struct ata_port *at); 724c339a5fSMatthew Dillon void ahci_issue_pending_commands(struct ahci_port *ap, struct ahci_ccb *ccb); 734c339a5fSMatthew Dillon void ahci_issue_saved_commands(struct ahci_port *ap, u_int32_t mask); 74258223a3SMatthew Dillon 7512feb904SMatthew Dillon int ahci_port_read_ncq_error(struct ahci_port *, int); 76258223a3SMatthew Dillon 77258223a3SMatthew Dillon struct ahci_dmamem *ahci_dmamem_alloc(struct ahci_softc *, bus_dma_tag_t tag); 78258223a3SMatthew Dillon void ahci_dmamem_free(struct ahci_softc *, struct ahci_dmamem *); 79258223a3SMatthew Dillon static void ahci_dmamem_saveseg(void *info, bus_dma_segment_t *segs, int nsegs, int error); 80258223a3SMatthew Dillon 8112feb904SMatthew Dillon static void ahci_dummy_done(struct ata_xfer *xa); 8212feb904SMatthew Dillon static void ahci_empty_done(struct ahci_ccb *ccb); 8312feb904SMatthew Dillon static void ahci_ata_cmd_done(struct ahci_ccb *ccb); 84492bffafSMatthew Dillon static u_int32_t ahci_pactive(struct ahci_port *ap); 85258223a3SMatthew Dillon 86fd8bd957SMatthew Dillon /* 87fd8bd957SMatthew Dillon * Initialize the global AHCI hardware. This code does not set up any of 88fd8bd957SMatthew Dillon * its ports. 89fd8bd957SMatthew Dillon */ 90258223a3SMatthew Dillon int 91258223a3SMatthew Dillon ahci_init(struct ahci_softc *sc) 92258223a3SMatthew Dillon { 9312feb904SMatthew Dillon u_int32_t cap, pi, pleft; 94831bc9e3SMatthew Dillon int i; 95831bc9e3SMatthew Dillon struct ahci_port *ap; 96258223a3SMatthew Dillon 97258223a3SMatthew Dillon DPRINTF(AHCI_D_VERBOSE, " GHC 0x%b", 98258223a3SMatthew Dillon ahci_read(sc, AHCI_REG_GHC), AHCI_FMT_GHC); 99258223a3SMatthew Dillon 100b012a2caSMatthew Dillon /* 101b012a2caSMatthew Dillon * save BIOS initialised parameters, enable staggered spin up 102b012a2caSMatthew Dillon */ 103258223a3SMatthew Dillon cap = ahci_read(sc, AHCI_REG_CAP); 104258223a3SMatthew Dillon cap &= AHCI_REG_CAP_SMPS; 105258223a3SMatthew Dillon cap |= AHCI_REG_CAP_SSS; 106258223a3SMatthew Dillon pi = ahci_read(sc, AHCI_REG_PI); 107258223a3SMatthew Dillon 108831bc9e3SMatthew Dillon /* 109b012a2caSMatthew Dillon * Unconditionally reset the controller, do not conditionalize on 110b012a2caSMatthew Dillon * trying to figure it if it was previously active or not. 111b012a2caSMatthew Dillon * 112b012a2caSMatthew Dillon * NOTE: On AE before HR. The AHCI-1.1 spec has a note in section 113b012a2caSMatthew Dillon * 5.2.2.1 regarding this. HR should be set to 1 only after 114b012a2caSMatthew Dillon * AE is set to 1. The reset sequence will clear HR when 115b012a2caSMatthew Dillon * it completes, and will also clear AE if SAM is 0. AE must 116b012a2caSMatthew Dillon * then be set again. When SAM is 1 the AE bit typically reads 117b012a2caSMatthew Dillon * as 1 (and is read-only). 118b012a2caSMatthew Dillon * 119b012a2caSMatthew Dillon * NOTE: Avoid PCI[e] transaction burst by issuing dummy reads, 120b012a2caSMatthew Dillon * otherwise the writes will only be separated by a few 121b012a2caSMatthew Dillon * nanoseconds. 122b012a2caSMatthew Dillon * 123b012a2caSMatthew Dillon * NOTE BRICKS (1) 124b012a2caSMatthew Dillon * 125b012a2caSMatthew Dillon * If you have a port multiplier and it does not have a device 126b012a2caSMatthew Dillon * in target 0, and it probes normally, but a later operation 127b012a2caSMatthew Dillon * mis-probes a target behind that PM, it is possible for the 128b012a2caSMatthew Dillon * port to brick such that only (a) a power cycle of the host 129b012a2caSMatthew Dillon * or (b) placing a device in target 0 will fix the problem. 130b012a2caSMatthew Dillon * Power cycling the PM has no effect (it works fine on another 131b012a2caSMatthew Dillon * host port). This issue is unrelated to CLO. 132b012a2caSMatthew Dillon */ 1334e21f4daSMatthew Dillon /* 1344e21f4daSMatthew Dillon * Wait for any prior reset sequence to complete 1354e21f4daSMatthew Dillon */ 1364e21f4daSMatthew Dillon if (ahci_wait_ne(sc, AHCI_REG_GHC, 1374e21f4daSMatthew Dillon AHCI_REG_GHC_HR, AHCI_REG_GHC_HR) != 0) { 1384e21f4daSMatthew Dillon device_printf(sc->sc_dev, "Controller is stuck in reset\n"); 1394e21f4daSMatthew Dillon return (1); 1404e21f4daSMatthew Dillon } 141b012a2caSMatthew Dillon ahci_write(sc, AHCI_REG_GHC, AHCI_REG_GHC_AE); 1424e21f4daSMatthew Dillon ahci_os_sleep(500); 143b012a2caSMatthew Dillon ahci_read(sc, AHCI_REG_GHC); /* flush */ 144b012a2caSMatthew Dillon ahci_write(sc, AHCI_REG_GHC, AHCI_REG_GHC_AE | AHCI_REG_GHC_HR); 1454e21f4daSMatthew Dillon ahci_os_sleep(500); 146b012a2caSMatthew Dillon ahci_read(sc, AHCI_REG_GHC); /* flush */ 147b012a2caSMatthew Dillon if (ahci_wait_ne(sc, AHCI_REG_GHC, 148b012a2caSMatthew Dillon AHCI_REG_GHC_HR, AHCI_REG_GHC_HR) != 0) { 1494e21f4daSMatthew Dillon device_printf(sc->sc_dev, "unable to reset controller\n"); 150b012a2caSMatthew Dillon return (1); 151b012a2caSMatthew Dillon } 1524e21f4daSMatthew Dillon if (ahci_read(sc, AHCI_REG_GHC) & AHCI_REG_GHC_AE) { 1534e21f4daSMatthew Dillon device_printf(sc->sc_dev, "AE did not auto-clear!\n"); 1544e21f4daSMatthew Dillon ahci_write(sc, AHCI_REG_GHC, 0); 1554e21f4daSMatthew Dillon ahci_os_sleep(500); 1564e21f4daSMatthew Dillon } 157b012a2caSMatthew Dillon 158b012a2caSMatthew Dillon /* 159b012a2caSMatthew Dillon * Enable ahci (global interrupts disabled) 160b012a2caSMatthew Dillon * 161b012a2caSMatthew Dillon * Restore saved parameters. Avoid pci transaction burst write 162b012a2caSMatthew Dillon * by issuing dummy reads. 163b012a2caSMatthew Dillon */ 1644e21f4daSMatthew Dillon ahci_os_sleep(500); 165b012a2caSMatthew Dillon ahci_write(sc, AHCI_REG_GHC, AHCI_REG_GHC_AE); 166b012a2caSMatthew Dillon ahci_os_sleep(500); 167b012a2caSMatthew Dillon 168b012a2caSMatthew Dillon ahci_read(sc, AHCI_REG_GHC); /* flush */ 169b012a2caSMatthew Dillon ahci_write(sc, AHCI_REG_CAP, cap); 170b012a2caSMatthew Dillon ahci_write(sc, AHCI_REG_PI, pi); 171b012a2caSMatthew Dillon ahci_read(sc, AHCI_REG_GHC); /* flush */ 172b012a2caSMatthew Dillon 173b012a2caSMatthew Dillon /* 174b012a2caSMatthew Dillon * Intel hocus pocus in case the BIOS has not set the chip up 175b012a2caSMatthew Dillon * properly for AHCI operation. 176b012a2caSMatthew Dillon */ 177b012a2caSMatthew Dillon if (pci_get_vendor(sc->sc_dev) == PCI_VENDOR_INTEL) { 178b012a2caSMatthew Dillon if ((pci_read_config(sc->sc_dev, 0x92, 2) & 0x0F) != 0x0F) 179b012a2caSMatthew Dillon device_printf(sc->sc_dev, "Intel hocus pocus\n"); 180b012a2caSMatthew Dillon pci_write_config(sc->sc_dev, 0x92, 181b012a2caSMatthew Dillon pci_read_config(sc->sc_dev, 0x92, 2) | 0x0F, 2); 182b012a2caSMatthew Dillon } 183b012a2caSMatthew Dillon 184b012a2caSMatthew Dillon /* 185831bc9e3SMatthew Dillon * This is a hack that currently does not appear to have 186831bc9e3SMatthew Dillon * a significant effect, but I noticed the port registers 187831bc9e3SMatthew Dillon * do not appear to be completely cleared after the host 188831bc9e3SMatthew Dillon * controller is reset. 18912feb904SMatthew Dillon * 19012feb904SMatthew Dillon * Use a temporary ap structure so we can call ahci_pwrite(). 1914e21f4daSMatthew Dillon * 1924e21f4daSMatthew Dillon * We must be sure to stop the port 193831bc9e3SMatthew Dillon */ 194831bc9e3SMatthew Dillon ap = kmalloc(sizeof(*ap), M_DEVBUF, M_WAITOK | M_ZERO); 195831bc9e3SMatthew Dillon ap->ap_sc = sc; 19612feb904SMatthew Dillon pleft = pi; 19712feb904SMatthew Dillon for (i = 0; i < AHCI_MAX_PORTS; ++i) { 19812feb904SMatthew Dillon if (pleft == 0) 19912feb904SMatthew Dillon break; 200831bc9e3SMatthew Dillon if ((pi & (1 << i)) == 0) 201831bc9e3SMatthew Dillon continue; 202831bc9e3SMatthew Dillon if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 203831bc9e3SMatthew Dillon AHCI_PORT_REGION(i), AHCI_PORT_SIZE, &ap->ap_ioh) != 0) { 204831bc9e3SMatthew Dillon device_printf(sc->sc_dev, "can't map port\n"); 205831bc9e3SMatthew Dillon return (1); 206831bc9e3SMatthew Dillon } 2074e21f4daSMatthew Dillon /* 2084e21f4daSMatthew Dillon * NOTE! Setting AHCI_PREG_SCTL_DET_DISABLE on AHCI1.0 or 2094e21f4daSMatthew Dillon * AHCI1.1 can brick the chipset. Not only brick it, 2104e21f4daSMatthew Dillon * but also crash the PC. The bit seems unreliable 2114e21f4daSMatthew Dillon * on AHCI1.2 as well. 2124e21f4daSMatthew Dillon */ 2134e21f4daSMatthew Dillon ahci_port_stop(ap, 1); 2144e21f4daSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SCTL, AHCI_PREG_SCTL_IPM_DISABLED); 215831bc9e3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 216831bc9e3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IE, 0); 21712feb904SMatthew Dillon ahci_write(ap->ap_sc, AHCI_REG_IS, 1 << i); 218831bc9e3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, 0); 21912feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, -1); 22012feb904SMatthew Dillon sc->sc_portmask |= (1 << i); 22112feb904SMatthew Dillon pleft &= ~(1 << i); 222831bc9e3SMatthew Dillon } 22312feb904SMatthew Dillon sc->sc_numports = i; 224831bc9e3SMatthew Dillon kfree(ap, M_DEVBUF); 225831bc9e3SMatthew Dillon 226258223a3SMatthew Dillon return (0); 227258223a3SMatthew Dillon } 228258223a3SMatthew Dillon 229fd8bd957SMatthew Dillon /* 230fd8bd957SMatthew Dillon * Allocate and initialize an AHCI port. 231fd8bd957SMatthew Dillon */ 232258223a3SMatthew Dillon int 233258223a3SMatthew Dillon ahci_port_alloc(struct ahci_softc *sc, u_int port) 234258223a3SMatthew Dillon { 235258223a3SMatthew Dillon struct ahci_port *ap; 2361980eff3SMatthew Dillon struct ata_port *at; 237258223a3SMatthew Dillon struct ahci_ccb *ccb; 238258223a3SMatthew Dillon u_int64_t dva; 239258223a3SMatthew Dillon u_int32_t cmd; 24012feb904SMatthew Dillon u_int32_t data; 241258223a3SMatthew Dillon struct ahci_cmd_hdr *hdr; 242258223a3SMatthew Dillon struct ahci_cmd_table *table; 243258223a3SMatthew Dillon int rc = ENOMEM; 244258223a3SMatthew Dillon int error; 245258223a3SMatthew Dillon int i; 246258223a3SMatthew Dillon 247258223a3SMatthew Dillon ap = kmalloc(sizeof(*ap), M_DEVBUF, M_WAITOK | M_ZERO); 24812feb904SMatthew Dillon ap->ap_err_scratch = kmalloc(512, M_DEVBUF, M_WAITOK | M_ZERO); 249258223a3SMatthew Dillon 250258223a3SMatthew Dillon ksnprintf(ap->ap_name, sizeof(ap->ap_name), "%s%d.%d", 251258223a3SMatthew Dillon device_get_name(sc->sc_dev), 252258223a3SMatthew Dillon device_get_unit(sc->sc_dev), 253258223a3SMatthew Dillon port); 254258223a3SMatthew Dillon sc->sc_ports[port] = ap; 255258223a3SMatthew Dillon 2561980eff3SMatthew Dillon /* 2571980eff3SMatthew Dillon * Allocate enough so we never have to reallocate, it makes 2581980eff3SMatthew Dillon * it easier. 2591980eff3SMatthew Dillon * 2601980eff3SMatthew Dillon * ap_pmcount will be reduced by the scan if we encounter the 2611980eff3SMatthew Dillon * port multiplier port prior to target 15. 262b012a2caSMatthew Dillon * 263b012a2caSMatthew Dillon * kmalloc power-of-2 allocations are guaranteed not to cross 264b012a2caSMatthew Dillon * a page boundary. Make sure the identify sub-structure in the 265b012a2caSMatthew Dillon * at structure does not cross a page boundary, just in case the 266b012a2caSMatthew Dillon * part is AHCI-1.1 and can't handle multiple DRQ blocks. 2671980eff3SMatthew Dillon */ 268b012a2caSMatthew Dillon if (ap->ap_ata[0] == NULL) { 269b012a2caSMatthew Dillon int pw2; 270b012a2caSMatthew Dillon 271b012a2caSMatthew Dillon for (pw2 = 1; pw2 < sizeof(*at); pw2 <<= 1) 272b012a2caSMatthew Dillon ; 2731980eff3SMatthew Dillon for (i = 0; i < AHCI_MAX_PMPORTS; ++i) { 274b012a2caSMatthew Dillon at = kmalloc(pw2, M_DEVBUF, M_INTWAIT | M_ZERO); 275b012a2caSMatthew Dillon ap->ap_ata[i] = at; 2761980eff3SMatthew Dillon at->at_ahci_port = ap; 2771980eff3SMatthew Dillon at->at_target = i; 2783209f581SMatthew Dillon at->at_probe = ATA_PROBE_NEED_INIT; 279831bc9e3SMatthew Dillon at->at_features |= ATA_PORT_F_RESCAN; 2801980eff3SMatthew Dillon ksnprintf(at->at_name, sizeof(at->at_name), 2811980eff3SMatthew Dillon "%s.%d", ap->ap_name, i); 2821980eff3SMatthew Dillon } 2831980eff3SMatthew Dillon } 284258223a3SMatthew Dillon if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 285258223a3SMatthew Dillon AHCI_PORT_REGION(port), AHCI_PORT_SIZE, &ap->ap_ioh) != 0) { 286258223a3SMatthew Dillon device_printf(sc->sc_dev, 287258223a3SMatthew Dillon "unable to create register window for port %d\n", 288258223a3SMatthew Dillon port); 289258223a3SMatthew Dillon goto freeport; 290258223a3SMatthew Dillon } 291258223a3SMatthew Dillon 292258223a3SMatthew Dillon ap->ap_sc = sc; 293258223a3SMatthew Dillon ap->ap_num = port; 2943209f581SMatthew Dillon ap->ap_probe = ATA_PROBE_NEED_INIT; 295f17a0cedSMatthew Dillon ap->link_pwr_mgmt = AHCI_LINK_PWR_MGMT_NONE; 296f17a0cedSMatthew Dillon ap->sysctl_tree = NULL; 297258223a3SMatthew Dillon TAILQ_INIT(&ap->ap_ccb_free); 298258223a3SMatthew Dillon TAILQ_INIT(&ap->ap_ccb_pending); 299258223a3SMatthew Dillon lockinit(&ap->ap_ccb_lock, "ahcipo", 0, 0); 300258223a3SMatthew Dillon 301258223a3SMatthew Dillon /* Disable port interrupts */ 302258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IE, 0); 303831bc9e3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 304258223a3SMatthew Dillon 30517eab71eSMatthew Dillon /* 30617eab71eSMatthew Dillon * Sec 10.1.2 - deinitialise port if it is already running 30717eab71eSMatthew Dillon */ 308258223a3SMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD); 3090be9576aSMatthew Dillon kprintf("%s: Caps %b\n", PORTNAME(ap), cmd, AHCI_PFMT_CMD); 3100be9576aSMatthew Dillon 311258223a3SMatthew Dillon if ((cmd & (AHCI_PREG_CMD_ST | AHCI_PREG_CMD_CR | 312258223a3SMatthew Dillon AHCI_PREG_CMD_FRE | AHCI_PREG_CMD_FR)) || 313258223a3SMatthew Dillon (ahci_pread(ap, AHCI_PREG_SCTL) & AHCI_PREG_SCTL_DET)) { 314258223a3SMatthew Dillon int r; 315258223a3SMatthew Dillon 316258223a3SMatthew Dillon r = ahci_port_stop(ap, 1); 317258223a3SMatthew Dillon if (r) { 318258223a3SMatthew Dillon device_printf(sc->sc_dev, 319258223a3SMatthew Dillon "unable to disable %s, ignoring port %d\n", 320258223a3SMatthew Dillon ((r == 2) ? "CR" : "FR"), port); 321258223a3SMatthew Dillon rc = ENXIO; 322258223a3SMatthew Dillon goto freeport; 323258223a3SMatthew Dillon } 324258223a3SMatthew Dillon 325258223a3SMatthew Dillon /* Write DET to zero */ 326cf5f3a81SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SCTL, AHCI_PREG_SCTL_IPM_DISABLED); 327258223a3SMatthew Dillon } 328258223a3SMatthew Dillon 329258223a3SMatthew Dillon /* Allocate RFIS */ 330258223a3SMatthew Dillon ap->ap_dmamem_rfis = ahci_dmamem_alloc(sc, sc->sc_tag_rfis); 331258223a3SMatthew Dillon if (ap->ap_dmamem_rfis == NULL) { 332cf5f3a81SMatthew Dillon kprintf("%s: NORFIS\n", PORTNAME(ap)); 333258223a3SMatthew Dillon goto nomem; 334258223a3SMatthew Dillon } 335258223a3SMatthew Dillon 336258223a3SMatthew Dillon /* Setup RFIS base address */ 337258223a3SMatthew Dillon ap->ap_rfis = (struct ahci_rfis *) AHCI_DMA_KVA(ap->ap_dmamem_rfis); 338258223a3SMatthew Dillon dva = AHCI_DMA_DVA(ap->ap_dmamem_rfis); 339258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_FBU, (u_int32_t)(dva >> 32)); 340258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_FB, (u_int32_t)dva); 341258223a3SMatthew Dillon 342831bc9e3SMatthew Dillon /* Clear SERR before starting FIS reception or ST or anything */ 343831bc9e3SMatthew Dillon ahci_flush_tfd(ap); 344831bc9e3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 345831bc9e3SMatthew Dillon 346258223a3SMatthew Dillon /* Enable FIS reception and activate port. */ 347258223a3SMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC; 3481980eff3SMatthew Dillon cmd &= ~(AHCI_PREG_CMD_CLO | AHCI_PREG_CMD_PMA); 349258223a3SMatthew Dillon cmd |= AHCI_PREG_CMD_FRE | AHCI_PREG_CMD_POD | AHCI_PREG_CMD_SUD; 350258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd | AHCI_PREG_CMD_ICC_ACTIVE); 351258223a3SMatthew Dillon 352258223a3SMatthew Dillon /* Check whether port activated. Skip it if not. */ 353258223a3SMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC; 354258223a3SMatthew Dillon if ((cmd & AHCI_PREG_CMD_FRE) == 0) { 355cf5f3a81SMatthew Dillon kprintf("%s: NOT-ACTIVATED\n", PORTNAME(ap)); 356258223a3SMatthew Dillon rc = ENXIO; 357258223a3SMatthew Dillon goto freeport; 358258223a3SMatthew Dillon } 359258223a3SMatthew Dillon 360258223a3SMatthew Dillon /* Allocate a CCB for each command slot */ 361258223a3SMatthew Dillon ap->ap_ccbs = kmalloc(sizeof(struct ahci_ccb) * sc->sc_ncmds, M_DEVBUF, 362258223a3SMatthew Dillon M_WAITOK | M_ZERO); 363258223a3SMatthew Dillon if (ap->ap_ccbs == NULL) { 364258223a3SMatthew Dillon device_printf(sc->sc_dev, 365258223a3SMatthew Dillon "unable to allocate command list for port %d\n", 366258223a3SMatthew Dillon port); 367258223a3SMatthew Dillon goto freeport; 368258223a3SMatthew Dillon } 369258223a3SMatthew Dillon 370258223a3SMatthew Dillon /* Command List Structures and Command Tables */ 371258223a3SMatthew Dillon ap->ap_dmamem_cmd_list = ahci_dmamem_alloc(sc, sc->sc_tag_cmdh); 372258223a3SMatthew Dillon ap->ap_dmamem_cmd_table = ahci_dmamem_alloc(sc, sc->sc_tag_cmdt); 373258223a3SMatthew Dillon if (ap->ap_dmamem_cmd_table == NULL || 374258223a3SMatthew Dillon ap->ap_dmamem_cmd_list == NULL) { 375258223a3SMatthew Dillon nomem: 376258223a3SMatthew Dillon device_printf(sc->sc_dev, 377258223a3SMatthew Dillon "unable to allocate DMA memory for port %d\n", 378258223a3SMatthew Dillon port); 379258223a3SMatthew Dillon goto freeport; 380258223a3SMatthew Dillon } 381258223a3SMatthew Dillon 382258223a3SMatthew Dillon /* Setup command list base address */ 383258223a3SMatthew Dillon dva = AHCI_DMA_DVA(ap->ap_dmamem_cmd_list); 384258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CLBU, (u_int32_t)(dva >> 32)); 385258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CLB, (u_int32_t)dva); 386258223a3SMatthew Dillon 387258223a3SMatthew Dillon /* Split CCB allocation into CCBs and assign to command header/table */ 388258223a3SMatthew Dillon hdr = AHCI_DMA_KVA(ap->ap_dmamem_cmd_list); 389258223a3SMatthew Dillon table = AHCI_DMA_KVA(ap->ap_dmamem_cmd_table); 390258223a3SMatthew Dillon for (i = 0; i < sc->sc_ncmds; i++) { 391258223a3SMatthew Dillon ccb = &ap->ap_ccbs[i]; 392258223a3SMatthew Dillon 393258223a3SMatthew Dillon error = bus_dmamap_create(sc->sc_tag_data, BUS_DMA_ALLOCNOW, 394258223a3SMatthew Dillon &ccb->ccb_dmamap); 395258223a3SMatthew Dillon if (error) { 396258223a3SMatthew Dillon device_printf(sc->sc_dev, 397258223a3SMatthew Dillon "unable to create dmamap for port %d " 398258223a3SMatthew Dillon "ccb %d\n", port, i); 399258223a3SMatthew Dillon goto freeport; 400258223a3SMatthew Dillon } 401258223a3SMatthew Dillon 402258223a3SMatthew Dillon callout_init(&ccb->ccb_timeout); 403258223a3SMatthew Dillon ccb->ccb_slot = i; 404258223a3SMatthew Dillon ccb->ccb_port = ap; 405258223a3SMatthew Dillon ccb->ccb_cmd_hdr = &hdr[i]; 406258223a3SMatthew Dillon ccb->ccb_cmd_table = &table[i]; 407258223a3SMatthew Dillon dva = AHCI_DMA_DVA(ap->ap_dmamem_cmd_table) + 408258223a3SMatthew Dillon ccb->ccb_slot * sizeof(struct ahci_cmd_table); 409258223a3SMatthew Dillon ccb->ccb_cmd_hdr->ctba_hi = htole32((u_int32_t)(dva >> 32)); 410258223a3SMatthew Dillon ccb->ccb_cmd_hdr->ctba_lo = htole32((u_int32_t)dva); 411258223a3SMatthew Dillon 412258223a3SMatthew Dillon ccb->ccb_xa.fis = 413258223a3SMatthew Dillon (struct ata_fis_h2d *)ccb->ccb_cmd_table->cfis; 414258223a3SMatthew Dillon ccb->ccb_xa.packetcmd = ccb->ccb_cmd_table->acmd; 415258223a3SMatthew Dillon ccb->ccb_xa.tag = i; 416258223a3SMatthew Dillon 417258223a3SMatthew Dillon ccb->ccb_xa.state = ATA_S_COMPLETE; 4181067474aSMatthew Dillon 4191067474aSMatthew Dillon /* 4201067474aSMatthew Dillon * CCB[1] is the error CCB and is not get or put. It is 4211067474aSMatthew Dillon * also used for probing. Numerous HBAs only load the 4221067474aSMatthew Dillon * signature from CCB[1] so it MUST be used for the second 4231067474aSMatthew Dillon * FIS. 4241067474aSMatthew Dillon */ 4251067474aSMatthew Dillon if (i == 1) 4261067474aSMatthew Dillon ap->ap_err_ccb = ccb; 4271067474aSMatthew Dillon else 428258223a3SMatthew Dillon ahci_put_ccb(ccb); 429258223a3SMatthew Dillon } 430258223a3SMatthew Dillon 43112feb904SMatthew Dillon /* 43212feb904SMatthew Dillon * Wait for ICC change to complete 43312feb904SMatthew Dillon */ 434258223a3SMatthew Dillon ahci_pwait_clr(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_ICC); 435258223a3SMatthew Dillon 436fd8bd957SMatthew Dillon /* 43712feb904SMatthew Dillon * Calculate the interrupt mask 43812feb904SMatthew Dillon */ 43912feb904SMatthew Dillon data = AHCI_PREG_IE_TFEE | AHCI_PREG_IE_HBFE | 44012feb904SMatthew Dillon AHCI_PREG_IE_IFE | AHCI_PREG_IE_OFE | 44112feb904SMatthew Dillon AHCI_PREG_IE_DPE | AHCI_PREG_IE_UFE | 44212feb904SMatthew Dillon AHCI_PREG_IE_PCE | AHCI_PREG_IE_PRCE | 44312feb904SMatthew Dillon AHCI_PREG_IE_DHRE | AHCI_PREG_IE_SDBE; 44412feb904SMatthew Dillon if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SSNTF) 44512feb904SMatthew Dillon data |= AHCI_PREG_IE_IPME; 44612feb904SMatthew Dillon #ifdef AHCI_COALESCE 44712feb904SMatthew Dillon if (sc->sc_ccc_ports & (1 << port) 44812feb904SMatthew Dillon data &= ~(AHCI_PREG_IE_SDBE | AHCI_PREG_IE_DHRE); 44912feb904SMatthew Dillon #endif 45012feb904SMatthew Dillon ap->ap_intmask = data; 45112feb904SMatthew Dillon 45212feb904SMatthew Dillon /* 453e8cf3f55SMatthew Dillon * Start the port helper thread. The helper thread will call 454e8cf3f55SMatthew Dillon * ahci_port_init() so the ports can all be started in parallel. 455e8cf3f55SMatthew Dillon * A failure by ahci_port_init() does not deallocate the port 456e8cf3f55SMatthew Dillon * since we still want hot-plug events. 457fd8bd957SMatthew Dillon */ 458f4553de1SMatthew Dillon ahci_os_start_port(ap); 459fd8bd957SMatthew Dillon return(0); 460fd8bd957SMatthew Dillon freeport: 461fd8bd957SMatthew Dillon ahci_port_free(sc, port); 462fd8bd957SMatthew Dillon return (rc); 463fd8bd957SMatthew Dillon } 464fd8bd957SMatthew Dillon 465fd8bd957SMatthew Dillon /* 466492bffafSMatthew Dillon * [re]initialize an idle port. No CCBs should be active. (from port thread) 467fd8bd957SMatthew Dillon * 468fd8bd957SMatthew Dillon * This function is called during the initial port allocation sequence 469fd8bd957SMatthew Dillon * and is also called on hot-plug insertion. We take no chances and 470fd8bd957SMatthew Dillon * use a portreset instead of a softreset. 471fd8bd957SMatthew Dillon * 47222181ab7SMatthew Dillon * This function is the only way to move a failed port back to active 47322181ab7SMatthew Dillon * status. 47422181ab7SMatthew Dillon * 475fd8bd957SMatthew Dillon * Returns 0 if a device is successfully detected. 476fd8bd957SMatthew Dillon */ 477fd8bd957SMatthew Dillon int 47812feb904SMatthew Dillon ahci_port_init(struct ahci_port *ap) 479fd8bd957SMatthew Dillon { 480492bffafSMatthew Dillon u_int32_t cmd; 481e8cf3f55SMatthew Dillon 482e8cf3f55SMatthew Dillon /* 483492bffafSMatthew Dillon * Register [re]initialization 484492bffafSMatthew Dillon * 485f17a0cedSMatthew Dillon * Flush the TFD and SERR and make sure the port is stopped before 486f17a0cedSMatthew Dillon * enabling its interrupt. We no longer cycle the port start as 487f17a0cedSMatthew Dillon * the port should not be started unless a device is present. 488f17a0cedSMatthew Dillon * 489f17a0cedSMatthew Dillon * XXX should we enable FIS reception? (FRE)? 490e8cf3f55SMatthew Dillon */ 491492bffafSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IE, 0); 492492bffafSMatthew Dillon ahci_port_stop(ap, 0); 493492bffafSMatthew Dillon if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SSNTF) 494492bffafSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SNTF, -1); 495f17a0cedSMatthew Dillon ahci_flush_tfd(ap); 496f17a0cedSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 497492bffafSMatthew Dillon 498492bffafSMatthew Dillon /* 499493d3201SMatthew Dillon * If we are being harsh try to kill the port completely. Normally 500493d3201SMatthew Dillon * we would want to hold on to some of the state the BIOS may have 501493d3201SMatthew Dillon * set, such as SUD (spin up device). 502492bffafSMatthew Dillon * 503492bffafSMatthew Dillon * AP_F_HARSH_REINIT is cleared in the hard reset state 504492bffafSMatthew Dillon */ 505492bffafSMatthew Dillon if (ap->ap_flags & AP_F_HARSH_REINIT) { 506492bffafSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SCTL, AHCI_PREG_SCTL_IPM_DISABLED); 507492bffafSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, 0); 508492bffafSMatthew Dillon 509492bffafSMatthew Dillon ahci_os_sleep(1000); 510492bffafSMatthew Dillon 511492bffafSMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC; 512492bffafSMatthew Dillon cmd &= ~(AHCI_PREG_CMD_CLO | AHCI_PREG_CMD_PMA); 513492bffafSMatthew Dillon cmd |= AHCI_PREG_CMD_FRE | AHCI_PREG_CMD_POD | 514492bffafSMatthew Dillon AHCI_PREG_CMD_SUD; 515492bffafSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd | AHCI_PREG_CMD_ICC_ACTIVE); 516492bffafSMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC; 517492bffafSMatthew Dillon if ((cmd & AHCI_PREG_CMD_FRE) == 0) { 518492bffafSMatthew Dillon kprintf("%s: Warning: FRE did not come up during " 519492bffafSMatthew Dillon "harsh reinitialization\n", 520492bffafSMatthew Dillon PORTNAME(ap)); 521492bffafSMatthew Dillon } 522492bffafSMatthew Dillon ahci_os_sleep(1000); 523492bffafSMatthew Dillon } 524492bffafSMatthew Dillon 525492bffafSMatthew Dillon /* 526492bffafSMatthew Dillon * Clear any pending garbage and re-enable the interrupt before 527492bffafSMatthew Dillon * going to the next stage. 528492bffafSMatthew Dillon */ 529492bffafSMatthew Dillon ap->ap_probe = ATA_PROBE_NEED_HARD_RESET; 530492bffafSMatthew Dillon ap->ap_pmcount = 0; 531492bffafSMatthew Dillon 532492bffafSMatthew Dillon if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SSNTF) 533492bffafSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SNTF, -1); 534492bffafSMatthew Dillon ahci_flush_tfd(ap); 535492bffafSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 536492bffafSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, -1); 537492bffafSMatthew Dillon 538f4553de1SMatthew Dillon ahci_port_interrupt_enable(ap); 539492bffafSMatthew Dillon 54012feb904SMatthew Dillon return (0); 541f4553de1SMatthew Dillon } 542f4553de1SMatthew Dillon 543f4553de1SMatthew Dillon /* 544f4553de1SMatthew Dillon * Enable or re-enable interrupts on a port. 545f4553de1SMatthew Dillon * 546f4553de1SMatthew Dillon * This routine is called from the port initialization code or from the 547f4553de1SMatthew Dillon * helper thread as the real interrupt may be forced to turn off certain 548f4553de1SMatthew Dillon * interrupt sources. 549f4553de1SMatthew Dillon */ 550f4553de1SMatthew Dillon void 551f4553de1SMatthew Dillon ahci_port_interrupt_enable(struct ahci_port *ap) 552f4553de1SMatthew Dillon { 55312feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IE, ap->ap_intmask); 5541980eff3SMatthew Dillon } 555258223a3SMatthew Dillon 556fd8bd957SMatthew Dillon /* 557f5caeaa0SMatthew Dillon * Manage the agressive link power management capability. 558f17a0cedSMatthew Dillon */ 559f17a0cedSMatthew Dillon void 560f17a0cedSMatthew Dillon ahci_port_link_pwr_mgmt(struct ahci_port *ap, int link_pwr_mgmt) 561f17a0cedSMatthew Dillon { 562f17a0cedSMatthew Dillon u_int32_t cmd, sctl; 563f17a0cedSMatthew Dillon 564f17a0cedSMatthew Dillon if (link_pwr_mgmt == ap->link_pwr_mgmt) 565f17a0cedSMatthew Dillon return; 566f17a0cedSMatthew Dillon 567f17a0cedSMatthew Dillon if ((ap->ap_sc->sc_cap & AHCI_REG_CAP_SALP) == 0) { 568f17a0cedSMatthew Dillon kprintf("%s: link power management not supported.\n", 569f17a0cedSMatthew Dillon PORTNAME(ap)); 570f17a0cedSMatthew Dillon return; 571f17a0cedSMatthew Dillon } 572f17a0cedSMatthew Dillon 573f17a0cedSMatthew Dillon ahci_os_lock_port(ap); 574f17a0cedSMatthew Dillon 575f17a0cedSMatthew Dillon if (link_pwr_mgmt == AHCI_LINK_PWR_MGMT_AGGR && 576f17a0cedSMatthew Dillon (ap->ap_sc->sc_cap & AHCI_REG_CAP_SSC)) { 577f17a0cedSMatthew Dillon kprintf("%s: enabling aggressive link power management.\n", 578f17a0cedSMatthew Dillon PORTNAME(ap)); 579f17a0cedSMatthew Dillon 580795adb22SMatthew Dillon ap->link_pwr_mgmt = link_pwr_mgmt; 581795adb22SMatthew Dillon 582f17a0cedSMatthew Dillon ap->ap_intmask &= ~AHCI_PREG_IE_PRCE; 583f17a0cedSMatthew Dillon ahci_port_interrupt_enable(ap); 584f17a0cedSMatthew Dillon 585f17a0cedSMatthew Dillon sctl = ahci_pread(ap, AHCI_PREG_SCTL); 586f17a0cedSMatthew Dillon sctl &= ~(AHCI_PREG_SCTL_IPM_DISABLED); 587f17a0cedSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SCTL, sctl); 588f17a0cedSMatthew Dillon 589795adb22SMatthew Dillon /* 590795adb22SMatthew Dillon * Enable device initiated link power management for 591795adb22SMatthew Dillon * directly attached devices that support it. 592795adb22SMatthew Dillon */ 593795adb22SMatthew Dillon if (ap->ap_type != ATA_PORT_T_PM && 594795adb22SMatthew Dillon ap->ap_ata[0]->at_identify.satafsup & (1 << 3)) { 595795adb22SMatthew Dillon if (ahci_set_feature(ap, NULL, ATA_SATAFT_DEVIPS, 1)) 596795adb22SMatthew Dillon kprintf("%s: Could not enable device initiated " 597795adb22SMatthew Dillon "link power management.\n", 598795adb22SMatthew Dillon PORTNAME(ap)); 599795adb22SMatthew Dillon } 600795adb22SMatthew Dillon 601f17a0cedSMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD); 602f17a0cedSMatthew Dillon cmd |= AHCI_PREG_CMD_ASP; 603f17a0cedSMatthew Dillon cmd |= AHCI_PREG_CMD_ALPE; 604f17a0cedSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd); 605f17a0cedSMatthew Dillon 606f17a0cedSMatthew Dillon } else if (link_pwr_mgmt == AHCI_LINK_PWR_MGMT_MEDIUM && 607f17a0cedSMatthew Dillon (ap->ap_sc->sc_cap & AHCI_REG_CAP_PSC)) { 608f17a0cedSMatthew Dillon kprintf("%s: enabling medium link power management.\n", 609f17a0cedSMatthew Dillon PORTNAME(ap)); 610f17a0cedSMatthew Dillon 611795adb22SMatthew Dillon ap->link_pwr_mgmt = link_pwr_mgmt; 612795adb22SMatthew Dillon 613f17a0cedSMatthew Dillon ap->ap_intmask &= ~AHCI_PREG_IE_PRCE; 614f17a0cedSMatthew Dillon ahci_port_interrupt_enable(ap); 615f17a0cedSMatthew Dillon 616f17a0cedSMatthew Dillon sctl = ahci_pread(ap, AHCI_PREG_SCTL); 617795adb22SMatthew Dillon sctl |= AHCI_PREG_SCTL_IPM_DISABLED; 618795adb22SMatthew Dillon sctl &= ~AHCI_PREG_SCTL_IPM_NOPARTIAL; 619f17a0cedSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SCTL, sctl); 620f17a0cedSMatthew Dillon 621f17a0cedSMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD); 622f17a0cedSMatthew Dillon cmd &= ~AHCI_PREG_CMD_ASP; 623f17a0cedSMatthew Dillon cmd |= AHCI_PREG_CMD_ALPE; 624f17a0cedSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd); 625f17a0cedSMatthew Dillon 626f17a0cedSMatthew Dillon } else if (link_pwr_mgmt == AHCI_LINK_PWR_MGMT_NONE) { 627f17a0cedSMatthew Dillon kprintf("%s: disabling link power management.\n", 628f17a0cedSMatthew Dillon PORTNAME(ap)); 629f17a0cedSMatthew Dillon 630795adb22SMatthew Dillon /* Disable device initiated link power management */ 631795adb22SMatthew Dillon if (ap->ap_type != ATA_PORT_T_PM && 632795adb22SMatthew Dillon ap->ap_ata[0]->at_identify.satafsup & (1 << 3)) 633795adb22SMatthew Dillon ahci_set_feature(ap, NULL, ATA_SATAFT_DEVIPS, 0); 634795adb22SMatthew Dillon 635f17a0cedSMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD); 636f17a0cedSMatthew Dillon cmd &= ~(AHCI_PREG_CMD_ALPE | AHCI_PREG_CMD_ASP); 637f17a0cedSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd); 638f17a0cedSMatthew Dillon 639f17a0cedSMatthew Dillon sctl = ahci_pread(ap, AHCI_PREG_SCTL); 640f17a0cedSMatthew Dillon sctl |= AHCI_PREG_SCTL_IPM_DISABLED; 641f17a0cedSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SCTL, sctl); 642f17a0cedSMatthew Dillon 643f17a0cedSMatthew Dillon /* let the drive come back to avoid PRCS interrupts later */ 644f17a0cedSMatthew Dillon ahci_os_unlock_port(ap); 645f17a0cedSMatthew Dillon ahci_os_sleep(1000); 646f17a0cedSMatthew Dillon ahci_os_lock_port(ap); 647f17a0cedSMatthew Dillon 648795adb22SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, 649795adb22SMatthew Dillon AHCI_PREG_SERR_DIAG_N | AHCI_PREG_SERR_DIAG_W); 650f17a0cedSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_PRCS); 651f17a0cedSMatthew Dillon 652f17a0cedSMatthew Dillon ap->ap_intmask |= AHCI_PREG_IE_PRCE; 653f17a0cedSMatthew Dillon ahci_port_interrupt_enable(ap); 654f17a0cedSMatthew Dillon 655f17a0cedSMatthew Dillon ap->link_pwr_mgmt = link_pwr_mgmt; 656f17a0cedSMatthew Dillon } else { 657f17a0cedSMatthew Dillon kprintf("%s: unsupported link power management state %d.\n", 658f17a0cedSMatthew Dillon PORTNAME(ap), link_pwr_mgmt); 659f17a0cedSMatthew Dillon } 660f17a0cedSMatthew Dillon 661f17a0cedSMatthew Dillon ahci_os_unlock_port(ap); 662f17a0cedSMatthew Dillon } 663f17a0cedSMatthew Dillon 664795adb22SMatthew Dillon /* 665795adb22SMatthew Dillon * Return current link power state. 666795adb22SMatthew Dillon */ 667795adb22SMatthew Dillon int 668795adb22SMatthew Dillon ahci_port_link_pwr_state(struct ahci_port *ap) 669795adb22SMatthew Dillon { 670795adb22SMatthew Dillon uint32_t r; 671795adb22SMatthew Dillon 672795adb22SMatthew Dillon r = ahci_pread(ap, AHCI_PREG_SSTS); 673795adb22SMatthew Dillon switch (r & SATA_PM_SSTS_IPM) { 674795adb22SMatthew Dillon case SATA_PM_SSTS_IPM_ACTIVE: 675795adb22SMatthew Dillon return 1; 676795adb22SMatthew Dillon case SATA_PM_SSTS_IPM_PARTIAL: 677795adb22SMatthew Dillon return 2; 678795adb22SMatthew Dillon case SATA_PM_SSTS_IPM_SLUMBER: 679795adb22SMatthew Dillon return 3; 680795adb22SMatthew Dillon default: 681795adb22SMatthew Dillon return 0; 682795adb22SMatthew Dillon } 683795adb22SMatthew Dillon } 684f17a0cedSMatthew Dillon 685f17a0cedSMatthew Dillon /* 6863209f581SMatthew Dillon * Run the port / target state machine from a main context. 6873209f581SMatthew Dillon * 6883209f581SMatthew Dillon * The state machine for the port is always run. 6893209f581SMatthew Dillon * 6903209f581SMatthew Dillon * If atx is non-NULL run the state machine for a particular target. 6913209f581SMatthew Dillon * If atx is NULL run the state machine for all targets. 6923209f581SMatthew Dillon */ 6933209f581SMatthew Dillon void 694831bc9e3SMatthew Dillon ahci_port_state_machine(struct ahci_port *ap, int initial) 6953209f581SMatthew Dillon { 6963209f581SMatthew Dillon struct ata_port *at; 6973209f581SMatthew Dillon u_int32_t data; 6983209f581SMatthew Dillon int target; 6993209f581SMatthew Dillon int didsleep; 700831bc9e3SMatthew Dillon int loop; 7013209f581SMatthew Dillon 702831bc9e3SMatthew Dillon /* 703831bc9e3SMatthew Dillon * State machine for port. Note that CAM is not yet associated 704831bc9e3SMatthew Dillon * during the initial parallel probe and the port's probe state 705831bc9e3SMatthew Dillon * will not get past ATA_PROBE_NEED_IDENT. 706831bc9e3SMatthew Dillon */ 707c408a8b3SMatthew Dillon { 7081067474aSMatthew Dillon if (initial == 0 && ap->ap_probe <= ATA_PROBE_NEED_HARD_RESET) { 7091067474aSMatthew Dillon kprintf("%s: Waiting 10 seconds on insertion\n", 7101067474aSMatthew Dillon PORTNAME(ap)); 7111067474aSMatthew Dillon ahci_os_sleep(10000); 7121067474aSMatthew Dillon initial = 1; 7133209f581SMatthew Dillon } 7141067474aSMatthew Dillon if (ap->ap_probe == ATA_PROBE_NEED_INIT) 71512feb904SMatthew Dillon ahci_port_init(ap); 7163209f581SMatthew Dillon if (ap->ap_probe == ATA_PROBE_NEED_HARD_RESET) 7173209f581SMatthew Dillon ahci_port_reset(ap, NULL, 1); 7183209f581SMatthew Dillon if (ap->ap_probe == ATA_PROBE_NEED_SOFT_RESET) 7193209f581SMatthew Dillon ahci_port_reset(ap, NULL, 0); 7203209f581SMatthew Dillon if (ap->ap_probe == ATA_PROBE_NEED_IDENT) 7213209f581SMatthew Dillon ahci_cam_probe(ap, NULL); 7223209f581SMatthew Dillon } 7233209f581SMatthew Dillon if (ap->ap_type != ATA_PORT_T_PM) { 7243209f581SMatthew Dillon if (ap->ap_probe == ATA_PROBE_FAILED) { 7253209f581SMatthew Dillon ahci_cam_changed(ap, NULL, 0); 726f4553de1SMatthew Dillon } else if (ap->ap_probe >= ATA_PROBE_NEED_IDENT) { 7273209f581SMatthew Dillon ahci_cam_changed(ap, NULL, 1); 7283209f581SMatthew Dillon } 7293209f581SMatthew Dillon return; 7303209f581SMatthew Dillon } 7313209f581SMatthew Dillon 732831bc9e3SMatthew Dillon /* 733831bc9e3SMatthew Dillon * Port Multiplier state machine. 734831bc9e3SMatthew Dillon * 735831bc9e3SMatthew Dillon * Get a mask of changed targets and combine with any runnable 736831bc9e3SMatthew Dillon * states already present. 737831bc9e3SMatthew Dillon */ 738831bc9e3SMatthew Dillon for (loop = 0; ;++loop) { 7392cc2e845SMatthew Dillon if (ahci_pm_read(ap, 15, SATA_PMREG_EINFO, &data)) { 7403209f581SMatthew Dillon kprintf("%s: PM unable to read hot-plug bitmap\n", 7413209f581SMatthew Dillon PORTNAME(ap)); 7423209f581SMatthew Dillon break; 7433209f581SMatthew Dillon } 7443209f581SMatthew Dillon 7453209f581SMatthew Dillon /* 746831bc9e3SMatthew Dillon * Do at least one loop, then stop if no more state changes 747831bc9e3SMatthew Dillon * have occured. The PM might not generate a new 748831bc9e3SMatthew Dillon * notification until we clear the entire bitmap. 7493209f581SMatthew Dillon */ 750831bc9e3SMatthew Dillon if (loop && data == 0) 7513209f581SMatthew Dillon break; 7523209f581SMatthew Dillon 7533209f581SMatthew Dillon /* 7543209f581SMatthew Dillon * New devices showing up in the bitmap require some spin-up 7553209f581SMatthew Dillon * time before we start probing them. Reset didsleep. The 7563209f581SMatthew Dillon * first new device we detect will sleep before probing. 757831bc9e3SMatthew Dillon * 758831bc9e3SMatthew Dillon * This only applies to devices whos change bit is set in 759831bc9e3SMatthew Dillon * the data, and does not apply to the initial boot-time 760831bc9e3SMatthew Dillon * probe. 7613209f581SMatthew Dillon */ 7623209f581SMatthew Dillon didsleep = 0; 7633209f581SMatthew Dillon 7643209f581SMatthew Dillon for (target = 0; target < ap->ap_pmcount; ++target) { 765b012a2caSMatthew Dillon at = ap->ap_ata[target]; 7663209f581SMatthew Dillon 7673209f581SMatthew Dillon /* 7683209f581SMatthew Dillon * Check the target state for targets behind the PM 7693209f581SMatthew Dillon * which have changed state. This will adjust 7703209f581SMatthew Dillon * at_probe and set ATA_PORT_F_RESCAN 7713209f581SMatthew Dillon * 7721067474aSMatthew Dillon * We want to wait at least 10 seconds before probing 7733209f581SMatthew Dillon * a newly inserted device. If the check status 7743209f581SMatthew Dillon * indicates a device is present and in need of a 7753209f581SMatthew Dillon * hard reset, we make sure we have slept before 7763209f581SMatthew Dillon * continuing. 777831bc9e3SMatthew Dillon * 7781067474aSMatthew Dillon * We also need to wait at least 1 second for the 7791067474aSMatthew Dillon * PHY state to change after insertion, if we 7801067474aSMatthew Dillon * haven't already waited the 10 seconds. 7811067474aSMatthew Dillon * 782831bc9e3SMatthew Dillon * NOTE: When pm_check_good finds a good port it 783831bc9e3SMatthew Dillon * typically starts us in probe state 784831bc9e3SMatthew Dillon * NEED_HARD_RESET rather than INIT. 7853209f581SMatthew Dillon */ 7863209f581SMatthew Dillon if (data & (1 << target)) { 7871067474aSMatthew Dillon if (initial == 0 && didsleep == 0) 7881067474aSMatthew Dillon ahci_os_sleep(1000); 7893209f581SMatthew Dillon ahci_pm_check_good(ap, target); 790831bc9e3SMatthew Dillon if (initial == 0 && didsleep == 0 && 791831bc9e3SMatthew Dillon at->at_probe <= ATA_PROBE_NEED_HARD_RESET 792831bc9e3SMatthew Dillon ) { 7933209f581SMatthew Dillon didsleep = 1; 794121d8e75SMatthew Dillon kprintf("%s: Waiting 10 seconds on insertion\n", PORTNAME(ap)); 795121d8e75SMatthew Dillon ahci_os_sleep(10000); 7963209f581SMatthew Dillon } 7973209f581SMatthew Dillon } 798831bc9e3SMatthew Dillon 799831bc9e3SMatthew Dillon /* 800831bc9e3SMatthew Dillon * Report hot-plug events before the probe state 801831bc9e3SMatthew Dillon * really gets hot. Only actual events are reported 802831bc9e3SMatthew Dillon * here to reduce spew. 803831bc9e3SMatthew Dillon */ 804831bc9e3SMatthew Dillon if (data & (1 << target)) { 805831bc9e3SMatthew Dillon kprintf("%s: HOTPLUG (PM) - ", ATANAME(ap, at)); 806831bc9e3SMatthew Dillon switch(at->at_probe) { 807831bc9e3SMatthew Dillon case ATA_PROBE_NEED_INIT: 808831bc9e3SMatthew Dillon case ATA_PROBE_NEED_HARD_RESET: 809831bc9e3SMatthew Dillon kprintf("Device inserted\n"); 810831bc9e3SMatthew Dillon break; 811831bc9e3SMatthew Dillon case ATA_PROBE_FAILED: 812831bc9e3SMatthew Dillon kprintf("Device removed\n"); 813831bc9e3SMatthew Dillon break; 814831bc9e3SMatthew Dillon default: 815831bc9e3SMatthew Dillon kprintf("Device probe in progress\n"); 816831bc9e3SMatthew Dillon break; 817831bc9e3SMatthew Dillon } 8183209f581SMatthew Dillon } 8193209f581SMatthew Dillon 8203209f581SMatthew Dillon /* 821831bc9e3SMatthew Dillon * Run through the state machine as necessary if 822831bc9e3SMatthew Dillon * the port is not marked failed. 823831bc9e3SMatthew Dillon * 824831bc9e3SMatthew Dillon * The state machine may stop at NEED_IDENT if 825831bc9e3SMatthew Dillon * CAM is not yet attached. 826831bc9e3SMatthew Dillon * 827831bc9e3SMatthew Dillon * Acquire exclusive access to the port while we 828831bc9e3SMatthew Dillon * are doing this. This prevents command-completion 829831bc9e3SMatthew Dillon * from queueing commands for non-polled targets 830831bc9e3SMatthew Dillon * inbetween our probe steps. We need to do this 831831bc9e3SMatthew Dillon * because the reset probes can generate severe PHY 832831bc9e3SMatthew Dillon * and protocol errors and soft-brick the port. 8333209f581SMatthew Dillon */ 834831bc9e3SMatthew Dillon if (at->at_probe != ATA_PROBE_FAILED && 835831bc9e3SMatthew Dillon at->at_probe != ATA_PROBE_GOOD) { 836831bc9e3SMatthew Dillon ahci_beg_exclusive_access(ap, at); 8373209f581SMatthew Dillon if (at->at_probe == ATA_PROBE_NEED_INIT) 83812feb904SMatthew Dillon ahci_pm_port_init(ap, at); 8393209f581SMatthew Dillon if (at->at_probe == ATA_PROBE_NEED_HARD_RESET) 8403209f581SMatthew Dillon ahci_port_reset(ap, at, 1); 8413209f581SMatthew Dillon if (at->at_probe == ATA_PROBE_NEED_SOFT_RESET) 8423209f581SMatthew Dillon ahci_port_reset(ap, at, 0); 8433209f581SMatthew Dillon if (at->at_probe == ATA_PROBE_NEED_IDENT) 8443209f581SMatthew Dillon ahci_cam_probe(ap, at); 845831bc9e3SMatthew Dillon ahci_end_exclusive_access(ap, at); 8463209f581SMatthew Dillon } 8473209f581SMatthew Dillon 8483209f581SMatthew Dillon /* 849831bc9e3SMatthew Dillon * Add or remove from CAM 8503209f581SMatthew Dillon */ 8513209f581SMatthew Dillon if (at->at_features & ATA_PORT_F_RESCAN) { 8523209f581SMatthew Dillon at->at_features &= ~ATA_PORT_F_RESCAN; 8533209f581SMatthew Dillon if (at->at_probe == ATA_PROBE_FAILED) { 8543209f581SMatthew Dillon ahci_cam_changed(ap, at, 0); 855f4553de1SMatthew Dillon } else if (at->at_probe >= ATA_PROBE_NEED_IDENT) { 8563209f581SMatthew Dillon ahci_cam_changed(ap, at, 1); 8573209f581SMatthew Dillon } 8583209f581SMatthew Dillon } 8593560ed94SMatthew Dillon data &= ~(1 << target); 8603560ed94SMatthew Dillon } 8613560ed94SMatthew Dillon if (data) { 8623560ed94SMatthew Dillon kprintf("%s: WARNING (PM): extra bits set in " 8633560ed94SMatthew Dillon "EINFO: %08x\n", PORTNAME(ap), data); 8643560ed94SMatthew Dillon while (target < AHCI_MAX_PMPORTS) { 8653560ed94SMatthew Dillon ahci_pm_check_good(ap, target); 8663560ed94SMatthew Dillon ++target; 8673560ed94SMatthew Dillon } 8683209f581SMatthew Dillon } 8693209f581SMatthew Dillon } 8703209f581SMatthew Dillon } 8713209f581SMatthew Dillon 8723209f581SMatthew Dillon 8733209f581SMatthew Dillon /* 874fd8bd957SMatthew Dillon * De-initialize and detach a port. 875fd8bd957SMatthew Dillon */ 876258223a3SMatthew Dillon void 877258223a3SMatthew Dillon ahci_port_free(struct ahci_softc *sc, u_int port) 878258223a3SMatthew Dillon { 879258223a3SMatthew Dillon struct ahci_port *ap = sc->sc_ports[port]; 880258223a3SMatthew Dillon struct ahci_ccb *ccb; 881b012a2caSMatthew Dillon int i; 882258223a3SMatthew Dillon 88317eab71eSMatthew Dillon /* 88417eab71eSMatthew Dillon * Ensure port is disabled and its interrupts are all flushed. 88517eab71eSMatthew Dillon */ 886258223a3SMatthew Dillon if (ap->ap_sc) { 88717eab71eSMatthew Dillon ahci_port_stop(ap, 1); 888f4553de1SMatthew Dillon ahci_os_stop_port(ap); 889258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, 0); 890258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IE, 0); 891258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, ahci_pread(ap, AHCI_PREG_IS)); 892258223a3SMatthew Dillon ahci_write(sc, AHCI_REG_IS, 1 << port); 893258223a3SMatthew Dillon } 894258223a3SMatthew Dillon 895258223a3SMatthew Dillon if (ap->ap_ccbs) { 896258223a3SMatthew Dillon while ((ccb = ahci_get_ccb(ap)) != NULL) { 897258223a3SMatthew Dillon if (ccb->ccb_dmamap) { 898258223a3SMatthew Dillon bus_dmamap_destroy(sc->sc_tag_data, 899258223a3SMatthew Dillon ccb->ccb_dmamap); 900258223a3SMatthew Dillon ccb->ccb_dmamap = NULL; 901258223a3SMatthew Dillon } 902258223a3SMatthew Dillon } 9031067474aSMatthew Dillon if ((ccb = ap->ap_err_ccb) != NULL) { 9041067474aSMatthew Dillon if (ccb->ccb_dmamap) { 9051067474aSMatthew Dillon bus_dmamap_destroy(sc->sc_tag_data, 9061067474aSMatthew Dillon ccb->ccb_dmamap); 9071067474aSMatthew Dillon ccb->ccb_dmamap = NULL; 9081067474aSMatthew Dillon } 9091067474aSMatthew Dillon ap->ap_err_ccb = NULL; 9101067474aSMatthew Dillon } 911258223a3SMatthew Dillon kfree(ap->ap_ccbs, M_DEVBUF); 912258223a3SMatthew Dillon ap->ap_ccbs = NULL; 913258223a3SMatthew Dillon } 914258223a3SMatthew Dillon 915258223a3SMatthew Dillon if (ap->ap_dmamem_cmd_list) { 916258223a3SMatthew Dillon ahci_dmamem_free(sc, ap->ap_dmamem_cmd_list); 917258223a3SMatthew Dillon ap->ap_dmamem_cmd_list = NULL; 918258223a3SMatthew Dillon } 919258223a3SMatthew Dillon if (ap->ap_dmamem_rfis) { 920258223a3SMatthew Dillon ahci_dmamem_free(sc, ap->ap_dmamem_rfis); 921258223a3SMatthew Dillon ap->ap_dmamem_rfis = NULL; 922258223a3SMatthew Dillon } 923258223a3SMatthew Dillon if (ap->ap_dmamem_cmd_table) { 924258223a3SMatthew Dillon ahci_dmamem_free(sc, ap->ap_dmamem_cmd_table); 925258223a3SMatthew Dillon ap->ap_dmamem_cmd_table = NULL; 926258223a3SMatthew Dillon } 9271980eff3SMatthew Dillon if (ap->ap_ata) { 928b012a2caSMatthew Dillon for (i = 0; i < AHCI_MAX_PMPORTS; ++i) { 929b012a2caSMatthew Dillon if (ap->ap_ata[i]) { 930b012a2caSMatthew Dillon kfree(ap->ap_ata[i], M_DEVBUF); 931b012a2caSMatthew Dillon ap->ap_ata[i] = NULL; 932b012a2caSMatthew Dillon } 933b012a2caSMatthew Dillon } 9341980eff3SMatthew Dillon } 93512feb904SMatthew Dillon if (ap->ap_err_scratch) { 93612feb904SMatthew Dillon kfree(ap->ap_err_scratch, M_DEVBUF); 93712feb904SMatthew Dillon ap->ap_err_scratch = NULL; 93812feb904SMatthew Dillon } 939258223a3SMatthew Dillon 940258223a3SMatthew Dillon /* bus_space(9) says we dont free the subregions handle */ 941258223a3SMatthew Dillon 942258223a3SMatthew Dillon kfree(ap, M_DEVBUF); 943258223a3SMatthew Dillon sc->sc_ports[port] = NULL; 944258223a3SMatthew Dillon } 945258223a3SMatthew Dillon 946492bffafSMatthew Dillon static 947492bffafSMatthew Dillon u_int32_t 948492bffafSMatthew Dillon ahci_pactive(struct ahci_port *ap) 949492bffafSMatthew Dillon { 950492bffafSMatthew Dillon u_int32_t mask; 951492bffafSMatthew Dillon 952492bffafSMatthew Dillon mask = ahci_pread(ap, AHCI_PREG_CI); 953492bffafSMatthew Dillon if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SNCQ) 954492bffafSMatthew Dillon mask |= ahci_pread(ap, AHCI_PREG_SACT); 955492bffafSMatthew Dillon return(mask); 956492bffafSMatthew Dillon } 957492bffafSMatthew Dillon 958fd8bd957SMatthew Dillon /* 959fd8bd957SMatthew Dillon * Start high-level command processing on the port 960fd8bd957SMatthew Dillon */ 961258223a3SMatthew Dillon int 96217eab71eSMatthew Dillon ahci_port_start(struct ahci_port *ap) 963258223a3SMatthew Dillon { 96412feb904SMatthew Dillon u_int32_t r, s, is, tfd; 965258223a3SMatthew Dillon 96617eab71eSMatthew Dillon /* 96717eab71eSMatthew Dillon * FRE must be turned on before ST. Wait for FR to go active 96817eab71eSMatthew Dillon * before turning on ST. The spec doesn't seem to think this 96917eab71eSMatthew Dillon * is necessary but waiting here avoids an on-off race in the 97017eab71eSMatthew Dillon * ahci_port_stop() code. 97117eab71eSMatthew Dillon */ 97212feb904SMatthew Dillon r = ahci_pread(ap, AHCI_PREG_CMD); 97317eab71eSMatthew Dillon if ((r & AHCI_PREG_CMD_FRE) == 0) { 974258223a3SMatthew Dillon r |= AHCI_PREG_CMD_FRE; 97517eab71eSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, r); 97617eab71eSMatthew Dillon } 97717eab71eSMatthew Dillon if ((ap->ap_sc->sc_flags & AHCI_F_IGN_FR) == 0) { 97817eab71eSMatthew Dillon if (ahci_pwait_set(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_FR)) { 97917eab71eSMatthew Dillon kprintf("%s: Cannot start FIS reception\n", 98017eab71eSMatthew Dillon PORTNAME(ap)); 98117eab71eSMatthew Dillon return (2); 98217eab71eSMatthew Dillon } 983f17a0cedSMatthew Dillon } else { 984f17a0cedSMatthew Dillon ahci_os_sleep(10); 98517eab71eSMatthew Dillon } 98617eab71eSMatthew Dillon 98717eab71eSMatthew Dillon /* 98817eab71eSMatthew Dillon * Turn on ST, wait for CR to come up. 98917eab71eSMatthew Dillon */ 990258223a3SMatthew Dillon r |= AHCI_PREG_CMD_ST; 991258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, r); 992f17a0cedSMatthew Dillon if (ahci_pwait_set_to(ap, 2000, AHCI_PREG_CMD, AHCI_PREG_CMD_CR)) { 9938bf6a3ffSMatthew Dillon s = ahci_pread(ap, AHCI_PREG_SERR); 9948bf6a3ffSMatthew Dillon is = ahci_pread(ap, AHCI_PREG_IS); 9958bf6a3ffSMatthew Dillon tfd = ahci_pread(ap, AHCI_PREG_TFD); 9961980eff3SMatthew Dillon kprintf("%s: Cannot start command DMA\n" 9971980eff3SMatthew Dillon "NCMP=%b NSERR=%b\n" 99812feb904SMatthew Dillon "NEWIS=%b\n" 99912feb904SMatthew Dillon "NEWTFD=%b\n", 10001980eff3SMatthew Dillon PORTNAME(ap), 10011980eff3SMatthew Dillon r, AHCI_PFMT_CMD, s, AHCI_PFMT_SERR, 100212feb904SMatthew Dillon is, AHCI_PFMT_IS, 100312feb904SMatthew Dillon tfd, AHCI_PFMT_TFD_STS); 100417eab71eSMatthew Dillon return (1); 100517eab71eSMatthew Dillon } 1006258223a3SMatthew Dillon 1007258223a3SMatthew Dillon #ifdef AHCI_COALESCE 100817eab71eSMatthew Dillon /* 100917eab71eSMatthew Dillon * (Re-)enable coalescing on the port. 101017eab71eSMatthew Dillon */ 1011258223a3SMatthew Dillon if (ap->ap_sc->sc_ccc_ports & (1 << ap->ap_num)) { 1012258223a3SMatthew Dillon ap->ap_sc->sc_ccc_ports_cur |= (1 << ap->ap_num); 1013258223a3SMatthew Dillon ahci_write(ap->ap_sc, AHCI_REG_CCC_PORTS, 1014258223a3SMatthew Dillon ap->ap_sc->sc_ccc_ports_cur); 1015258223a3SMatthew Dillon } 1016258223a3SMatthew Dillon #endif 1017258223a3SMatthew Dillon 1018258223a3SMatthew Dillon return (0); 1019258223a3SMatthew Dillon } 1020258223a3SMatthew Dillon 1021fd8bd957SMatthew Dillon /* 1022fd8bd957SMatthew Dillon * Stop high-level command processing on a port 10234c339a5fSMatthew Dillon * 10244c339a5fSMatthew Dillon * WARNING! If the port is stopped while CR is still active our saved 10254c339a5fSMatthew Dillon * CI/SACT will race any commands completed by the command 10264c339a5fSMatthew Dillon * processor prior to being able to stop. Thus we never call 10274c339a5fSMatthew Dillon * this function unless we intend to dispose of any remaining 10284c339a5fSMatthew Dillon * active commands. In particular, this complicates the timeout 10294c339a5fSMatthew Dillon * code. 1030fd8bd957SMatthew Dillon */ 1031258223a3SMatthew Dillon int 1032258223a3SMatthew Dillon ahci_port_stop(struct ahci_port *ap, int stop_fis_rx) 1033258223a3SMatthew Dillon { 1034258223a3SMatthew Dillon u_int32_t r; 1035258223a3SMatthew Dillon 1036258223a3SMatthew Dillon #ifdef AHCI_COALESCE 103717eab71eSMatthew Dillon /* 103817eab71eSMatthew Dillon * Disable coalescing on the port while it is stopped. 103917eab71eSMatthew Dillon */ 1040258223a3SMatthew Dillon if (ap->ap_sc->sc_ccc_ports & (1 << ap->ap_num)) { 1041258223a3SMatthew Dillon ap->ap_sc->sc_ccc_ports_cur &= ~(1 << ap->ap_num); 1042258223a3SMatthew Dillon ahci_write(ap->ap_sc, AHCI_REG_CCC_PORTS, 1043258223a3SMatthew Dillon ap->ap_sc->sc_ccc_ports_cur); 1044258223a3SMatthew Dillon } 1045258223a3SMatthew Dillon #endif 1046258223a3SMatthew Dillon 104717eab71eSMatthew Dillon /* 104817eab71eSMatthew Dillon * Turn off ST, then wait for CR to go off. 104917eab71eSMatthew Dillon */ 1050258223a3SMatthew Dillon r = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC; 1051258223a3SMatthew Dillon r &= ~AHCI_PREG_CMD_ST; 1052258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, r); 1053258223a3SMatthew Dillon 105417eab71eSMatthew Dillon if (ahci_pwait_clr(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_CR)) { 105517eab71eSMatthew Dillon kprintf("%s: Port bricked, unable to stop (ST)\n", 105617eab71eSMatthew Dillon PORTNAME(ap)); 1057258223a3SMatthew Dillon return (1); 105817eab71eSMatthew Dillon } 1059258223a3SMatthew Dillon 10601980eff3SMatthew Dillon #if 0 106117eab71eSMatthew Dillon /* 106217eab71eSMatthew Dillon * Turn off FRE, then wait for FR to go off. FRE cannot 106317eab71eSMatthew Dillon * be turned off until CR transitions to 0. 106417eab71eSMatthew Dillon */ 10651980eff3SMatthew Dillon if ((r & AHCI_PREG_CMD_FR) == 0) { 10661980eff3SMatthew Dillon kprintf("%s: FR stopped, clear FRE for next start\n", 10671980eff3SMatthew Dillon PORTNAME(ap)); 10681980eff3SMatthew Dillon stop_fis_rx = 2; 10691980eff3SMatthew Dillon } 10701980eff3SMatthew Dillon #endif 107117eab71eSMatthew Dillon if (stop_fis_rx) { 107217eab71eSMatthew Dillon r &= ~AHCI_PREG_CMD_FRE; 107317eab71eSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, r); 107417eab71eSMatthew Dillon if (ahci_pwait_clr(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_FR)) { 107517eab71eSMatthew Dillon kprintf("%s: Port bricked, unable to stop (FRE)\n", 107617eab71eSMatthew Dillon PORTNAME(ap)); 1077258223a3SMatthew Dillon return (2); 107817eab71eSMatthew Dillon } 107917eab71eSMatthew Dillon } 1080258223a3SMatthew Dillon 1081258223a3SMatthew Dillon return (0); 1082258223a3SMatthew Dillon } 1083258223a3SMatthew Dillon 1084fd8bd957SMatthew Dillon /* 1085fd8bd957SMatthew Dillon * AHCI command list override -> forcibly clear TFD.STS.{BSY,DRQ} 1086fd8bd957SMatthew Dillon */ 1087258223a3SMatthew Dillon int 1088258223a3SMatthew Dillon ahci_port_clo(struct ahci_port *ap) 1089258223a3SMatthew Dillon { 1090258223a3SMatthew Dillon struct ahci_softc *sc = ap->ap_sc; 1091258223a3SMatthew Dillon u_int32_t cmd; 1092258223a3SMatthew Dillon 1093258223a3SMatthew Dillon /* Only attempt CLO if supported by controller */ 1094258223a3SMatthew Dillon if ((ahci_read(sc, AHCI_REG_CAP) & AHCI_REG_CAP_SCLO) == 0) 1095258223a3SMatthew Dillon return (1); 1096258223a3SMatthew Dillon 1097258223a3SMatthew Dillon /* Issue CLO */ 1098258223a3SMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC; 1099258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd | AHCI_PREG_CMD_CLO); 1100258223a3SMatthew Dillon 1101258223a3SMatthew Dillon /* Wait for completion */ 1102258223a3SMatthew Dillon if (ahci_pwait_clr(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_CLO)) { 1103258223a3SMatthew Dillon kprintf("%s: CLO did not complete\n", PORTNAME(ap)); 1104258223a3SMatthew Dillon return (1); 1105258223a3SMatthew Dillon } 1106258223a3SMatthew Dillon 1107258223a3SMatthew Dillon return (0); 1108258223a3SMatthew Dillon } 1109258223a3SMatthew Dillon 1110fd8bd957SMatthew Dillon /* 11111980eff3SMatthew Dillon * Reset a port. 111217eab71eSMatthew Dillon * 11131980eff3SMatthew Dillon * If hard is 0 perform a softreset of the port. 111417eab71eSMatthew Dillon * If hard is 1 perform a hard reset of the port. 11151980eff3SMatthew Dillon * 11161980eff3SMatthew Dillon * If at is non-NULL an indirect port via a port-multiplier is being 11171980eff3SMatthew Dillon * reset, otherwise a direct port is being reset. 11181980eff3SMatthew Dillon * 11191980eff3SMatthew Dillon * NOTE: Indirect ports can only be soft-reset. 112017eab71eSMatthew Dillon */ 112117eab71eSMatthew Dillon int 11221980eff3SMatthew Dillon ahci_port_reset(struct ahci_port *ap, struct ata_port *at, int hard) 112317eab71eSMatthew Dillon { 112417eab71eSMatthew Dillon int rc; 112517eab71eSMatthew Dillon 112617eab71eSMatthew Dillon if (hard) { 11271980eff3SMatthew Dillon if (at) 11281980eff3SMatthew Dillon rc = ahci_pm_hardreset(ap, at->at_target, hard); 11291980eff3SMatthew Dillon else 11301980eff3SMatthew Dillon rc = ahci_port_hardreset(ap, hard); 113117eab71eSMatthew Dillon } else { 11321980eff3SMatthew Dillon if (at) 11331980eff3SMatthew Dillon rc = ahci_pm_softreset(ap, at->at_target); 11341980eff3SMatthew Dillon else 113517eab71eSMatthew Dillon rc = ahci_port_softreset(ap); 113617eab71eSMatthew Dillon } 113717eab71eSMatthew Dillon return(rc); 113817eab71eSMatthew Dillon } 113917eab71eSMatthew Dillon 114017eab71eSMatthew Dillon /* 1141fd8bd957SMatthew Dillon * AHCI soft reset, Section 10.4.1 1142fd8bd957SMatthew Dillon * 11431980eff3SMatthew Dillon * (at) will be NULL when soft-resetting a directly-attached device, and 11441980eff3SMatthew Dillon * non-NULL when soft-resetting a device through a port multiplier. 11451980eff3SMatthew Dillon * 1146fd8bd957SMatthew Dillon * This function keeps port communications intact and attempts to generate 11471980eff3SMatthew Dillon * a reset to the connected device using device commands. 1148fd8bd957SMatthew Dillon */ 1149258223a3SMatthew Dillon int 1150258223a3SMatthew Dillon ahci_port_softreset(struct ahci_port *ap) 1151258223a3SMatthew Dillon { 1152258223a3SMatthew Dillon struct ahci_ccb *ccb = NULL; 1153258223a3SMatthew Dillon struct ahci_cmd_hdr *cmd_slot; 1154258223a3SMatthew Dillon u_int8_t *fis; 11553209f581SMatthew Dillon int error; 1156258223a3SMatthew Dillon 11573209f581SMatthew Dillon error = EIO; 11581980eff3SMatthew Dillon 1159074579dfSMatthew Dillon if (bootverbose) { 11601980eff3SMatthew Dillon kprintf("%s: START SOFTRESET %b\n", PORTNAME(ap), 11611980eff3SMatthew Dillon ahci_pread(ap, AHCI_PREG_CMD), AHCI_PFMT_CMD); 1162074579dfSMatthew Dillon } 11631980eff3SMatthew Dillon 1164258223a3SMatthew Dillon DPRINTF(AHCI_D_VERBOSE, "%s: soft reset\n", PORTNAME(ap)); 1165258223a3SMatthew Dillon 1166258223a3SMatthew Dillon crit_enter(); 11671980eff3SMatthew Dillon ap->ap_flags |= AP_F_IN_RESET; 11681980eff3SMatthew Dillon ap->ap_state = AP_S_NORMAL; 1169258223a3SMatthew Dillon 11701980eff3SMatthew Dillon /* 11711980eff3SMatthew Dillon * Remember port state in cmd (main to restore start/stop) 11721980eff3SMatthew Dillon * 11731980eff3SMatthew Dillon * Idle port. 11741980eff3SMatthew Dillon */ 1175258223a3SMatthew Dillon if (ahci_port_stop(ap, 0)) { 1176258223a3SMatthew Dillon kprintf("%s: failed to stop port, cannot softreset\n", 1177258223a3SMatthew Dillon PORTNAME(ap)); 1178258223a3SMatthew Dillon goto err; 1179258223a3SMatthew Dillon } 1180cf5f3a81SMatthew Dillon 1181cf5f3a81SMatthew Dillon /* 11821980eff3SMatthew Dillon * Request CLO if device appears hung. 1183cf5f3a81SMatthew Dillon */ 1184258223a3SMatthew Dillon if (ahci_pread(ap, AHCI_PREG_TFD) & 1185258223a3SMatthew Dillon (AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) { 1186258223a3SMatthew Dillon ahci_port_clo(ap); 1187258223a3SMatthew Dillon } 1188258223a3SMatthew Dillon 11891980eff3SMatthew Dillon /* 11901980eff3SMatthew Dillon * This is an attempt to clear errors so a new signature will 11911980eff3SMatthew Dillon * be latched. It isn't working properly. XXX 11921980eff3SMatthew Dillon */ 1193cf5f3a81SMatthew Dillon ahci_flush_tfd(ap); 11941980eff3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 1195258223a3SMatthew Dillon 1196258223a3SMatthew Dillon /* Restart port */ 119717eab71eSMatthew Dillon if (ahci_port_start(ap)) { 1198258223a3SMatthew Dillon kprintf("%s: failed to start port, cannot softreset\n", 1199258223a3SMatthew Dillon PORTNAME(ap)); 1200258223a3SMatthew Dillon goto err; 1201258223a3SMatthew Dillon } 1202258223a3SMatthew Dillon 1203258223a3SMatthew Dillon /* Check whether CLO worked */ 1204258223a3SMatthew Dillon if (ahci_pwait_clr(ap, AHCI_PREG_TFD, 1205258223a3SMatthew Dillon AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) { 1206258223a3SMatthew Dillon kprintf("%s: CLO %s, need port reset\n", 1207258223a3SMatthew Dillon PORTNAME(ap), 1208258223a3SMatthew Dillon (ahci_read(ap->ap_sc, AHCI_REG_CAP) & AHCI_REG_CAP_SCLO) 1209258223a3SMatthew Dillon ? "failed" : "unsupported"); 12103209f581SMatthew Dillon error = EBUSY; 1211258223a3SMatthew Dillon goto err; 1212258223a3SMatthew Dillon } 1213258223a3SMatthew Dillon 1214cec85a37SMatthew Dillon /* 1215cec85a37SMatthew Dillon * Prep first D2H command with SRST feature & clear busy/reset flags 1216cec85a37SMatthew Dillon * 1217cec85a37SMatthew Dillon * It is unclear which other fields in the FIS are used. Just zero 1218cec85a37SMatthew Dillon * everything. 12191067474aSMatthew Dillon * 12201067474aSMatthew Dillon * NOTE! This CCB is used for both the first and second commands. 12211067474aSMatthew Dillon * The second command must use CCB slot 1 to properly load 12221067474aSMatthew Dillon * the signature. 1223cec85a37SMatthew Dillon */ 1224258223a3SMatthew Dillon ccb = ahci_get_err_ccb(ap); 122512feb904SMatthew Dillon ccb->ccb_xa.complete = ahci_dummy_done; 122612feb904SMatthew Dillon ccb->ccb_xa.flags = ATA_F_POLL | ATA_F_EXCLUSIVE; 12271067474aSMatthew Dillon KKASSERT(ccb->ccb_slot == 1); 12281980eff3SMatthew Dillon ccb->ccb_xa.at = NULL; 1229258223a3SMatthew Dillon cmd_slot = ccb->ccb_cmd_hdr; 1230258223a3SMatthew Dillon 1231258223a3SMatthew Dillon fis = ccb->ccb_cmd_table->cfis; 1232cec85a37SMatthew Dillon bzero(fis, sizeof(ccb->ccb_cmd_table->cfis)); 12331980eff3SMatthew Dillon fis[0] = ATA_FIS_TYPE_H2D; 12341980eff3SMatthew Dillon fis[15] = ATA_FIS_CONTROL_SRST|ATA_FIS_CONTROL_4BIT; 1235258223a3SMatthew Dillon 1236258223a3SMatthew Dillon cmd_slot->prdtl = 0; 1237258223a3SMatthew Dillon cmd_slot->flags = htole16(5); /* FIS length: 5 DWORDS */ 1238258223a3SMatthew Dillon cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_C); /* Clear busy on OK */ 1239258223a3SMatthew Dillon cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_R); /* Reset */ 1240258223a3SMatthew Dillon 1241258223a3SMatthew Dillon ccb->ccb_xa.state = ATA_S_PENDING; 124212feb904SMatthew Dillon 1243831bc9e3SMatthew Dillon if (ahci_poll(ccb, 1000, ahci_quick_timeout) != ATA_S_COMPLETE) { 12445f8c1efdSMatthew Dillon kprintf("%s: First FIS failed\n", PORTNAME(ap)); 1245258223a3SMatthew Dillon goto err; 1246cec85a37SMatthew Dillon } 1247258223a3SMatthew Dillon 1248cec85a37SMatthew Dillon /* 1249831bc9e3SMatthew Dillon * WARNING! TIME SENSITIVE SPACE! WARNING! 1250831bc9e3SMatthew Dillon * 1251831bc9e3SMatthew Dillon * The two FISes are supposed to be back to back. Don't issue other 1252831bc9e3SMatthew Dillon * commands or even delay if we can help it. 12531980eff3SMatthew Dillon */ 12541980eff3SMatthew Dillon 12551980eff3SMatthew Dillon /* 1256cec85a37SMatthew Dillon * Prep second D2H command to read status and complete reset sequence 1257cec85a37SMatthew Dillon * AHCI 10.4.1 and "Serial ATA Revision 2.6". I can't find the ATA 1258cec85a37SMatthew Dillon * Rev 2.6 and it is unclear how the second FIS should be set up 1259cec85a37SMatthew Dillon * from the AHCI document. 1260cec85a37SMatthew Dillon * 1261cec85a37SMatthew Dillon * It is unclear which other fields in the FIS are used. Just zero 1262cec85a37SMatthew Dillon * everything. 1263cec85a37SMatthew Dillon */ 126412feb904SMatthew Dillon ccb->ccb_xa.flags = ATA_F_POLL | ATA_F_AUTOSENSE | ATA_F_EXCLUSIVE; 126512feb904SMatthew Dillon 1266cec85a37SMatthew Dillon bzero(fis, sizeof(ccb->ccb_cmd_table->cfis)); 12671980eff3SMatthew Dillon fis[0] = ATA_FIS_TYPE_H2D; 12681980eff3SMatthew Dillon fis[15] = ATA_FIS_CONTROL_4BIT; 1269258223a3SMatthew Dillon 1270258223a3SMatthew Dillon cmd_slot->prdtl = 0; 1271258223a3SMatthew Dillon cmd_slot->flags = htole16(5); /* FIS length: 5 DWORDS */ 1272258223a3SMatthew Dillon 1273258223a3SMatthew Dillon ccb->ccb_xa.state = ATA_S_PENDING; 1274831bc9e3SMatthew Dillon if (ahci_poll(ccb, 1000, ahci_quick_timeout) != ATA_S_COMPLETE) { 12755f8c1efdSMatthew Dillon kprintf("%s: Second FIS failed\n", PORTNAME(ap)); 1276258223a3SMatthew Dillon goto err; 1277cec85a37SMatthew Dillon } 1278258223a3SMatthew Dillon 12791980eff3SMatthew Dillon if (ahci_pwait_clr(ap, AHCI_PREG_TFD, 12801980eff3SMatthew Dillon AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) { 1281258223a3SMatthew Dillon kprintf("%s: device didn't come ready after reset, TFD: 0x%b\n", 1282258223a3SMatthew Dillon PORTNAME(ap), 1283258223a3SMatthew Dillon ahci_pread(ap, AHCI_PREG_TFD), AHCI_PFMT_TFD_STS); 12843209f581SMatthew Dillon error = EBUSY; 1285258223a3SMatthew Dillon goto err; 1286258223a3SMatthew Dillon } 1287258223a3SMatthew Dillon 1288fd8bd957SMatthew Dillon /* 1289fd8bd957SMatthew Dillon * If the softreset is trying to clear a BSY condition after a 1290fd8bd957SMatthew Dillon * normal portreset we assign the port type. 1291fd8bd957SMatthew Dillon * 1292fd8bd957SMatthew Dillon * If the softreset is being run first as part of the ccb error 1293fd8bd957SMatthew Dillon * processing code then report if the device signature changed 1294fd8bd957SMatthew Dillon * unexpectedly. 1295fd8bd957SMatthew Dillon */ 1296493d3201SMatthew Dillon ahci_os_sleep(100); 12971980eff3SMatthew Dillon if (ap->ap_type == ATA_PORT_T_NONE) { 12981980eff3SMatthew Dillon ap->ap_type = ahci_port_signature_detect(ap, NULL); 1299fd8bd957SMatthew Dillon } else { 13001980eff3SMatthew Dillon if (ahci_port_signature_detect(ap, NULL) != ap->ap_type) { 13011980eff3SMatthew Dillon kprintf("%s: device signature unexpectedly " 13021980eff3SMatthew Dillon "changed\n", PORTNAME(ap)); 13033209f581SMatthew Dillon error = EBUSY; /* XXX */ 1304fd8bd957SMatthew Dillon } 1305fd8bd957SMatthew Dillon } 13063209f581SMatthew Dillon error = 0; 13071980eff3SMatthew Dillon 13083209f581SMatthew Dillon ahci_os_sleep(3); 1309258223a3SMatthew Dillon err: 1310258223a3SMatthew Dillon if (ccb != NULL) { 1311258223a3SMatthew Dillon ahci_put_err_ccb(ccb); 13121980eff3SMatthew Dillon 13131980eff3SMatthew Dillon /* 13141980eff3SMatthew Dillon * If the target is busy use CLO to clear the busy 13151980eff3SMatthew Dillon * condition. The BSY should be cleared on the next 13161980eff3SMatthew Dillon * start. 13171980eff3SMatthew Dillon */ 13181980eff3SMatthew Dillon if (ahci_pread(ap, AHCI_PREG_TFD) & 13191980eff3SMatthew Dillon (AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) { 13201980eff3SMatthew Dillon ahci_port_clo(ap); 13211980eff3SMatthew Dillon } 1322258223a3SMatthew Dillon } 1323258223a3SMatthew Dillon 1324cf5f3a81SMatthew Dillon /* 1325cf5f3a81SMatthew Dillon * If we failed to softreset make the port quiescent, otherwise 1326cf5f3a81SMatthew Dillon * make sure the port's start/stop state matches what it was on 1327cf5f3a81SMatthew Dillon * entry. 13281980eff3SMatthew Dillon * 13291980eff3SMatthew Dillon * Don't kill the port if the softreset is on a port multiplier 13301980eff3SMatthew Dillon * target, that would kill all the targets! 1331cf5f3a81SMatthew Dillon */ 13323209f581SMatthew Dillon if (error) { 1333cf5f3a81SMatthew Dillon ahci_port_hardstop(ap); 13343209f581SMatthew Dillon /* ap_probe set to failed */ 1335cf5f3a81SMatthew Dillon } else { 13363209f581SMatthew Dillon ap->ap_probe = ATA_PROBE_NEED_IDENT; 133712feb904SMatthew Dillon ap->ap_pmcount = 1; 13384c339a5fSMatthew Dillon ahci_port_start(ap); 1339cf5f3a81SMatthew Dillon } 13403209f581SMatthew Dillon ap->ap_flags &= ~AP_F_IN_RESET; 1341258223a3SMatthew Dillon crit_exit(); 1342258223a3SMatthew Dillon 1343074579dfSMatthew Dillon if (bootverbose) 13441980eff3SMatthew Dillon kprintf("%s: END SOFTRESET\n", PORTNAME(ap)); 13451980eff3SMatthew Dillon 13463209f581SMatthew Dillon return (error); 1347258223a3SMatthew Dillon } 1348258223a3SMatthew Dillon 1349fd8bd957SMatthew Dillon /* 1350493d3201SMatthew Dillon * Issue just do the core COMRESET and basic device detection on a port. 1351fd8bd957SMatthew Dillon * 1352493d3201SMatthew Dillon * NOTE: Only called by ahci_port_hardreset(). 1353fd8bd957SMatthew Dillon */ 1354493d3201SMatthew Dillon static int 1355493d3201SMatthew Dillon ahci_comreset(struct ahci_port *ap, int *pmdetectp) 1356258223a3SMatthew Dillon { 1357493d3201SMatthew Dillon u_int32_t cmd; 1358493d3201SMatthew Dillon u_int32_t r; 13593209f581SMatthew Dillon int error; 13601980eff3SMatthew Dillon int loop; 1361258223a3SMatthew Dillon 1362cf5f3a81SMatthew Dillon /* 13631980eff3SMatthew Dillon * Idle the port, 13641980eff3SMatthew Dillon */ 1365493d3201SMatthew Dillon *pmdetectp = 0; 13661980eff3SMatthew Dillon ahci_port_stop(ap, 0); 13671980eff3SMatthew Dillon ap->ap_state = AP_S_NORMAL; 1368493d3201SMatthew Dillon ahci_os_sleep(10); 13691980eff3SMatthew Dillon 13701980eff3SMatthew Dillon /* 13711980eff3SMatthew Dillon * The port may have been quiescent with its SUD bit cleared, so 13721980eff3SMatthew Dillon * set the SUD (spin up device). 1373493d3201SMatthew Dillon * 1374493d3201SMatthew Dillon * NOTE: I do not know if SUD is a hardware pin/low-level signal 1375493d3201SMatthew Dillon * or if it is messaged. 1376cf5f3a81SMatthew Dillon */ 1377cf5f3a81SMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC; 1378493d3201SMatthew Dillon 1379493d3201SMatthew Dillon cmd |= AHCI_PREG_CMD_SUD | AHCI_PREG_CMD_POD; 1380cf5f3a81SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd); 1381493d3201SMatthew Dillon ahci_os_sleep(10); 1382258223a3SMatthew Dillon 13831980eff3SMatthew Dillon /* 1384493d3201SMatthew Dillon * Make sure that all power management is disabled. 13851067474aSMatthew Dillon * 1386493d3201SMatthew Dillon * NOTE! AHCI_PREG_SCTL_DET_DISABLE seems to be highly unreliable 13874e21f4daSMatthew Dillon * on multiple chipsets and can brick the chipset or even 13884e21f4daSMatthew Dillon * the whole PC. Never use it. 13891980eff3SMatthew Dillon */ 13901980eff3SMatthew Dillon ap->ap_type = ATA_PORT_T_NONE; 1391258223a3SMatthew Dillon 1392493d3201SMatthew Dillon r = AHCI_PREG_SCTL_IPM_DISABLED | 1393493d3201SMatthew Dillon AHCI_PREG_SCTL_SPM_DISABLED; 13941980eff3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SCTL, r); 13953209f581SMatthew Dillon ahci_os_sleep(10); 13961980eff3SMatthew Dillon 13971980eff3SMatthew Dillon /* 1398493d3201SMatthew Dillon * Start transmitting COMRESET. The spec says that COMRESET must 1399493d3201SMatthew Dillon * be sent for at least 1ms but in actual fact numerous devices 1400493d3201SMatthew Dillon * appear to take much longer. Delay a whole second here. 1401493d3201SMatthew Dillon * 1402493d3201SMatthew Dillon * In addition, SATA-3 ports can take longer to train, so even 1403493d3201SMatthew Dillon * SATA-2 devices which would normally detect very quickly may 1404493d3201SMatthew Dillon * take longer when plugged into a SATA-3 port. 14051980eff3SMatthew Dillon */ 1406493d3201SMatthew Dillon r |= AHCI_PREG_SCTL_DET_INIT; 1407*8986d351SMatthew Dillon switch(AhciForceGen) { 1408*8986d351SMatthew Dillon case 0: 1409258223a3SMatthew Dillon r |= AHCI_PREG_SCTL_SPD_ANY; 1410*8986d351SMatthew Dillon break; 1411*8986d351SMatthew Dillon case 1: 1412*8986d351SMatthew Dillon r |= AHCI_PREG_SCTL_SPD_GEN1; 1413*8986d351SMatthew Dillon break; 1414*8986d351SMatthew Dillon case 2: 1415*8986d351SMatthew Dillon r |= AHCI_PREG_SCTL_SPD_GEN2; 1416*8986d351SMatthew Dillon break; 1417*8986d351SMatthew Dillon case 3: 1418*8986d351SMatthew Dillon r |= AHCI_PREG_SCTL_SPD_GEN3; 1419*8986d351SMatthew Dillon break; 1420*8986d351SMatthew Dillon default: 1421*8986d351SMatthew Dillon r |= AHCI_PREG_SCTL_SPD_GEN3; 1422*8986d351SMatthew Dillon break; 1423*8986d351SMatthew Dillon } 1424258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SCTL, r); 1425492bffafSMatthew Dillon ahci_os_sleep(1000); 1426493d3201SMatthew Dillon r &= ~AHCI_PREG_SCTL_SPD; 1427493d3201SMatthew Dillon 1428492bffafSMatthew Dillon ap->ap_flags &= ~AP_F_HARSH_REINIT; 1429cf5f3a81SMatthew Dillon 1430cf5f3a81SMatthew Dillon /* 1431cf5f3a81SMatthew Dillon * Only SERR_DIAG_X needs to be cleared for TFD updates, but 1432cf5f3a81SMatthew Dillon * since we are hard-resetting the port we might as well clear 1433493d3201SMatthew Dillon * the whole enchillada. 1434493d3201SMatthew Dillon * 1435493d3201SMatthew Dillon * Wait 1 whole second after clearing INIT before checking 1436493d3201SMatthew Dillon * the device detection bits in an attempt to work around chipsets 1437493d3201SMatthew Dillon * which do not properly mask PCS/PRCS during low level init. 1438cf5f3a81SMatthew Dillon */ 1439cf5f3a81SMatthew Dillon ahci_flush_tfd(ap); 1440cf5f3a81SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 1441493d3201SMatthew Dillon ahci_os_sleep(10); 1442493d3201SMatthew Dillon 1443258223a3SMatthew Dillon r &= ~AHCI_PREG_SCTL_DET_INIT; 1444258223a3SMatthew Dillon r |= AHCI_PREG_SCTL_DET_NONE; 1445258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SCTL, r); 1446493d3201SMatthew Dillon ahci_os_sleep(1000); 1447258223a3SMatthew Dillon 14481980eff3SMatthew Dillon /* 14491980eff3SMatthew Dillon * Try to determine if there is a device on the port. 14501980eff3SMatthew Dillon * 14511980eff3SMatthew Dillon * Give the device 3/10 second to at least be detected. 14521980eff3SMatthew Dillon * If we fail clear PRCS (phy detect) since we may cycled 14531980eff3SMatthew Dillon * the phy and probably caused another PRCS interrupt. 14541980eff3SMatthew Dillon */ 145576497a9cSMatthew Dillon loop = 300; 145676497a9cSMatthew Dillon while (loop > 0) { 14571980eff3SMatthew Dillon r = ahci_pread(ap, AHCI_PREG_SSTS); 14581980eff3SMatthew Dillon if (r & AHCI_PREG_SSTS_DET) 14591980eff3SMatthew Dillon break; 146076497a9cSMatthew Dillon loop -= ahci_os_softsleep(); 14611980eff3SMatthew Dillon } 14621980eff3SMatthew Dillon if (loop == 0) { 14631980eff3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_PRCS); 1464074579dfSMatthew Dillon if (bootverbose) { 14651980eff3SMatthew Dillon kprintf("%s: Port appears to be unplugged\n", 14661980eff3SMatthew Dillon PORTNAME(ap)); 1467074579dfSMatthew Dillon } 14683209f581SMatthew Dillon error = ENODEV; 146912feb904SMatthew Dillon goto done; 1470258223a3SMatthew Dillon } 1471258223a3SMatthew Dillon 1472cec85a37SMatthew Dillon /* 1473493d3201SMatthew Dillon * There is something on the port. Regardless of what happens 1474493d3201SMatthew Dillon * after this tell the caller to try to detect a port multiplier. 1475493d3201SMatthew Dillon * 1476493d3201SMatthew Dillon * Give the device 3 seconds to fully negotiate. 14771980eff3SMatthew Dillon */ 1478493d3201SMatthew Dillon *pmdetectp = 1; 1479493d3201SMatthew Dillon 148012feb904SMatthew Dillon if (ahci_pwait_eq(ap, 3000, AHCI_PREG_SSTS, 14811980eff3SMatthew Dillon AHCI_PREG_SSTS_DET, AHCI_PREG_SSTS_DET_DEV)) { 1482074579dfSMatthew Dillon if (bootverbose) { 14831980eff3SMatthew Dillon kprintf("%s: Device may be powered down\n", 14841980eff3SMatthew Dillon PORTNAME(ap)); 1485074579dfSMatthew Dillon } 14863209f581SMatthew Dillon error = ENODEV; 1487493d3201SMatthew Dillon goto done; 14881980eff3SMatthew Dillon } 14891980eff3SMatthew Dillon 149012feb904SMatthew Dillon /* 149112feb904SMatthew Dillon * We got something that definitely looks like a device. Give 149212feb904SMatthew Dillon * the device time to send us its first D2H FIS. Waiting for 149312feb904SMatthew Dillon * BSY to clear accomplishes this. 149412feb904SMatthew Dillon * 1495493d3201SMatthew Dillon * NOTE: A port multiplier may or may not clear BSY here, 149612feb904SMatthew Dillon * depending on what is sitting in target 0 behind it. 149712feb904SMatthew Dillon */ 1498c408a8b3SMatthew Dillon ahci_flush_tfd(ap); 149912feb904SMatthew Dillon if (ahci_pwait_clr_to(ap, 3000, AHCI_PREG_TFD, 15001980eff3SMatthew Dillon AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) { 150112feb904SMatthew Dillon error = EBUSY; 15021980eff3SMatthew Dillon } else { 15033209f581SMatthew Dillon error = 0; 15041980eff3SMatthew Dillon } 1505258223a3SMatthew Dillon 150612feb904SMatthew Dillon done: 1507493d3201SMatthew Dillon ahci_flush_tfd(ap); 1508493d3201SMatthew Dillon return error; 1509493d3201SMatthew Dillon } 1510493d3201SMatthew Dillon 1511493d3201SMatthew Dillon 1512493d3201SMatthew Dillon /* 1513493d3201SMatthew Dillon * AHCI port reset, Section 10.4.2 1514493d3201SMatthew Dillon * 1515493d3201SMatthew Dillon * This function does a hard reset of the port. Note that the device 1516493d3201SMatthew Dillon * connected to the port could still end-up hung. 1517493d3201SMatthew Dillon */ 1518493d3201SMatthew Dillon int 1519493d3201SMatthew Dillon ahci_port_hardreset(struct ahci_port *ap, int hard) 1520493d3201SMatthew Dillon { 1521493d3201SMatthew Dillon u_int32_t data; 1522493d3201SMatthew Dillon int error; 1523493d3201SMatthew Dillon int pmdetect; 1524493d3201SMatthew Dillon 1525493d3201SMatthew Dillon if (bootverbose) 1526493d3201SMatthew Dillon kprintf("%s: START HARDRESET\n", PORTNAME(ap)); 1527493d3201SMatthew Dillon ap->ap_flags |= AP_F_IN_RESET; 1528493d3201SMatthew Dillon 1529493d3201SMatthew Dillon error = ahci_comreset(ap, &pmdetect); 1530493d3201SMatthew Dillon 1531493d3201SMatthew Dillon /* 1532493d3201SMatthew Dillon * We may be asked to perform a port multiplier check even if the 1533493d3201SMatthew Dillon * comreset failed. This typically occurs when the PM has nothing 1534493d3201SMatthew Dillon * in slot 0, which can cause BSY to remain set. 1535493d3201SMatthew Dillon * 1536493d3201SMatthew Dillon * If the PM detection is successful it will override (error), 1537493d3201SMatthew Dillon * otherwise (error) is retained. If an error does occur it 1538493d3201SMatthew Dillon * is possible that a normal device has blown up on us DUE to 1539493d3201SMatthew Dillon * the PM detection code, so re-run the comreset and assume 1540493d3201SMatthew Dillon * a normal device. 1541493d3201SMatthew Dillon */ 1542493d3201SMatthew Dillon if (pmdetect) { 1543493d3201SMatthew Dillon if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SPM) { 1544493d3201SMatthew Dillon error = ahci_pm_port_probe(ap, error); 1545493d3201SMatthew Dillon if (error) { 1546493d3201SMatthew Dillon error = ahci_comreset(ap, &pmdetect); 1547493d3201SMatthew Dillon } 1548493d3201SMatthew Dillon } 1549493d3201SMatthew Dillon } 1550493d3201SMatthew Dillon 155112feb904SMatthew Dillon /* 155212feb904SMatthew Dillon * Finish up. 155312feb904SMatthew Dillon */ 1554493d3201SMatthew Dillon ahci_os_sleep(500); 1555493d3201SMatthew Dillon 155612feb904SMatthew Dillon switch(error) { 155712feb904SMatthew Dillon case 0: 155812feb904SMatthew Dillon /* 155912feb904SMatthew Dillon * All good, make sure the port is running and set the 156012feb904SMatthew Dillon * probe state. Ignore the signature junk (it's unreliable) 156112feb904SMatthew Dillon * until we get to the softreset code. 156212feb904SMatthew Dillon */ 156312feb904SMatthew Dillon if (ahci_port_start(ap)) { 156412feb904SMatthew Dillon kprintf("%s: failed to start command DMA on port, " 156512feb904SMatthew Dillon "disabling\n", PORTNAME(ap)); 156612feb904SMatthew Dillon error = EBUSY; 1567493d3201SMatthew Dillon break; 156812feb904SMatthew Dillon } 1569f4553de1SMatthew Dillon if (ap->ap_type == ATA_PORT_T_PM) 1570f4553de1SMatthew Dillon ap->ap_probe = ATA_PROBE_GOOD; 1571f4553de1SMatthew Dillon else 1572f4553de1SMatthew Dillon ap->ap_probe = ATA_PROBE_NEED_SOFT_RESET; 157312feb904SMatthew Dillon break; 157412feb904SMatthew Dillon case ENODEV: 1575fd8bd957SMatthew Dillon /* 157612feb904SMatthew Dillon * Normal device probe failure 15771980eff3SMatthew Dillon */ 157812feb904SMatthew Dillon data = ahci_pread(ap, AHCI_PREG_SSTS); 15791980eff3SMatthew Dillon 158012feb904SMatthew Dillon switch(data & AHCI_PREG_SSTS_DET) { 158112feb904SMatthew Dillon case AHCI_PREG_SSTS_DET_DEV_NE: 158212feb904SMatthew Dillon kprintf("%s: Device not communicating\n", 15831980eff3SMatthew Dillon PORTNAME(ap)); 158412feb904SMatthew Dillon break; 158512feb904SMatthew Dillon case AHCI_PREG_SSTS_DET_PHYOFFLINE: 158612feb904SMatthew Dillon kprintf("%s: PHY offline\n", 158712feb904SMatthew Dillon PORTNAME(ap)); 158812feb904SMatthew Dillon break; 158912feb904SMatthew Dillon default: 159012feb904SMatthew Dillon kprintf("%s: No device detected\n", 159112feb904SMatthew Dillon PORTNAME(ap)); 159212feb904SMatthew Dillon break; 15931980eff3SMatthew Dillon } 159412feb904SMatthew Dillon ahci_port_hardstop(ap); 159512feb904SMatthew Dillon break; 159612feb904SMatthew Dillon default: 15971980eff3SMatthew Dillon /* 159812feb904SMatthew Dillon * Abnormal probe (EBUSY) 15991980eff3SMatthew Dillon */ 160012feb904SMatthew Dillon kprintf("%s: Device on port is bricked\n", 160112feb904SMatthew Dillon PORTNAME(ap)); 160212feb904SMatthew Dillon ahci_port_hardstop(ap); 160312feb904SMatthew Dillon #if 0 160412feb904SMatthew Dillon rc = ahci_port_reset(ap, atx, 0); 160512feb904SMatthew Dillon if (rc) { 160612feb904SMatthew Dillon kprintf("%s: Unable unbrick device\n", 160712feb904SMatthew Dillon PORTNAME(ap)); 16081980eff3SMatthew Dillon } else { 160912feb904SMatthew Dillon kprintf("%s: Successfully unbricked\n", 16103209f581SMatthew Dillon PORTNAME(ap)); 161112feb904SMatthew Dillon } 161212feb904SMatthew Dillon #endif 161312feb904SMatthew Dillon break; 16143209f581SMatthew Dillon } 16151067474aSMatthew Dillon 16161067474aSMatthew Dillon /* 161712feb904SMatthew Dillon * Clean up 16181067474aSMatthew Dillon */ 161912feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 162012feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_PCS | AHCI_PREG_IS_PRCS); 16213209f581SMatthew Dillon 162212feb904SMatthew Dillon ap->ap_flags &= ~AP_F_IN_RESET; 16231980eff3SMatthew Dillon 162412feb904SMatthew Dillon if (bootverbose) 162512feb904SMatthew Dillon kprintf("%s: END HARDRESET %d\n", PORTNAME(ap), error); 1626831bc9e3SMatthew Dillon return (error); 16271980eff3SMatthew Dillon } 16281980eff3SMatthew Dillon 16291980eff3SMatthew Dillon /* 1630cf5f3a81SMatthew Dillon * Hard-stop on hot-swap device removal. See 10.10.1 1631cf5f3a81SMatthew Dillon * 1632cf5f3a81SMatthew Dillon * Place the port in a mode that will allow it to detect hot-swap insertions. 1633cf5f3a81SMatthew Dillon * This is a bit imprecise because just setting-up SCTL to DET_INIT doesn't 1634cf5f3a81SMatthew Dillon * seem to do the job. 1635f17a0cedSMatthew Dillon * 1636f17a0cedSMatthew Dillon * FIS reception is left enabled but command processing is disabled. 1637f17a0cedSMatthew Dillon * Cycling FIS reception (FRE) can brick ports. 1638cf5f3a81SMatthew Dillon */ 1639cf5f3a81SMatthew Dillon void 1640cf5f3a81SMatthew Dillon ahci_port_hardstop(struct ahci_port *ap) 1641cf5f3a81SMatthew Dillon { 164276497a9cSMatthew Dillon struct ahci_ccb *ccb; 16431980eff3SMatthew Dillon struct ata_port *at; 1644cf5f3a81SMatthew Dillon u_int32_t r; 1645cf5f3a81SMatthew Dillon u_int32_t cmd; 164676497a9cSMatthew Dillon int slot; 16471980eff3SMatthew Dillon int i; 1648cf5f3a81SMatthew Dillon 1649cf5f3a81SMatthew Dillon /* 1650cf5f3a81SMatthew Dillon * Stop the port. We can't modify things like SUD if the port 1651cf5f3a81SMatthew Dillon * is running. 1652cf5f3a81SMatthew Dillon */ 1653cf5f3a81SMatthew Dillon ap->ap_state = AP_S_FATAL_ERROR; 16541980eff3SMatthew Dillon ap->ap_probe = ATA_PROBE_FAILED; 16551980eff3SMatthew Dillon ap->ap_type = ATA_PORT_T_NONE; 1656cf5f3a81SMatthew Dillon ahci_port_stop(ap, 0); 1657cf5f3a81SMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD); 1658492bffafSMatthew Dillon cmd &= ~(AHCI_PREG_CMD_CLO | AHCI_PREG_CMD_PMA | AHCI_PREG_CMD_ICC); 1659492bffafSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd); 1660cf5f3a81SMatthew Dillon 1661cf5f3a81SMatthew Dillon /* 16621980eff3SMatthew Dillon * Clean up AT sub-ports on SATA port. 16631980eff3SMatthew Dillon */ 16641980eff3SMatthew Dillon for (i = 0; ap->ap_ata && i < AHCI_MAX_PMPORTS; ++i) { 1665b012a2caSMatthew Dillon at = ap->ap_ata[i]; 16661980eff3SMatthew Dillon at->at_type = ATA_PORT_T_NONE; 16673209f581SMatthew Dillon at->at_probe = ATA_PROBE_FAILED; 16681980eff3SMatthew Dillon } 16691980eff3SMatthew Dillon 16701980eff3SMatthew Dillon /* 1671cf5f3a81SMatthew Dillon * Make sure FRE is active. There isn't anything we can do if it 1672cf5f3a81SMatthew Dillon * fails so just ignore errors. 1673cf5f3a81SMatthew Dillon */ 1674cf5f3a81SMatthew Dillon if ((cmd & AHCI_PREG_CMD_FRE) == 0) { 1675cf5f3a81SMatthew Dillon cmd |= AHCI_PREG_CMD_FRE; 1676cf5f3a81SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd); 1677cf5f3a81SMatthew Dillon if ((ap->ap_sc->sc_flags & AHCI_F_IGN_FR) == 0) 1678cf5f3a81SMatthew Dillon ahci_pwait_set(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_FR); 1679cf5f3a81SMatthew Dillon } 1680cf5f3a81SMatthew Dillon 1681cf5f3a81SMatthew Dillon /* 1682cf5f3a81SMatthew Dillon * 10.10.1 place us in the Listen state. 1683cf5f3a81SMatthew Dillon * 16845502cf24SMatthew Dillon * 10.10.3 DET must be set to 0 and found to be 0 before 16855502cf24SMatthew Dillon * setting SUD to 0. 16865502cf24SMatthew Dillon * 16875502cf24SMatthew Dillon * Deactivating SUD only applies if the controller supports SUD, it 16885502cf24SMatthew Dillon * is a bit unclear what happens w/regards to detecting hotplug 16895502cf24SMatthew Dillon * if it doesn't. 1690cf5f3a81SMatthew Dillon */ 16915502cf24SMatthew Dillon r = AHCI_PREG_SCTL_IPM_DISABLED | 16925502cf24SMatthew Dillon AHCI_PREG_SCTL_SPM_DISABLED; 16935502cf24SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SCTL, r); 16945502cf24SMatthew Dillon ahci_os_sleep(10); 1695cf5f3a81SMatthew Dillon cmd &= ~AHCI_PREG_CMD_SUD; 1696cf5f3a81SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd); 16975502cf24SMatthew Dillon ahci_os_sleep(10); 1698cf5f3a81SMatthew Dillon 1699cf5f3a81SMatthew Dillon /* 17005502cf24SMatthew Dillon * 10.10.1 17015502cf24SMatthew Dillon * 17025502cf24SMatthew Dillon * Transition su to the spin-up state. HBA shall send COMRESET and 17035502cf24SMatthew Dillon * begin initialization sequence (whatever that means). Presumably 17045502cf24SMatthew Dillon * this is edge-triggered. Following the spin-up state the HBA 17055502cf24SMatthew Dillon * will automatically transition to the Normal state. 1706cf5f3a81SMatthew Dillon * 1707cf5f3a81SMatthew Dillon * This only applies if the controller supports SUD. 17084e21f4daSMatthew Dillon * NEVER use AHCI_PREG_DET_DISABLE. 1709cf5f3a81SMatthew Dillon */ 17105502cf24SMatthew Dillon cmd |= AHCI_PREG_CMD_POD | 17115502cf24SMatthew Dillon AHCI_PREG_CMD_SUD | 17125502cf24SMatthew Dillon AHCI_PREG_CMD_ICC_ACTIVE; 1713cf5f3a81SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd); 17145502cf24SMatthew Dillon ahci_os_sleep(10); 1715cf5f3a81SMatthew Dillon 1716cf5f3a81SMatthew Dillon /* 1717cf5f3a81SMatthew Dillon * Flush SERR_DIAG_X so the TFD can update. 1718cf5f3a81SMatthew Dillon */ 1719cf5f3a81SMatthew Dillon ahci_flush_tfd(ap); 1720cf5f3a81SMatthew Dillon 1721cf5f3a81SMatthew Dillon /* 172276497a9cSMatthew Dillon * Clean out pending ccbs 172376497a9cSMatthew Dillon */ 172476497a9cSMatthew Dillon while (ap->ap_active) { 172576497a9cSMatthew Dillon slot = ffs(ap->ap_active) - 1; 172676497a9cSMatthew Dillon ap->ap_active &= ~(1 << slot); 172776497a9cSMatthew Dillon ap->ap_expired &= ~(1 << slot); 172876497a9cSMatthew Dillon --ap->ap_active_cnt; 172976497a9cSMatthew Dillon ccb = &ap->ap_ccbs[slot]; 173076497a9cSMatthew Dillon if (ccb->ccb_xa.flags & ATA_F_TIMEOUT_RUNNING) { 173176497a9cSMatthew Dillon callout_stop(&ccb->ccb_timeout); 173276497a9cSMatthew Dillon ccb->ccb_xa.flags &= ~ATA_F_TIMEOUT_RUNNING; 173376497a9cSMatthew Dillon } 173476497a9cSMatthew Dillon ccb->ccb_xa.flags &= ~(ATA_F_TIMEOUT_DESIRED | 173576497a9cSMatthew Dillon ATA_F_TIMEOUT_EXPIRED); 173676497a9cSMatthew Dillon ccb->ccb_xa.state = ATA_S_TIMEOUT; 173776497a9cSMatthew Dillon ccb->ccb_done(ccb); 173876497a9cSMatthew Dillon ccb->ccb_xa.complete(&ccb->ccb_xa); 173976497a9cSMatthew Dillon } 174076497a9cSMatthew Dillon while (ap->ap_sactive) { 174176497a9cSMatthew Dillon slot = ffs(ap->ap_sactive) - 1; 174276497a9cSMatthew Dillon ap->ap_sactive &= ~(1 << slot); 174376497a9cSMatthew Dillon ap->ap_expired &= ~(1 << slot); 174476497a9cSMatthew Dillon ccb = &ap->ap_ccbs[slot]; 174576497a9cSMatthew Dillon if (ccb->ccb_xa.flags & ATA_F_TIMEOUT_RUNNING) { 174676497a9cSMatthew Dillon callout_stop(&ccb->ccb_timeout); 174776497a9cSMatthew Dillon ccb->ccb_xa.flags &= ~ATA_F_TIMEOUT_RUNNING; 174876497a9cSMatthew Dillon } 174976497a9cSMatthew Dillon ccb->ccb_xa.flags &= ~(ATA_F_TIMEOUT_DESIRED | 175076497a9cSMatthew Dillon ATA_F_TIMEOUT_EXPIRED); 175176497a9cSMatthew Dillon ccb->ccb_xa.state = ATA_S_TIMEOUT; 175276497a9cSMatthew Dillon ccb->ccb_done(ccb); 175376497a9cSMatthew Dillon ccb->ccb_xa.complete(&ccb->ccb_xa); 175476497a9cSMatthew Dillon } 175576497a9cSMatthew Dillon KKASSERT(ap->ap_active_cnt == 0); 175676497a9cSMatthew Dillon 175776497a9cSMatthew Dillon while ((ccb = TAILQ_FIRST(&ap->ap_ccb_pending)) != NULL) { 175876497a9cSMatthew Dillon TAILQ_REMOVE(&ap->ap_ccb_pending, ccb, ccb_entry); 175976497a9cSMatthew Dillon ccb->ccb_xa.state = ATA_S_TIMEOUT; 176076497a9cSMatthew Dillon ccb->ccb_xa.flags &= ~ATA_F_TIMEOUT_DESIRED; 176176497a9cSMatthew Dillon ccb->ccb_done(ccb); 176276497a9cSMatthew Dillon ccb->ccb_xa.complete(&ccb->ccb_xa); 176376497a9cSMatthew Dillon } 176476497a9cSMatthew Dillon 176576497a9cSMatthew Dillon /* 17665502cf24SMatthew Dillon * Hot-plug device detection should work at this point. e.g. on 17675502cf24SMatthew Dillon * AMD chipsets Spin-Up/Normal state is sufficient for hot-plug 17685502cf24SMatthew Dillon * detection and entering RESET (continuous COMRESET by setting INIT) 17695502cf24SMatthew Dillon * will actually prevent hot-plug detection from working properly. 1770cf5f3a81SMatthew Dillon * 17715502cf24SMatthew Dillon * There may be cases where this will fail to work, I have some 17725502cf24SMatthew Dillon * additional code to place the HBA in RESET (send continuous 17735502cf24SMatthew Dillon * COMRESET) and hopefully get DIAG.X or other events when something 17745502cf24SMatthew Dillon * is plugged in. Unfortunately this isn't universal and can 17755502cf24SMatthew Dillon * also prevent events from generating interrupts. 1776cf5f3a81SMatthew Dillon */ 17775502cf24SMatthew Dillon 17785502cf24SMatthew Dillon #if 0 17795502cf24SMatthew Dillon /* 17805502cf24SMatthew Dillon * Transition us to the Reset state. Theoretically we send a 17815502cf24SMatthew Dillon * continuous stream of COMRESETs in this state. 17825502cf24SMatthew Dillon */ 17835502cf24SMatthew Dillon r |= AHCI_PREG_SCTL_DET_INIT; 17845502cf24SMatthew Dillon if (AhciForceGen1 & (1 << ap->ap_num)) { 17855502cf24SMatthew Dillon kprintf("%s: Force 1.5Gbits\n", PORTNAME(ap)); 17865502cf24SMatthew Dillon r |= AHCI_PREG_SCTL_SPD_GEN1; 17875502cf24SMatthew Dillon } else { 17885502cf24SMatthew Dillon r |= AHCI_PREG_SCTL_SPD_ANY; 17895502cf24SMatthew Dillon } 17905502cf24SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SCTL, r); 17915502cf24SMatthew Dillon ahci_os_sleep(10); 17925502cf24SMatthew Dillon 17935502cf24SMatthew Dillon /* 17945502cf24SMatthew Dillon * Flush SERR_DIAG_X so the TFD can update. 17955502cf24SMatthew Dillon */ 17965502cf24SMatthew Dillon ahci_flush_tfd(ap); 17975502cf24SMatthew Dillon #endif 1798cf5f3a81SMatthew Dillon /* NOP */ 1799cf5f3a81SMatthew Dillon } 1800cf5f3a81SMatthew Dillon 1801cf5f3a81SMatthew Dillon /* 1802c408a8b3SMatthew Dillon * We can't loop on the X bit, a continuous COMINIT received will make 1803c408a8b3SMatthew Dillon * it loop forever. Just assume one event has built up and clear X 1804c408a8b3SMatthew Dillon * so the task file descriptor can update. 1805cf5f3a81SMatthew Dillon */ 1806cf5f3a81SMatthew Dillon void 1807cf5f3a81SMatthew Dillon ahci_flush_tfd(struct ahci_port *ap) 1808cf5f3a81SMatthew Dillon { 1809cf5f3a81SMatthew Dillon u_int32_t r; 1810cf5f3a81SMatthew Dillon 1811cf5f3a81SMatthew Dillon r = ahci_pread(ap, AHCI_PREG_SERR); 1812c408a8b3SMatthew Dillon if (r & AHCI_PREG_SERR_DIAG_X) 18131980eff3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, AHCI_PREG_SERR_DIAG_X); 1814cf5f3a81SMatthew Dillon } 1815cf5f3a81SMatthew Dillon 1816cf5f3a81SMatthew Dillon /* 1817fd8bd957SMatthew Dillon * Figure out what type of device is connected to the port, ATAPI or 1818fd8bd957SMatthew Dillon * DISK. 1819fd8bd957SMatthew Dillon */ 1820fd8bd957SMatthew Dillon int 18211980eff3SMatthew Dillon ahci_port_signature_detect(struct ahci_port *ap, struct ata_port *at) 1822fd8bd957SMatthew Dillon { 1823fd8bd957SMatthew Dillon u_int32_t sig; 1824fd8bd957SMatthew Dillon 1825fd8bd957SMatthew Dillon sig = ahci_pread(ap, AHCI_PREG_SIG); 1826074579dfSMatthew Dillon if (bootverbose) 18271980eff3SMatthew Dillon kprintf("%s: sig %08x\n", ATANAME(ap, at), sig); 1828fd8bd957SMatthew Dillon if ((sig & 0xffff0000) == (SATA_SIGNATURE_ATAPI & 0xffff0000)) { 1829fd8bd957SMatthew Dillon return(ATA_PORT_T_ATAPI); 18301980eff3SMatthew Dillon } else if ((sig & 0xffff0000) == 18311980eff3SMatthew Dillon (SATA_SIGNATURE_PORT_MULTIPLIER & 0xffff0000)) { 18321980eff3SMatthew Dillon return(ATA_PORT_T_PM); 1833fd8bd957SMatthew Dillon } else { 1834fd8bd957SMatthew Dillon return(ATA_PORT_T_DISK); 1835fd8bd957SMatthew Dillon } 1836fd8bd957SMatthew Dillon } 1837fd8bd957SMatthew Dillon 1838fd8bd957SMatthew Dillon /* 1839fd8bd957SMatthew Dillon * Load the DMA descriptor table for a CCB's buffer. 1840fd8bd957SMatthew Dillon */ 1841258223a3SMatthew Dillon int 1842258223a3SMatthew Dillon ahci_load_prdt(struct ahci_ccb *ccb) 1843258223a3SMatthew Dillon { 1844258223a3SMatthew Dillon struct ahci_port *ap = ccb->ccb_port; 1845258223a3SMatthew Dillon struct ahci_softc *sc = ap->ap_sc; 1846258223a3SMatthew Dillon struct ata_xfer *xa = &ccb->ccb_xa; 1847258223a3SMatthew Dillon struct ahci_prdt *prdt = ccb->ccb_cmd_table->prdt; 1848258223a3SMatthew Dillon bus_dmamap_t dmap = ccb->ccb_dmamap; 1849258223a3SMatthew Dillon struct ahci_cmd_hdr *cmd_slot = ccb->ccb_cmd_hdr; 1850258223a3SMatthew Dillon int error; 1851258223a3SMatthew Dillon 1852258223a3SMatthew Dillon if (xa->datalen == 0) { 1853258223a3SMatthew Dillon ccb->ccb_cmd_hdr->prdtl = 0; 1854258223a3SMatthew Dillon return (0); 1855258223a3SMatthew Dillon } 1856258223a3SMatthew Dillon 1857258223a3SMatthew Dillon error = bus_dmamap_load(sc->sc_tag_data, dmap, 1858258223a3SMatthew Dillon xa->data, xa->datalen, 1859258223a3SMatthew Dillon ahci_load_prdt_callback, 1860258223a3SMatthew Dillon &prdt, 1861258223a3SMatthew Dillon ((xa->flags & ATA_F_NOWAIT) ? 1862258223a3SMatthew Dillon BUS_DMA_NOWAIT : BUS_DMA_WAITOK)); 1863258223a3SMatthew Dillon if (error != 0) { 1864258223a3SMatthew Dillon kprintf("%s: error %d loading dmamap\n", PORTNAME(ap), error); 1865258223a3SMatthew Dillon return (1); 1866258223a3SMatthew Dillon } 186712feb904SMatthew Dillon #if 0 1868258223a3SMatthew Dillon if (xa->flags & ATA_F_PIO) 1869258223a3SMatthew Dillon prdt->flags |= htole32(AHCI_PRDT_FLAG_INTR); 187012feb904SMatthew Dillon #endif 1871258223a3SMatthew Dillon 1872258223a3SMatthew Dillon cmd_slot->prdtl = htole16(prdt - ccb->ccb_cmd_table->prdt + 1); 1873258223a3SMatthew Dillon 1874b012a2caSMatthew Dillon if (xa->flags & ATA_F_READ) 1875b012a2caSMatthew Dillon bus_dmamap_sync(sc->sc_tag_data, dmap, BUS_DMASYNC_PREREAD); 1876b012a2caSMatthew Dillon if (xa->flags & ATA_F_WRITE) 1877b012a2caSMatthew Dillon bus_dmamap_sync(sc->sc_tag_data, dmap, BUS_DMASYNC_PREWRITE); 1878258223a3SMatthew Dillon 1879258223a3SMatthew Dillon return (0); 1880258223a3SMatthew Dillon } 1881258223a3SMatthew Dillon 1882258223a3SMatthew Dillon /* 1883258223a3SMatthew Dillon * Callback from BUSDMA system to load the segment list. The passed segment 1884258223a3SMatthew Dillon * list is a temporary structure. 1885258223a3SMatthew Dillon */ 1886258223a3SMatthew Dillon static 1887258223a3SMatthew Dillon void 1888258223a3SMatthew Dillon ahci_load_prdt_callback(void *info, bus_dma_segment_t *segs, int nsegs, 1889258223a3SMatthew Dillon int error) 1890258223a3SMatthew Dillon { 1891258223a3SMatthew Dillon struct ahci_prdt *prd = *(void **)info; 1892258223a3SMatthew Dillon u_int64_t addr; 1893258223a3SMatthew Dillon 1894258223a3SMatthew Dillon KKASSERT(nsegs <= AHCI_MAX_PRDT); 1895258223a3SMatthew Dillon 1896258223a3SMatthew Dillon while (nsegs) { 1897258223a3SMatthew Dillon addr = segs->ds_addr; 1898258223a3SMatthew Dillon prd->dba_hi = htole32((u_int32_t)(addr >> 32)); 1899258223a3SMatthew Dillon prd->dba_lo = htole32((u_int32_t)addr); 1900258223a3SMatthew Dillon prd->flags = htole32(segs->ds_len - 1); 1901258223a3SMatthew Dillon --nsegs; 1902258223a3SMatthew Dillon if (nsegs) 1903258223a3SMatthew Dillon ++prd; 1904258223a3SMatthew Dillon ++segs; 1905258223a3SMatthew Dillon } 1906258223a3SMatthew Dillon *(void **)info = prd; /* return last valid segment */ 1907258223a3SMatthew Dillon } 1908258223a3SMatthew Dillon 1909258223a3SMatthew Dillon void 1910258223a3SMatthew Dillon ahci_unload_prdt(struct ahci_ccb *ccb) 1911258223a3SMatthew Dillon { 1912258223a3SMatthew Dillon struct ahci_port *ap = ccb->ccb_port; 1913258223a3SMatthew Dillon struct ahci_softc *sc = ap->ap_sc; 1914258223a3SMatthew Dillon struct ata_xfer *xa = &ccb->ccb_xa; 1915258223a3SMatthew Dillon bus_dmamap_t dmap = ccb->ccb_dmamap; 1916258223a3SMatthew Dillon 1917258223a3SMatthew Dillon if (xa->datalen != 0) { 1918b012a2caSMatthew Dillon if (xa->flags & ATA_F_READ) { 1919258223a3SMatthew Dillon bus_dmamap_sync(sc->sc_tag_data, dmap, 1920b012a2caSMatthew Dillon BUS_DMASYNC_POSTREAD); 1921b012a2caSMatthew Dillon } 1922b012a2caSMatthew Dillon if (xa->flags & ATA_F_WRITE) { 1923b012a2caSMatthew Dillon bus_dmamap_sync(sc->sc_tag_data, dmap, 1924b012a2caSMatthew Dillon BUS_DMASYNC_POSTWRITE); 1925b012a2caSMatthew Dillon } 1926258223a3SMatthew Dillon bus_dmamap_unload(sc->sc_tag_data, dmap); 1927258223a3SMatthew Dillon 1928f7d09f74SMatthew Dillon /* 1929f7d09f74SMatthew Dillon * prdbc is only updated by hardware for non-NCQ commands. 1930f7d09f74SMatthew Dillon */ 1931f7d09f74SMatthew Dillon if (ccb->ccb_xa.flags & ATA_F_NCQ) { 1932f7d09f74SMatthew Dillon xa->resid = 0; 1933f7d09f74SMatthew Dillon } else { 193450a3ecb6SMatthew Dillon if (ccb->ccb_cmd_hdr->prdbc == 0 && 193550a3ecb6SMatthew Dillon ccb->ccb_xa.state == ATA_S_COMPLETE) { 1936f7d09f74SMatthew Dillon kprintf("%s: WARNING! Unload prdbc resid " 1937f7d09f74SMatthew Dillon "was zero! tag=%d\n", 193812feb904SMatthew Dillon ATANAME(ap, xa->at), ccb->ccb_slot); 193912feb904SMatthew Dillon } 1940258223a3SMatthew Dillon xa->resid = xa->datalen - 1941258223a3SMatthew Dillon le32toh(ccb->ccb_cmd_hdr->prdbc); 1942258223a3SMatthew Dillon } 1943258223a3SMatthew Dillon } 1944f7d09f74SMatthew Dillon } 1945258223a3SMatthew Dillon 19465f8c1efdSMatthew Dillon /* 19475f8c1efdSMatthew Dillon * Start a command and poll for completion. 19485f8c1efdSMatthew Dillon * 19493209f581SMatthew Dillon * timeout is in ms and only counts once the command gets on-chip. 19503209f581SMatthew Dillon * 1951831bc9e3SMatthew Dillon * Returns ATA_S_* state, compare against ATA_S_COMPLETE to determine 1952831bc9e3SMatthew Dillon * that no error occured. 1953831bc9e3SMatthew Dillon * 19545f8c1efdSMatthew Dillon * NOTE: If the caller specifies a NULL timeout function the caller is 19555f8c1efdSMatthew Dillon * responsible for clearing hardware state on failure, but we will 19565f8c1efdSMatthew Dillon * deal with removing the ccb from any pending queue. 19575f8c1efdSMatthew Dillon * 19585f8c1efdSMatthew Dillon * NOTE: NCQ should never be used with this function. 1959cf5f3a81SMatthew Dillon * 1960cf5f3a81SMatthew Dillon * NOTE: If the port is in a failed state and stopped we do not try 1961cf5f3a81SMatthew Dillon * to activate the ccb. 19625f8c1efdSMatthew Dillon */ 1963258223a3SMatthew Dillon int 1964831bc9e3SMatthew Dillon ahci_poll(struct ahci_ccb *ccb, int timeout, 1965831bc9e3SMatthew Dillon void (*timeout_fn)(struct ahci_ccb *)) 1966258223a3SMatthew Dillon { 1967258223a3SMatthew Dillon struct ahci_port *ap = ccb->ccb_port; 1968258223a3SMatthew Dillon 1969cf5f3a81SMatthew Dillon if (ccb->ccb_port->ap_state == AP_S_FATAL_ERROR) { 1970cf5f3a81SMatthew Dillon ccb->ccb_xa.state = ATA_S_ERROR; 1971831bc9e3SMatthew Dillon return(ccb->ccb_xa.state); 1972cf5f3a81SMatthew Dillon } 1973258223a3SMatthew Dillon crit_enter(); 197412feb904SMatthew Dillon #if 0 197512feb904SMatthew Dillon kprintf("%s: Start command %02x tag=%d\n", 197612feb904SMatthew Dillon ATANAME(ccb->ccb_port, ccb->ccb_xa.at), 197712feb904SMatthew Dillon ccb->ccb_xa.fis->command, ccb->ccb_slot); 197812feb904SMatthew Dillon #endif 1979258223a3SMatthew Dillon ahci_start(ccb); 19801980eff3SMatthew Dillon 1981258223a3SMatthew Dillon do { 1982f4553de1SMatthew Dillon ahci_port_intr(ap, 1); 1983831bc9e3SMatthew Dillon switch(ccb->ccb_xa.state) { 1984831bc9e3SMatthew Dillon case ATA_S_ONCHIP: 1985831bc9e3SMatthew Dillon timeout -= ahci_os_softsleep(); 1986f4553de1SMatthew Dillon break; 1987831bc9e3SMatthew Dillon case ATA_S_PENDING: 1988831bc9e3SMatthew Dillon ahci_os_softsleep(); 1989831bc9e3SMatthew Dillon ahci_check_active_timeouts(ap); 1990831bc9e3SMatthew Dillon break; 1991831bc9e3SMatthew Dillon default: 1992831bc9e3SMatthew Dillon crit_exit(); 1993831bc9e3SMatthew Dillon return (ccb->ccb_xa.state); 1994f4553de1SMatthew Dillon } 19953209f581SMatthew Dillon } while (timeout > 0); 19965f8c1efdSMatthew Dillon 1997492bffafSMatthew Dillon if ((ccb->ccb_xa.flags & ATA_F_SILENT) == 0) { 1998831bc9e3SMatthew Dillon kprintf("%s: Poll timeout slot %d CMD: %b TFD: 0x%b SERR: %b\n", 1999831bc9e3SMatthew Dillon ATANAME(ap, ccb->ccb_xa.at), ccb->ccb_slot, 2000831bc9e3SMatthew Dillon ahci_pread(ap, AHCI_PREG_CMD), AHCI_PFMT_CMD, 2001831bc9e3SMatthew Dillon ahci_pread(ap, AHCI_PREG_TFD), AHCI_PFMT_TFD_STS, 2002831bc9e3SMatthew Dillon ahci_pread(ap, AHCI_PREG_SERR), AHCI_PFMT_SERR); 2003492bffafSMatthew Dillon } 20045f8c1efdSMatthew Dillon 2005258223a3SMatthew Dillon timeout_fn(ccb); 2006831bc9e3SMatthew Dillon 2007258223a3SMatthew Dillon crit_exit(); 2008258223a3SMatthew Dillon 2009831bc9e3SMatthew Dillon return(ccb->ccb_xa.state); 2010831bc9e3SMatthew Dillon } 2011831bc9e3SMatthew Dillon 2012831bc9e3SMatthew Dillon /* 2013831bc9e3SMatthew Dillon * When polling we have to check if the currently active CCB(s) 2014831bc9e3SMatthew Dillon * have timed out as the callout will be deadlocked while we 2015831bc9e3SMatthew Dillon * hold the port lock. 2016831bc9e3SMatthew Dillon */ 2017831bc9e3SMatthew Dillon void 2018831bc9e3SMatthew Dillon ahci_check_active_timeouts(struct ahci_port *ap) 2019831bc9e3SMatthew Dillon { 2020831bc9e3SMatthew Dillon struct ahci_ccb *ccb; 2021831bc9e3SMatthew Dillon u_int32_t mask; 2022831bc9e3SMatthew Dillon int tag; 2023831bc9e3SMatthew Dillon 2024831bc9e3SMatthew Dillon mask = ap->ap_active | ap->ap_sactive; 2025831bc9e3SMatthew Dillon while (mask) { 2026831bc9e3SMatthew Dillon tag = ffs(mask) - 1; 2027831bc9e3SMatthew Dillon mask &= ~(1 << tag); 2028831bc9e3SMatthew Dillon ccb = &ap->ap_ccbs[tag]; 2029831bc9e3SMatthew Dillon if (ccb->ccb_xa.flags & ATA_F_TIMEOUT_EXPIRED) { 2030831bc9e3SMatthew Dillon ahci_ata_cmd_timeout(ccb); 2031831bc9e3SMatthew Dillon } 2032831bc9e3SMatthew Dillon } 2033258223a3SMatthew Dillon } 2034258223a3SMatthew Dillon 20353209f581SMatthew Dillon static 20363209f581SMatthew Dillon __inline 20373209f581SMatthew Dillon void 20383209f581SMatthew Dillon ahci_start_timeout(struct ahci_ccb *ccb) 20393209f581SMatthew Dillon { 20403209f581SMatthew Dillon if (ccb->ccb_xa.flags & ATA_F_TIMEOUT_DESIRED) { 20413209f581SMatthew Dillon ccb->ccb_xa.flags |= ATA_F_TIMEOUT_RUNNING; 20423209f581SMatthew Dillon callout_reset(&ccb->ccb_timeout, 20433209f581SMatthew Dillon (ccb->ccb_xa.timeout * hz + 999) / 1000, 20443209f581SMatthew Dillon ahci_ata_cmd_timeout_unserialized, ccb); 20453209f581SMatthew Dillon } 20463209f581SMatthew Dillon } 20473209f581SMatthew Dillon 2048258223a3SMatthew Dillon void 2049258223a3SMatthew Dillon ahci_start(struct ahci_ccb *ccb) 2050258223a3SMatthew Dillon { 2051258223a3SMatthew Dillon struct ahci_port *ap = ccb->ccb_port; 2052258223a3SMatthew Dillon struct ahci_softc *sc = ap->ap_sc; 2053258223a3SMatthew Dillon 2054258223a3SMatthew Dillon KKASSERT(ccb->ccb_xa.state == ATA_S_PENDING); 2055258223a3SMatthew Dillon 2056258223a3SMatthew Dillon /* Zero transferred byte count before transfer */ 2057258223a3SMatthew Dillon ccb->ccb_cmd_hdr->prdbc = 0; 2058258223a3SMatthew Dillon 2059258223a3SMatthew Dillon /* Sync command list entry and corresponding command table entry */ 2060258223a3SMatthew Dillon bus_dmamap_sync(sc->sc_tag_cmdh, 2061258223a3SMatthew Dillon AHCI_DMA_MAP(ap->ap_dmamem_cmd_list), 2062258223a3SMatthew Dillon BUS_DMASYNC_PREWRITE); 2063258223a3SMatthew Dillon bus_dmamap_sync(sc->sc_tag_cmdt, 2064258223a3SMatthew Dillon AHCI_DMA_MAP(ap->ap_dmamem_cmd_table), 2065258223a3SMatthew Dillon BUS_DMASYNC_PREWRITE); 2066258223a3SMatthew Dillon 2067258223a3SMatthew Dillon /* Prepare RFIS area for write by controller */ 2068258223a3SMatthew Dillon bus_dmamap_sync(sc->sc_tag_rfis, 2069258223a3SMatthew Dillon AHCI_DMA_MAP(ap->ap_dmamem_rfis), 2070258223a3SMatthew Dillon BUS_DMASYNC_PREREAD); 2071258223a3SMatthew Dillon 20721980eff3SMatthew Dillon /* 20734c339a5fSMatthew Dillon * There's no point trying to optimize this, it only shaves a few 20744c339a5fSMatthew Dillon * nanoseconds so just queue the command and call our generic issue. 20751980eff3SMatthew Dillon */ 20764c339a5fSMatthew Dillon ahci_issue_pending_commands(ap, ccb); 2077258223a3SMatthew Dillon } 2078258223a3SMatthew Dillon 2079831bc9e3SMatthew Dillon /* 2080831bc9e3SMatthew Dillon * While holding the port lock acquire exclusive access to the port. 2081831bc9e3SMatthew Dillon * 2082831bc9e3SMatthew Dillon * This is used when running the state machine to initialize and identify 2083831bc9e3SMatthew Dillon * targets over a port multiplier. Setting exclusive access prevents 2084831bc9e3SMatthew Dillon * ahci_port_intr() from activating any requests sitting on the pending 2085831bc9e3SMatthew Dillon * queue. 2086831bc9e3SMatthew Dillon */ 2087831bc9e3SMatthew Dillon void 2088831bc9e3SMatthew Dillon ahci_beg_exclusive_access(struct ahci_port *ap, struct ata_port *at) 2089831bc9e3SMatthew Dillon { 2090831bc9e3SMatthew Dillon KKASSERT((ap->ap_flags & AP_F_EXCLUSIVE_ACCESS) == 0); 2091831bc9e3SMatthew Dillon ap->ap_flags |= AP_F_EXCLUSIVE_ACCESS; 2092831bc9e3SMatthew Dillon while (ap->ap_active || ap->ap_sactive) { 2093831bc9e3SMatthew Dillon ahci_port_intr(ap, 1); 2094831bc9e3SMatthew Dillon ahci_os_softsleep(); 2095831bc9e3SMatthew Dillon } 2096831bc9e3SMatthew Dillon } 2097831bc9e3SMatthew Dillon 2098831bc9e3SMatthew Dillon void 2099831bc9e3SMatthew Dillon ahci_end_exclusive_access(struct ahci_port *ap, struct ata_port *at) 2100831bc9e3SMatthew Dillon { 2101831bc9e3SMatthew Dillon KKASSERT((ap->ap_flags & AP_F_EXCLUSIVE_ACCESS) != 0); 2102831bc9e3SMatthew Dillon ap->ap_flags &= ~AP_F_EXCLUSIVE_ACCESS; 21034c339a5fSMatthew Dillon ahci_issue_pending_commands(ap, NULL); 2104831bc9e3SMatthew Dillon } 2105831bc9e3SMatthew Dillon 210612feb904SMatthew Dillon #if 0 210712feb904SMatthew Dillon 210812feb904SMatthew Dillon static void 210912feb904SMatthew Dillon fubar(struct ahci_ccb *ccb) 211012feb904SMatthew Dillon { 211112feb904SMatthew Dillon struct ahci_port *ap = ccb->ccb_port; 211212feb904SMatthew Dillon struct ahci_cmd_hdr *cmd; 211312feb904SMatthew Dillon struct ahci_cmd_table *tab; 211412feb904SMatthew Dillon struct ahci_prdt *prdt; 211512feb904SMatthew Dillon int i; 211612feb904SMatthew Dillon 211712feb904SMatthew Dillon kprintf("%s: ISSUE %02x\n", 211812feb904SMatthew Dillon ATANAME(ap, ccb->ccb_xa.at), 211912feb904SMatthew Dillon ccb->ccb_xa.fis->command); 212012feb904SMatthew Dillon cmd = ccb->ccb_cmd_hdr; 212112feb904SMatthew Dillon tab = ccb->ccb_cmd_table; 212212feb904SMatthew Dillon prdt = ccb->ccb_cmd_table->prdt; 212312feb904SMatthew Dillon kprintf("cmd flags=%04x prdtl=%d prdbc=%d ctba=%08x%08x\n", 212412feb904SMatthew Dillon cmd->flags, cmd->prdtl, cmd->prdbc, 212512feb904SMatthew Dillon cmd->ctba_hi, cmd->ctba_lo); 212612feb904SMatthew Dillon for (i = 0; i < cmd->prdtl; ++i) { 212712feb904SMatthew Dillon kprintf("\t%d dba=%08x%08x res=%08x flags=%08x\n", 212812feb904SMatthew Dillon i, prdt->dba_hi, prdt->dba_lo, prdt->reserved, 212912feb904SMatthew Dillon prdt->flags); 213012feb904SMatthew Dillon } 213112feb904SMatthew Dillon kprintf("tab\n"); 213212feb904SMatthew Dillon } 213312feb904SMatthew Dillon 213412feb904SMatthew Dillon #endif 213512feb904SMatthew Dillon 21361980eff3SMatthew Dillon /* 21374c339a5fSMatthew Dillon * If ccb is not NULL enqueue and/or issue it. 21384c339a5fSMatthew Dillon * 21394c339a5fSMatthew Dillon * If ccb is NULL issue whatever we can from the queue. However, nothing 21404c339a5fSMatthew Dillon * new is issued if the exclusive access flag is set or expired ccb's are 21414c339a5fSMatthew Dillon * present. 21424c339a5fSMatthew Dillon * 21434c339a5fSMatthew Dillon * If existing commands are still active (ap_active/ap_sactive) we can only 21444c339a5fSMatthew Dillon * issue matching new commands. 21451980eff3SMatthew Dillon */ 21464c339a5fSMatthew Dillon void 21474c339a5fSMatthew Dillon ahci_issue_pending_commands(struct ahci_port *ap, struct ahci_ccb *ccb) 21484c339a5fSMatthew Dillon { 21494c339a5fSMatthew Dillon u_int32_t mask; 21504c339a5fSMatthew Dillon int limit; 2151258223a3SMatthew Dillon 21521980eff3SMatthew Dillon /* 21534c339a5fSMatthew Dillon * Enqueue the ccb. 21544c339a5fSMatthew Dillon * 21554c339a5fSMatthew Dillon * If just running the queue and in exclusive access mode we 21564c339a5fSMatthew Dillon * just return. Also in this case if there are any expired ccb's 21574c339a5fSMatthew Dillon * we want to clear the queue so the port can be safely stopped. 21584c339a5fSMatthew Dillon */ 21594c339a5fSMatthew Dillon if (ccb) { 21604c339a5fSMatthew Dillon TAILQ_INSERT_TAIL(&ap->ap_ccb_pending, ccb, ccb_entry); 21614c339a5fSMatthew Dillon } else if ((ap->ap_flags & AP_F_EXCLUSIVE_ACCESS) || ap->ap_expired) { 21624c339a5fSMatthew Dillon return; 21634c339a5fSMatthew Dillon } 21644c339a5fSMatthew Dillon 21654c339a5fSMatthew Dillon /* 21664c339a5fSMatthew Dillon * Pull the next ccb off the queue and run it if possible. 21674c339a5fSMatthew Dillon */ 21684c339a5fSMatthew Dillon if ((ccb = TAILQ_FIRST(&ap->ap_ccb_pending)) == NULL) 21694c339a5fSMatthew Dillon return; 21704c339a5fSMatthew Dillon 217112feb904SMatthew Dillon /* 217212feb904SMatthew Dillon * Handle exclusivity requirements. 217312feb904SMatthew Dillon * 217412feb904SMatthew Dillon * ATA_F_EXCLUSIVE is used when we want to be the only command 217512feb904SMatthew Dillon * running. 217612feb904SMatthew Dillon * 217712feb904SMatthew Dillon * ATA_F_AUTOSENSE is used when we want the D2H rfis loaded 217812feb904SMatthew Dillon * back into the ccb on a normal (non-errored) command completion. 217912feb904SMatthew Dillon * For example, for PM requests to target 15. Because the AHCI 218012feb904SMatthew Dillon * spec does not stop the command processor and has only one rfis 218112feb904SMatthew Dillon * area (for non-FBSS anyway), AUTOSENSE currently implies EXCLUSIVE. 218212feb904SMatthew Dillon * Otherwise multiple completions can destroy the rfis data before 218312feb904SMatthew Dillon * we have a chance to copy it. 218412feb904SMatthew Dillon */ 218512feb904SMatthew Dillon if (ap->ap_active & ~ap->ap_expired) { 218612feb904SMatthew Dillon /* 218712feb904SMatthew Dillon * There may be multiple ccb's already running, 218812feb904SMatthew Dillon * if any are running and ap_run_flags sets 218912feb904SMatthew Dillon * one of these flags then we know only one is 219012feb904SMatthew Dillon * running. 219112feb904SMatthew Dillon * 219212feb904SMatthew Dillon * XXX Current AUTOSENSE code forces exclusivity 219312feb904SMatthew Dillon * to simplify the code. 219412feb904SMatthew Dillon */ 219512feb904SMatthew Dillon if (ap->ap_run_flags & 219612feb904SMatthew Dillon (ATA_F_EXCLUSIVE | ATA_F_AUTOSENSE)) { 219712feb904SMatthew Dillon return; 219812feb904SMatthew Dillon } 219912feb904SMatthew Dillon 220012feb904SMatthew Dillon if (ccb->ccb_xa.flags & 220112feb904SMatthew Dillon (ATA_F_EXCLUSIVE | ATA_F_AUTOSENSE)) { 220212feb904SMatthew Dillon return; 220312feb904SMatthew Dillon } 220412feb904SMatthew Dillon } 220512feb904SMatthew Dillon 22064c339a5fSMatthew Dillon if (ccb->ccb_xa.flags & ATA_F_NCQ) { 22074c339a5fSMatthew Dillon /* 22084c339a5fSMatthew Dillon * The next command is a NCQ command and can be issued as 22094c339a5fSMatthew Dillon * long as currently active commands are not standard. 22104c339a5fSMatthew Dillon */ 22114c339a5fSMatthew Dillon if (ap->ap_active) { 22124c339a5fSMatthew Dillon KKASSERT(ap->ap_active_cnt > 0); 22134c339a5fSMatthew Dillon return; 22144c339a5fSMatthew Dillon } 22154c339a5fSMatthew Dillon KKASSERT(ap->ap_active_cnt == 0); 22164c339a5fSMatthew Dillon 22174c339a5fSMatthew Dillon mask = 0; 22184c339a5fSMatthew Dillon do { 22194c339a5fSMatthew Dillon TAILQ_REMOVE(&ap->ap_ccb_pending, ccb, ccb_entry); 22204c339a5fSMatthew Dillon mask |= 1 << ccb->ccb_slot; 22214c339a5fSMatthew Dillon ccb->ccb_xa.state = ATA_S_ONCHIP; 222212feb904SMatthew Dillon ahci_start_timeout(ccb); 222312feb904SMatthew Dillon ap->ap_run_flags = ccb->ccb_xa.flags; 22244c339a5fSMatthew Dillon ccb = TAILQ_FIRST(&ap->ap_ccb_pending); 222512feb904SMatthew Dillon } while (ccb && (ccb->ccb_xa.flags & ATA_F_NCQ) && 222612feb904SMatthew Dillon (ap->ap_run_flags & 222712feb904SMatthew Dillon (ATA_F_EXCLUSIVE | ATA_F_AUTOSENSE)) == 0); 22284c339a5fSMatthew Dillon 22294c339a5fSMatthew Dillon ap->ap_sactive |= mask; 22304c339a5fSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SACT, mask); 22314c339a5fSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CI, mask); 22324c339a5fSMatthew Dillon } else { 22334c339a5fSMatthew Dillon /* 22344c339a5fSMatthew Dillon * The next command is a standard command and can be issued 22354c339a5fSMatthew Dillon * as long as currently active commands are not NCQ. 22364c339a5fSMatthew Dillon * 22374c339a5fSMatthew Dillon * We limit ourself to 1 command if we have a port multiplier, 22384c339a5fSMatthew Dillon * (at least without FBSS support), otherwise timeouts on 22394c339a5fSMatthew Dillon * one port can race completions on other ports (see 22404c339a5fSMatthew Dillon * ahci_ata_cmd_timeout() for more information). 22414c339a5fSMatthew Dillon * 22424c339a5fSMatthew Dillon * If not on a port multiplier generally allow up to 4 22434c339a5fSMatthew Dillon * standard commands to be enqueued. Remember that the 22444c339a5fSMatthew Dillon * command processor will still process them sequentially. 22451980eff3SMatthew Dillon */ 22461980eff3SMatthew Dillon if (ap->ap_sactive) 2247258223a3SMatthew Dillon return; 22484c339a5fSMatthew Dillon if (ap->ap_type == ATA_PORT_T_PM) 22494c339a5fSMatthew Dillon limit = 1; 22504c339a5fSMatthew Dillon else if (ap->ap_sc->sc_ncmds > 4) 22514c339a5fSMatthew Dillon limit = 4; 22524c339a5fSMatthew Dillon else 22534c339a5fSMatthew Dillon limit = 2; 2254258223a3SMatthew Dillon 22554c339a5fSMatthew Dillon while (ap->ap_active_cnt < limit && ccb && 22564c339a5fSMatthew Dillon (ccb->ccb_xa.flags & ATA_F_NCQ) == 0) { 22574c339a5fSMatthew Dillon TAILQ_REMOVE(&ap->ap_ccb_pending, ccb, ccb_entry); 225812feb904SMatthew Dillon #if 0 225912feb904SMatthew Dillon fubar(ccb); 226012feb904SMatthew Dillon #endif 22614c339a5fSMatthew Dillon ap->ap_active |= 1 << ccb->ccb_slot; 2262258223a3SMatthew Dillon ap->ap_active_cnt++; 226312feb904SMatthew Dillon ap->ap_run_flags = ccb->ccb_xa.flags; 22644c339a5fSMatthew Dillon ccb->ccb_xa.state = ATA_S_ONCHIP; 22654c339a5fSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CI, 1 << ccb->ccb_slot); 226612feb904SMatthew Dillon ahci_start_timeout(ccb); 226722726f69SMatthew Dillon if ((ap->ap_run_flags & 226822726f69SMatthew Dillon (ATA_F_EXCLUSIVE | ATA_F_AUTOSENSE)) == 0) { 226922726f69SMatthew Dillon break; 227022726f69SMatthew Dillon } 22714c339a5fSMatthew Dillon ccb = TAILQ_FIRST(&ap->ap_ccb_pending); 227212feb904SMatthew Dillon if (ccb && (ccb->ccb_xa.flags & 227312feb904SMatthew Dillon (ATA_F_EXCLUSIVE | ATA_F_AUTOSENSE))) { 227412feb904SMatthew Dillon break; 227512feb904SMatthew Dillon } 22761980eff3SMatthew Dillon } 2277258223a3SMatthew Dillon } 2278258223a3SMatthew Dillon } 2279258223a3SMatthew Dillon 2280258223a3SMatthew Dillon void 2281258223a3SMatthew Dillon ahci_intr(void *arg) 2282258223a3SMatthew Dillon { 2283258223a3SMatthew Dillon struct ahci_softc *sc = arg; 2284f4553de1SMatthew Dillon struct ahci_port *ap; 228512feb904SMatthew Dillon u_int32_t is; 228612feb904SMatthew Dillon u_int32_t ack; 2287258223a3SMatthew Dillon int port; 2288258223a3SMatthew Dillon 2289f4553de1SMatthew Dillon /* 2290f4553de1SMatthew Dillon * Check if the master enable is up, and whether any interrupts are 2291f4553de1SMatthew Dillon * pending. 2292f4553de1SMatthew Dillon */ 2293f4553de1SMatthew Dillon if ((sc->sc_flags & AHCI_F_INT_GOOD) == 0) 2294f4553de1SMatthew Dillon return; 2295258223a3SMatthew Dillon is = ahci_read(sc, AHCI_REG_IS); 229612feb904SMatthew Dillon if (is == 0 || is == 0xffffffff) { 2297258223a3SMatthew Dillon return; 229812feb904SMatthew Dillon } 229912feb904SMatthew Dillon is &= sc->sc_portmask; 2300258223a3SMatthew Dillon 2301258223a3SMatthew Dillon #ifdef AHCI_COALESCE 2302258223a3SMatthew Dillon /* Check coalescing interrupt first */ 2303258223a3SMatthew Dillon if (is & sc->sc_ccc_mask) { 2304258223a3SMatthew Dillon DPRINTF(AHCI_D_INTR, "%s: command coalescing interrupt\n", 2305258223a3SMatthew Dillon DEVNAME(sc)); 2306258223a3SMatthew Dillon is &= ~sc->sc_ccc_mask; 2307258223a3SMatthew Dillon is |= sc->sc_ccc_ports_cur; 2308258223a3SMatthew Dillon } 2309258223a3SMatthew Dillon #endif 2310258223a3SMatthew Dillon 2311f4553de1SMatthew Dillon /* 2312f4553de1SMatthew Dillon * Process interrupts for each port in a non-blocking fashion. 231312feb904SMatthew Dillon * 231412feb904SMatthew Dillon * The global IS bit is forced on if any unmasked port interrupts 231512feb904SMatthew Dillon * are pending, even if we clear. 2316f4553de1SMatthew Dillon */ 231712feb904SMatthew Dillon for (ack = 0; is; is &= ~(1 << port)) { 2318258223a3SMatthew Dillon port = ffs(is) - 1; 231912feb904SMatthew Dillon ack |= 1 << port; 232012feb904SMatthew Dillon 2321f4553de1SMatthew Dillon ap = sc->sc_ports[port]; 232212feb904SMatthew Dillon if (ap == NULL) 232312feb904SMatthew Dillon continue; 232412feb904SMatthew Dillon 2325f4553de1SMatthew Dillon if (ahci_os_lock_port_nb(ap) == 0) { 2326f4553de1SMatthew Dillon ahci_port_intr(ap, 0); 2327f4553de1SMatthew Dillon ahci_os_unlock_port(ap); 2328f4553de1SMatthew Dillon } else { 2329f4553de1SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IE, 0); 2330f4553de1SMatthew Dillon ahci_os_signal_port_thread(ap, AP_SIGF_PORTINT); 2331f4553de1SMatthew Dillon } 2332f4553de1SMatthew Dillon } 2333258223a3SMatthew Dillon ahci_write(sc, AHCI_REG_IS, ack); 2334258223a3SMatthew Dillon } 2335258223a3SMatthew Dillon 2336f4553de1SMatthew Dillon /* 2337f4553de1SMatthew Dillon * Core called from helper thread. 2338f4553de1SMatthew Dillon */ 23393209f581SMatthew Dillon void 2340f4553de1SMatthew Dillon ahci_port_thread_core(struct ahci_port *ap, int mask) 2341f4553de1SMatthew Dillon { 2342f4553de1SMatthew Dillon /* 2343f4553de1SMatthew Dillon * Process any expired timedouts. 2344f4553de1SMatthew Dillon */ 2345f4553de1SMatthew Dillon ahci_os_lock_port(ap); 2346f4553de1SMatthew Dillon if (mask & AP_SIGF_TIMEOUT) { 2347831bc9e3SMatthew Dillon ahci_check_active_timeouts(ap); 2348f4553de1SMatthew Dillon } 2349f4553de1SMatthew Dillon 2350f4553de1SMatthew Dillon /* 2351f4553de1SMatthew Dillon * Process port interrupts which require a higher level of 2352f4553de1SMatthew Dillon * intervention. 2353f4553de1SMatthew Dillon */ 2354f4553de1SMatthew Dillon if (mask & AP_SIGF_PORTINT) { 2355f4553de1SMatthew Dillon ahci_port_intr(ap, 1); 2356f4553de1SMatthew Dillon ahci_port_interrupt_enable(ap); 2357831bc9e3SMatthew Dillon ahci_os_unlock_port(ap); 235812feb904SMatthew Dillon } else if (ap->ap_probe != ATA_PROBE_FAILED) { 235912feb904SMatthew Dillon ahci_port_intr(ap, 1); 236012feb904SMatthew Dillon ahci_port_interrupt_enable(ap); 236112feb904SMatthew Dillon ahci_os_unlock_port(ap); 2362f4553de1SMatthew Dillon } else { 2363f4553de1SMatthew Dillon ahci_os_unlock_port(ap); 2364f4553de1SMatthew Dillon } 2365f4553de1SMatthew Dillon } 2366f4553de1SMatthew Dillon 2367f4553de1SMatthew Dillon /* 2368f4553de1SMatthew Dillon * Core per-port interrupt handler. 2369f4553de1SMatthew Dillon * 2370f4553de1SMatthew Dillon * If blockable is 0 we cannot call ahci_os_sleep() at all and we can only 2371f4553de1SMatthew Dillon * deal with normal command completions which do not require blocking. 2372f4553de1SMatthew Dillon */ 2373f4553de1SMatthew Dillon void 2374f4553de1SMatthew Dillon ahci_port_intr(struct ahci_port *ap, int blockable) 2375258223a3SMatthew Dillon { 2376258223a3SMatthew Dillon struct ahci_softc *sc = ap->ap_sc; 23773209f581SMatthew Dillon u_int32_t is, ci_saved, ci_masked; 237822181ab7SMatthew Dillon int slot; 2379492bffafSMatthew Dillon int stopped = 0; 2380258223a3SMatthew Dillon struct ahci_ccb *ccb = NULL; 23811980eff3SMatthew Dillon struct ata_port *ccb_at = NULL; 2382258223a3SMatthew Dillon volatile u_int32_t *active; 2383f4553de1SMatthew Dillon const u_int32_t blockable_mask = AHCI_PREG_IS_TFES | 2384f4553de1SMatthew Dillon AHCI_PREG_IS_IFS | 2385f4553de1SMatthew Dillon AHCI_PREG_IS_PCS | 2386f4553de1SMatthew Dillon AHCI_PREG_IS_PRCS | 2387f4553de1SMatthew Dillon AHCI_PREG_IS_HBFS | 2388f4553de1SMatthew Dillon AHCI_PREG_IS_OFS | 2389f4553de1SMatthew Dillon AHCI_PREG_IS_UFS; 2390f4553de1SMatthew Dillon 2391492bffafSMatthew Dillon enum { NEED_NOTHING, NEED_REINIT, NEED_RESTART, 2392492bffafSMatthew Dillon NEED_HOTPLUG_INSERT, NEED_HOTPLUG_REMOVE } need = NEED_NOTHING; 2393258223a3SMatthew Dillon 2394f4553de1SMatthew Dillon /* 2395f4553de1SMatthew Dillon * All basic command completions are always processed. 2396f4553de1SMatthew Dillon */ 239712feb904SMatthew Dillon is = ahci_pread(ap, AHCI_PREG_IS); 2398cec07d75SMatthew Dillon if (is & AHCI_PREG_IS_DPS) 2399cec07d75SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, is & AHCI_PREG_IS_DPS); 2400258223a3SMatthew Dillon 2401f4553de1SMatthew Dillon /* 2402f4553de1SMatthew Dillon * If we can't block then we can't handle these here. Disable 2403f4553de1SMatthew Dillon * the interrupts in question so we don't live-lock, the helper 2404f4553de1SMatthew Dillon * thread will re-enable them. 2405f4553de1SMatthew Dillon * 2406f4553de1SMatthew Dillon * If the port is in a completely failed state we do not want 2407dbef6246SMatthew Dillon * to drop through to failed-command-processing if blockable is 0, 2408f4553de1SMatthew Dillon * just let the thread deal with it all. 2409dbef6246SMatthew Dillon * 2410dbef6246SMatthew Dillon * Otherwise we fall through and still handle DHRS and any commands 2411dbef6246SMatthew Dillon * which completed normally. Even if we are errored we haven't 2412dbef6246SMatthew Dillon * stopped the port yet so CI/SACT are still good. 2413f4553de1SMatthew Dillon */ 2414f4553de1SMatthew Dillon if (blockable == 0) { 2415f4553de1SMatthew Dillon if (ap->ap_state == AP_S_FATAL_ERROR) { 241612feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IE, 0); 2417f4553de1SMatthew Dillon ahci_os_signal_port_thread(ap, AP_SIGF_PORTINT); 2418f4553de1SMatthew Dillon return; 2419f4553de1SMatthew Dillon } 2420f4553de1SMatthew Dillon if (is & blockable_mask) { 242112feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IE, 0); 2422f4553de1SMatthew Dillon ahci_os_signal_port_thread(ap, AP_SIGF_PORTINT); 242312feb904SMatthew Dillon return; 2424f4553de1SMatthew Dillon } 2425f4553de1SMatthew Dillon } 2426f4553de1SMatthew Dillon 24273209f581SMatthew Dillon /* 2428f4553de1SMatthew Dillon * Either NCQ or non-NCQ commands will be active, never both. 24293209f581SMatthew Dillon */ 2430258223a3SMatthew Dillon if (ap->ap_sactive) { 2431258223a3SMatthew Dillon KKASSERT(ap->ap_active == 0); 2432258223a3SMatthew Dillon KKASSERT(ap->ap_active_cnt == 0); 2433258223a3SMatthew Dillon ci_saved = ahci_pread(ap, AHCI_PREG_SACT); 2434258223a3SMatthew Dillon active = &ap->ap_sactive; 2435258223a3SMatthew Dillon } else { 2436258223a3SMatthew Dillon ci_saved = ahci_pread(ap, AHCI_PREG_CI); 2437258223a3SMatthew Dillon active = &ap->ap_active; 2438258223a3SMatthew Dillon } 243912feb904SMatthew Dillon KKASSERT(!(ap->ap_sactive && ap->ap_active)); 244012feb904SMatthew Dillon #if 0 244112feb904SMatthew Dillon kprintf("CHECK act=%08x/%08x sact=%08x/%08x\n", 244212feb904SMatthew Dillon ap->ap_active, ahci_pread(ap, AHCI_PREG_CI), 244312feb904SMatthew Dillon ap->ap_sactive, ahci_pread(ap, AHCI_PREG_SACT)); 244412feb904SMatthew Dillon #endif 2445258223a3SMatthew Dillon 2446492bffafSMatthew Dillon /* 2447492bffafSMatthew Dillon * Ignore AHCI_PREG_IS_PRCS when link power management is on 2448492bffafSMatthew Dillon */ 2449795adb22SMatthew Dillon if (ap->link_pwr_mgmt != AHCI_LINK_PWR_MGMT_NONE) { 2450795adb22SMatthew Dillon is &= ~AHCI_PREG_IS_PRCS; 2451795adb22SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, 2452795adb22SMatthew Dillon AHCI_PREG_SERR_DIAG_N | AHCI_PREG_SERR_DIAG_W); 2453795adb22SMatthew Dillon } 2454795adb22SMatthew Dillon 2455cf5f3a81SMatthew Dillon /* 2456f4553de1SMatthew Dillon * Command failed (blockable). 2457f4553de1SMatthew Dillon * 2458f4553de1SMatthew Dillon * See AHCI 1.1 spec 6.2.2.1 and 6.2.2.2. 24591980eff3SMatthew Dillon * 24601980eff3SMatthew Dillon * This stops command processing. 2461cf5f3a81SMatthew Dillon */ 2462492bffafSMatthew Dillon if (is & AHCI_PREG_IS_TFES) { 2463258223a3SMatthew Dillon u_int32_t tfd, serr; 2464258223a3SMatthew Dillon int err_slot; 2465258223a3SMatthew Dillon 246612feb904SMatthew Dillon process_error: 2467258223a3SMatthew Dillon tfd = ahci_pread(ap, AHCI_PREG_TFD); 2468258223a3SMatthew Dillon serr = ahci_pread(ap, AHCI_PREG_SERR); 2469258223a3SMatthew Dillon 2470cf5f3a81SMatthew Dillon /* 247112feb904SMatthew Dillon * Load the error slot and restart command processing. 247212feb904SMatthew Dillon * CLO if we need to. The error slot may not be valid. 247312feb904SMatthew Dillon * MUST BE DONE BEFORE CLEARING ST! 247412feb904SMatthew Dillon * 247512feb904SMatthew Dillon * Cycle ST. 247612feb904SMatthew Dillon * 247712feb904SMatthew Dillon * It is unclear but we may have to clear SERR to reenable 247812feb904SMatthew Dillon * error processing. 2479cf5f3a81SMatthew Dillon */ 248012feb904SMatthew Dillon err_slot = AHCI_PREG_CMD_CCS(ahci_pread(ap, AHCI_PREG_CMD)); 248112feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_TFES | 248212feb904SMatthew Dillon AHCI_PREG_IS_PSS | 248312feb904SMatthew Dillon AHCI_PREG_IS_DHRS | 248412feb904SMatthew Dillon AHCI_PREG_IS_SDBS); 248512feb904SMatthew Dillon is &= ~(AHCI_PREG_IS_TFES | AHCI_PREG_IS_PSS | 248612feb904SMatthew Dillon AHCI_PREG_IS_DHRS | AHCI_PREG_IS_SDBS); 248712feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, serr); 2488258223a3SMatthew Dillon ahci_port_stop(ap, 0); 248912feb904SMatthew Dillon ahci_os_hardsleep(10); 249012feb904SMatthew Dillon if (tfd & (AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) { 249112feb904SMatthew Dillon kprintf("%s: Issuing CLO\n", PORTNAME(ap)); 249212feb904SMatthew Dillon ahci_port_clo(ap); 249312feb904SMatthew Dillon } 2494492bffafSMatthew Dillon 2495492bffafSMatthew Dillon /* 2496492bffafSMatthew Dillon * We are now stopped and need a restart. If we have to 2497492bffafSMatthew Dillon * process a NCQ error we will temporarily start and then 2498492bffafSMatthew Dillon * stop the port again, so this condition holds. 2499492bffafSMatthew Dillon */ 2500492bffafSMatthew Dillon stopped = 1; 250122181ab7SMatthew Dillon need = NEED_RESTART; 2502258223a3SMatthew Dillon 250350a3ecb6SMatthew Dillon /* 250450a3ecb6SMatthew Dillon * ATAPI errors are fairly common from probing, just 250550a3ecb6SMatthew Dillon * report disk errors or if bootverbose is on. 250650a3ecb6SMatthew Dillon */ 250750a3ecb6SMatthew Dillon if (bootverbose || ap->ap_type != ATA_PORT_T_ATAPI) { 250812feb904SMatthew Dillon kprintf("%s: TFES slot %d ci_saved = %08x\n", 250912feb904SMatthew Dillon PORTNAME(ap), err_slot, ci_saved); 251050a3ecb6SMatthew Dillon } 2511258223a3SMatthew Dillon 25121980eff3SMatthew Dillon /* 251312feb904SMatthew Dillon * If we got an error on an error CCB just complete it 251412feb904SMatthew Dillon * with an error. ci_saved has the mask to restart 251512feb904SMatthew Dillon * (the err_ccb will be removed from it by finish_error). 25161980eff3SMatthew Dillon */ 251712feb904SMatthew Dillon if (ap->ap_flags & AP_F_ERR_CCB_RESERVED) { 251812feb904SMatthew Dillon err_slot = ap->ap_err_ccb->ccb_slot; 251912feb904SMatthew Dillon goto finish_error; 2520258223a3SMatthew Dillon } 2521258223a3SMatthew Dillon 25221980eff3SMatthew Dillon /* 252312feb904SMatthew Dillon * If NCQ commands were active get the error slot from 252412feb904SMatthew Dillon * the log page. NCQ is not supported for PM's so this 252512feb904SMatthew Dillon * is a direct-attached target. 25261980eff3SMatthew Dillon * 252712feb904SMatthew Dillon * Otherwise if no commands were active we have a problem. 252812feb904SMatthew Dillon * 252912feb904SMatthew Dillon * Otherwise if the error slot is bad we have a problem. 253012feb904SMatthew Dillon * 253112feb904SMatthew Dillon * Otherwise process the error for the slot. 25321980eff3SMatthew Dillon */ 253312feb904SMatthew Dillon if (ap->ap_sactive) { 2534492bffafSMatthew Dillon ahci_port_start(ap); 253512feb904SMatthew Dillon err_slot = ahci_port_read_ncq_error(ap, 0); 2536492bffafSMatthew Dillon ahci_port_stop(ap, 0); 253712feb904SMatthew Dillon } else if (ap->ap_active == 0) { 253812feb904SMatthew Dillon kprintf("%s: TFES with no commands pending\n", 253912feb904SMatthew Dillon PORTNAME(ap)); 254012feb904SMatthew Dillon err_slot = -1; 254112feb904SMatthew Dillon } else if (err_slot < 0 || err_slot >= ap->ap_sc->sc_ncmds) { 254212feb904SMatthew Dillon kprintf("%s: bad error slot %d\n", 2543258223a3SMatthew Dillon PORTNAME(ap), err_slot); 254412feb904SMatthew Dillon err_slot = -1; 2545258223a3SMatthew Dillon } else { 254612feb904SMatthew Dillon ccb = &ap->ap_ccbs[err_slot]; 254712feb904SMatthew Dillon 25484c339a5fSMatthew Dillon /* 254912feb904SMatthew Dillon * Validate the errored ccb. Note that ccb_at can 255012feb904SMatthew Dillon * be NULL for direct-attached ccb's. 255112feb904SMatthew Dillon * 255212feb904SMatthew Dillon * Copy received taskfile data from the RFIS. 25534c339a5fSMatthew Dillon */ 255412feb904SMatthew Dillon if (ccb->ccb_xa.state == ATA_S_ONCHIP) { 255512feb904SMatthew Dillon ccb_at = ccb->ccb_xa.at; 255612feb904SMatthew Dillon memcpy(&ccb->ccb_xa.rfis, ap->ap_rfis->rfis, 255712feb904SMatthew Dillon sizeof(struct ata_fis_d2h)); 255850a3ecb6SMatthew Dillon if (bootverbose) { 255950a3ecb6SMatthew Dillon kprintf("%s: Copying rfis slot %d\n", 256012feb904SMatthew Dillon ATANAME(ap, ccb_at), err_slot); 256150a3ecb6SMatthew Dillon } 256212feb904SMatthew Dillon } else { 256312feb904SMatthew Dillon kprintf("%s: Cannot copy rfis, CCB slot " 256412feb904SMatthew Dillon "%d is not on-chip (state=%d)\n", 256512feb904SMatthew Dillon ATANAME(ap, ccb->ccb_xa.at), 256612feb904SMatthew Dillon err_slot, ccb->ccb_xa.state); 256712feb904SMatthew Dillon err_slot = -1; 256812feb904SMatthew Dillon } 2569258223a3SMatthew Dillon } 2570258223a3SMatthew Dillon 2571258223a3SMatthew Dillon /* 257212feb904SMatthew Dillon * If we could not determine the errored slot then 257312feb904SMatthew Dillon * reset the port. 2574258223a3SMatthew Dillon */ 257512feb904SMatthew Dillon if (err_slot < 0) { 257612feb904SMatthew Dillon kprintf("%s: TFES: Unable to determine errored slot\n", 257712feb904SMatthew Dillon PORTNAME(ap)); 25781980eff3SMatthew Dillon if (ap->ap_flags & AP_F_IN_RESET) 25791980eff3SMatthew Dillon goto fatal; 2580258223a3SMatthew Dillon goto failall; 2581258223a3SMatthew Dillon } 2582258223a3SMatthew Dillon 258312feb904SMatthew Dillon /* 258412feb904SMatthew Dillon * Finish error on slot. We will restart ci_saved 258512feb904SMatthew Dillon * commands except the errored slot which we generate 258612feb904SMatthew Dillon * a failure for. 258712feb904SMatthew Dillon */ 258812feb904SMatthew Dillon finish_error: 258912feb904SMatthew Dillon ccb = &ap->ap_ccbs[err_slot]; 2590258223a3SMatthew Dillon ci_saved &= ~(1 << err_slot); 2591258223a3SMatthew Dillon KKASSERT(ccb->ccb_xa.state == ATA_S_ONCHIP); 2592258223a3SMatthew Dillon ccb->ccb_xa.state = ATA_S_ERROR; 25931980eff3SMatthew Dillon } else if (is & AHCI_PREG_IS_DHRS) { 25941980eff3SMatthew Dillon /* 2595f4553de1SMatthew Dillon * Command posted D2H register FIS to the rfis (non-blocking). 2596f4553de1SMatthew Dillon * 259712feb904SMatthew Dillon * A normal completion with an error may set DHRS instead 259812feb904SMatthew Dillon * of TFES. The CCS bits are only valid if ERR was set. 259912feb904SMatthew Dillon * If ERR is set command processing was probably stopped. 26008bf6a3ffSMatthew Dillon * 260112feb904SMatthew Dillon * If ERR was not set we can only copy-back data for 260212feb904SMatthew Dillon * exclusive-mode commands because otherwise we won't know 260312feb904SMatthew Dillon * which tag the rfis belonged to. 260412feb904SMatthew Dillon * 260512feb904SMatthew Dillon * err_slot must be read from the CCS before any other port 260612feb904SMatthew Dillon * action, such as stopping the port. 260712feb904SMatthew Dillon * 260812feb904SMatthew Dillon * WARNING! This is not well documented in the AHCI spec. 260912feb904SMatthew Dillon * It can be found in the state machine tables 261012feb904SMatthew Dillon * but not in the explanations. 26111980eff3SMatthew Dillon */ 261212feb904SMatthew Dillon u_int32_t tfd; 261312feb904SMatthew Dillon u_int32_t cmd; 26141980eff3SMatthew Dillon int err_slot; 26151980eff3SMatthew Dillon 261612feb904SMatthew Dillon tfd = ahci_pread(ap, AHCI_PREG_TFD); 261712feb904SMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD); 261812feb904SMatthew Dillon 261912feb904SMatthew Dillon if ((tfd & AHCI_PREG_TFD_STS_ERR) && 262012feb904SMatthew Dillon (cmd & AHCI_PREG_CMD_CR) == 0) { 26211980eff3SMatthew Dillon err_slot = AHCI_PREG_CMD_CCS( 26221980eff3SMatthew Dillon ahci_pread(ap, AHCI_PREG_CMD)); 26231980eff3SMatthew Dillon ccb = &ap->ap_ccbs[err_slot]; 262412feb904SMatthew Dillon kprintf("%s: DHRS tfd=%b err_slot=%d cmd=%02x\n", 262512feb904SMatthew Dillon PORTNAME(ap), 262612feb904SMatthew Dillon tfd, AHCI_PFMT_TFD_STS, 262712feb904SMatthew Dillon err_slot, ccb->ccb_xa.fis->command); 262812feb904SMatthew Dillon goto process_error; 2629258223a3SMatthew Dillon } 263012feb904SMatthew Dillon /* 263112feb904SMatthew Dillon * NO ELSE... copy back is in the normal command completion 263212feb904SMatthew Dillon * code and only if no error occured and ATA_F_AUTOSENSE 263312feb904SMatthew Dillon * was set. 263412feb904SMatthew Dillon */ 2635cec07d75SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_DHRS); 26361980eff3SMatthew Dillon } 26371980eff3SMatthew Dillon 26381980eff3SMatthew Dillon /* 2639f4553de1SMatthew Dillon * Device notification to us (non-blocking) 26401980eff3SMatthew Dillon * 264112feb904SMatthew Dillon * NOTE! On some parts notification bits can cause an IPMS 264212feb904SMatthew Dillon * interrupt instead of a SDBS interrupt. 2643cec07d75SMatthew Dillon * 264412feb904SMatthew Dillon * NOTE! On some parts (e.g. VBOX, probably intel ICHx), 264512feb904SMatthew Dillon * SDBS notifies us of the completion of a NCQ command 264612feb904SMatthew Dillon * and DBS does not. 26471980eff3SMatthew Dillon */ 264812feb904SMatthew Dillon if (is & (AHCI_PREG_IS_SDBS | AHCI_PREG_IS_IPMS)) { 26491980eff3SMatthew Dillon u_int32_t data; 26501980eff3SMatthew Dillon 265112feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, 265212feb904SMatthew Dillon AHCI_PREG_IS_SDBS | AHCI_PREG_IS_IPMS); 265312feb904SMatthew Dillon if (sc->sc_cap & AHCI_REG_CAP_SSNTF) { 26541980eff3SMatthew Dillon data = ahci_pread(ap, AHCI_PREG_SNTF); 2655cec07d75SMatthew Dillon if (data) { 265612feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, 265712feb904SMatthew Dillon AHCI_PREG_IS_SDBS); 265812feb904SMatthew Dillon kprintf("%s: NOTIFY %08x\n", 265912feb904SMatthew Dillon PORTNAME(ap), data); 266012feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, 266112feb904SMatthew Dillon AHCI_PREG_SERR_DIAG_N); 26623209f581SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SNTF, data); 26633209f581SMatthew Dillon ahci_cam_changed(ap, NULL, -1); 26641980eff3SMatthew Dillon } 26651980eff3SMatthew Dillon } 266612feb904SMatthew Dillon is &= ~(AHCI_PREG_IS_SDBS | AHCI_PREG_IS_IPMS); 266712feb904SMatthew Dillon } 26683209f581SMatthew Dillon 26693209f581SMatthew Dillon /* 2670492bffafSMatthew Dillon * Spurious IFS errors (blockable) - when AP_F_IGNORE_IFS is set. 2671f4553de1SMatthew Dillon * 26723209f581SMatthew Dillon * Spurious IFS errors can occur while we are doing a reset 2673492bffafSMatthew Dillon * sequence through a PM, probably due to an unexpected FIS 2674492bffafSMatthew Dillon * being received during the PM target reset sequence. Chipsets 2675492bffafSMatthew Dillon * are supposed to mask these events but some do not. 2676492bffafSMatthew Dillon * 2677492bffafSMatthew Dillon * Try to recover from the condition. 26783209f581SMatthew Dillon */ 26793209f581SMatthew Dillon if ((is & AHCI_PREG_IS_IFS) && (ap->ap_flags & AP_F_IGNORE_IFS)) { 26801980eff3SMatthew Dillon u_int32_t serr = ahci_pread(ap, AHCI_PREG_SERR); 26813209f581SMatthew Dillon if ((ap->ap_flags & AP_F_IFS_IGNORED) == 0) { 2682492bffafSMatthew Dillon kprintf("%s: IFS during PM probe (ignored) " 2683492bffafSMatthew Dillon "IS=%b, SERR=%b\n", 26841980eff3SMatthew Dillon PORTNAME(ap), 26851980eff3SMatthew Dillon is, AHCI_PFMT_IS, 26861980eff3SMatthew Dillon serr, AHCI_PFMT_SERR); 26873209f581SMatthew Dillon ap->ap_flags |= AP_F_IFS_IGNORED; 26883209f581SMatthew Dillon } 2689492bffafSMatthew Dillon 2690492bffafSMatthew Dillon /* 2691492bffafSMatthew Dillon * Try to clear the error condition. The IFS error killed 2692492bffafSMatthew Dillon * the port so stop it so we can restart it. 2693492bffafSMatthew Dillon */ 26941980eff3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 26951980eff3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_IFS); 26961980eff3SMatthew Dillon is &= ~AHCI_PREG_IS_IFS; 2697492bffafSMatthew Dillon need = NEED_RESTART; 269812feb904SMatthew Dillon goto failall; 26991980eff3SMatthew Dillon } 2700258223a3SMatthew Dillon 2701258223a3SMatthew Dillon /* 2702f4553de1SMatthew Dillon * Port change (hot-plug) (blockable). 2703258223a3SMatthew Dillon * 2704492bffafSMatthew Dillon * A PRCS interrupt can occur: 2705492bffafSMatthew Dillon * (1) On hot-unplug / normal-unplug (phy lost) 2706492bffafSMatthew Dillon * (2) Sometimes on hot-plug too. 2707258223a3SMatthew Dillon * 2708492bffafSMatthew Dillon * A PCS interrupt can occur in a number of situations: 2709492bffafSMatthew Dillon * (1) On hot-plug once communication is established 2710492bffafSMatthew Dillon * (2) On hot-unplug sometimes. 2711492bffafSMatthew Dillon * (3) For chipsets with badly written firmware it can occur 2712492bffafSMatthew Dillon * during INIT/RESET sequences due to the device reset. 2713492bffafSMatthew Dillon * (4) For chipsets with badly written firmware it can occur 2714492bffafSMatthew Dillon * when it thinks an unsolicited COMRESET is received 2715492bffafSMatthew Dillon * during a INIT/RESET sequence, even though we actually 2716492bffafSMatthew Dillon * did request it. 2717258223a3SMatthew Dillon * 271822181ab7SMatthew Dillon * XXX We can then check the CPS (Cold Presence State) bit, if 271922181ab7SMatthew Dillon * supported, to determine if a device is plugged in or not and do 272022181ab7SMatthew Dillon * the right thing. 272122181ab7SMatthew Dillon * 2722492bffafSMatthew Dillon * PCS interrupts are cleared by clearing DIAG_X. If this occurs 2723492bffafSMatthew Dillon * command processing is automatically stopped (CR goes inactive) 2724492bffafSMatthew Dillon * and the port must be stopped and restarted. 2725492bffafSMatthew Dillon * 2726492bffafSMatthew Dillon * WARNING: AMD parts (e.g. 880G chipset, probably others) can 2727492bffafSMatthew Dillon * generate PCS on initialization even when device is 2728492bffafSMatthew Dillon * already connected up. It is unclear why this happens. 2729492bffafSMatthew Dillon * Depending on the state of the device detect this can 2730492bffafSMatthew Dillon * cause us to go into harsh reinit or hot-plug insertion 2731492bffafSMatthew Dillon * mode. 2732492bffafSMatthew Dillon * 2733492bffafSMatthew Dillon * WARNING: PCS errors can be repetitive (e.g. unsolicited COMRESET 2734492bffafSMatthew Dillon * continues to flow in from the device), we must clear the 2735492bffafSMatthew Dillon * interrupt in all cases and enforce a delay to prevent 2736492bffafSMatthew Dillon * a livelock and give the port time to settle down. 2737492bffafSMatthew Dillon * Only print something if we aren't in INIT/HARD-RESET. 2738258223a3SMatthew Dillon */ 2739258223a3SMatthew Dillon if (is & (AHCI_PREG_IS_PCS | AHCI_PREG_IS_PRCS)) { 2740492bffafSMatthew Dillon /* 2741492bffafSMatthew Dillon * Try to clear the error. Because of the repetitiveness 2742492bffafSMatthew Dillon * of this interrupt avoid any harsh action if the port is 2743492bffafSMatthew Dillon * already in the init or hard-reset probe state. 2744492bffafSMatthew Dillon */ 2745492bffafSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 2746492bffafSMatthew Dillon /* (AHCI_PREG_SERR_DIAG_N | AHCI_PREG_SERR_DIAG_X) */ 2747cec07d75SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, 2748cec07d75SMatthew Dillon is & (AHCI_PREG_IS_PCS | AHCI_PREG_IS_PRCS)); 2749492bffafSMatthew Dillon 2750493d3201SMatthew Dillon /* 2751493d3201SMatthew Dillon * Ignore PCS/PRCS errors during probes (but still clear the 2752493d3201SMatthew Dillon * interrupt to avoid a livelock). The AMD 880/890/SB850 2753493d3201SMatthew Dillon * chipsets do not mask PCS/PRCS internally during reset 2754493d3201SMatthew Dillon * sequences. 2755493d3201SMatthew Dillon */ 27565502cf24SMatthew Dillon if (ap->ap_flags & AP_F_IN_RESET) 2757493d3201SMatthew Dillon goto skip_pcs; 2758493d3201SMatthew Dillon 2759492bffafSMatthew Dillon if (ap->ap_probe == ATA_PROBE_NEED_INIT || 2760492bffafSMatthew Dillon ap->ap_probe == ATA_PROBE_NEED_HARD_RESET) { 2761cec07d75SMatthew Dillon is &= ~(AHCI_PREG_IS_PCS | AHCI_PREG_IS_PRCS); 2762492bffafSMatthew Dillon need = NEED_NOTHING; 2763492bffafSMatthew Dillon ahci_os_sleep(1000); 2764492bffafSMatthew Dillon goto failall; 2765492bffafSMatthew Dillon } 2766492bffafSMatthew Dillon kprintf("%s: Transient Errors: %b (%d)\n", 2767492bffafSMatthew Dillon PORTNAME(ap), is, AHCI_PFMT_IS, ap->ap_probe); 2768492bffafSMatthew Dillon is &= ~(AHCI_PREG_IS_PCS | AHCI_PREG_IS_PRCS); 2769492bffafSMatthew Dillon ahci_os_sleep(200); 2770492bffafSMatthew Dillon 2771492bffafSMatthew Dillon /* 2772492bffafSMatthew Dillon * Stop the port and figure out what to do next. 2773492bffafSMatthew Dillon */ 277422181ab7SMatthew Dillon ahci_port_stop(ap, 0); 2775492bffafSMatthew Dillon stopped = 1; 27760be9576aSMatthew Dillon 2777258223a3SMatthew Dillon switch (ahci_pread(ap, AHCI_PREG_SSTS) & AHCI_PREG_SSTS_DET) { 2778258223a3SMatthew Dillon case AHCI_PREG_SSTS_DET_DEV: 2779492bffafSMatthew Dillon /* 2780492bffafSMatthew Dillon * Device detect 2781492bffafSMatthew Dillon */ 278212feb904SMatthew Dillon if (ap->ap_probe == ATA_PROBE_FAILED) { 278322181ab7SMatthew Dillon need = NEED_HOTPLUG_INSERT; 278422181ab7SMatthew Dillon goto fatal; 2785258223a3SMatthew Dillon } 278622181ab7SMatthew Dillon need = NEED_RESTART; 2787258223a3SMatthew Dillon break; 2788492bffafSMatthew Dillon case AHCI_PREG_SSTS_DET_DEV_NE: 2789492bffafSMatthew Dillon /* 2790492bffafSMatthew Dillon * Device not communicating. AMD parts seem to 2791492bffafSMatthew Dillon * like to throw this error on initialization 2792492bffafSMatthew Dillon * for no reason that I can fathom. 2793492bffafSMatthew Dillon */ 2794492bffafSMatthew Dillon kprintf("%s: Device present but not communicating, " 2795492bffafSMatthew Dillon "attempting port restart\n", 2796492bffafSMatthew Dillon PORTNAME(ap)); 2797492bffafSMatthew Dillon need = NEED_REINIT; 2798492bffafSMatthew Dillon goto fatal; 2799258223a3SMatthew Dillon default: 28000be9576aSMatthew Dillon if (ap->ap_probe != ATA_PROBE_FAILED) { 280122181ab7SMatthew Dillon need = NEED_HOTPLUG_REMOVE; 280222181ab7SMatthew Dillon goto fatal; 2803258223a3SMatthew Dillon } 280422181ab7SMatthew Dillon need = NEED_RESTART; 2805258223a3SMatthew Dillon break; 2806258223a3SMatthew Dillon } 2807493d3201SMatthew Dillon skip_pcs: 2808493d3201SMatthew Dillon ; 2809258223a3SMatthew Dillon } 2810258223a3SMatthew Dillon 281122181ab7SMatthew Dillon /* 2812f4553de1SMatthew Dillon * Check for remaining errors - they are fatal. (blockable) 281322181ab7SMatthew Dillon */ 2814258223a3SMatthew Dillon if (is & (AHCI_PREG_IS_TFES | AHCI_PREG_IS_HBFS | AHCI_PREG_IS_IFS | 2815258223a3SMatthew Dillon AHCI_PREG_IS_OFS | AHCI_PREG_IS_UFS)) { 2816cec07d75SMatthew Dillon u_int32_t serr; 2817cec07d75SMatthew Dillon 2818cec07d75SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, 2819cec07d75SMatthew Dillon is & (AHCI_PREG_IS_TFES | AHCI_PREG_IS_HBFS | 2820cec07d75SMatthew Dillon AHCI_PREG_IS_IFS | AHCI_PREG_IS_OFS | 2821cec07d75SMatthew Dillon AHCI_PREG_IS_UFS)); 2822cec07d75SMatthew Dillon serr = ahci_pread(ap, AHCI_PREG_SERR); 2823831bc9e3SMatthew Dillon kprintf("%s: Unrecoverable errors (IS: %b, SERR: %b), " 28244444122dSMatthew Dillon "disabling port.\n", 28254444122dSMatthew Dillon PORTNAME(ap), 28264444122dSMatthew Dillon is, AHCI_PFMT_IS, 28271980eff3SMatthew Dillon serr, AHCI_PFMT_SERR 28284444122dSMatthew Dillon ); 2829831bc9e3SMatthew Dillon is &= ~(AHCI_PREG_IS_TFES | AHCI_PREG_IS_HBFS | 2830831bc9e3SMatthew Dillon AHCI_PREG_IS_IFS | AHCI_PREG_IS_OFS | 2831831bc9e3SMatthew Dillon AHCI_PREG_IS_UFS); 2832492bffafSMatthew Dillon 2833492bffafSMatthew Dillon /* 2834492bffafSMatthew Dillon * Fail all commands but then what? For now try to 2835492bffafSMatthew Dillon * reinitialize the port. 2836492bffafSMatthew Dillon */ 2837492bffafSMatthew Dillon need = NEED_REINIT; 2838258223a3SMatthew Dillon goto fatal; 2839258223a3SMatthew Dillon } 2840258223a3SMatthew Dillon 284122181ab7SMatthew Dillon /* 284222181ab7SMatthew Dillon * Fail all outstanding commands if we know the port won't recover. 28431980eff3SMatthew Dillon * 28441980eff3SMatthew Dillon * We may have a ccb_at if the failed command is known and was 28451980eff3SMatthew Dillon * being sent to a device over a port multiplier (PM). In this 28461980eff3SMatthew Dillon * case if the port itself has not completely failed we fail just 28471980eff3SMatthew Dillon * the commands related to that target. 284812feb904SMatthew Dillon * 284912feb904SMatthew Dillon * ci_saved contains the mask of active commands as of when the 285012feb904SMatthew Dillon * error occured, prior to any port stops. 285122181ab7SMatthew Dillon */ 2852258223a3SMatthew Dillon if (ap->ap_state == AP_S_FATAL_ERROR) { 2853258223a3SMatthew Dillon fatal: 2854258223a3SMatthew Dillon ap->ap_state = AP_S_FATAL_ERROR; 285512feb904SMatthew Dillon failall: 2856492bffafSMatthew Dillon ahci_port_stop(ap, 0); 2857492bffafSMatthew Dillon stopped = 1; 2858258223a3SMatthew Dillon 28591980eff3SMatthew Dillon /* 2860492bffafSMatthew Dillon * Error all the active slots not already errored. 28611980eff3SMatthew Dillon */ 286212feb904SMatthew Dillon ci_masked = ci_saved & *active & ~ap->ap_expired; 2863492bffafSMatthew Dillon if (ci_masked) { 2864492bffafSMatthew Dillon kprintf("%s: Failing all commands: %08x\n", 2865492bffafSMatthew Dillon PORTNAME(ap), ci_masked); 2866492bffafSMatthew Dillon } 2867492bffafSMatthew Dillon 2868258223a3SMatthew Dillon while (ci_masked) { 2869258223a3SMatthew Dillon slot = ffs(ci_masked) - 1; 2870258223a3SMatthew Dillon ccb = &ap->ap_ccbs[slot]; 287112feb904SMatthew Dillon ccb->ccb_xa.state = ATA_S_TIMEOUT; 287212feb904SMatthew Dillon ap->ap_expired |= 1 << slot; 287312feb904SMatthew Dillon ci_saved &= ~(1 << slot); 287412feb904SMatthew Dillon ci_masked &= ~(1 << slot); 28751980eff3SMatthew Dillon } 2876258223a3SMatthew Dillon 287712feb904SMatthew Dillon /* 287812feb904SMatthew Dillon * Clear bits in ci_saved (cause completions to be run) 287912feb904SMatthew Dillon * for all slots which are not active. 288012feb904SMatthew Dillon */ 2881258223a3SMatthew Dillon ci_saved &= ~*active; 2882258223a3SMatthew Dillon 2883258223a3SMatthew Dillon /* 2884258223a3SMatthew Dillon * Don't restart the port if our problems were deemed fatal. 2885258223a3SMatthew Dillon * 2886258223a3SMatthew Dillon * Also acknowlege all fatal interrupt sources to prevent 2887258223a3SMatthew Dillon * a livelock. 2888258223a3SMatthew Dillon */ 2889258223a3SMatthew Dillon if (ap->ap_state == AP_S_FATAL_ERROR) { 289022181ab7SMatthew Dillon if (need == NEED_RESTART) 289122181ab7SMatthew Dillon need = NEED_NOTHING; 2892258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, 2893258223a3SMatthew Dillon AHCI_PREG_IS_TFES | AHCI_PREG_IS_HBFS | 2894258223a3SMatthew Dillon AHCI_PREG_IS_IFS | AHCI_PREG_IS_OFS | 2895258223a3SMatthew Dillon AHCI_PREG_IS_UFS); 2896258223a3SMatthew Dillon } 2897258223a3SMatthew Dillon } 2898258223a3SMatthew Dillon 2899258223a3SMatthew Dillon /* 2900492bffafSMatthew Dillon * If we are stopped the AHCI chipset is supposed to have cleared 2901492bffafSMatthew Dillon * CI and SACT. Did it? If it didn't we try very hard to clear 2902492bffafSMatthew Dillon * the fields otherwise we may end up completing CCBs which are 2903492bffafSMatthew Dillon * actually still active. 2904492bffafSMatthew Dillon * 2905492bffafSMatthew Dillon * IFS errors on (at least) AMD chipsets create this confusion. 2906492bffafSMatthew Dillon */ 2907492bffafSMatthew Dillon if (stopped) { 2908492bffafSMatthew Dillon u_int32_t mask; 2909492bffafSMatthew Dillon if ((mask = ahci_pactive(ap)) != 0) { 2910492bffafSMatthew Dillon kprintf("%s: chipset failed to clear " 2911492bffafSMatthew Dillon "active cmds %08x\n", 2912492bffafSMatthew Dillon PORTNAME(ap), mask); 2913492bffafSMatthew Dillon ahci_port_start(ap); 2914492bffafSMatthew Dillon ahci_port_stop(ap, 0); 2915492bffafSMatthew Dillon if ((mask = ahci_pactive(ap)) != 0) { 2916492bffafSMatthew Dillon kprintf("%s: unable to prod the chip into " 2917492bffafSMatthew Dillon "clearing active cmds %08x\n", 2918492bffafSMatthew Dillon PORTNAME(ap), mask); 2919492bffafSMatthew Dillon /* what do we do now? */ 2920492bffafSMatthew Dillon } 2921492bffafSMatthew Dillon } 2922492bffafSMatthew Dillon } 2923492bffafSMatthew Dillon 2924492bffafSMatthew Dillon /* 2925f4553de1SMatthew Dillon * CCB completion (non blocking). 2926f4553de1SMatthew Dillon * 2927258223a3SMatthew Dillon * CCB completion is detected by noticing its slot's bit in CI has 2928258223a3SMatthew Dillon * changed to zero some time after we activated it. 2929258223a3SMatthew Dillon * If we are polling, we may only be interested in particular slot(s). 2930cf5f3a81SMatthew Dillon * 2931cf5f3a81SMatthew Dillon * Any active bits not saved are completed within the restrictions 2932cf5f3a81SMatthew Dillon * imposed by the caller. 2933258223a3SMatthew Dillon */ 29343209f581SMatthew Dillon ci_masked = ~ci_saved & *active; 2935258223a3SMatthew Dillon while (ci_masked) { 2936258223a3SMatthew Dillon slot = ffs(ci_masked) - 1; 2937258223a3SMatthew Dillon ccb = &ap->ap_ccbs[slot]; 2938258223a3SMatthew Dillon ci_masked &= ~(1 << slot); 2939258223a3SMatthew Dillon 2940258223a3SMatthew Dillon DPRINTF(AHCI_D_INTR, "%s: slot %d is complete%s\n", 2941258223a3SMatthew Dillon PORTNAME(ap), slot, ccb->ccb_xa.state == ATA_S_ERROR ? 2942258223a3SMatthew Dillon " (error)" : ""); 2943258223a3SMatthew Dillon 2944258223a3SMatthew Dillon bus_dmamap_sync(sc->sc_tag_cmdh, 2945258223a3SMatthew Dillon AHCI_DMA_MAP(ap->ap_dmamem_cmd_list), 2946258223a3SMatthew Dillon BUS_DMASYNC_POSTWRITE); 2947258223a3SMatthew Dillon 2948258223a3SMatthew Dillon bus_dmamap_sync(sc->sc_tag_cmdt, 2949258223a3SMatthew Dillon AHCI_DMA_MAP(ap->ap_dmamem_cmd_table), 2950258223a3SMatthew Dillon BUS_DMASYNC_POSTWRITE); 2951258223a3SMatthew Dillon 2952258223a3SMatthew Dillon bus_dmamap_sync(sc->sc_tag_rfis, 2953258223a3SMatthew Dillon AHCI_DMA_MAP(ap->ap_dmamem_rfis), 2954258223a3SMatthew Dillon BUS_DMASYNC_POSTREAD); 2955258223a3SMatthew Dillon 2956258223a3SMatthew Dillon *active &= ~(1 << ccb->ccb_slot); 29571980eff3SMatthew Dillon if (active == &ap->ap_active) { 29581980eff3SMatthew Dillon KKASSERT(ap->ap_active_cnt > 0); 29591980eff3SMatthew Dillon --ap->ap_active_cnt; 29601980eff3SMatthew Dillon } 29614c339a5fSMatthew Dillon 29624c339a5fSMatthew Dillon /* 29634c339a5fSMatthew Dillon * Complete the ccb. If the ccb was marked expired it 29644c339a5fSMatthew Dillon * was probably already removed from the command processor, 29654c339a5fSMatthew Dillon * so don't take the clear ci_saved bit as meaning the 29664c339a5fSMatthew Dillon * command actually succeeded, it didn't. 29674c339a5fSMatthew Dillon */ 29684c339a5fSMatthew Dillon if (ap->ap_expired & (1 << ccb->ccb_slot)) { 296976497a9cSMatthew Dillon ap->ap_expired &= ~(1 << ccb->ccb_slot); 29704c339a5fSMatthew Dillon ccb->ccb_xa.state = ATA_S_TIMEOUT; 2971258223a3SMatthew Dillon ccb->ccb_done(ccb); 29724c339a5fSMatthew Dillon ccb->ccb_xa.complete(&ccb->ccb_xa); 29734c339a5fSMatthew Dillon } else { 297412feb904SMatthew Dillon if (ccb->ccb_xa.state == ATA_S_ONCHIP) { 29754c339a5fSMatthew Dillon ccb->ccb_xa.state = ATA_S_COMPLETE; 297612feb904SMatthew Dillon if (ccb->ccb_xa.flags & ATA_F_AUTOSENSE) { 297712feb904SMatthew Dillon memcpy(&ccb->ccb_xa.rfis, 297812feb904SMatthew Dillon ap->ap_rfis->rfis, 297912feb904SMatthew Dillon sizeof(struct ata_fis_d2h)); 298012feb904SMatthew Dillon if (ccb->ccb_xa.state == ATA_S_TIMEOUT) 298112feb904SMatthew Dillon ccb->ccb_xa.state = ATA_S_ERROR; 298212feb904SMatthew Dillon } 298312feb904SMatthew Dillon } 29844c339a5fSMatthew Dillon ccb->ccb_done(ccb); 29854c339a5fSMatthew Dillon } 2986258223a3SMatthew Dillon } 2987258223a3SMatthew Dillon 2988f4553de1SMatthew Dillon /* 2989f4553de1SMatthew Dillon * Cleanup. Will not be set if non-blocking. 2990f4553de1SMatthew Dillon */ 299122181ab7SMatthew Dillon switch(need) { 2992f3de36f7SMatthew Dillon case NEED_NOTHING: 2993f3de36f7SMatthew Dillon /* 2994f3de36f7SMatthew Dillon * If operating normally and not stopped the interrupt was 2995f3de36f7SMatthew Dillon * probably just a normal completion and we may be able to 2996f3de36f7SMatthew Dillon * issue more commands. 2997f3de36f7SMatthew Dillon */ 2998f3de36f7SMatthew Dillon if (stopped == 0 && ap->ap_state != AP_S_FATAL_ERROR) 2999f3de36f7SMatthew Dillon ahci_issue_pending_commands(ap, NULL); 3000f3de36f7SMatthew Dillon break; 300122181ab7SMatthew Dillon case NEED_RESTART: 300222181ab7SMatthew Dillon /* 300322181ab7SMatthew Dillon * A recoverable error occured and we can restart outstanding 300422181ab7SMatthew Dillon * commands on the port. 300522181ab7SMatthew Dillon */ 300612feb904SMatthew Dillon ci_saved &= ~ap->ap_expired; 3007258223a3SMatthew Dillon if (ci_saved) { 300812feb904SMatthew Dillon kprintf("%s: Restart %08x\n", PORTNAME(ap), ci_saved); 30094c339a5fSMatthew Dillon ahci_issue_saved_commands(ap, ci_saved); 3010258223a3SMatthew Dillon } 3011492bffafSMatthew Dillon 3012492bffafSMatthew Dillon /* 3013492bffafSMatthew Dillon * Potentially issue new commands if not in a failed 3014492bffafSMatthew Dillon * state. 3015492bffafSMatthew Dillon */ 3016492bffafSMatthew Dillon if (ap->ap_state != AP_S_FATAL_ERROR) { 3017492bffafSMatthew Dillon ahci_port_start(ap); 3018492bffafSMatthew Dillon ahci_issue_pending_commands(ap, NULL); 3019492bffafSMatthew Dillon } 3020492bffafSMatthew Dillon break; 3021492bffafSMatthew Dillon case NEED_REINIT: 3022492bffafSMatthew Dillon /* 3023492bffafSMatthew Dillon * Something horrible happened to the port and we 3024492bffafSMatthew Dillon * need to reinitialize it. 3025492bffafSMatthew Dillon */ 3026492bffafSMatthew Dillon kprintf("%s: REINIT - Attempting to reinitialize the port " 3027492bffafSMatthew Dillon "after it had a horrible accident\n", 3028492bffafSMatthew Dillon PORTNAME(ap)); 3029492bffafSMatthew Dillon ap->ap_flags |= AP_F_IN_RESET; 3030492bffafSMatthew Dillon ap->ap_flags |= AP_F_HARSH_REINIT; 3031492bffafSMatthew Dillon ap->ap_probe = ATA_PROBE_NEED_INIT; 3032492bffafSMatthew Dillon ahci_cam_changed(ap, NULL, -1); 303322181ab7SMatthew Dillon break; 303422181ab7SMatthew Dillon case NEED_HOTPLUG_INSERT: 303522181ab7SMatthew Dillon /* 3036cf5f3a81SMatthew Dillon * A hot-plug insertion event has occured and all 3037cf5f3a81SMatthew Dillon * outstanding commands have already been revoked. 30381980eff3SMatthew Dillon * 30391980eff3SMatthew Dillon * Don't recurse if this occurs while we are 30401980eff3SMatthew Dillon * resetting the port. 304122181ab7SMatthew Dillon */ 30421980eff3SMatthew Dillon if ((ap->ap_flags & AP_F_IN_RESET) == 0) { 304322181ab7SMatthew Dillon kprintf("%s: HOTPLUG - Device inserted\n", 304422181ab7SMatthew Dillon PORTNAME(ap)); 30453209f581SMatthew Dillon ap->ap_probe = ATA_PROBE_NEED_INIT; 30463209f581SMatthew Dillon ahci_cam_changed(ap, NULL, -1); 30471980eff3SMatthew Dillon } 304822181ab7SMatthew Dillon break; 304922181ab7SMatthew Dillon case NEED_HOTPLUG_REMOVE: 3050cf5f3a81SMatthew Dillon /* 3051cf5f3a81SMatthew Dillon * A hot-plug removal event has occured and all 3052cf5f3a81SMatthew Dillon * outstanding commands have already been revoked. 30531980eff3SMatthew Dillon * 30541980eff3SMatthew Dillon * Don't recurse if this occurs while we are 30551980eff3SMatthew Dillon * resetting the port. 3056cf5f3a81SMatthew Dillon */ 30571980eff3SMatthew Dillon if ((ap->ap_flags & AP_F_IN_RESET) == 0) { 305822181ab7SMatthew Dillon kprintf("%s: HOTPLUG - Device removed\n", 305922181ab7SMatthew Dillon PORTNAME(ap)); 3060cf5f3a81SMatthew Dillon ahci_port_hardstop(ap); 30613209f581SMatthew Dillon /* ap_probe set to failed */ 30623209f581SMatthew Dillon ahci_cam_changed(ap, NULL, -1); 30631980eff3SMatthew Dillon } 306422181ab7SMatthew Dillon break; 306522181ab7SMatthew Dillon default: 306622181ab7SMatthew Dillon break; 3067258223a3SMatthew Dillon } 3068258223a3SMatthew Dillon } 3069258223a3SMatthew Dillon 3070258223a3SMatthew Dillon struct ahci_ccb * 3071258223a3SMatthew Dillon ahci_get_ccb(struct ahci_port *ap) 3072258223a3SMatthew Dillon { 3073258223a3SMatthew Dillon struct ahci_ccb *ccb; 3074258223a3SMatthew Dillon 3075258223a3SMatthew Dillon lockmgr(&ap->ap_ccb_lock, LK_EXCLUSIVE); 3076258223a3SMatthew Dillon ccb = TAILQ_FIRST(&ap->ap_ccb_free); 3077258223a3SMatthew Dillon if (ccb != NULL) { 3078258223a3SMatthew Dillon KKASSERT(ccb->ccb_xa.state == ATA_S_PUT); 3079258223a3SMatthew Dillon TAILQ_REMOVE(&ap->ap_ccb_free, ccb, ccb_entry); 3080258223a3SMatthew Dillon ccb->ccb_xa.state = ATA_S_SETUP; 3081492bffafSMatthew Dillon ccb->ccb_xa.flags = 0; 30821980eff3SMatthew Dillon ccb->ccb_xa.at = NULL; 3083258223a3SMatthew Dillon } 3084258223a3SMatthew Dillon lockmgr(&ap->ap_ccb_lock, LK_RELEASE); 3085258223a3SMatthew Dillon 3086258223a3SMatthew Dillon return (ccb); 3087258223a3SMatthew Dillon } 3088258223a3SMatthew Dillon 3089258223a3SMatthew Dillon void 3090258223a3SMatthew Dillon ahci_put_ccb(struct ahci_ccb *ccb) 3091258223a3SMatthew Dillon { 3092258223a3SMatthew Dillon struct ahci_port *ap = ccb->ccb_port; 3093258223a3SMatthew Dillon 3094258223a3SMatthew Dillon ccb->ccb_xa.state = ATA_S_PUT; 3095258223a3SMatthew Dillon lockmgr(&ap->ap_ccb_lock, LK_EXCLUSIVE); 3096258223a3SMatthew Dillon TAILQ_INSERT_TAIL(&ap->ap_ccb_free, ccb, ccb_entry); 3097258223a3SMatthew Dillon lockmgr(&ap->ap_ccb_lock, LK_RELEASE); 3098258223a3SMatthew Dillon } 3099258223a3SMatthew Dillon 3100258223a3SMatthew Dillon struct ahci_ccb * 3101258223a3SMatthew Dillon ahci_get_err_ccb(struct ahci_port *ap) 3102258223a3SMatthew Dillon { 3103258223a3SMatthew Dillon struct ahci_ccb *err_ccb; 3104258223a3SMatthew Dillon u_int32_t sact; 3105b012a2caSMatthew Dillon u_int32_t ci; 3106258223a3SMatthew Dillon 3107258223a3SMatthew Dillon /* No commands may be active on the chip. */ 3108b012a2caSMatthew Dillon 3109b012a2caSMatthew Dillon if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SNCQ) { 3110258223a3SMatthew Dillon sact = ahci_pread(ap, AHCI_PREG_SACT); 3111192ee1d0SMatthew Dillon if (sact != 0) { 3112192ee1d0SMatthew Dillon kprintf("%s: ahci_get_err_ccb but SACT %08x != 0?\n", 3113192ee1d0SMatthew Dillon PORTNAME(ap), sact); 3114192ee1d0SMatthew Dillon } 3115b012a2caSMatthew Dillon } 3116b012a2caSMatthew Dillon ci = ahci_pread(ap, AHCI_PREG_CI); 3117b012a2caSMatthew Dillon if (ci) { 3118b012a2caSMatthew Dillon kprintf("%s: ahci_get_err_ccb: ci not 0 (%08x)\n", 3119b012a2caSMatthew Dillon ap->ap_name, ci); 3120b012a2caSMatthew Dillon } 3121b012a2caSMatthew Dillon KKASSERT(ci == 0); 3122baef7501SMatthew Dillon KKASSERT((ap->ap_flags & AP_F_ERR_CCB_RESERVED) == 0); 3123baef7501SMatthew Dillon ap->ap_flags |= AP_F_ERR_CCB_RESERVED; 3124258223a3SMatthew Dillon 3125258223a3SMatthew Dillon /* Save outstanding command state. */ 3126258223a3SMatthew Dillon ap->ap_err_saved_active = ap->ap_active; 3127258223a3SMatthew Dillon ap->ap_err_saved_active_cnt = ap->ap_active_cnt; 3128258223a3SMatthew Dillon ap->ap_err_saved_sactive = ap->ap_sactive; 3129258223a3SMatthew Dillon 3130258223a3SMatthew Dillon /* 3131258223a3SMatthew Dillon * Pretend we have no commands outstanding, so that completions won't 3132258223a3SMatthew Dillon * run prematurely. 3133258223a3SMatthew Dillon */ 3134258223a3SMatthew Dillon ap->ap_active = ap->ap_active_cnt = ap->ap_sactive = 0; 3135258223a3SMatthew Dillon 3136258223a3SMatthew Dillon /* 3137258223a3SMatthew Dillon * Grab a CCB to use for error recovery. This should never fail, as 3138258223a3SMatthew Dillon * we ask atascsi to reserve one for us at init time. 3139258223a3SMatthew Dillon */ 31401067474aSMatthew Dillon err_ccb = ap->ap_err_ccb; 3141258223a3SMatthew Dillon KKASSERT(err_ccb != NULL); 3142258223a3SMatthew Dillon err_ccb->ccb_xa.flags = 0; 3143258223a3SMatthew Dillon err_ccb->ccb_done = ahci_empty_done; 3144258223a3SMatthew Dillon 3145258223a3SMatthew Dillon return err_ccb; 3146258223a3SMatthew Dillon } 3147258223a3SMatthew Dillon 3148258223a3SMatthew Dillon void 3149258223a3SMatthew Dillon ahci_put_err_ccb(struct ahci_ccb *ccb) 3150258223a3SMatthew Dillon { 3151258223a3SMatthew Dillon struct ahci_port *ap = ccb->ccb_port; 3152258223a3SMatthew Dillon u_int32_t sact; 31535f8c1efdSMatthew Dillon u_int32_t ci; 3154258223a3SMatthew Dillon 3155baef7501SMatthew Dillon KKASSERT((ap->ap_flags & AP_F_ERR_CCB_RESERVED) != 0); 3156baef7501SMatthew Dillon 31575f8c1efdSMatthew Dillon /* 31585f8c1efdSMatthew Dillon * No commands may be active on the chip 31595f8c1efdSMatthew Dillon */ 3160b012a2caSMatthew Dillon if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SNCQ) { 3161258223a3SMatthew Dillon sact = ahci_pread(ap, AHCI_PREG_SACT); 31625f8c1efdSMatthew Dillon if (sact) { 31635f8c1efdSMatthew Dillon panic("ahci_port_err_ccb(%d) but SACT %08x != 0\n", 31645f8c1efdSMatthew Dillon ccb->ccb_slot, sact); 3165258223a3SMatthew Dillon } 3166b012a2caSMatthew Dillon } 31675f8c1efdSMatthew Dillon ci = ahci_pread(ap, AHCI_PREG_CI); 31685f8c1efdSMatthew Dillon if (ci) { 3169cf5f3a81SMatthew Dillon panic("ahci_put_err_ccb(%d) but CI %08x != 0 " 3170cf5f3a81SMatthew Dillon "(act=%08x sact=%08x)\n", 3171cf5f3a81SMatthew Dillon ccb->ccb_slot, ci, 3172cf5f3a81SMatthew Dillon ap->ap_active, ap->ap_sactive); 31735f8c1efdSMatthew Dillon } 3174258223a3SMatthew Dillon 31751067474aSMatthew Dillon KKASSERT(ccb == ap->ap_err_ccb); 3176258223a3SMatthew Dillon 3177258223a3SMatthew Dillon /* Restore outstanding command state */ 3178258223a3SMatthew Dillon ap->ap_sactive = ap->ap_err_saved_sactive; 3179258223a3SMatthew Dillon ap->ap_active_cnt = ap->ap_err_saved_active_cnt; 3180258223a3SMatthew Dillon ap->ap_active = ap->ap_err_saved_active; 3181258223a3SMatthew Dillon 3182baef7501SMatthew Dillon ap->ap_flags &= ~AP_F_ERR_CCB_RESERVED; 3183258223a3SMatthew Dillon } 3184258223a3SMatthew Dillon 31851980eff3SMatthew Dillon /* 31861980eff3SMatthew Dillon * Read log page to get NCQ error. 31871980eff3SMatthew Dillon * 31881980eff3SMatthew Dillon * NOTE: NCQ not currently supported on port multipliers. XXX 31891980eff3SMatthew Dillon */ 3190258223a3SMatthew Dillon int 319112feb904SMatthew Dillon ahci_port_read_ncq_error(struct ahci_port *ap, int target) 3192258223a3SMatthew Dillon { 319312feb904SMatthew Dillon struct ata_log_page_10h *log; 3194258223a3SMatthew Dillon struct ahci_ccb *ccb; 3195e1014452SMatthew Dillon struct ahci_ccb *ccb2; 3196258223a3SMatthew Dillon struct ahci_cmd_hdr *cmd_slot; 3197258223a3SMatthew Dillon struct ata_fis_h2d *fis; 319812feb904SMatthew Dillon int err_slot; 3199258223a3SMatthew Dillon 320012feb904SMatthew Dillon if (bootverbose) { 320112feb904SMatthew Dillon kprintf("%s: READ LOG PAGE target %d\n", PORTNAME(ap), 320212feb904SMatthew Dillon target); 320312feb904SMatthew Dillon } 3204258223a3SMatthew Dillon 320512feb904SMatthew Dillon /* 320612feb904SMatthew Dillon * Prep error CCB for READ LOG EXT, page 10h, 1 sector. 320712feb904SMatthew Dillon * 320812feb904SMatthew Dillon * Getting err_ccb clears active/sactive/active_cnt, putting 320912feb904SMatthew Dillon * it back restores the fields. 321012feb904SMatthew Dillon */ 3211258223a3SMatthew Dillon ccb = ahci_get_err_ccb(ap); 321212feb904SMatthew Dillon ccb->ccb_xa.flags = ATA_F_READ | ATA_F_POLL; 3213258223a3SMatthew Dillon ccb->ccb_xa.data = ap->ap_err_scratch; 3214258223a3SMatthew Dillon ccb->ccb_xa.datalen = 512; 321512feb904SMatthew Dillon ccb->ccb_xa.complete = ahci_dummy_done; 3216b012a2caSMatthew Dillon ccb->ccb_xa.at = ap->ap_ata[target]; 3217258223a3SMatthew Dillon 3218258223a3SMatthew Dillon fis = (struct ata_fis_h2d *)ccb->ccb_cmd_table->cfis; 321912feb904SMatthew Dillon bzero(fis, sizeof(*fis)); 3220258223a3SMatthew Dillon fis->type = ATA_FIS_TYPE_H2D; 322112feb904SMatthew Dillon fis->flags = ATA_H2D_FLAGS_CMD | target; 3222258223a3SMatthew Dillon fis->command = ATA_C_READ_LOG_EXT; 3223258223a3SMatthew Dillon fis->lba_low = 0x10; /* queued error log page (10h) */ 3224258223a3SMatthew Dillon fis->sector_count = 1; /* number of sectors (1) */ 3225258223a3SMatthew Dillon fis->sector_count_exp = 0; 3226258223a3SMatthew Dillon fis->lba_mid = 0; /* starting offset */ 3227258223a3SMatthew Dillon fis->lba_mid_exp = 0; 3228258223a3SMatthew Dillon fis->device = 0; 3229258223a3SMatthew Dillon 323012feb904SMatthew Dillon cmd_slot = ccb->ccb_cmd_hdr; 3231258223a3SMatthew Dillon cmd_slot->flags = htole16(5); /* FIS length: 5 DWORDS */ 3232258223a3SMatthew Dillon 3233258223a3SMatthew Dillon if (ahci_load_prdt(ccb) != 0) { 323412feb904SMatthew Dillon err_slot = -1; 3235258223a3SMatthew Dillon goto err; 3236258223a3SMatthew Dillon } 3237258223a3SMatthew Dillon 3238258223a3SMatthew Dillon ccb->ccb_xa.state = ATA_S_PENDING; 323912feb904SMatthew Dillon if (ahci_poll(ccb, 1000, ahci_quick_timeout) != ATA_S_COMPLETE) { 324012feb904SMatthew Dillon err_slot = -1; 3241258223a3SMatthew Dillon ahci_unload_prdt(ccb); 324212feb904SMatthew Dillon goto err; 324312feb904SMatthew Dillon } 324412feb904SMatthew Dillon ahci_unload_prdt(ccb); 3245258223a3SMatthew Dillon 324612feb904SMatthew Dillon /* 324712feb904SMatthew Dillon * Success, extract failed register set and tags from the scratch 324812feb904SMatthew Dillon * space. 324912feb904SMatthew Dillon */ 3250258223a3SMatthew Dillon log = (struct ata_log_page_10h *)ap->ap_err_scratch; 3251258223a3SMatthew Dillon if (log->err_regs.type & ATA_LOG_10H_TYPE_NOTQUEUED) { 3252258223a3SMatthew Dillon /* Not queued bit was set - wasn't an NCQ error? */ 325312feb904SMatthew Dillon kprintf("%s: read NCQ error page, but not an NCQ error?\n", 3254258223a3SMatthew Dillon PORTNAME(ap)); 325512feb904SMatthew Dillon err_slot = -1; 3256258223a3SMatthew Dillon } else { 3257258223a3SMatthew Dillon /* Copy back the log record as a D2H register FIS. */ 325812feb904SMatthew Dillon err_slot = log->err_regs.type & ATA_LOG_10H_TYPE_TAG_MASK; 3259258223a3SMatthew Dillon 3260e1014452SMatthew Dillon ccb2 = &ap->ap_ccbs[err_slot]; 3261e1014452SMatthew Dillon if (ccb2->ccb_xa.state == ATA_S_ONCHIP) { 326212feb904SMatthew Dillon kprintf("%s: read NCQ error page slot=%d\n", 3263e1014452SMatthew Dillon ATANAME(ap, ccb2->ccb_xa.at), 326412feb904SMatthew Dillon err_slot); 3265e1014452SMatthew Dillon memcpy(&ccb2->ccb_xa.rfis, &log->err_regs, 3266258223a3SMatthew Dillon sizeof(struct ata_fis_d2h)); 3267e1014452SMatthew Dillon ccb2->ccb_xa.rfis.type = ATA_FIS_TYPE_D2H; 3268e1014452SMatthew Dillon ccb2->ccb_xa.rfis.flags = 0; 326912feb904SMatthew Dillon } else { 327012feb904SMatthew Dillon kprintf("%s: read NCQ error page slot=%d, " 327112feb904SMatthew Dillon "slot does not match any cmds\n", 3272e1014452SMatthew Dillon ATANAME(ccb2->ccb_port, ccb2->ccb_xa.at), 327312feb904SMatthew Dillon err_slot); 327412feb904SMatthew Dillon err_slot = -1; 3275258223a3SMatthew Dillon } 3276258223a3SMatthew Dillon } 327712feb904SMatthew Dillon err: 327812feb904SMatthew Dillon ahci_put_err_ccb(ccb); 327912feb904SMatthew Dillon kprintf("%s: DONE log page target %d err_slot=%d\n", 328012feb904SMatthew Dillon PORTNAME(ap), target, err_slot); 328112feb904SMatthew Dillon return (err_slot); 3282258223a3SMatthew Dillon } 3283258223a3SMatthew Dillon 3284258223a3SMatthew Dillon /* 3285258223a3SMatthew Dillon * Allocate memory for various structures DMAd by hardware. The maximum 3286258223a3SMatthew Dillon * number of segments for these tags is 1 so the DMA memory will have a 3287258223a3SMatthew Dillon * single physical base address. 3288258223a3SMatthew Dillon */ 3289258223a3SMatthew Dillon struct ahci_dmamem * 3290258223a3SMatthew Dillon ahci_dmamem_alloc(struct ahci_softc *sc, bus_dma_tag_t tag) 3291258223a3SMatthew Dillon { 3292258223a3SMatthew Dillon struct ahci_dmamem *adm; 3293258223a3SMatthew Dillon int error; 3294258223a3SMatthew Dillon 3295258223a3SMatthew Dillon adm = kmalloc(sizeof(*adm), M_DEVBUF, M_INTWAIT | M_ZERO); 3296258223a3SMatthew Dillon 3297258223a3SMatthew Dillon error = bus_dmamem_alloc(tag, (void **)&adm->adm_kva, 3298258223a3SMatthew Dillon BUS_DMA_ZERO, &adm->adm_map); 3299258223a3SMatthew Dillon if (error == 0) { 3300258223a3SMatthew Dillon adm->adm_tag = tag; 3301258223a3SMatthew Dillon error = bus_dmamap_load(tag, adm->adm_map, 3302258223a3SMatthew Dillon adm->adm_kva, 3303258223a3SMatthew Dillon bus_dma_tag_getmaxsize(tag), 3304258223a3SMatthew Dillon ahci_dmamem_saveseg, &adm->adm_busaddr, 3305258223a3SMatthew Dillon 0); 3306258223a3SMatthew Dillon } 3307258223a3SMatthew Dillon if (error) { 3308258223a3SMatthew Dillon if (adm->adm_map) { 3309258223a3SMatthew Dillon bus_dmamap_destroy(tag, adm->adm_map); 3310258223a3SMatthew Dillon adm->adm_map = NULL; 3311258223a3SMatthew Dillon adm->adm_tag = NULL; 3312258223a3SMatthew Dillon adm->adm_kva = NULL; 3313258223a3SMatthew Dillon } 3314258223a3SMatthew Dillon kfree(adm, M_DEVBUF); 3315258223a3SMatthew Dillon adm = NULL; 3316258223a3SMatthew Dillon } 3317258223a3SMatthew Dillon return (adm); 3318258223a3SMatthew Dillon } 3319258223a3SMatthew Dillon 3320258223a3SMatthew Dillon static 3321258223a3SMatthew Dillon void 3322258223a3SMatthew Dillon ahci_dmamem_saveseg(void *info, bus_dma_segment_t *segs, int nsegs, int error) 3323258223a3SMatthew Dillon { 3324258223a3SMatthew Dillon KKASSERT(error == 0); 3325258223a3SMatthew Dillon KKASSERT(nsegs == 1); 3326258223a3SMatthew Dillon *(bus_addr_t *)info = segs->ds_addr; 3327258223a3SMatthew Dillon } 3328258223a3SMatthew Dillon 3329258223a3SMatthew Dillon 3330258223a3SMatthew Dillon void 3331258223a3SMatthew Dillon ahci_dmamem_free(struct ahci_softc *sc, struct ahci_dmamem *adm) 3332258223a3SMatthew Dillon { 3333258223a3SMatthew Dillon if (adm->adm_map) { 3334258223a3SMatthew Dillon bus_dmamap_unload(adm->adm_tag, adm->adm_map); 3335258223a3SMatthew Dillon bus_dmamap_destroy(adm->adm_tag, adm->adm_map); 3336258223a3SMatthew Dillon adm->adm_map = NULL; 3337258223a3SMatthew Dillon adm->adm_tag = NULL; 3338258223a3SMatthew Dillon adm->adm_kva = NULL; 3339258223a3SMatthew Dillon } 3340258223a3SMatthew Dillon kfree(adm, M_DEVBUF); 3341258223a3SMatthew Dillon } 3342258223a3SMatthew Dillon 3343258223a3SMatthew Dillon u_int32_t 3344258223a3SMatthew Dillon ahci_read(struct ahci_softc *sc, bus_size_t r) 3345258223a3SMatthew Dillon { 3346258223a3SMatthew Dillon bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4, 3347258223a3SMatthew Dillon BUS_SPACE_BARRIER_READ); 3348258223a3SMatthew Dillon return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, r)); 3349258223a3SMatthew Dillon } 3350258223a3SMatthew Dillon 3351258223a3SMatthew Dillon void 3352258223a3SMatthew Dillon ahci_write(struct ahci_softc *sc, bus_size_t r, u_int32_t v) 3353258223a3SMatthew Dillon { 3354258223a3SMatthew Dillon bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v); 3355258223a3SMatthew Dillon bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4, 3356258223a3SMatthew Dillon BUS_SPACE_BARRIER_WRITE); 3357258223a3SMatthew Dillon } 3358258223a3SMatthew Dillon 3359258223a3SMatthew Dillon u_int32_t 3360258223a3SMatthew Dillon ahci_pread(struct ahci_port *ap, bus_size_t r) 3361258223a3SMatthew Dillon { 3362258223a3SMatthew Dillon bus_space_barrier(ap->ap_sc->sc_iot, ap->ap_ioh, r, 4, 3363258223a3SMatthew Dillon BUS_SPACE_BARRIER_READ); 3364258223a3SMatthew Dillon return (bus_space_read_4(ap->ap_sc->sc_iot, ap->ap_ioh, r)); 3365258223a3SMatthew Dillon } 3366258223a3SMatthew Dillon 3367258223a3SMatthew Dillon void 3368258223a3SMatthew Dillon ahci_pwrite(struct ahci_port *ap, bus_size_t r, u_int32_t v) 3369258223a3SMatthew Dillon { 3370258223a3SMatthew Dillon bus_space_write_4(ap->ap_sc->sc_iot, ap->ap_ioh, r, v); 3371258223a3SMatthew Dillon bus_space_barrier(ap->ap_sc->sc_iot, ap->ap_ioh, r, 4, 3372258223a3SMatthew Dillon BUS_SPACE_BARRIER_WRITE); 3373258223a3SMatthew Dillon } 3374258223a3SMatthew Dillon 3375831bc9e3SMatthew Dillon /* 3376831bc9e3SMatthew Dillon * Wait up to (timeout) milliseconds for the masked port register to 3377831bc9e3SMatthew Dillon * match the target. 3378831bc9e3SMatthew Dillon * 3379831bc9e3SMatthew Dillon * Timeout is in milliseconds. 3380831bc9e3SMatthew Dillon */ 3381258223a3SMatthew Dillon int 3382cec85a37SMatthew Dillon ahci_pwait_eq(struct ahci_port *ap, int timeout, 3383cec85a37SMatthew Dillon bus_size_t r, u_int32_t mask, u_int32_t target) 3384258223a3SMatthew Dillon { 3385831bc9e3SMatthew Dillon int t; 3386258223a3SMatthew Dillon 3387831bc9e3SMatthew Dillon /* 3388831bc9e3SMatthew Dillon * Loop hard up to 100uS 3389831bc9e3SMatthew Dillon */ 3390831bc9e3SMatthew Dillon for (t = 0; t < 100; ++t) { 3391258223a3SMatthew Dillon if ((ahci_pread(ap, r) & mask) == target) 3392258223a3SMatthew Dillon return (0); 3393831bc9e3SMatthew Dillon ahci_os_hardsleep(1); /* us */ 3394258223a3SMatthew Dillon } 3395258223a3SMatthew Dillon 3396831bc9e3SMatthew Dillon do { 3397831bc9e3SMatthew Dillon timeout -= ahci_os_softsleep(); 3398831bc9e3SMatthew Dillon if ((ahci_pread(ap, r) & mask) == target) 3399831bc9e3SMatthew Dillon return (0); 3400831bc9e3SMatthew Dillon } while (timeout > 0); 3401831bc9e3SMatthew Dillon return (1); 3402831bc9e3SMatthew Dillon } 3403831bc9e3SMatthew Dillon 3404831bc9e3SMatthew Dillon int 3405831bc9e3SMatthew Dillon ahci_wait_ne(struct ahci_softc *sc, bus_size_t r, u_int32_t mask, 3406831bc9e3SMatthew Dillon u_int32_t target) 3407831bc9e3SMatthew Dillon { 3408831bc9e3SMatthew Dillon int t; 3409831bc9e3SMatthew Dillon 3410831bc9e3SMatthew Dillon /* 3411831bc9e3SMatthew Dillon * Loop hard up to 100uS 3412831bc9e3SMatthew Dillon */ 3413831bc9e3SMatthew Dillon for (t = 0; t < 100; ++t) { 3414831bc9e3SMatthew Dillon if ((ahci_read(sc, r) & mask) != target) 3415831bc9e3SMatthew Dillon return (0); 3416831bc9e3SMatthew Dillon ahci_os_hardsleep(1); /* us */ 3417831bc9e3SMatthew Dillon } 3418831bc9e3SMatthew Dillon 3419831bc9e3SMatthew Dillon /* 3420831bc9e3SMatthew Dillon * And one millisecond the slow way 3421831bc9e3SMatthew Dillon */ 3422831bc9e3SMatthew Dillon t = 1000; 3423831bc9e3SMatthew Dillon do { 3424831bc9e3SMatthew Dillon t -= ahci_os_softsleep(); 3425831bc9e3SMatthew Dillon if ((ahci_read(sc, r) & mask) != target) 3426831bc9e3SMatthew Dillon return (0); 3427831bc9e3SMatthew Dillon } while (t > 0); 3428831bc9e3SMatthew Dillon 3429258223a3SMatthew Dillon return (1); 3430258223a3SMatthew Dillon } 3431258223a3SMatthew Dillon 3432831bc9e3SMatthew Dillon 34331980eff3SMatthew Dillon /* 34341980eff3SMatthew Dillon * Acquire an ata transfer. 34351980eff3SMatthew Dillon * 34361980eff3SMatthew Dillon * Pass a NULL at for direct-attached transfers, and a non-NULL at for 34371980eff3SMatthew Dillon * targets that go through the port multiplier. 34381980eff3SMatthew Dillon */ 3439258223a3SMatthew Dillon struct ata_xfer * 34401980eff3SMatthew Dillon ahci_ata_get_xfer(struct ahci_port *ap, struct ata_port *at) 3441258223a3SMatthew Dillon { 3442258223a3SMatthew Dillon struct ahci_ccb *ccb; 3443258223a3SMatthew Dillon 3444258223a3SMatthew Dillon ccb = ahci_get_ccb(ap); 3445258223a3SMatthew Dillon if (ccb == NULL) { 3446258223a3SMatthew Dillon DPRINTF(AHCI_D_XFER, "%s: ahci_ata_get_xfer: NULL ccb\n", 3447258223a3SMatthew Dillon PORTNAME(ap)); 3448258223a3SMatthew Dillon return (NULL); 3449258223a3SMatthew Dillon } 3450258223a3SMatthew Dillon 3451258223a3SMatthew Dillon DPRINTF(AHCI_D_XFER, "%s: ahci_ata_get_xfer got slot %d\n", 3452258223a3SMatthew Dillon PORTNAME(ap), ccb->ccb_slot); 3453258223a3SMatthew Dillon 34542cc2e845SMatthew Dillon bzero(ccb->ccb_xa.fis, sizeof(*ccb->ccb_xa.fis)); 34551980eff3SMatthew Dillon ccb->ccb_xa.at = at; 3456258223a3SMatthew Dillon ccb->ccb_xa.fis->type = ATA_FIS_TYPE_H2D; 3457258223a3SMatthew Dillon 3458258223a3SMatthew Dillon return (&ccb->ccb_xa); 3459258223a3SMatthew Dillon } 3460258223a3SMatthew Dillon 3461258223a3SMatthew Dillon void 3462258223a3SMatthew Dillon ahci_ata_put_xfer(struct ata_xfer *xa) 3463258223a3SMatthew Dillon { 3464258223a3SMatthew Dillon struct ahci_ccb *ccb = (struct ahci_ccb *)xa; 3465258223a3SMatthew Dillon 3466258223a3SMatthew Dillon DPRINTF(AHCI_D_XFER, "ahci_ata_put_xfer slot %d\n", ccb->ccb_slot); 3467258223a3SMatthew Dillon 3468258223a3SMatthew Dillon ahci_put_ccb(ccb); 3469258223a3SMatthew Dillon } 3470258223a3SMatthew Dillon 3471258223a3SMatthew Dillon int 3472258223a3SMatthew Dillon ahci_ata_cmd(struct ata_xfer *xa) 3473258223a3SMatthew Dillon { 3474258223a3SMatthew Dillon struct ahci_ccb *ccb = (struct ahci_ccb *)xa; 3475258223a3SMatthew Dillon struct ahci_cmd_hdr *cmd_slot; 3476258223a3SMatthew Dillon 3477258223a3SMatthew Dillon KKASSERT(xa->state == ATA_S_SETUP); 3478258223a3SMatthew Dillon 3479258223a3SMatthew Dillon if (ccb->ccb_port->ap_state == AP_S_FATAL_ERROR) 3480258223a3SMatthew Dillon goto failcmd; 3481258223a3SMatthew Dillon ccb->ccb_done = ahci_ata_cmd_done; 3482258223a3SMatthew Dillon 3483258223a3SMatthew Dillon cmd_slot = ccb->ccb_cmd_hdr; 3484258223a3SMatthew Dillon cmd_slot->flags = htole16(5); /* FIS length (in DWORDs) */ 34851980eff3SMatthew Dillon if (ccb->ccb_xa.at) { 34861980eff3SMatthew Dillon cmd_slot->flags |= htole16(ccb->ccb_xa.at->at_target << 34871980eff3SMatthew Dillon AHCI_CMD_LIST_FLAG_PMP_SHIFT); 34881980eff3SMatthew Dillon } 3489258223a3SMatthew Dillon 3490258223a3SMatthew Dillon if (xa->flags & ATA_F_WRITE) 3491258223a3SMatthew Dillon cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_W); 3492258223a3SMatthew Dillon 3493258223a3SMatthew Dillon if (xa->flags & ATA_F_PACKET) 3494258223a3SMatthew Dillon cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_A); 3495258223a3SMatthew Dillon 3496258223a3SMatthew Dillon if (ahci_load_prdt(ccb) != 0) 3497258223a3SMatthew Dillon goto failcmd; 3498258223a3SMatthew Dillon 3499258223a3SMatthew Dillon xa->state = ATA_S_PENDING; 3500258223a3SMatthew Dillon 3501831bc9e3SMatthew Dillon if (xa->flags & ATA_F_POLL) 3502831bc9e3SMatthew Dillon return (ahci_poll(ccb, xa->timeout, ahci_ata_cmd_timeout)); 3503258223a3SMatthew Dillon 3504258223a3SMatthew Dillon crit_enter(); 3505f4553de1SMatthew Dillon KKASSERT((xa->flags & ATA_F_TIMEOUT_EXPIRED) == 0); 35063209f581SMatthew Dillon xa->flags |= ATA_F_TIMEOUT_DESIRED; 3507258223a3SMatthew Dillon ahci_start(ccb); 3508258223a3SMatthew Dillon crit_exit(); 3509831bc9e3SMatthew Dillon return (xa->state); 3510258223a3SMatthew Dillon 3511258223a3SMatthew Dillon failcmd: 3512258223a3SMatthew Dillon crit_enter(); 3513258223a3SMatthew Dillon xa->state = ATA_S_ERROR; 3514258223a3SMatthew Dillon xa->complete(xa); 3515258223a3SMatthew Dillon crit_exit(); 3516831bc9e3SMatthew Dillon return (ATA_S_ERROR); 3517258223a3SMatthew Dillon } 3518258223a3SMatthew Dillon 3519258223a3SMatthew Dillon void 3520258223a3SMatthew Dillon ahci_ata_cmd_done(struct ahci_ccb *ccb) 3521258223a3SMatthew Dillon { 3522258223a3SMatthew Dillon struct ata_xfer *xa = &ccb->ccb_xa; 3523258223a3SMatthew Dillon 3524831bc9e3SMatthew Dillon /* 3525831bc9e3SMatthew Dillon * NOTE: callout does not lock port and may race us modifying 3526831bc9e3SMatthew Dillon * the flags, so make sure its stopped. 3527831bc9e3SMatthew Dillon */ 3528258223a3SMatthew Dillon if (xa->flags & ATA_F_TIMEOUT_RUNNING) { 3529258223a3SMatthew Dillon callout_stop(&ccb->ccb_timeout); 3530831bc9e3SMatthew Dillon xa->flags &= ~ATA_F_TIMEOUT_RUNNING; 3531258223a3SMatthew Dillon } 3532f4553de1SMatthew Dillon xa->flags &= ~(ATA_F_TIMEOUT_DESIRED | ATA_F_TIMEOUT_EXPIRED); 3533258223a3SMatthew Dillon 35344c339a5fSMatthew Dillon KKASSERT(xa->state != ATA_S_ONCHIP); 3535258223a3SMatthew Dillon ahci_unload_prdt(ccb); 3536258223a3SMatthew Dillon 3537258223a3SMatthew Dillon if (xa->state != ATA_S_TIMEOUT) 3538258223a3SMatthew Dillon xa->complete(xa); 3539258223a3SMatthew Dillon } 3540258223a3SMatthew Dillon 3541f4553de1SMatthew Dillon /* 3542f4553de1SMatthew Dillon * Timeout from callout, MPSAFE - nothing can mess with the CCB's flags 3543f4553de1SMatthew Dillon * while the callout is runing. 3544f4553de1SMatthew Dillon * 3545f4553de1SMatthew Dillon * We can't safely get the port lock here or delay, we could block 3546f4553de1SMatthew Dillon * the callout thread. 3547f4553de1SMatthew Dillon */ 3548258223a3SMatthew Dillon static void 3549258223a3SMatthew Dillon ahci_ata_cmd_timeout_unserialized(void *arg) 3550258223a3SMatthew Dillon { 3551258223a3SMatthew Dillon struct ahci_ccb *ccb = arg; 3552258223a3SMatthew Dillon struct ahci_port *ap = ccb->ccb_port; 3553258223a3SMatthew Dillon 3554f4553de1SMatthew Dillon ccb->ccb_xa.flags &= ~ATA_F_TIMEOUT_RUNNING; 3555f4553de1SMatthew Dillon ccb->ccb_xa.flags |= ATA_F_TIMEOUT_EXPIRED; 3556f4553de1SMatthew Dillon ahci_os_signal_port_thread(ap, AP_SIGF_TIMEOUT); 3557258223a3SMatthew Dillon } 3558258223a3SMatthew Dillon 35594c339a5fSMatthew Dillon /* 35604c339a5fSMatthew Dillon * Timeout code, typically called when the port command processor is running. 35614c339a5fSMatthew Dillon * 35624c339a5fSMatthew Dillon * We have to be very very careful here. We cannot stop the port unless 35634c339a5fSMatthew Dillon * CR is already clear or the only active commands remaining are timed-out 35644c339a5fSMatthew Dillon * ones. Otherwise stopping the port will race the command processor and 35654c339a5fSMatthew Dillon * we can lose events. While we can theoretically just restart everything 35664c339a5fSMatthew Dillon * that could result in a double-issue which will not work for ATAPI commands. 35674c339a5fSMatthew Dillon */ 35681980eff3SMatthew Dillon void 3569831bc9e3SMatthew Dillon ahci_ata_cmd_timeout(struct ahci_ccb *ccb) 3570258223a3SMatthew Dillon { 3571258223a3SMatthew Dillon struct ata_xfer *xa = &ccb->ccb_xa; 3572258223a3SMatthew Dillon struct ahci_port *ap = ccb->ccb_port; 35734c339a5fSMatthew Dillon struct ata_port *at; 3574492bffafSMatthew Dillon u_int32_t ci_saved; 3575492bffafSMatthew Dillon u_int32_t mask; 35764c339a5fSMatthew Dillon int slot; 3577258223a3SMatthew Dillon 35784c339a5fSMatthew Dillon at = ccb->ccb_xa.at; 35794c339a5fSMatthew Dillon 35804c339a5fSMatthew Dillon kprintf("%s: CMD TIMEOUT state=%d slot=%d\n" 35814c339a5fSMatthew Dillon "\tcmd-reg 0x%b\n" 35824c339a5fSMatthew Dillon "\tsactive=%08x active=%08x expired=%08x\n" 358308fb24a7SMatthew Dillon "\t sact=%08x ci=%08x\n" 358408fb24a7SMatthew Dillon "\t STS=%b\n", 35854c339a5fSMatthew Dillon ATANAME(ap, at), 35864c339a5fSMatthew Dillon ccb->ccb_xa.state, ccb->ccb_slot, 3587258223a3SMatthew Dillon ahci_pread(ap, AHCI_PREG_CMD), AHCI_PFMT_CMD, 35884c339a5fSMatthew Dillon ap->ap_sactive, ap->ap_active, ap->ap_expired, 3589258223a3SMatthew Dillon ahci_pread(ap, AHCI_PREG_SACT), 359008fb24a7SMatthew Dillon ahci_pread(ap, AHCI_PREG_CI), 359108fb24a7SMatthew Dillon ahci_pread(ap, AHCI_PREG_TFD), AHCI_PFMT_TFD_STS 359208fb24a7SMatthew Dillon ); 359308fb24a7SMatthew Dillon 3594258223a3SMatthew Dillon 35959e145b23SMatthew Dillon /* 35969e145b23SMatthew Dillon * NOTE: Timeout will not be running if the command was polled. 35973209f581SMatthew Dillon * If we got here at least one of these flags should be set. 35989e145b23SMatthew Dillon */ 35993209f581SMatthew Dillon KKASSERT(xa->flags & (ATA_F_POLL | ATA_F_TIMEOUT_DESIRED | 36003209f581SMatthew Dillon ATA_F_TIMEOUT_RUNNING)); 3601f4553de1SMatthew Dillon xa->flags &= ~(ATA_F_TIMEOUT_RUNNING | ATA_F_TIMEOUT_EXPIRED); 3602258223a3SMatthew Dillon 3603258223a3SMatthew Dillon if (ccb->ccb_xa.state == ATA_S_PENDING) { 3604258223a3SMatthew Dillon TAILQ_REMOVE(&ap->ap_ccb_pending, ccb, ccb_entry); 36054c339a5fSMatthew Dillon ccb->ccb_xa.state = ATA_S_TIMEOUT; 36064c339a5fSMatthew Dillon ccb->ccb_done(ccb); 36074c339a5fSMatthew Dillon xa->complete(xa); 36084c339a5fSMatthew Dillon ahci_issue_pending_commands(ap, NULL); 36094c339a5fSMatthew Dillon return; 36104c339a5fSMatthew Dillon } 36114c339a5fSMatthew Dillon if (ccb->ccb_xa.state != ATA_S_ONCHIP) { 36124c339a5fSMatthew Dillon kprintf("%s: Unexpected state during timeout: %d\n", 36134c339a5fSMatthew Dillon ATANAME(ap, at), ccb->ccb_xa.state); 36144c339a5fSMatthew Dillon return; 36154c339a5fSMatthew Dillon } 36164c339a5fSMatthew Dillon 36174c339a5fSMatthew Dillon /* 36184c339a5fSMatthew Dillon * Ok, we can only get this command off the chip if CR is inactive 36194c339a5fSMatthew Dillon * or if the only commands running on the chip are all expired. 36204c339a5fSMatthew Dillon * Otherwise we have to wait until the port is in a safe state. 36214c339a5fSMatthew Dillon * 36224c339a5fSMatthew Dillon * Do not set state here, it will cause polls to return when the 36234c339a5fSMatthew Dillon * ccb is not yet off the chip. 36244c339a5fSMatthew Dillon */ 36254c339a5fSMatthew Dillon ap->ap_expired |= 1 << ccb->ccb_slot; 36264c339a5fSMatthew Dillon 36274c339a5fSMatthew Dillon if ((ahci_pread(ap, AHCI_PREG_CMD) & AHCI_PREG_CMD_CR) && 36284c339a5fSMatthew Dillon (ap->ap_active | ap->ap_sactive) != ap->ap_expired) { 36294c339a5fSMatthew Dillon /* 36304c339a5fSMatthew Dillon * If using FBSS or NCQ we can't safely stop the port 36314c339a5fSMatthew Dillon * right now. 36324c339a5fSMatthew Dillon */ 36334c339a5fSMatthew Dillon kprintf("%s: Deferred timeout until its safe, slot %d\n", 36344c339a5fSMatthew Dillon ATANAME(ap, at), ccb->ccb_slot); 36354c339a5fSMatthew Dillon return; 36364c339a5fSMatthew Dillon } 36374c339a5fSMatthew Dillon 36384c339a5fSMatthew Dillon /* 36394c339a5fSMatthew Dillon * We can safely stop the port and process all expired ccb's, 36404c339a5fSMatthew Dillon * which will include our current ccb. 36414c339a5fSMatthew Dillon */ 36424c339a5fSMatthew Dillon ci_saved = (ap->ap_sactive) ? ahci_pread(ap, AHCI_PREG_SACT) : 36434c339a5fSMatthew Dillon ahci_pread(ap, AHCI_PREG_CI); 36444c339a5fSMatthew Dillon ahci_port_stop(ap, 0); 36454c339a5fSMatthew Dillon 36464c339a5fSMatthew Dillon while (ap->ap_expired) { 36474c339a5fSMatthew Dillon slot = ffs(ap->ap_expired) - 1; 36484c339a5fSMatthew Dillon ap->ap_expired &= ~(1 << slot); 36494c339a5fSMatthew Dillon ci_saved &= ~(1 << slot); 36504c339a5fSMatthew Dillon ccb = &ap->ap_ccbs[slot]; 36514c339a5fSMatthew Dillon ccb->ccb_xa.state = ATA_S_TIMEOUT; 36524c339a5fSMatthew Dillon if (ccb->ccb_xa.flags & ATA_F_NCQ) { 36534c339a5fSMatthew Dillon KKASSERT(ap->ap_sactive & (1 << slot)); 36544c339a5fSMatthew Dillon ap->ap_sactive &= ~(1 << slot); 36554c339a5fSMatthew Dillon } else { 36564c339a5fSMatthew Dillon KKASSERT(ap->ap_active & (1 << slot)); 36574c339a5fSMatthew Dillon ap->ap_active &= ~(1 << slot); 36581980eff3SMatthew Dillon --ap->ap_active_cnt; 36591980eff3SMatthew Dillon } 3660258223a3SMatthew Dillon ccb->ccb_done(ccb); 36614c339a5fSMatthew Dillon ccb->ccb_xa.complete(&ccb->ccb_xa); 3662258223a3SMatthew Dillon } 36634c339a5fSMatthew Dillon /* ccb invalid now */ 3664258223a3SMatthew Dillon 36654c339a5fSMatthew Dillon /* 36664c339a5fSMatthew Dillon * We can safely CLO the port to clear any BSY/DRQ, a case which 36674c339a5fSMatthew Dillon * can occur with port multipliers. This will unbrick the port 36684c339a5fSMatthew Dillon * and allow commands to other targets behind the PM continue. 36694c339a5fSMatthew Dillon * (FBSS). 36704c339a5fSMatthew Dillon * 36714c339a5fSMatthew Dillon * Finally, once the port has been restarted we can issue any 36724c339a5fSMatthew Dillon * previously saved pending commands, and run the port interrupt 36734c339a5fSMatthew Dillon * code to handle any completions which may have occured when 36744c339a5fSMatthew Dillon * we saved CI. 36754c339a5fSMatthew Dillon */ 36764c339a5fSMatthew Dillon if (ahci_pread(ap, AHCI_PREG_TFD) & 36774c339a5fSMatthew Dillon (AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) { 36784c339a5fSMatthew Dillon kprintf("%s: Warning, issuing CLO after timeout\n", 36794c339a5fSMatthew Dillon ATANAME(ap, at)); 3680131be210SMatthew Dillon ahci_port_clo(ap); 36814c339a5fSMatthew Dillon } 3682131be210SMatthew Dillon ahci_port_start(ap); 3683492bffafSMatthew Dillon 3684492bffafSMatthew Dillon /* 3685492bffafSMatthew Dillon * We absolutely must make sure the chipset cleared activity on 3686492bffafSMatthew Dillon * all slots. This sometimes might not happen due to races with 3687492bffafSMatthew Dillon * a chipset interrupt which stops the port before we can manage 3688492bffafSMatthew Dillon * to. For some reason some chipsets don't clear the active 3689492bffafSMatthew Dillon * commands when we turn off CMD_ST after the chip has stopped 3690492bffafSMatthew Dillon * operations itself. 3691492bffafSMatthew Dillon */ 3692492bffafSMatthew Dillon if (ahci_pactive(ap) != 0) { 3693492bffafSMatthew Dillon ahci_port_stop(ap, 0); 3694492bffafSMatthew Dillon ahci_port_start(ap); 3695492bffafSMatthew Dillon if ((mask = ahci_pactive(ap)) != 0) { 3696492bffafSMatthew Dillon kprintf("%s: quick-timeout: chipset failed " 3697492bffafSMatthew Dillon "to clear active cmds %08x\n", 3698492bffafSMatthew Dillon PORTNAME(ap), mask); 3699492bffafSMatthew Dillon } 3700492bffafSMatthew Dillon } 37014c339a5fSMatthew Dillon ahci_issue_saved_commands(ap, ci_saved & ~ap->ap_expired); 37024c339a5fSMatthew Dillon ahci_issue_pending_commands(ap, NULL); 37034c339a5fSMatthew Dillon ahci_port_intr(ap, 0); 37044c339a5fSMatthew Dillon } 37054c339a5fSMatthew Dillon 3706cf5f3a81SMatthew Dillon /* 37074c339a5fSMatthew Dillon * Issue a previously saved set of commands 3708cf5f3a81SMatthew Dillon */ 37094c339a5fSMatthew Dillon void 37104c339a5fSMatthew Dillon ahci_issue_saved_commands(struct ahci_port *ap, u_int32_t ci_saved) 37114c339a5fSMatthew Dillon { 37124c339a5fSMatthew Dillon if (ci_saved) { 37134c339a5fSMatthew Dillon KKASSERT(!((ap->ap_active & ci_saved) && 37144c339a5fSMatthew Dillon (ap->ap_sactive & ci_saved))); 37154c339a5fSMatthew Dillon KKASSERT((ci_saved & ap->ap_expired) == 0); 37164c339a5fSMatthew Dillon if (ap->ap_sactive & ci_saved) 37174c339a5fSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SACT, ci_saved); 37184c339a5fSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CI, ci_saved); 3719131be210SMatthew Dillon } 3720258223a3SMatthew Dillon } 3721258223a3SMatthew Dillon 3722831bc9e3SMatthew Dillon /* 3723831bc9e3SMatthew Dillon * Used by the softreset, pmprobe, and read_ncq_error only, in very 3724831bc9e3SMatthew Dillon * specialized, controlled circumstances. 3725831bc9e3SMatthew Dillon * 3726831bc9e3SMatthew Dillon * Only one command may be pending. 3727831bc9e3SMatthew Dillon */ 3728831bc9e3SMatthew Dillon void 3729831bc9e3SMatthew Dillon ahci_quick_timeout(struct ahci_ccb *ccb) 3730831bc9e3SMatthew Dillon { 3731831bc9e3SMatthew Dillon struct ahci_port *ap = ccb->ccb_port; 3732492bffafSMatthew Dillon u_int32_t mask; 3733831bc9e3SMatthew Dillon 3734831bc9e3SMatthew Dillon switch (ccb->ccb_xa.state) { 3735831bc9e3SMatthew Dillon case ATA_S_PENDING: 3736831bc9e3SMatthew Dillon TAILQ_REMOVE(&ap->ap_ccb_pending, ccb, ccb_entry); 3737831bc9e3SMatthew Dillon ccb->ccb_xa.state = ATA_S_TIMEOUT; 3738831bc9e3SMatthew Dillon break; 3739831bc9e3SMatthew Dillon case ATA_S_ONCHIP: 3740492bffafSMatthew Dillon /* 3741492bffafSMatthew Dillon * We have to clear the command on-chip. 3742492bffafSMatthew Dillon */ 3743831bc9e3SMatthew Dillon KKASSERT(ap->ap_active == (1 << ccb->ccb_slot) && 3744831bc9e3SMatthew Dillon ap->ap_sactive == 0); 3745831bc9e3SMatthew Dillon ahci_port_stop(ap, 0); 3746831bc9e3SMatthew Dillon ahci_port_start(ap); 3747492bffafSMatthew Dillon if (ahci_pactive(ap) != 0) { 3748492bffafSMatthew Dillon ahci_port_stop(ap, 0); 3749492bffafSMatthew Dillon ahci_port_start(ap); 3750492bffafSMatthew Dillon if ((mask = ahci_pactive(ap)) != 0) { 3751492bffafSMatthew Dillon kprintf("%s: quick-timeout: chipset failed " 3752492bffafSMatthew Dillon "to clear active cmds %08x\n", 3753492bffafSMatthew Dillon PORTNAME(ap), mask); 3754492bffafSMatthew Dillon } 3755492bffafSMatthew Dillon } 3756831bc9e3SMatthew Dillon 3757831bc9e3SMatthew Dillon ccb->ccb_xa.state = ATA_S_TIMEOUT; 3758831bc9e3SMatthew Dillon ap->ap_active &= ~(1 << ccb->ccb_slot); 3759831bc9e3SMatthew Dillon KKASSERT(ap->ap_active_cnt > 0); 3760831bc9e3SMatthew Dillon --ap->ap_active_cnt; 3761831bc9e3SMatthew Dillon break; 3762831bc9e3SMatthew Dillon default: 3763831bc9e3SMatthew Dillon panic("%s: ahci_quick_timeout: ccb in bad state %d", 3764831bc9e3SMatthew Dillon ATANAME(ap, ccb->ccb_xa.at), ccb->ccb_xa.state); 3765831bc9e3SMatthew Dillon } 3766831bc9e3SMatthew Dillon } 3767831bc9e3SMatthew Dillon 376812feb904SMatthew Dillon static void 376912feb904SMatthew Dillon ahci_dummy_done(struct ata_xfer *xa) 377012feb904SMatthew Dillon { 377112feb904SMatthew Dillon } 377212feb904SMatthew Dillon 377312feb904SMatthew Dillon static void 3774258223a3SMatthew Dillon ahci_empty_done(struct ahci_ccb *ccb) 3775258223a3SMatthew Dillon { 3776258223a3SMatthew Dillon } 3777795adb22SMatthew Dillon 3778795adb22SMatthew Dillon int 3779492bffafSMatthew Dillon ahci_set_feature(struct ahci_port *ap, struct ata_port *atx, 3780492bffafSMatthew Dillon int feature, int enable) 3781795adb22SMatthew Dillon { 3782795adb22SMatthew Dillon struct ata_port *at; 3783795adb22SMatthew Dillon struct ata_xfer *xa; 3784795adb22SMatthew Dillon int error; 3785795adb22SMatthew Dillon 3786795adb22SMatthew Dillon at = atx ? atx : ap->ap_ata[0]; 3787795adb22SMatthew Dillon 3788795adb22SMatthew Dillon xa = ahci_ata_get_xfer(ap, atx); 3789795adb22SMatthew Dillon 3790795adb22SMatthew Dillon xa->fis->type = ATA_FIS_TYPE_H2D; 3791795adb22SMatthew Dillon xa->fis->flags = ATA_H2D_FLAGS_CMD | at->at_target; 3792795adb22SMatthew Dillon xa->fis->command = ATA_C_SET_FEATURES; 3793795adb22SMatthew Dillon xa->fis->features = enable ? ATA_C_SATA_FEATURE_ENA : 3794795adb22SMatthew Dillon ATA_C_SATA_FEATURE_DIS; 3795795adb22SMatthew Dillon xa->fis->sector_count = feature; 3796795adb22SMatthew Dillon xa->fis->control = ATA_FIS_CONTROL_4BIT; 3797795adb22SMatthew Dillon 3798795adb22SMatthew Dillon xa->complete = ahci_dummy_done; 3799795adb22SMatthew Dillon xa->datalen = 0; 3800795adb22SMatthew Dillon xa->flags = ATA_F_POLL; 3801795adb22SMatthew Dillon xa->timeout = 1000; 3802795adb22SMatthew Dillon 3803795adb22SMatthew Dillon if (ahci_ata_cmd(xa) == ATA_S_COMPLETE) 3804795adb22SMatthew Dillon error = 0; 3805795adb22SMatthew Dillon else 3806795adb22SMatthew Dillon error = EIO; 3807795adb22SMatthew Dillon ahci_ata_put_xfer(xa); 3808795adb22SMatthew Dillon return(error); 3809795adb22SMatthew Dillon } 3810