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 { 934b450139SMatthew Dillon u_int32_t pi, pleft; 944b450139SMatthew Dillon u_int32_t bios_cap, vers; 95831bc9e3SMatthew Dillon int i; 96831bc9e3SMatthew Dillon struct ahci_port *ap; 97258223a3SMatthew Dillon 98258223a3SMatthew Dillon DPRINTF(AHCI_D_VERBOSE, " GHC 0x%b", 99258223a3SMatthew Dillon ahci_read(sc, AHCI_REG_GHC), AHCI_FMT_GHC); 100258223a3SMatthew Dillon 101b012a2caSMatthew Dillon /* 1024b450139SMatthew Dillon * AHCI version. 1034b450139SMatthew Dillon */ 1044b450139SMatthew Dillon vers = ahci_read(sc, AHCI_REG_VS); 1054b450139SMatthew Dillon 1064b450139SMatthew Dillon /* 107b012a2caSMatthew Dillon * save BIOS initialised parameters, enable staggered spin up 108b012a2caSMatthew Dillon */ 1094b450139SMatthew Dillon bios_cap = ahci_read(sc, AHCI_REG_CAP); 1104b450139SMatthew Dillon bios_cap &= AHCI_REG_CAP_SMPS | AHCI_REG_CAP_SSS; 1114b450139SMatthew Dillon 112258223a3SMatthew Dillon pi = ahci_read(sc, AHCI_REG_PI); 113258223a3SMatthew Dillon 114831bc9e3SMatthew Dillon /* 115b012a2caSMatthew Dillon * Unconditionally reset the controller, do not conditionalize on 116b012a2caSMatthew Dillon * trying to figure it if it was previously active or not. 117b012a2caSMatthew Dillon * 118b012a2caSMatthew Dillon * NOTE: On AE before HR. The AHCI-1.1 spec has a note in section 119b012a2caSMatthew Dillon * 5.2.2.1 regarding this. HR should be set to 1 only after 120b012a2caSMatthew Dillon * AE is set to 1. The reset sequence will clear HR when 121b012a2caSMatthew Dillon * it completes, and will also clear AE if SAM is 0. AE must 122b012a2caSMatthew Dillon * then be set again. When SAM is 1 the AE bit typically reads 123b012a2caSMatthew Dillon * as 1 (and is read-only). 124b012a2caSMatthew Dillon * 125b012a2caSMatthew Dillon * NOTE: Avoid PCI[e] transaction burst by issuing dummy reads, 126b012a2caSMatthew Dillon * otherwise the writes will only be separated by a few 127b012a2caSMatthew Dillon * nanoseconds. 128b012a2caSMatthew Dillon * 129b012a2caSMatthew Dillon * NOTE BRICKS (1) 130b012a2caSMatthew Dillon * 131b012a2caSMatthew Dillon * If you have a port multiplier and it does not have a device 132b012a2caSMatthew Dillon * in target 0, and it probes normally, but a later operation 133b012a2caSMatthew Dillon * mis-probes a target behind that PM, it is possible for the 134b012a2caSMatthew Dillon * port to brick such that only (a) a power cycle of the host 135b012a2caSMatthew Dillon * or (b) placing a device in target 0 will fix the problem. 136b012a2caSMatthew Dillon * Power cycling the PM has no effect (it works fine on another 137b012a2caSMatthew Dillon * host port). This issue is unrelated to CLO. 138b012a2caSMatthew Dillon */ 1394e21f4daSMatthew Dillon /* 1404e21f4daSMatthew Dillon * Wait for any prior reset sequence to complete 1414e21f4daSMatthew Dillon */ 1424e21f4daSMatthew Dillon if (ahci_wait_ne(sc, AHCI_REG_GHC, 1434e21f4daSMatthew Dillon AHCI_REG_GHC_HR, AHCI_REG_GHC_HR) != 0) { 1444e21f4daSMatthew Dillon device_printf(sc->sc_dev, "Controller is stuck in reset\n"); 1454e21f4daSMatthew Dillon return (1); 1464e21f4daSMatthew Dillon } 147b012a2caSMatthew Dillon ahci_write(sc, AHCI_REG_GHC, AHCI_REG_GHC_AE); 1484e21f4daSMatthew Dillon ahci_os_sleep(500); 149b012a2caSMatthew Dillon ahci_read(sc, AHCI_REG_GHC); /* flush */ 150b012a2caSMatthew Dillon ahci_write(sc, AHCI_REG_GHC, AHCI_REG_GHC_AE | AHCI_REG_GHC_HR); 1514e21f4daSMatthew Dillon ahci_os_sleep(500); 152b012a2caSMatthew Dillon ahci_read(sc, AHCI_REG_GHC); /* flush */ 153b012a2caSMatthew Dillon if (ahci_wait_ne(sc, AHCI_REG_GHC, 154b012a2caSMatthew Dillon AHCI_REG_GHC_HR, AHCI_REG_GHC_HR) != 0) { 1554e21f4daSMatthew Dillon device_printf(sc->sc_dev, "unable to reset controller\n"); 156b012a2caSMatthew Dillon return (1); 157b012a2caSMatthew Dillon } 1584e21f4daSMatthew Dillon if (ahci_read(sc, AHCI_REG_GHC) & AHCI_REG_GHC_AE) { 1594e21f4daSMatthew Dillon device_printf(sc->sc_dev, "AE did not auto-clear!\n"); 1604e21f4daSMatthew Dillon ahci_write(sc, AHCI_REG_GHC, 0); 1614e21f4daSMatthew Dillon ahci_os_sleep(500); 1624e21f4daSMatthew Dillon } 163b012a2caSMatthew Dillon 164b012a2caSMatthew Dillon /* 165b012a2caSMatthew Dillon * Enable ahci (global interrupts disabled) 166b012a2caSMatthew Dillon * 167b012a2caSMatthew Dillon * Restore saved parameters. Avoid pci transaction burst write 168b012a2caSMatthew Dillon * by issuing dummy reads. 169b012a2caSMatthew Dillon */ 1704e21f4daSMatthew Dillon ahci_os_sleep(500); 171b012a2caSMatthew Dillon ahci_write(sc, AHCI_REG_GHC, AHCI_REG_GHC_AE); 172b012a2caSMatthew Dillon ahci_os_sleep(500); 173b012a2caSMatthew Dillon 174b012a2caSMatthew Dillon ahci_read(sc, AHCI_REG_GHC); /* flush */ 1754b450139SMatthew Dillon 1764b450139SMatthew Dillon bios_cap |= AHCI_REG_CAP_SSS; 1774b450139SMatthew Dillon ahci_write(sc, AHCI_REG_CAP, ahci_read(sc, AHCI_REG_CAP) | bios_cap); 178b012a2caSMatthew Dillon ahci_write(sc, AHCI_REG_PI, pi); 179b012a2caSMatthew Dillon ahci_read(sc, AHCI_REG_GHC); /* flush */ 180b012a2caSMatthew Dillon 181b012a2caSMatthew Dillon /* 182b012a2caSMatthew Dillon * Intel hocus pocus in case the BIOS has not set the chip up 183b012a2caSMatthew Dillon * properly for AHCI operation. 184b012a2caSMatthew Dillon */ 185b012a2caSMatthew Dillon if (pci_get_vendor(sc->sc_dev) == PCI_VENDOR_INTEL) { 186b012a2caSMatthew Dillon if ((pci_read_config(sc->sc_dev, 0x92, 2) & 0x0F) != 0x0F) 187b012a2caSMatthew Dillon device_printf(sc->sc_dev, "Intel hocus pocus\n"); 188b012a2caSMatthew Dillon pci_write_config(sc->sc_dev, 0x92, 189b012a2caSMatthew Dillon pci_read_config(sc->sc_dev, 0x92, 2) | 0x0F, 2); 190b012a2caSMatthew Dillon } 191b012a2caSMatthew Dillon 192b012a2caSMatthew Dillon /* 193831bc9e3SMatthew Dillon * This is a hack that currently does not appear to have 194831bc9e3SMatthew Dillon * a significant effect, but I noticed the port registers 195831bc9e3SMatthew Dillon * do not appear to be completely cleared after the host 196831bc9e3SMatthew Dillon * controller is reset. 19712feb904SMatthew Dillon * 19812feb904SMatthew Dillon * Use a temporary ap structure so we can call ahci_pwrite(). 1994e21f4daSMatthew Dillon * 2004e21f4daSMatthew Dillon * We must be sure to stop the port 201831bc9e3SMatthew Dillon */ 202831bc9e3SMatthew Dillon ap = kmalloc(sizeof(*ap), M_DEVBUF, M_WAITOK | M_ZERO); 203831bc9e3SMatthew Dillon ap->ap_sc = sc; 20412feb904SMatthew Dillon pleft = pi; 20512feb904SMatthew Dillon for (i = 0; i < AHCI_MAX_PORTS; ++i) { 20612feb904SMatthew Dillon if (pleft == 0) 20712feb904SMatthew Dillon break; 208831bc9e3SMatthew Dillon if ((pi & (1 << i)) == 0) 209831bc9e3SMatthew Dillon continue; 210831bc9e3SMatthew Dillon if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 211831bc9e3SMatthew Dillon AHCI_PORT_REGION(i), AHCI_PORT_SIZE, &ap->ap_ioh) != 0) { 212831bc9e3SMatthew Dillon device_printf(sc->sc_dev, "can't map port\n"); 213831bc9e3SMatthew Dillon return (1); 214831bc9e3SMatthew Dillon } 2154e21f4daSMatthew Dillon /* 2164e21f4daSMatthew Dillon * NOTE! Setting AHCI_PREG_SCTL_DET_DISABLE on AHCI1.0 or 2174e21f4daSMatthew Dillon * AHCI1.1 can brick the chipset. Not only brick it, 2184e21f4daSMatthew Dillon * but also crash the PC. The bit seems unreliable 2194e21f4daSMatthew Dillon * on AHCI1.2 as well. 2204e21f4daSMatthew Dillon */ 2214e21f4daSMatthew Dillon ahci_port_stop(ap, 1); 2229abd2bb8SImre Vadász ahci_pwrite(ap, AHCI_PREG_SCTL, ap->ap_sc->sc_ipm_disable); 223831bc9e3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 224831bc9e3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IE, 0); 22512feb904SMatthew Dillon ahci_write(ap->ap_sc, AHCI_REG_IS, 1 << i); 226831bc9e3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, 0); 22712feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, -1); 22812feb904SMatthew Dillon sc->sc_portmask |= (1 << i); 22912feb904SMatthew Dillon pleft &= ~(1 << i); 230831bc9e3SMatthew Dillon } 23112feb904SMatthew Dillon sc->sc_numports = i; 232831bc9e3SMatthew Dillon kfree(ap, M_DEVBUF); 233831bc9e3SMatthew Dillon 234258223a3SMatthew Dillon return (0); 235258223a3SMatthew Dillon } 236258223a3SMatthew Dillon 237fd8bd957SMatthew Dillon /* 238fd8bd957SMatthew Dillon * Allocate and initialize an AHCI port. 239fd8bd957SMatthew Dillon */ 240258223a3SMatthew Dillon int 241258223a3SMatthew Dillon ahci_port_alloc(struct ahci_softc *sc, u_int port) 242258223a3SMatthew Dillon { 243258223a3SMatthew Dillon struct ahci_port *ap; 2441980eff3SMatthew Dillon struct ata_port *at; 245258223a3SMatthew Dillon struct ahci_ccb *ccb; 246258223a3SMatthew Dillon u_int64_t dva; 247258223a3SMatthew Dillon u_int32_t cmd; 24812feb904SMatthew Dillon u_int32_t data; 249258223a3SMatthew Dillon struct ahci_cmd_hdr *hdr; 250258223a3SMatthew Dillon struct ahci_cmd_table *table; 251258223a3SMatthew Dillon int rc = ENOMEM; 252258223a3SMatthew Dillon int error; 253258223a3SMatthew Dillon int i; 254258223a3SMatthew Dillon 255258223a3SMatthew Dillon ap = kmalloc(sizeof(*ap), M_DEVBUF, M_WAITOK | M_ZERO); 25612feb904SMatthew Dillon ap->ap_err_scratch = kmalloc(512, M_DEVBUF, M_WAITOK | M_ZERO); 257258223a3SMatthew Dillon 258258223a3SMatthew Dillon ksnprintf(ap->ap_name, sizeof(ap->ap_name), "%s%d.%d", 259258223a3SMatthew Dillon device_get_name(sc->sc_dev), 260258223a3SMatthew Dillon device_get_unit(sc->sc_dev), 261258223a3SMatthew Dillon port); 262258223a3SMatthew Dillon sc->sc_ports[port] = ap; 263258223a3SMatthew Dillon 2641980eff3SMatthew Dillon /* 2651980eff3SMatthew Dillon * Allocate enough so we never have to reallocate, it makes 2661980eff3SMatthew Dillon * it easier. 2671980eff3SMatthew Dillon * 2681980eff3SMatthew Dillon * ap_pmcount will be reduced by the scan if we encounter the 2691980eff3SMatthew Dillon * port multiplier port prior to target 15. 270b012a2caSMatthew Dillon * 271b012a2caSMatthew Dillon * kmalloc power-of-2 allocations are guaranteed not to cross 272b012a2caSMatthew Dillon * a page boundary. Make sure the identify sub-structure in the 273b012a2caSMatthew Dillon * at structure does not cross a page boundary, just in case the 274b012a2caSMatthew Dillon * part is AHCI-1.1 and can't handle multiple DRQ blocks. 2751980eff3SMatthew Dillon */ 276b012a2caSMatthew Dillon if (ap->ap_ata[0] == NULL) { 277b012a2caSMatthew Dillon int pw2; 278b012a2caSMatthew Dillon 279b012a2caSMatthew Dillon for (pw2 = 1; pw2 < sizeof(*at); pw2 <<= 1) 280b012a2caSMatthew Dillon ; 2811980eff3SMatthew Dillon for (i = 0; i < AHCI_MAX_PMPORTS; ++i) { 282b012a2caSMatthew Dillon at = kmalloc(pw2, M_DEVBUF, M_INTWAIT | M_ZERO); 283b012a2caSMatthew Dillon ap->ap_ata[i] = at; 2841980eff3SMatthew Dillon at->at_ahci_port = ap; 2851980eff3SMatthew Dillon at->at_target = i; 2863209f581SMatthew Dillon at->at_probe = ATA_PROBE_NEED_INIT; 287831bc9e3SMatthew Dillon at->at_features |= ATA_PORT_F_RESCAN; 2881980eff3SMatthew Dillon ksnprintf(at->at_name, sizeof(at->at_name), 2891980eff3SMatthew Dillon "%s.%d", ap->ap_name, i); 2901980eff3SMatthew Dillon } 2911980eff3SMatthew Dillon } 292258223a3SMatthew Dillon if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 293258223a3SMatthew Dillon AHCI_PORT_REGION(port), AHCI_PORT_SIZE, &ap->ap_ioh) != 0) { 294258223a3SMatthew Dillon device_printf(sc->sc_dev, 295258223a3SMatthew Dillon "unable to create register window for port %d\n", 296258223a3SMatthew Dillon port); 297258223a3SMatthew Dillon goto freeport; 298258223a3SMatthew Dillon } 299258223a3SMatthew Dillon 300258223a3SMatthew Dillon ap->ap_sc = sc; 301258223a3SMatthew Dillon ap->ap_num = port; 3023209f581SMatthew Dillon ap->ap_probe = ATA_PROBE_NEED_INIT; 303f17a0cedSMatthew Dillon ap->link_pwr_mgmt = AHCI_LINK_PWR_MGMT_NONE; 304f17a0cedSMatthew Dillon ap->sysctl_tree = NULL; 305258223a3SMatthew Dillon TAILQ_INIT(&ap->ap_ccb_free); 306258223a3SMatthew Dillon TAILQ_INIT(&ap->ap_ccb_pending); 307258223a3SMatthew Dillon lockinit(&ap->ap_ccb_lock, "ahcipo", 0, 0); 308258223a3SMatthew Dillon 309258223a3SMatthew Dillon /* Disable port interrupts */ 310258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IE, 0); 311831bc9e3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 312258223a3SMatthew Dillon 31317eab71eSMatthew Dillon /* 31417eab71eSMatthew Dillon * Sec 10.1.2 - deinitialise port if it is already running 31517eab71eSMatthew Dillon */ 316258223a3SMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD); 3170be9576aSMatthew Dillon 318258223a3SMatthew Dillon if ((cmd & (AHCI_PREG_CMD_ST | AHCI_PREG_CMD_CR | 319258223a3SMatthew Dillon AHCI_PREG_CMD_FRE | AHCI_PREG_CMD_FR)) || 320258223a3SMatthew Dillon (ahci_pread(ap, AHCI_PREG_SCTL) & AHCI_PREG_SCTL_DET)) { 321258223a3SMatthew Dillon int r; 322258223a3SMatthew Dillon 323258223a3SMatthew Dillon r = ahci_port_stop(ap, 1); 324258223a3SMatthew Dillon if (r) { 325258223a3SMatthew Dillon device_printf(sc->sc_dev, 326258223a3SMatthew Dillon "unable to disable %s, ignoring port %d\n", 327258223a3SMatthew Dillon ((r == 2) ? "CR" : "FR"), port); 328258223a3SMatthew Dillon rc = ENXIO; 329258223a3SMatthew Dillon goto freeport; 330258223a3SMatthew Dillon } 331258223a3SMatthew Dillon 332258223a3SMatthew Dillon /* Write DET to zero */ 3339abd2bb8SImre Vadász ahci_pwrite(ap, AHCI_PREG_SCTL, ap->ap_sc->sc_ipm_disable); 334258223a3SMatthew Dillon } 335258223a3SMatthew Dillon 336258223a3SMatthew Dillon /* Allocate RFIS */ 337258223a3SMatthew Dillon ap->ap_dmamem_rfis = ahci_dmamem_alloc(sc, sc->sc_tag_rfis); 338258223a3SMatthew Dillon if (ap->ap_dmamem_rfis == NULL) { 339cf5f3a81SMatthew Dillon kprintf("%s: NORFIS\n", PORTNAME(ap)); 340258223a3SMatthew Dillon goto nomem; 341258223a3SMatthew Dillon } 342258223a3SMatthew Dillon 343258223a3SMatthew Dillon /* Setup RFIS base address */ 344258223a3SMatthew Dillon ap->ap_rfis = (struct ahci_rfis *) AHCI_DMA_KVA(ap->ap_dmamem_rfis); 3450e589b85SMatthew Dillon bzero(ap->ap_rfis, sc->sc_rfis_size); 3460e589b85SMatthew Dillon 347258223a3SMatthew Dillon dva = AHCI_DMA_DVA(ap->ap_dmamem_rfis); 348258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_FB, (u_int32_t)dva); 3490e589b85SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_FBU, (u_int32_t)(dva >> 32)); 350258223a3SMatthew Dillon 351831bc9e3SMatthew Dillon /* Clear SERR before starting FIS reception or ST or anything */ 352831bc9e3SMatthew Dillon ahci_flush_tfd(ap); 353831bc9e3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 354831bc9e3SMatthew Dillon 355eb9f4c83SMatthew Dillon /* 356*46d04d11SMatthew Dillon * Power up any device sitting on the port. 357*46d04d11SMatthew Dillon * 358*46d04d11SMatthew Dillon * Don't turn on FIS reception here, it will be handled in the first 359*46d04d11SMatthew Dillon * ahci_port_start(). 360*46d04d11SMatthew Dillon * 361*46d04d11SMatthew Dillon * Don't make the ICC ACTIVE here, it will be handled in port_init. 362eb9f4c83SMatthew Dillon */ 363258223a3SMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC; 3641980eff3SMatthew Dillon cmd &= ~(AHCI_PREG_CMD_CLO | AHCI_PREG_CMD_PMA); 365eb9f4c83SMatthew Dillon cmd |= AHCI_PREG_CMD_POD | AHCI_PREG_CMD_SUD; 366*46d04d11SMatthew Dillon #if 0 367*46d04d11SMatthew Dillon /* this will be done in ahci_pm_port_probe() */ 368*46d04d11SMatthew Dillon if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SPM) 369*46d04d11SMatthew Dillon cmd |= AHCI_PREG_CMD_PMA; 370*46d04d11SMatthew Dillon #endif 371*46d04d11SMatthew Dillon 372eb9f4c83SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd); 373258223a3SMatthew Dillon 374258223a3SMatthew Dillon /* Allocate a CCB for each command slot */ 375258223a3SMatthew Dillon ap->ap_ccbs = kmalloc(sizeof(struct ahci_ccb) * sc->sc_ncmds, M_DEVBUF, 376258223a3SMatthew Dillon M_WAITOK | M_ZERO); 377258223a3SMatthew Dillon if (ap->ap_ccbs == NULL) { 378258223a3SMatthew Dillon device_printf(sc->sc_dev, 379258223a3SMatthew Dillon "unable to allocate command list for port %d\n", 380258223a3SMatthew Dillon port); 381258223a3SMatthew Dillon goto freeport; 382258223a3SMatthew Dillon } 383258223a3SMatthew Dillon 384258223a3SMatthew Dillon /* Command List Structures and Command Tables */ 385258223a3SMatthew Dillon ap->ap_dmamem_cmd_list = ahci_dmamem_alloc(sc, sc->sc_tag_cmdh); 386258223a3SMatthew Dillon ap->ap_dmamem_cmd_table = ahci_dmamem_alloc(sc, sc->sc_tag_cmdt); 387258223a3SMatthew Dillon if (ap->ap_dmamem_cmd_table == NULL || 388258223a3SMatthew Dillon ap->ap_dmamem_cmd_list == NULL) { 389258223a3SMatthew Dillon nomem: 390258223a3SMatthew Dillon device_printf(sc->sc_dev, 391258223a3SMatthew Dillon "unable to allocate DMA memory for port %d\n", 392258223a3SMatthew Dillon port); 393258223a3SMatthew Dillon goto freeport; 394258223a3SMatthew Dillon } 395258223a3SMatthew Dillon 396258223a3SMatthew Dillon /* Setup command list base address */ 397258223a3SMatthew Dillon dva = AHCI_DMA_DVA(ap->ap_dmamem_cmd_list); 398258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CLB, (u_int32_t)dva); 3990e589b85SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CLBU, (u_int32_t)(dva >> 32)); 400258223a3SMatthew Dillon 401258223a3SMatthew Dillon /* Split CCB allocation into CCBs and assign to command header/table */ 402258223a3SMatthew Dillon hdr = AHCI_DMA_KVA(ap->ap_dmamem_cmd_list); 403258223a3SMatthew Dillon table = AHCI_DMA_KVA(ap->ap_dmamem_cmd_table); 4040e589b85SMatthew Dillon bzero(hdr, sc->sc_cmdlist_size); 4050e589b85SMatthew Dillon 406258223a3SMatthew Dillon for (i = 0; i < sc->sc_ncmds; i++) { 407258223a3SMatthew Dillon ccb = &ap->ap_ccbs[i]; 408258223a3SMatthew Dillon 409258223a3SMatthew Dillon error = bus_dmamap_create(sc->sc_tag_data, BUS_DMA_ALLOCNOW, 410258223a3SMatthew Dillon &ccb->ccb_dmamap); 411258223a3SMatthew Dillon if (error) { 412258223a3SMatthew Dillon device_printf(sc->sc_dev, 413258223a3SMatthew Dillon "unable to create dmamap for port %d " 414258223a3SMatthew Dillon "ccb %d\n", port, i); 415258223a3SMatthew Dillon goto freeport; 416258223a3SMatthew Dillon } 417258223a3SMatthew Dillon 418bf0ecf68SMatthew Dillon callout_init_mp(&ccb->ccb_timeout); 419258223a3SMatthew Dillon ccb->ccb_slot = i; 420258223a3SMatthew Dillon ccb->ccb_port = ap; 421258223a3SMatthew Dillon ccb->ccb_cmd_hdr = &hdr[i]; 422258223a3SMatthew Dillon ccb->ccb_cmd_table = &table[i]; 423258223a3SMatthew Dillon dva = AHCI_DMA_DVA(ap->ap_dmamem_cmd_table) + 424258223a3SMatthew Dillon ccb->ccb_slot * sizeof(struct ahci_cmd_table); 425258223a3SMatthew Dillon ccb->ccb_cmd_hdr->ctba_hi = htole32((u_int32_t)(dva >> 32)); 426258223a3SMatthew Dillon ccb->ccb_cmd_hdr->ctba_lo = htole32((u_int32_t)dva); 427258223a3SMatthew Dillon 428258223a3SMatthew Dillon ccb->ccb_xa.fis = 429258223a3SMatthew Dillon (struct ata_fis_h2d *)ccb->ccb_cmd_table->cfis; 430258223a3SMatthew Dillon ccb->ccb_xa.packetcmd = ccb->ccb_cmd_table->acmd; 431258223a3SMatthew Dillon ccb->ccb_xa.tag = i; 432258223a3SMatthew Dillon 433258223a3SMatthew Dillon ccb->ccb_xa.state = ATA_S_COMPLETE; 4341067474aSMatthew Dillon 4351067474aSMatthew Dillon /* 4361067474aSMatthew Dillon * CCB[1] is the error CCB and is not get or put. It is 4371067474aSMatthew Dillon * also used for probing. Numerous HBAs only load the 4381067474aSMatthew Dillon * signature from CCB[1] so it MUST be used for the second 4391067474aSMatthew Dillon * FIS. 4401067474aSMatthew Dillon */ 4411067474aSMatthew Dillon if (i == 1) 4421067474aSMatthew Dillon ap->ap_err_ccb = ccb; 4431067474aSMatthew Dillon else 444258223a3SMatthew Dillon ahci_put_ccb(ccb); 445258223a3SMatthew Dillon } 446258223a3SMatthew Dillon 44712feb904SMatthew Dillon /* 44812feb904SMatthew Dillon * Wait for ICC change to complete 44912feb904SMatthew Dillon */ 450258223a3SMatthew Dillon ahci_pwait_clr(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_ICC); 451258223a3SMatthew Dillon 452fd8bd957SMatthew Dillon /* 45312feb904SMatthew Dillon * Calculate the interrupt mask 45412feb904SMatthew Dillon */ 45512feb904SMatthew Dillon data = AHCI_PREG_IE_TFEE | AHCI_PREG_IE_HBFE | 45612feb904SMatthew Dillon AHCI_PREG_IE_IFE | AHCI_PREG_IE_OFE | 45712feb904SMatthew Dillon AHCI_PREG_IE_DPE | AHCI_PREG_IE_UFE | 45812feb904SMatthew Dillon AHCI_PREG_IE_PCE | AHCI_PREG_IE_PRCE | 45912feb904SMatthew Dillon AHCI_PREG_IE_DHRE | AHCI_PREG_IE_SDBE; 46012feb904SMatthew Dillon if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SSNTF) 46112feb904SMatthew Dillon data |= AHCI_PREG_IE_IPME; 46212feb904SMatthew Dillon #ifdef AHCI_COALESCE 46312feb904SMatthew Dillon if (sc->sc_ccc_ports & (1 << port) 46412feb904SMatthew Dillon data &= ~(AHCI_PREG_IE_SDBE | AHCI_PREG_IE_DHRE); 46512feb904SMatthew Dillon #endif 46612feb904SMatthew Dillon ap->ap_intmask = data; 46712feb904SMatthew Dillon 46812feb904SMatthew Dillon /* 469e8cf3f55SMatthew Dillon * Start the port helper thread. The helper thread will call 470e8cf3f55SMatthew Dillon * ahci_port_init() so the ports can all be started in parallel. 471e8cf3f55SMatthew Dillon * A failure by ahci_port_init() does not deallocate the port 472e8cf3f55SMatthew Dillon * since we still want hot-plug events. 473fd8bd957SMatthew Dillon */ 474f4553de1SMatthew Dillon ahci_os_start_port(ap); 475fd8bd957SMatthew Dillon return(0); 476fd8bd957SMatthew Dillon freeport: 477fd8bd957SMatthew Dillon ahci_port_free(sc, port); 478fd8bd957SMatthew Dillon return (rc); 479fd8bd957SMatthew Dillon } 480fd8bd957SMatthew Dillon 481fd8bd957SMatthew Dillon /* 482492bffafSMatthew Dillon * [re]initialize an idle port. No CCBs should be active. (from port thread) 483fd8bd957SMatthew Dillon * 484fd8bd957SMatthew Dillon * This function is called during the initial port allocation sequence 485fd8bd957SMatthew Dillon * and is also called on hot-plug insertion. We take no chances and 486fd8bd957SMatthew Dillon * use a portreset instead of a softreset. 487fd8bd957SMatthew Dillon * 48822181ab7SMatthew Dillon * This function is the only way to move a failed port back to active 48922181ab7SMatthew Dillon * status. 49022181ab7SMatthew Dillon * 491fd8bd957SMatthew Dillon * Returns 0 if a device is successfully detected. 492fd8bd957SMatthew Dillon */ 493fd8bd957SMatthew Dillon int 49412feb904SMatthew Dillon ahci_port_init(struct ahci_port *ap) 495fd8bd957SMatthew Dillon { 496492bffafSMatthew Dillon u_int32_t cmd; 497e8cf3f55SMatthew Dillon 498e8cf3f55SMatthew Dillon /* 499492bffafSMatthew Dillon * Register [re]initialization 500492bffafSMatthew Dillon * 501f17a0cedSMatthew Dillon * Flush the TFD and SERR and make sure the port is stopped before 502f17a0cedSMatthew Dillon * enabling its interrupt. We no longer cycle the port start as 503f17a0cedSMatthew Dillon * the port should not be started unless a device is present. 504f17a0cedSMatthew Dillon * 505f17a0cedSMatthew Dillon * XXX should we enable FIS reception? (FRE)? 506e8cf3f55SMatthew Dillon */ 507492bffafSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IE, 0); 508492bffafSMatthew Dillon ahci_port_stop(ap, 0); 509492bffafSMatthew Dillon if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SSNTF) 510492bffafSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SNTF, -1); 511f17a0cedSMatthew Dillon ahci_flush_tfd(ap); 512f17a0cedSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 513492bffafSMatthew Dillon 514492bffafSMatthew Dillon /* 515493d3201SMatthew Dillon * If we are being harsh try to kill the port completely. Normally 516493d3201SMatthew Dillon * we would want to hold on to some of the state the BIOS may have 517493d3201SMatthew Dillon * set, such as SUD (spin up device). 518492bffafSMatthew Dillon * 519492bffafSMatthew Dillon * AP_F_HARSH_REINIT is cleared in the hard reset state 520492bffafSMatthew Dillon */ 521492bffafSMatthew Dillon if (ap->ap_flags & AP_F_HARSH_REINIT) { 5229abd2bb8SImre Vadász ahci_pwrite(ap, AHCI_PREG_SCTL, ap->ap_sc->sc_ipm_disable); 523492bffafSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, 0); 524492bffafSMatthew Dillon 525492bffafSMatthew Dillon ahci_os_sleep(1000); 526492bffafSMatthew Dillon 527492bffafSMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC; 528492bffafSMatthew Dillon cmd &= ~(AHCI_PREG_CMD_CLO | AHCI_PREG_CMD_PMA); 529eb9f4c83SMatthew Dillon cmd |= AHCI_PREG_CMD_POD | AHCI_PREG_CMD_SUD; 530eb9f4c83SMatthew Dillon cmd |= AHCI_PREG_CMD_ICC_ACTIVE; 531eb9f4c83SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd); 532eb9f4c83SMatthew Dillon ahci_pwait_clr(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_ICC); 533492bffafSMatthew Dillon ahci_os_sleep(1000); 534492bffafSMatthew Dillon } 535492bffafSMatthew Dillon 536492bffafSMatthew Dillon /* 537492bffafSMatthew Dillon * Clear any pending garbage and re-enable the interrupt before 538492bffafSMatthew Dillon * going to the next stage. 539492bffafSMatthew Dillon */ 540492bffafSMatthew Dillon ap->ap_probe = ATA_PROBE_NEED_HARD_RESET; 541492bffafSMatthew Dillon ap->ap_pmcount = 0; 542492bffafSMatthew Dillon 543492bffafSMatthew Dillon if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SSNTF) 544492bffafSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SNTF, -1); 545492bffafSMatthew Dillon ahci_flush_tfd(ap); 546492bffafSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 547492bffafSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, -1); 548492bffafSMatthew Dillon 549f4553de1SMatthew Dillon ahci_port_interrupt_enable(ap); 550492bffafSMatthew Dillon 55112feb904SMatthew Dillon return (0); 552f4553de1SMatthew Dillon } 553f4553de1SMatthew Dillon 554f4553de1SMatthew Dillon /* 555f4553de1SMatthew Dillon * Enable or re-enable interrupts on a port. 556f4553de1SMatthew Dillon * 557f4553de1SMatthew Dillon * This routine is called from the port initialization code or from the 558f4553de1SMatthew Dillon * helper thread as the real interrupt may be forced to turn off certain 559f4553de1SMatthew Dillon * interrupt sources. 560f4553de1SMatthew Dillon */ 561f4553de1SMatthew Dillon void 562f4553de1SMatthew Dillon ahci_port_interrupt_enable(struct ahci_port *ap) 563f4553de1SMatthew Dillon { 56412feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IE, ap->ap_intmask); 5651980eff3SMatthew Dillon } 566258223a3SMatthew Dillon 567fd8bd957SMatthew Dillon /* 568f5caeaa0SMatthew Dillon * Manage the agressive link power management capability. 569f17a0cedSMatthew Dillon */ 570f17a0cedSMatthew Dillon void 571f17a0cedSMatthew Dillon ahci_port_link_pwr_mgmt(struct ahci_port *ap, int link_pwr_mgmt) 572f17a0cedSMatthew Dillon { 573f17a0cedSMatthew Dillon u_int32_t cmd, sctl; 574f17a0cedSMatthew Dillon 575f17a0cedSMatthew Dillon if (link_pwr_mgmt == ap->link_pwr_mgmt) 576f17a0cedSMatthew Dillon return; 577f17a0cedSMatthew Dillon 578f17a0cedSMatthew Dillon if ((ap->ap_sc->sc_cap & AHCI_REG_CAP_SALP) == 0) { 579f17a0cedSMatthew Dillon kprintf("%s: link power management not supported.\n", 580f17a0cedSMatthew Dillon PORTNAME(ap)); 581f17a0cedSMatthew Dillon return; 582f17a0cedSMatthew Dillon } 583f17a0cedSMatthew Dillon 584f17a0cedSMatthew Dillon ahci_os_lock_port(ap); 585f17a0cedSMatthew Dillon 586f17a0cedSMatthew Dillon if (link_pwr_mgmt == AHCI_LINK_PWR_MGMT_AGGR && 587f17a0cedSMatthew Dillon (ap->ap_sc->sc_cap & AHCI_REG_CAP_SSC)) { 588f17a0cedSMatthew Dillon kprintf("%s: enabling aggressive link power management.\n", 589f17a0cedSMatthew Dillon PORTNAME(ap)); 590f17a0cedSMatthew Dillon 591795adb22SMatthew Dillon ap->link_pwr_mgmt = link_pwr_mgmt; 592795adb22SMatthew Dillon 593f17a0cedSMatthew Dillon ap->ap_intmask &= ~AHCI_PREG_IE_PRCE; 594f17a0cedSMatthew Dillon ahci_port_interrupt_enable(ap); 595f17a0cedSMatthew Dillon 596f17a0cedSMatthew Dillon sctl = ahci_pread(ap, AHCI_PREG_SCTL); 5979abd2bb8SImre Vadász sctl &= ~(AHCI_PREG_SCTL_IPM); 5989abd2bb8SImre Vadász if (ap->ap_sc->sc_cap2 & AHCI_REG_CAP2_SDS) 5999abd2bb8SImre Vadász sctl |= AHCI_PREG_SCTL_IPM_NODEVSLP; 600f17a0cedSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SCTL, sctl); 601f17a0cedSMatthew Dillon 602795adb22SMatthew Dillon /* 603795adb22SMatthew Dillon * Enable device initiated link power management for 604795adb22SMatthew Dillon * directly attached devices that support it. 605795adb22SMatthew Dillon */ 606795adb22SMatthew Dillon if (ap->ap_type != ATA_PORT_T_PM && 607750495d0SImre Vadász (ap->ap_ata[0]->at_identify.satafsup & 608750495d0SImre Vadász SATA_FEATURE_SUP_DEVIPS)) { 609795adb22SMatthew Dillon if (ahci_set_feature(ap, NULL, ATA_SATAFT_DEVIPS, 1)) 610795adb22SMatthew Dillon kprintf("%s: Could not enable device initiated " 611795adb22SMatthew Dillon "link power management.\n", 612795adb22SMatthew Dillon PORTNAME(ap)); 613795adb22SMatthew Dillon } 614795adb22SMatthew Dillon 615f17a0cedSMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD); 616f17a0cedSMatthew Dillon cmd |= AHCI_PREG_CMD_ASP; 617f17a0cedSMatthew Dillon cmd |= AHCI_PREG_CMD_ALPE; 618f17a0cedSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd); 619f17a0cedSMatthew Dillon } else if (link_pwr_mgmt == AHCI_LINK_PWR_MGMT_MEDIUM && 620f17a0cedSMatthew Dillon (ap->ap_sc->sc_cap & AHCI_REG_CAP_PSC)) { 621f17a0cedSMatthew Dillon kprintf("%s: enabling medium link power management.\n", 622f17a0cedSMatthew Dillon PORTNAME(ap)); 623f17a0cedSMatthew Dillon 624795adb22SMatthew Dillon ap->link_pwr_mgmt = link_pwr_mgmt; 625795adb22SMatthew Dillon 626f17a0cedSMatthew Dillon ap->ap_intmask &= ~AHCI_PREG_IE_PRCE; 627f17a0cedSMatthew Dillon ahci_port_interrupt_enable(ap); 628f17a0cedSMatthew Dillon 629f17a0cedSMatthew Dillon sctl = ahci_pread(ap, AHCI_PREG_SCTL); 6309abd2bb8SImre Vadász sctl &= ~(AHCI_PREG_SCTL_IPM); 6319abd2bb8SImre Vadász sctl |= AHCI_PREG_SCTL_IPM_NOSLUMBER; 6329abd2bb8SImre Vadász if (ap->ap_sc->sc_cap2 & AHCI_REG_CAP2_SDS) 6339abd2bb8SImre Vadász sctl |= AHCI_PREG_SCTL_IPM_NODEVSLP; 634f17a0cedSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SCTL, sctl); 635f17a0cedSMatthew Dillon 636f17a0cedSMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD); 637f17a0cedSMatthew Dillon cmd &= ~AHCI_PREG_CMD_ASP; 638f17a0cedSMatthew Dillon cmd |= AHCI_PREG_CMD_ALPE; 639f17a0cedSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd); 640f17a0cedSMatthew Dillon 641f17a0cedSMatthew Dillon } else if (link_pwr_mgmt == AHCI_LINK_PWR_MGMT_NONE) { 642f17a0cedSMatthew Dillon kprintf("%s: disabling link power management.\n", 643f17a0cedSMatthew Dillon PORTNAME(ap)); 644f17a0cedSMatthew Dillon 645795adb22SMatthew Dillon /* Disable device initiated link power management */ 646795adb22SMatthew Dillon if (ap->ap_type != ATA_PORT_T_PM && 647750495d0SImre Vadász (ap->ap_ata[0]->at_identify.satafsup & 648750495d0SImre Vadász SATA_FEATURE_SUP_DEVIPS)) { 649795adb22SMatthew Dillon ahci_set_feature(ap, NULL, ATA_SATAFT_DEVIPS, 0); 650750495d0SImre Vadász } 651795adb22SMatthew Dillon 652f17a0cedSMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD); 653f17a0cedSMatthew Dillon cmd &= ~(AHCI_PREG_CMD_ALPE | AHCI_PREG_CMD_ASP); 654f17a0cedSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd); 655f17a0cedSMatthew Dillon 656f17a0cedSMatthew Dillon sctl = ahci_pread(ap, AHCI_PREG_SCTL); 6579abd2bb8SImre Vadász sctl &= ~(AHCI_PREG_SCTL_IPM); 6589abd2bb8SImre Vadász sctl |= ap->ap_sc->sc_ipm_disable; 659f17a0cedSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SCTL, sctl); 660f17a0cedSMatthew Dillon 661f17a0cedSMatthew Dillon /* let the drive come back to avoid PRCS interrupts later */ 662f17a0cedSMatthew Dillon ahci_os_unlock_port(ap); 663f17a0cedSMatthew Dillon ahci_os_sleep(1000); 664f17a0cedSMatthew Dillon ahci_os_lock_port(ap); 665f17a0cedSMatthew Dillon 666795adb22SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, 667795adb22SMatthew Dillon AHCI_PREG_SERR_DIAG_N | AHCI_PREG_SERR_DIAG_W); 668f17a0cedSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_PRCS); 669f17a0cedSMatthew Dillon 670f17a0cedSMatthew Dillon ap->ap_intmask |= AHCI_PREG_IE_PRCE; 671f17a0cedSMatthew Dillon ahci_port_interrupt_enable(ap); 672f17a0cedSMatthew Dillon 673f17a0cedSMatthew Dillon ap->link_pwr_mgmt = link_pwr_mgmt; 674f17a0cedSMatthew Dillon } else { 675f17a0cedSMatthew Dillon kprintf("%s: unsupported link power management state %d.\n", 676f17a0cedSMatthew Dillon PORTNAME(ap), link_pwr_mgmt); 677f17a0cedSMatthew Dillon } 678f17a0cedSMatthew Dillon 679f17a0cedSMatthew Dillon ahci_os_unlock_port(ap); 680f17a0cedSMatthew Dillon } 681f17a0cedSMatthew Dillon 682795adb22SMatthew Dillon /* 683795adb22SMatthew Dillon * Return current link power state. 684795adb22SMatthew Dillon */ 685795adb22SMatthew Dillon int 686795adb22SMatthew Dillon ahci_port_link_pwr_state(struct ahci_port *ap) 687795adb22SMatthew Dillon { 688795adb22SMatthew Dillon uint32_t r; 689795adb22SMatthew Dillon 690795adb22SMatthew Dillon r = ahci_pread(ap, AHCI_PREG_SSTS); 691d90e4fd1SImre Vadász switch (r & AHCI_PREG_SSTS_IPM) { 692d90e4fd1SImre Vadász case AHCI_PREG_SSTS_IPM_ACTIVE: 693795adb22SMatthew Dillon return 1; 694d90e4fd1SImre Vadász case AHCI_PREG_SSTS_IPM_PARTIAL: 695795adb22SMatthew Dillon return 2; 696d90e4fd1SImre Vadász case AHCI_PREG_SSTS_IPM_SLUMBER: 697795adb22SMatthew Dillon return 3; 698d90e4fd1SImre Vadász case AHCI_PREG_SSTS_IPM_DEVSLEEP: 699d90e4fd1SImre Vadász return 4; 700795adb22SMatthew Dillon default: 701795adb22SMatthew Dillon return 0; 702795adb22SMatthew Dillon } 703795adb22SMatthew Dillon } 704f17a0cedSMatthew Dillon 705f17a0cedSMatthew Dillon /* 7063209f581SMatthew Dillon * Run the port / target state machine from a main context. 7073209f581SMatthew Dillon * 7083209f581SMatthew Dillon * The state machine for the port is always run. 7093209f581SMatthew Dillon * 7103209f581SMatthew Dillon * If atx is non-NULL run the state machine for a particular target. 7113209f581SMatthew Dillon * If atx is NULL run the state machine for all targets. 7123209f581SMatthew Dillon */ 7133209f581SMatthew Dillon void 714831bc9e3SMatthew Dillon ahci_port_state_machine(struct ahci_port *ap, int initial) 7153209f581SMatthew Dillon { 7163209f581SMatthew Dillon struct ata_port *at; 7173209f581SMatthew Dillon u_int32_t data; 7183209f581SMatthew Dillon int target; 7193209f581SMatthew Dillon int didsleep; 720831bc9e3SMatthew Dillon int loop; 7213209f581SMatthew Dillon 722831bc9e3SMatthew Dillon /* 723831bc9e3SMatthew Dillon * State machine for port. Note that CAM is not yet associated 724831bc9e3SMatthew Dillon * during the initial parallel probe and the port's probe state 725831bc9e3SMatthew Dillon * will not get past ATA_PROBE_NEED_IDENT. 726831bc9e3SMatthew Dillon */ 727c408a8b3SMatthew Dillon { 7281067474aSMatthew Dillon if (initial == 0 && ap->ap_probe <= ATA_PROBE_NEED_HARD_RESET) { 7291067474aSMatthew Dillon kprintf("%s: Waiting 10 seconds on insertion\n", 7301067474aSMatthew Dillon PORTNAME(ap)); 7311067474aSMatthew Dillon ahci_os_sleep(10000); 7321067474aSMatthew Dillon initial = 1; 7333209f581SMatthew Dillon } 7341067474aSMatthew Dillon if (ap->ap_probe == ATA_PROBE_NEED_INIT) 73512feb904SMatthew Dillon ahci_port_init(ap); 7363209f581SMatthew Dillon if (ap->ap_probe == ATA_PROBE_NEED_HARD_RESET) 7373209f581SMatthew Dillon ahci_port_reset(ap, NULL, 1); 7383209f581SMatthew Dillon if (ap->ap_probe == ATA_PROBE_NEED_SOFT_RESET) 7393209f581SMatthew Dillon ahci_port_reset(ap, NULL, 0); 7403209f581SMatthew Dillon if (ap->ap_probe == ATA_PROBE_NEED_IDENT) 7413209f581SMatthew Dillon ahci_cam_probe(ap, NULL); 7423209f581SMatthew Dillon } 7433209f581SMatthew Dillon if (ap->ap_type != ATA_PORT_T_PM) { 7443209f581SMatthew Dillon if (ap->ap_probe == ATA_PROBE_FAILED) { 7453209f581SMatthew Dillon ahci_cam_changed(ap, NULL, 0); 746f4553de1SMatthew Dillon } else if (ap->ap_probe >= ATA_PROBE_NEED_IDENT) { 7473209f581SMatthew Dillon ahci_cam_changed(ap, NULL, 1); 7483209f581SMatthew Dillon } 7493209f581SMatthew Dillon return; 7503209f581SMatthew Dillon } 7513209f581SMatthew Dillon 752831bc9e3SMatthew Dillon /* 753831bc9e3SMatthew Dillon * Port Multiplier state machine. 754831bc9e3SMatthew Dillon * 755831bc9e3SMatthew Dillon * Get a mask of changed targets and combine with any runnable 756831bc9e3SMatthew Dillon * states already present. 757831bc9e3SMatthew Dillon */ 758831bc9e3SMatthew Dillon for (loop = 0; ;++loop) { 7592cc2e845SMatthew Dillon if (ahci_pm_read(ap, 15, SATA_PMREG_EINFO, &data)) { 7603209f581SMatthew Dillon kprintf("%s: PM unable to read hot-plug bitmap\n", 7613209f581SMatthew Dillon PORTNAME(ap)); 7623209f581SMatthew Dillon break; 7633209f581SMatthew Dillon } 7643209f581SMatthew Dillon 7653209f581SMatthew Dillon /* 766831bc9e3SMatthew Dillon * Do at least one loop, then stop if no more state changes 767831bc9e3SMatthew Dillon * have occured. The PM might not generate a new 768831bc9e3SMatthew Dillon * notification until we clear the entire bitmap. 7693209f581SMatthew Dillon */ 770831bc9e3SMatthew Dillon if (loop && data == 0) 7713209f581SMatthew Dillon break; 7723209f581SMatthew Dillon 7733209f581SMatthew Dillon /* 7743209f581SMatthew Dillon * New devices showing up in the bitmap require some spin-up 7753209f581SMatthew Dillon * time before we start probing them. Reset didsleep. The 7763209f581SMatthew Dillon * first new device we detect will sleep before probing. 777831bc9e3SMatthew Dillon * 778831bc9e3SMatthew Dillon * This only applies to devices whos change bit is set in 779831bc9e3SMatthew Dillon * the data, and does not apply to the initial boot-time 780831bc9e3SMatthew Dillon * probe. 7813209f581SMatthew Dillon */ 7823209f581SMatthew Dillon didsleep = 0; 7833209f581SMatthew Dillon 7843209f581SMatthew Dillon for (target = 0; target < ap->ap_pmcount; ++target) { 785b012a2caSMatthew Dillon at = ap->ap_ata[target]; 7863209f581SMatthew Dillon 7873209f581SMatthew Dillon /* 7883209f581SMatthew Dillon * Check the target state for targets behind the PM 7893209f581SMatthew Dillon * which have changed state. This will adjust 7903209f581SMatthew Dillon * at_probe and set ATA_PORT_F_RESCAN 7913209f581SMatthew Dillon * 7921067474aSMatthew Dillon * We want to wait at least 10 seconds before probing 7933209f581SMatthew Dillon * a newly inserted device. If the check status 7943209f581SMatthew Dillon * indicates a device is present and in need of a 7953209f581SMatthew Dillon * hard reset, we make sure we have slept before 7963209f581SMatthew Dillon * continuing. 797831bc9e3SMatthew Dillon * 7981067474aSMatthew Dillon * We also need to wait at least 1 second for the 7991067474aSMatthew Dillon * PHY state to change after insertion, if we 8001067474aSMatthew Dillon * haven't already waited the 10 seconds. 8011067474aSMatthew Dillon * 802831bc9e3SMatthew Dillon * NOTE: When pm_check_good finds a good port it 803831bc9e3SMatthew Dillon * typically starts us in probe state 804831bc9e3SMatthew Dillon * NEED_HARD_RESET rather than INIT. 8053209f581SMatthew Dillon */ 8063209f581SMatthew Dillon if (data & (1 << target)) { 8071067474aSMatthew Dillon if (initial == 0 && didsleep == 0) 8081067474aSMatthew Dillon ahci_os_sleep(1000); 8093209f581SMatthew Dillon ahci_pm_check_good(ap, target); 810831bc9e3SMatthew Dillon if (initial == 0 && didsleep == 0 && 811831bc9e3SMatthew Dillon at->at_probe <= ATA_PROBE_NEED_HARD_RESET 812831bc9e3SMatthew Dillon ) { 8133209f581SMatthew Dillon didsleep = 1; 814121d8e75SMatthew Dillon kprintf("%s: Waiting 10 seconds on insertion\n", PORTNAME(ap)); 815121d8e75SMatthew Dillon ahci_os_sleep(10000); 8163209f581SMatthew Dillon } 8173209f581SMatthew Dillon } 818831bc9e3SMatthew Dillon 819831bc9e3SMatthew Dillon /* 820831bc9e3SMatthew Dillon * Report hot-plug events before the probe state 821831bc9e3SMatthew Dillon * really gets hot. Only actual events are reported 822831bc9e3SMatthew Dillon * here to reduce spew. 823831bc9e3SMatthew Dillon */ 824831bc9e3SMatthew Dillon if (data & (1 << target)) { 825831bc9e3SMatthew Dillon kprintf("%s: HOTPLUG (PM) - ", ATANAME(ap, at)); 826831bc9e3SMatthew Dillon switch(at->at_probe) { 827831bc9e3SMatthew Dillon case ATA_PROBE_NEED_INIT: 828831bc9e3SMatthew Dillon case ATA_PROBE_NEED_HARD_RESET: 829831bc9e3SMatthew Dillon kprintf("Device inserted\n"); 830831bc9e3SMatthew Dillon break; 831831bc9e3SMatthew Dillon case ATA_PROBE_FAILED: 832831bc9e3SMatthew Dillon kprintf("Device removed\n"); 833831bc9e3SMatthew Dillon break; 834831bc9e3SMatthew Dillon default: 835831bc9e3SMatthew Dillon kprintf("Device probe in progress\n"); 836831bc9e3SMatthew Dillon break; 837831bc9e3SMatthew Dillon } 8383209f581SMatthew Dillon } 8393209f581SMatthew Dillon 8403209f581SMatthew Dillon /* 841831bc9e3SMatthew Dillon * Run through the state machine as necessary if 842831bc9e3SMatthew Dillon * the port is not marked failed. 843831bc9e3SMatthew Dillon * 844831bc9e3SMatthew Dillon * The state machine may stop at NEED_IDENT if 845831bc9e3SMatthew Dillon * CAM is not yet attached. 846831bc9e3SMatthew Dillon * 847831bc9e3SMatthew Dillon * Acquire exclusive access to the port while we 848831bc9e3SMatthew Dillon * are doing this. This prevents command-completion 849831bc9e3SMatthew Dillon * from queueing commands for non-polled targets 850831bc9e3SMatthew Dillon * inbetween our probe steps. We need to do this 851831bc9e3SMatthew Dillon * because the reset probes can generate severe PHY 852831bc9e3SMatthew Dillon * and protocol errors and soft-brick the port. 8533209f581SMatthew Dillon */ 854831bc9e3SMatthew Dillon if (at->at_probe != ATA_PROBE_FAILED && 855831bc9e3SMatthew Dillon at->at_probe != ATA_PROBE_GOOD) { 856831bc9e3SMatthew Dillon ahci_beg_exclusive_access(ap, at); 8573209f581SMatthew Dillon if (at->at_probe == ATA_PROBE_NEED_INIT) 85812feb904SMatthew Dillon ahci_pm_port_init(ap, at); 8593209f581SMatthew Dillon if (at->at_probe == ATA_PROBE_NEED_HARD_RESET) 8603209f581SMatthew Dillon ahci_port_reset(ap, at, 1); 8613209f581SMatthew Dillon if (at->at_probe == ATA_PROBE_NEED_SOFT_RESET) 8623209f581SMatthew Dillon ahci_port_reset(ap, at, 0); 8633209f581SMatthew Dillon if (at->at_probe == ATA_PROBE_NEED_IDENT) 8643209f581SMatthew Dillon ahci_cam_probe(ap, at); 865831bc9e3SMatthew Dillon ahci_end_exclusive_access(ap, at); 8663209f581SMatthew Dillon } 8673209f581SMatthew Dillon 8683209f581SMatthew Dillon /* 869831bc9e3SMatthew Dillon * Add or remove from CAM 8703209f581SMatthew Dillon */ 8713209f581SMatthew Dillon if (at->at_features & ATA_PORT_F_RESCAN) { 8723209f581SMatthew Dillon at->at_features &= ~ATA_PORT_F_RESCAN; 8733209f581SMatthew Dillon if (at->at_probe == ATA_PROBE_FAILED) { 8743209f581SMatthew Dillon ahci_cam_changed(ap, at, 0); 875f4553de1SMatthew Dillon } else if (at->at_probe >= ATA_PROBE_NEED_IDENT) { 8763209f581SMatthew Dillon ahci_cam_changed(ap, at, 1); 8773209f581SMatthew Dillon } 8783209f581SMatthew Dillon } 8793560ed94SMatthew Dillon data &= ~(1 << target); 8803560ed94SMatthew Dillon } 8813560ed94SMatthew Dillon if (data) { 8823560ed94SMatthew Dillon kprintf("%s: WARNING (PM): extra bits set in " 8833560ed94SMatthew Dillon "EINFO: %08x\n", PORTNAME(ap), data); 8843560ed94SMatthew Dillon while (target < AHCI_MAX_PMPORTS) { 8853560ed94SMatthew Dillon ahci_pm_check_good(ap, target); 8863560ed94SMatthew Dillon ++target; 8873560ed94SMatthew Dillon } 8883209f581SMatthew Dillon } 8893209f581SMatthew Dillon } 8903209f581SMatthew Dillon } 8913209f581SMatthew Dillon 8923209f581SMatthew Dillon 8933209f581SMatthew Dillon /* 894fd8bd957SMatthew Dillon * De-initialize and detach a port. 895fd8bd957SMatthew Dillon */ 896258223a3SMatthew Dillon void 897258223a3SMatthew Dillon ahci_port_free(struct ahci_softc *sc, u_int port) 898258223a3SMatthew Dillon { 899258223a3SMatthew Dillon struct ahci_port *ap = sc->sc_ports[port]; 900258223a3SMatthew Dillon struct ahci_ccb *ccb; 901b012a2caSMatthew Dillon int i; 902258223a3SMatthew Dillon 90317eab71eSMatthew Dillon /* 90417eab71eSMatthew Dillon * Ensure port is disabled and its interrupts are all flushed. 90517eab71eSMatthew Dillon */ 906258223a3SMatthew Dillon if (ap->ap_sc) { 90717eab71eSMatthew Dillon ahci_port_stop(ap, 1); 908f4553de1SMatthew Dillon ahci_os_stop_port(ap); 909258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, 0); 910258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IE, 0); 911258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, ahci_pread(ap, AHCI_PREG_IS)); 912258223a3SMatthew Dillon ahci_write(sc, AHCI_REG_IS, 1 << port); 913258223a3SMatthew Dillon } 914258223a3SMatthew Dillon 915258223a3SMatthew Dillon if (ap->ap_ccbs) { 916258223a3SMatthew Dillon while ((ccb = ahci_get_ccb(ap)) != NULL) { 917258223a3SMatthew Dillon if (ccb->ccb_dmamap) { 918258223a3SMatthew Dillon bus_dmamap_destroy(sc->sc_tag_data, 919258223a3SMatthew Dillon ccb->ccb_dmamap); 920258223a3SMatthew Dillon ccb->ccb_dmamap = NULL; 921258223a3SMatthew Dillon } 922258223a3SMatthew Dillon } 9231067474aSMatthew Dillon if ((ccb = ap->ap_err_ccb) != NULL) { 9241067474aSMatthew Dillon if (ccb->ccb_dmamap) { 9251067474aSMatthew Dillon bus_dmamap_destroy(sc->sc_tag_data, 9261067474aSMatthew Dillon ccb->ccb_dmamap); 9271067474aSMatthew Dillon ccb->ccb_dmamap = NULL; 9281067474aSMatthew Dillon } 9291067474aSMatthew Dillon ap->ap_err_ccb = NULL; 9301067474aSMatthew Dillon } 931258223a3SMatthew Dillon kfree(ap->ap_ccbs, M_DEVBUF); 932258223a3SMatthew Dillon ap->ap_ccbs = NULL; 933258223a3SMatthew Dillon } 934258223a3SMatthew Dillon 935258223a3SMatthew Dillon if (ap->ap_dmamem_cmd_list) { 936258223a3SMatthew Dillon ahci_dmamem_free(sc, ap->ap_dmamem_cmd_list); 937258223a3SMatthew Dillon ap->ap_dmamem_cmd_list = NULL; 938258223a3SMatthew Dillon } 939258223a3SMatthew Dillon if (ap->ap_dmamem_rfis) { 940258223a3SMatthew Dillon ahci_dmamem_free(sc, ap->ap_dmamem_rfis); 941258223a3SMatthew Dillon ap->ap_dmamem_rfis = NULL; 942258223a3SMatthew Dillon } 943258223a3SMatthew Dillon if (ap->ap_dmamem_cmd_table) { 944258223a3SMatthew Dillon ahci_dmamem_free(sc, ap->ap_dmamem_cmd_table); 945258223a3SMatthew Dillon ap->ap_dmamem_cmd_table = NULL; 946258223a3SMatthew Dillon } 9471980eff3SMatthew Dillon if (ap->ap_ata) { 948b012a2caSMatthew Dillon for (i = 0; i < AHCI_MAX_PMPORTS; ++i) { 949b012a2caSMatthew Dillon if (ap->ap_ata[i]) { 950b012a2caSMatthew Dillon kfree(ap->ap_ata[i], M_DEVBUF); 951b012a2caSMatthew Dillon ap->ap_ata[i] = NULL; 952b012a2caSMatthew Dillon } 953b012a2caSMatthew Dillon } 9541980eff3SMatthew Dillon } 95512feb904SMatthew Dillon if (ap->ap_err_scratch) { 95612feb904SMatthew Dillon kfree(ap->ap_err_scratch, M_DEVBUF); 95712feb904SMatthew Dillon ap->ap_err_scratch = NULL; 95812feb904SMatthew Dillon } 959258223a3SMatthew Dillon 960258223a3SMatthew Dillon /* bus_space(9) says we dont free the subregions handle */ 961258223a3SMatthew Dillon 962258223a3SMatthew Dillon kfree(ap, M_DEVBUF); 963258223a3SMatthew Dillon sc->sc_ports[port] = NULL; 964258223a3SMatthew Dillon } 965258223a3SMatthew Dillon 966492bffafSMatthew Dillon static 967492bffafSMatthew Dillon u_int32_t 968492bffafSMatthew Dillon ahci_pactive(struct ahci_port *ap) 969492bffafSMatthew Dillon { 970492bffafSMatthew Dillon u_int32_t mask; 971492bffafSMatthew Dillon 972492bffafSMatthew Dillon mask = ahci_pread(ap, AHCI_PREG_CI); 973492bffafSMatthew Dillon if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SNCQ) 974492bffafSMatthew Dillon mask |= ahci_pread(ap, AHCI_PREG_SACT); 975492bffafSMatthew Dillon return(mask); 976492bffafSMatthew Dillon } 977492bffafSMatthew Dillon 978fd8bd957SMatthew Dillon /* 979fd8bd957SMatthew Dillon * Start high-level command processing on the port 980fd8bd957SMatthew Dillon */ 981258223a3SMatthew Dillon int 98217eab71eSMatthew Dillon ahci_port_start(struct ahci_port *ap) 983258223a3SMatthew Dillon { 98412feb904SMatthew Dillon u_int32_t r, s, is, tfd; 985258223a3SMatthew Dillon 98617eab71eSMatthew Dillon /* 98717eab71eSMatthew Dillon * FRE must be turned on before ST. Wait for FR to go active 98817eab71eSMatthew Dillon * before turning on ST. The spec doesn't seem to think this 98917eab71eSMatthew Dillon * is necessary but waiting here avoids an on-off race in the 99017eab71eSMatthew Dillon * ahci_port_stop() code. 99117eab71eSMatthew Dillon */ 99212feb904SMatthew Dillon r = ahci_pread(ap, AHCI_PREG_CMD); 99317eab71eSMatthew Dillon if ((r & AHCI_PREG_CMD_FRE) == 0) { 994258223a3SMatthew Dillon r |= AHCI_PREG_CMD_FRE; 99517eab71eSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, r); 99617eab71eSMatthew Dillon } 99717eab71eSMatthew Dillon if ((ap->ap_sc->sc_flags & AHCI_F_IGN_FR) == 0) { 99817eab71eSMatthew Dillon if (ahci_pwait_set(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_FR)) { 99917eab71eSMatthew Dillon kprintf("%s: Cannot start FIS reception\n", 100017eab71eSMatthew Dillon PORTNAME(ap)); 100117eab71eSMatthew Dillon return (2); 100217eab71eSMatthew Dillon } 1003f17a0cedSMatthew Dillon } else { 1004f17a0cedSMatthew Dillon ahci_os_sleep(10); 100517eab71eSMatthew Dillon } 100617eab71eSMatthew Dillon 100717eab71eSMatthew Dillon /* 100817eab71eSMatthew Dillon * Turn on ST, wait for CR to come up. 100917eab71eSMatthew Dillon */ 1010258223a3SMatthew Dillon r |= AHCI_PREG_CMD_ST; 1011258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, r); 1012eb9f4c83SMatthew Dillon 1013eb9f4c83SMatthew Dillon if ((ap->ap_sc->sc_flags & AHCI_F_IGN_CR) == 0 && 1014eb9f4c83SMatthew Dillon ahci_pwait_set_to(ap, 2000, AHCI_PREG_CMD, AHCI_PREG_CMD_CR)) { 10158bf6a3ffSMatthew Dillon s = ahci_pread(ap, AHCI_PREG_SERR); 10168bf6a3ffSMatthew Dillon is = ahci_pread(ap, AHCI_PREG_IS); 10178bf6a3ffSMatthew Dillon tfd = ahci_pread(ap, AHCI_PREG_TFD); 10181980eff3SMatthew Dillon kprintf("%s: Cannot start command DMA\n" 10191980eff3SMatthew Dillon "NCMP=%b NSERR=%b\n" 102012feb904SMatthew Dillon "NEWIS=%b\n" 102112feb904SMatthew Dillon "NEWTFD=%b\n", 10221980eff3SMatthew Dillon PORTNAME(ap), 10231980eff3SMatthew Dillon r, AHCI_PFMT_CMD, s, AHCI_PFMT_SERR, 102412feb904SMatthew Dillon is, AHCI_PFMT_IS, 102512feb904SMatthew Dillon tfd, AHCI_PFMT_TFD_STS); 102617eab71eSMatthew Dillon return (1); 102717eab71eSMatthew Dillon } 1028258223a3SMatthew Dillon 1029258223a3SMatthew Dillon #ifdef AHCI_COALESCE 103017eab71eSMatthew Dillon /* 103117eab71eSMatthew Dillon * (Re-)enable coalescing on the port. 103217eab71eSMatthew Dillon */ 1033258223a3SMatthew Dillon if (ap->ap_sc->sc_ccc_ports & (1 << ap->ap_num)) { 1034258223a3SMatthew Dillon ap->ap_sc->sc_ccc_ports_cur |= (1 << ap->ap_num); 1035258223a3SMatthew Dillon ahci_write(ap->ap_sc, AHCI_REG_CCC_PORTS, 1036258223a3SMatthew Dillon ap->ap_sc->sc_ccc_ports_cur); 1037258223a3SMatthew Dillon } 1038258223a3SMatthew Dillon #endif 1039258223a3SMatthew Dillon 1040258223a3SMatthew Dillon return (0); 1041258223a3SMatthew Dillon } 1042258223a3SMatthew Dillon 1043fd8bd957SMatthew Dillon /* 1044fd8bd957SMatthew Dillon * Stop high-level command processing on a port 10454c339a5fSMatthew Dillon * 10464c339a5fSMatthew Dillon * WARNING! If the port is stopped while CR is still active our saved 10474c339a5fSMatthew Dillon * CI/SACT will race any commands completed by the command 10484c339a5fSMatthew Dillon * processor prior to being able to stop. Thus we never call 10494c339a5fSMatthew Dillon * this function unless we intend to dispose of any remaining 10504c339a5fSMatthew Dillon * active commands. In particular, this complicates the timeout 10514c339a5fSMatthew Dillon * code. 1052fd8bd957SMatthew Dillon */ 1053258223a3SMatthew Dillon int 1054258223a3SMatthew Dillon ahci_port_stop(struct ahci_port *ap, int stop_fis_rx) 1055258223a3SMatthew Dillon { 1056258223a3SMatthew Dillon u_int32_t r; 1057258223a3SMatthew Dillon 1058258223a3SMatthew Dillon #ifdef AHCI_COALESCE 105917eab71eSMatthew Dillon /* 106017eab71eSMatthew Dillon * Disable coalescing on the port while it is stopped. 106117eab71eSMatthew Dillon */ 1062258223a3SMatthew Dillon if (ap->ap_sc->sc_ccc_ports & (1 << ap->ap_num)) { 1063258223a3SMatthew Dillon ap->ap_sc->sc_ccc_ports_cur &= ~(1 << ap->ap_num); 1064258223a3SMatthew Dillon ahci_write(ap->ap_sc, AHCI_REG_CCC_PORTS, 1065258223a3SMatthew Dillon ap->ap_sc->sc_ccc_ports_cur); 1066258223a3SMatthew Dillon } 1067258223a3SMatthew Dillon #endif 1068258223a3SMatthew Dillon 106917eab71eSMatthew Dillon /* 107017eab71eSMatthew Dillon * Turn off ST, then wait for CR to go off. 107117eab71eSMatthew Dillon */ 1072258223a3SMatthew Dillon r = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC; 10738119d5f5SMatthew Dillon if (r & AHCI_PREG_CMD_ST) { 1074258223a3SMatthew Dillon r &= ~AHCI_PREG_CMD_ST; 1075258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, r); 10768119d5f5SMatthew Dillon } 1077258223a3SMatthew Dillon 107817eab71eSMatthew Dillon if (ahci_pwait_clr(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_CR)) { 107917eab71eSMatthew Dillon kprintf("%s: Port bricked, unable to stop (ST)\n", 108017eab71eSMatthew Dillon PORTNAME(ap)); 1081258223a3SMatthew Dillon return (1); 108217eab71eSMatthew Dillon } 1083258223a3SMatthew Dillon 10841980eff3SMatthew Dillon #if 0 108517eab71eSMatthew Dillon /* 108617eab71eSMatthew Dillon * Turn off FRE, then wait for FR to go off. FRE cannot 108717eab71eSMatthew Dillon * be turned off until CR transitions to 0. 108817eab71eSMatthew Dillon */ 10891980eff3SMatthew Dillon if ((r & AHCI_PREG_CMD_FR) == 0) { 10901980eff3SMatthew Dillon kprintf("%s: FR stopped, clear FRE for next start\n", 10911980eff3SMatthew Dillon PORTNAME(ap)); 10921980eff3SMatthew Dillon stop_fis_rx = 2; 10931980eff3SMatthew Dillon } 10941980eff3SMatthew Dillon #endif 109517eab71eSMatthew Dillon if (stop_fis_rx) { 109617eab71eSMatthew Dillon r &= ~AHCI_PREG_CMD_FRE; 109717eab71eSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, r); 109817eab71eSMatthew Dillon if (ahci_pwait_clr(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_FR)) { 109917eab71eSMatthew Dillon kprintf("%s: Port bricked, unable to stop (FRE)\n", 110017eab71eSMatthew Dillon PORTNAME(ap)); 1101258223a3SMatthew Dillon return (2); 110217eab71eSMatthew Dillon } 110317eab71eSMatthew Dillon } 1104258223a3SMatthew Dillon return (0); 1105258223a3SMatthew Dillon } 1106258223a3SMatthew Dillon 1107fd8bd957SMatthew Dillon /* 1108fd8bd957SMatthew Dillon * AHCI command list override -> forcibly clear TFD.STS.{BSY,DRQ} 1109fd8bd957SMatthew Dillon */ 1110258223a3SMatthew Dillon int 1111258223a3SMatthew Dillon ahci_port_clo(struct ahci_port *ap) 1112258223a3SMatthew Dillon { 1113258223a3SMatthew Dillon struct ahci_softc *sc = ap->ap_sc; 1114258223a3SMatthew Dillon u_int32_t cmd; 1115258223a3SMatthew Dillon 1116258223a3SMatthew Dillon /* Only attempt CLO if supported by controller */ 11178119d5f5SMatthew Dillon if ((sc->sc_cap & AHCI_REG_CAP_SCLO) == 0) 1118258223a3SMatthew Dillon return (1); 1119258223a3SMatthew Dillon 1120258223a3SMatthew Dillon /* Issue CLO */ 1121258223a3SMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC; 1122258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd | AHCI_PREG_CMD_CLO); 1123258223a3SMatthew Dillon 1124258223a3SMatthew Dillon /* Wait for completion */ 1125258223a3SMatthew Dillon if (ahci_pwait_clr(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_CLO)) { 1126258223a3SMatthew Dillon kprintf("%s: CLO did not complete\n", PORTNAME(ap)); 1127258223a3SMatthew Dillon return (1); 1128258223a3SMatthew Dillon } 1129258223a3SMatthew Dillon 1130258223a3SMatthew Dillon return (0); 1131258223a3SMatthew Dillon } 1132258223a3SMatthew Dillon 1133fd8bd957SMatthew Dillon /* 11341980eff3SMatthew Dillon * Reset a port. 113517eab71eSMatthew Dillon * 11361980eff3SMatthew Dillon * If hard is 0 perform a softreset of the port. 113717eab71eSMatthew Dillon * If hard is 1 perform a hard reset of the port. 11381980eff3SMatthew Dillon * 11391980eff3SMatthew Dillon * If at is non-NULL an indirect port via a port-multiplier is being 11401980eff3SMatthew Dillon * reset, otherwise a direct port is being reset. 11411980eff3SMatthew Dillon * 11421980eff3SMatthew Dillon * NOTE: Indirect ports can only be soft-reset. 114317eab71eSMatthew Dillon */ 114417eab71eSMatthew Dillon int 11451980eff3SMatthew Dillon ahci_port_reset(struct ahci_port *ap, struct ata_port *at, int hard) 114617eab71eSMatthew Dillon { 114717eab71eSMatthew Dillon int rc; 114817eab71eSMatthew Dillon 114917eab71eSMatthew Dillon if (hard) { 11501980eff3SMatthew Dillon if (at) 11511980eff3SMatthew Dillon rc = ahci_pm_hardreset(ap, at->at_target, hard); 11521980eff3SMatthew Dillon else 11531980eff3SMatthew Dillon rc = ahci_port_hardreset(ap, hard); 115417eab71eSMatthew Dillon } else { 11551980eff3SMatthew Dillon if (at) 11561980eff3SMatthew Dillon rc = ahci_pm_softreset(ap, at->at_target); 11571980eff3SMatthew Dillon else 115817eab71eSMatthew Dillon rc = ahci_port_softreset(ap); 115917eab71eSMatthew Dillon } 116017eab71eSMatthew Dillon return(rc); 116117eab71eSMatthew Dillon } 116217eab71eSMatthew Dillon 116317eab71eSMatthew Dillon /* 1164fd8bd957SMatthew Dillon * AHCI soft reset, Section 10.4.1 1165fd8bd957SMatthew Dillon * 11661980eff3SMatthew Dillon * (at) will be NULL when soft-resetting a directly-attached device, and 11671980eff3SMatthew Dillon * non-NULL when soft-resetting a device through a port multiplier. 11681980eff3SMatthew Dillon * 1169fd8bd957SMatthew Dillon * This function keeps port communications intact and attempts to generate 11701980eff3SMatthew Dillon * a reset to the connected device using device commands. 1171fd8bd957SMatthew Dillon */ 1172258223a3SMatthew Dillon int 1173258223a3SMatthew Dillon ahci_port_softreset(struct ahci_port *ap) 1174258223a3SMatthew Dillon { 1175258223a3SMatthew Dillon struct ahci_ccb *ccb = NULL; 1176258223a3SMatthew Dillon struct ahci_cmd_hdr *cmd_slot; 1177258223a3SMatthew Dillon u_int8_t *fis; 11783209f581SMatthew Dillon int error; 1179258223a3SMatthew Dillon 11803209f581SMatthew Dillon error = EIO; 11811980eff3SMatthew Dillon 1182074579dfSMatthew Dillon if (bootverbose) { 11831980eff3SMatthew Dillon kprintf("%s: START SOFTRESET %b\n", PORTNAME(ap), 11841980eff3SMatthew Dillon ahci_pread(ap, AHCI_PREG_CMD), AHCI_PFMT_CMD); 1185074579dfSMatthew Dillon } 11861980eff3SMatthew Dillon 1187258223a3SMatthew Dillon DPRINTF(AHCI_D_VERBOSE, "%s: soft reset\n", PORTNAME(ap)); 1188258223a3SMatthew Dillon 1189258223a3SMatthew Dillon crit_enter(); 11901980eff3SMatthew Dillon ap->ap_flags |= AP_F_IN_RESET; 11911980eff3SMatthew Dillon ap->ap_state = AP_S_NORMAL; 1192258223a3SMatthew Dillon 11931980eff3SMatthew Dillon /* 11941980eff3SMatthew Dillon * Remember port state in cmd (main to restore start/stop) 11951980eff3SMatthew Dillon * 11961980eff3SMatthew Dillon * Idle port. 11971980eff3SMatthew Dillon */ 1198258223a3SMatthew Dillon if (ahci_port_stop(ap, 0)) { 1199258223a3SMatthew Dillon kprintf("%s: failed to stop port, cannot softreset\n", 1200258223a3SMatthew Dillon PORTNAME(ap)); 1201258223a3SMatthew Dillon goto err; 1202258223a3SMatthew Dillon } 1203cf5f3a81SMatthew Dillon 1204cf5f3a81SMatthew Dillon /* 12051980eff3SMatthew Dillon * Request CLO if device appears hung. 1206cf5f3a81SMatthew Dillon */ 1207258223a3SMatthew Dillon if (ahci_pread(ap, AHCI_PREG_TFD) & 1208258223a3SMatthew Dillon (AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) { 1209258223a3SMatthew Dillon ahci_port_clo(ap); 1210258223a3SMatthew Dillon } 1211258223a3SMatthew Dillon 12121980eff3SMatthew Dillon /* 12131980eff3SMatthew Dillon * This is an attempt to clear errors so a new signature will 12141980eff3SMatthew Dillon * be latched. It isn't working properly. XXX 12151980eff3SMatthew Dillon */ 1216cf5f3a81SMatthew Dillon ahci_flush_tfd(ap); 12171980eff3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 1218258223a3SMatthew Dillon 1219258223a3SMatthew Dillon /* Restart port */ 122017eab71eSMatthew Dillon if (ahci_port_start(ap)) { 1221258223a3SMatthew Dillon kprintf("%s: failed to start port, cannot softreset\n", 1222258223a3SMatthew Dillon PORTNAME(ap)); 1223258223a3SMatthew Dillon goto err; 1224258223a3SMatthew Dillon } 1225258223a3SMatthew Dillon 1226258223a3SMatthew Dillon /* Check whether CLO worked */ 1227258223a3SMatthew Dillon if (ahci_pwait_clr(ap, AHCI_PREG_TFD, 1228258223a3SMatthew Dillon AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) { 1229258223a3SMatthew Dillon kprintf("%s: CLO %s, need port reset\n", 1230258223a3SMatthew Dillon PORTNAME(ap), 1231258223a3SMatthew Dillon (ahci_read(ap->ap_sc, AHCI_REG_CAP) & AHCI_REG_CAP_SCLO) 1232258223a3SMatthew Dillon ? "failed" : "unsupported"); 12333209f581SMatthew Dillon error = EBUSY; 1234258223a3SMatthew Dillon goto err; 1235258223a3SMatthew Dillon } 1236258223a3SMatthew Dillon 1237cec85a37SMatthew Dillon /* 1238cec85a37SMatthew Dillon * Prep first D2H command with SRST feature & clear busy/reset flags 1239cec85a37SMatthew Dillon * 1240cec85a37SMatthew Dillon * It is unclear which other fields in the FIS are used. Just zero 1241cec85a37SMatthew Dillon * everything. 12421067474aSMatthew Dillon * 12431067474aSMatthew Dillon * NOTE! This CCB is used for both the first and second commands. 12441067474aSMatthew Dillon * The second command must use CCB slot 1 to properly load 12451067474aSMatthew Dillon * the signature. 1246cec85a37SMatthew Dillon */ 1247258223a3SMatthew Dillon ccb = ahci_get_err_ccb(ap); 124812feb904SMatthew Dillon ccb->ccb_xa.complete = ahci_dummy_done; 124912feb904SMatthew Dillon ccb->ccb_xa.flags = ATA_F_POLL | ATA_F_EXCLUSIVE; 12501067474aSMatthew Dillon KKASSERT(ccb->ccb_slot == 1); 12511980eff3SMatthew Dillon ccb->ccb_xa.at = NULL; 1252258223a3SMatthew Dillon cmd_slot = ccb->ccb_cmd_hdr; 1253258223a3SMatthew Dillon 1254258223a3SMatthew Dillon fis = ccb->ccb_cmd_table->cfis; 1255cec85a37SMatthew Dillon bzero(fis, sizeof(ccb->ccb_cmd_table->cfis)); 12561980eff3SMatthew Dillon fis[0] = ATA_FIS_TYPE_H2D; 12571980eff3SMatthew Dillon fis[15] = ATA_FIS_CONTROL_SRST|ATA_FIS_CONTROL_4BIT; 1258258223a3SMatthew Dillon 1259258223a3SMatthew Dillon cmd_slot->prdtl = 0; 1260258223a3SMatthew Dillon cmd_slot->flags = htole16(5); /* FIS length: 5 DWORDS */ 1261258223a3SMatthew Dillon cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_C); /* Clear busy on OK */ 1262258223a3SMatthew Dillon cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_R); /* Reset */ 1263258223a3SMatthew Dillon 1264258223a3SMatthew Dillon ccb->ccb_xa.state = ATA_S_PENDING; 126512feb904SMatthew Dillon 1266831bc9e3SMatthew Dillon if (ahci_poll(ccb, 1000, ahci_quick_timeout) != ATA_S_COMPLETE) { 12675f8c1efdSMatthew Dillon kprintf("%s: First FIS failed\n", PORTNAME(ap)); 1268258223a3SMatthew Dillon goto err; 1269cec85a37SMatthew Dillon } 1270258223a3SMatthew Dillon 1271cec85a37SMatthew Dillon /* 1272831bc9e3SMatthew Dillon * WARNING! TIME SENSITIVE SPACE! WARNING! 1273831bc9e3SMatthew Dillon * 1274831bc9e3SMatthew Dillon * The two FISes are supposed to be back to back. Don't issue other 1275831bc9e3SMatthew Dillon * commands or even delay if we can help it. 12761980eff3SMatthew Dillon */ 12771980eff3SMatthew Dillon 12781980eff3SMatthew Dillon /* 1279cec85a37SMatthew Dillon * Prep second D2H command to read status and complete reset sequence 1280cec85a37SMatthew Dillon * AHCI 10.4.1 and "Serial ATA Revision 2.6". I can't find the ATA 1281cec85a37SMatthew Dillon * Rev 2.6 and it is unclear how the second FIS should be set up 1282cec85a37SMatthew Dillon * from the AHCI document. 1283cec85a37SMatthew Dillon * 1284cec85a37SMatthew Dillon * It is unclear which other fields in the FIS are used. Just zero 1285cec85a37SMatthew Dillon * everything. 1286cec85a37SMatthew Dillon */ 128712feb904SMatthew Dillon ccb->ccb_xa.flags = ATA_F_POLL | ATA_F_AUTOSENSE | ATA_F_EXCLUSIVE; 128812feb904SMatthew Dillon 1289cec85a37SMatthew Dillon bzero(fis, sizeof(ccb->ccb_cmd_table->cfis)); 12901980eff3SMatthew Dillon fis[0] = ATA_FIS_TYPE_H2D; 12911980eff3SMatthew Dillon fis[15] = ATA_FIS_CONTROL_4BIT; 1292258223a3SMatthew Dillon 1293258223a3SMatthew Dillon cmd_slot->prdtl = 0; 1294258223a3SMatthew Dillon cmd_slot->flags = htole16(5); /* FIS length: 5 DWORDS */ 1295258223a3SMatthew Dillon 1296258223a3SMatthew Dillon ccb->ccb_xa.state = ATA_S_PENDING; 1297831bc9e3SMatthew Dillon if (ahci_poll(ccb, 1000, ahci_quick_timeout) != ATA_S_COMPLETE) { 12985f8c1efdSMatthew Dillon kprintf("%s: Second FIS failed\n", PORTNAME(ap)); 1299258223a3SMatthew Dillon goto err; 1300cec85a37SMatthew Dillon } 1301258223a3SMatthew Dillon 13021980eff3SMatthew Dillon if (ahci_pwait_clr(ap, AHCI_PREG_TFD, 13031980eff3SMatthew Dillon AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) { 1304258223a3SMatthew Dillon kprintf("%s: device didn't come ready after reset, TFD: 0x%b\n", 1305258223a3SMatthew Dillon PORTNAME(ap), 1306258223a3SMatthew Dillon ahci_pread(ap, AHCI_PREG_TFD), AHCI_PFMT_TFD_STS); 13073209f581SMatthew Dillon error = EBUSY; 1308258223a3SMatthew Dillon goto err; 1309258223a3SMatthew Dillon } 1310258223a3SMatthew Dillon 1311fd8bd957SMatthew Dillon /* 1312fd8bd957SMatthew Dillon * If the softreset is trying to clear a BSY condition after a 1313fd8bd957SMatthew Dillon * normal portreset we assign the port type. 1314fd8bd957SMatthew Dillon * 1315fd8bd957SMatthew Dillon * If the softreset is being run first as part of the ccb error 1316fd8bd957SMatthew Dillon * processing code then report if the device signature changed 1317fd8bd957SMatthew Dillon * unexpectedly. 1318fd8bd957SMatthew Dillon */ 1319493d3201SMatthew Dillon ahci_os_sleep(100); 13201980eff3SMatthew Dillon if (ap->ap_type == ATA_PORT_T_NONE) { 13211980eff3SMatthew Dillon ap->ap_type = ahci_port_signature_detect(ap, NULL); 1322fd8bd957SMatthew Dillon } else { 13231980eff3SMatthew Dillon if (ahci_port_signature_detect(ap, NULL) != ap->ap_type) { 13241980eff3SMatthew Dillon kprintf("%s: device signature unexpectedly " 13251980eff3SMatthew Dillon "changed\n", PORTNAME(ap)); 13263209f581SMatthew Dillon error = EBUSY; /* XXX */ 1327fd8bd957SMatthew Dillon } 1328fd8bd957SMatthew Dillon } 13293209f581SMatthew Dillon error = 0; 13301980eff3SMatthew Dillon 13313209f581SMatthew Dillon ahci_os_sleep(3); 1332258223a3SMatthew Dillon err: 1333258223a3SMatthew Dillon if (ccb != NULL) { 1334258223a3SMatthew Dillon ahci_put_err_ccb(ccb); 13351980eff3SMatthew Dillon 13361980eff3SMatthew Dillon /* 13371980eff3SMatthew Dillon * If the target is busy use CLO to clear the busy 13381980eff3SMatthew Dillon * condition. The BSY should be cleared on the next 13391980eff3SMatthew Dillon * start. 13401980eff3SMatthew Dillon */ 13411980eff3SMatthew Dillon if (ahci_pread(ap, AHCI_PREG_TFD) & 13421980eff3SMatthew Dillon (AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) { 13431980eff3SMatthew Dillon ahci_port_clo(ap); 13441980eff3SMatthew Dillon } 1345258223a3SMatthew Dillon } 1346258223a3SMatthew Dillon 1347cf5f3a81SMatthew Dillon /* 1348cf5f3a81SMatthew Dillon * If we failed to softreset make the port quiescent, otherwise 1349cf5f3a81SMatthew Dillon * make sure the port's start/stop state matches what it was on 1350cf5f3a81SMatthew Dillon * entry. 13511980eff3SMatthew Dillon * 13521980eff3SMatthew Dillon * Don't kill the port if the softreset is on a port multiplier 13531980eff3SMatthew Dillon * target, that would kill all the targets! 1354cf5f3a81SMatthew Dillon */ 13553209f581SMatthew Dillon if (error) { 1356cf5f3a81SMatthew Dillon ahci_port_hardstop(ap); 13573209f581SMatthew Dillon /* ap_probe set to failed */ 1358cf5f3a81SMatthew Dillon } else { 13593209f581SMatthew Dillon ap->ap_probe = ATA_PROBE_NEED_IDENT; 136012feb904SMatthew Dillon ap->ap_pmcount = 1; 13614c339a5fSMatthew Dillon ahci_port_start(ap); 1362cf5f3a81SMatthew Dillon } 13633209f581SMatthew Dillon ap->ap_flags &= ~AP_F_IN_RESET; 1364258223a3SMatthew Dillon crit_exit(); 1365258223a3SMatthew Dillon 1366074579dfSMatthew Dillon if (bootverbose) 13671980eff3SMatthew Dillon kprintf("%s: END SOFTRESET\n", PORTNAME(ap)); 13681980eff3SMatthew Dillon 13693209f581SMatthew Dillon return (error); 1370258223a3SMatthew Dillon } 1371258223a3SMatthew Dillon 1372fd8bd957SMatthew Dillon /* 1373493d3201SMatthew Dillon * Issue just do the core COMRESET and basic device detection on a port. 1374fd8bd957SMatthew Dillon * 1375493d3201SMatthew Dillon * NOTE: Only called by ahci_port_hardreset(). 1376fd8bd957SMatthew Dillon */ 13778119d5f5SMatthew Dillon int 1378493d3201SMatthew Dillon ahci_comreset(struct ahci_port *ap, int *pmdetectp) 1379258223a3SMatthew Dillon { 1380493d3201SMatthew Dillon u_int32_t cmd; 1381493d3201SMatthew Dillon u_int32_t r; 13823209f581SMatthew Dillon int error; 13831980eff3SMatthew Dillon int loop; 1384f2dba700SMatthew Dillon int retries = 0; 1385258223a3SMatthew Dillon 1386cf5f3a81SMatthew Dillon /* 1387eb9f4c83SMatthew Dillon * Idle the port. We must cycle FRE for certain chips that silently 1388eb9f4c83SMatthew Dillon * clear FR on disconnect. Normally we do not want to cycle FRE 1389eb9f4c83SMatthew Dillon * because other chipsets might react badly to that. 13901980eff3SMatthew Dillon */ 1391493d3201SMatthew Dillon *pmdetectp = 0; 1392eb9f4c83SMatthew Dillon if (ap->ap_sc->sc_flags & AHCI_F_CYCLE_FR) 1393eb9f4c83SMatthew Dillon ahci_port_stop(ap, 1); 1394eb9f4c83SMatthew Dillon else 13951980eff3SMatthew Dillon ahci_port_stop(ap, 0); 13961980eff3SMatthew Dillon ap->ap_state = AP_S_NORMAL; 1397493d3201SMatthew Dillon ahci_os_sleep(10); 13981980eff3SMatthew Dillon 13991980eff3SMatthew Dillon /* 14008119d5f5SMatthew Dillon * FIS-based switching must be turned off when doing a hardware 14018119d5f5SMatthew Dillon * reset, and will be turned on again during the PM probe. 14028119d5f5SMatthew Dillon */ 14038119d5f5SMatthew Dillon if (ap->ap_flags & AP_F_FBSS_ENABLED) { 14048119d5f5SMatthew Dillon ap->ap_flags &= ~AP_F_FBSS_ENABLED; 14058119d5f5SMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_FBS); 14068119d5f5SMatthew Dillon cmd &= ~AHCI_PREG_FBS_EN; 14078119d5f5SMatthew Dillon cmd |= AHCI_PREG_FBS_DEC; 14088119d5f5SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_FBS, cmd); 14098119d5f5SMatthew Dillon } 14108119d5f5SMatthew Dillon 14118119d5f5SMatthew Dillon /* 14121980eff3SMatthew Dillon * The port may have been quiescent with its SUD bit cleared, so 1413eb9f4c83SMatthew Dillon * set the SUD (spin up device). Also POD (Power up device), 1414eb9f4c83SMatthew Dillon * and issue an ICC_ACTIVE request to bring up communications. 1415493d3201SMatthew Dillon * 1416493d3201SMatthew Dillon * NOTE: I do not know if SUD is a hardware pin/low-level signal 1417493d3201SMatthew Dillon * or if it is messaged. 1418cf5f3a81SMatthew Dillon */ 1419eb9f4c83SMatthew Dillon r = ap->ap_sc->sc_ipm_disable; 1420eb9f4c83SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SCTL, r); 1421493d3201SMatthew Dillon 1422eb9f4c83SMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD) & ~AHCI_PREG_CMD_ICC; 1423493d3201SMatthew Dillon cmd |= AHCI_PREG_CMD_SUD | AHCI_PREG_CMD_POD; 1424eb9f4c83SMatthew Dillon cmd |= AHCI_PREG_CMD_ICC_ACTIVE; 1425cf5f3a81SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd); 1426eb9f4c83SMatthew Dillon ahci_pwait_clr(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_ICC); 1427eb9f4c83SMatthew Dillon 1428eb9f4c83SMatthew Dillon /* 1429eb9f4c83SMatthew Dillon * Some parts need FIS reception enabled to be able to COMINIT at 1430eb9f4c83SMatthew Dillon * all, so we can't delay FRE until port-start. Even though that 1431eb9f4c83SMatthew Dillon * isn't what the spec says. 1432eb9f4c83SMatthew Dillon * 1433eb9f4c83SMatthew Dillon * This is typically the first enablement of FRE, but in most cases 1434eb9f4c83SMatthew Dillon * we never turn it off making this a NOP for later calls. 1435eb9f4c83SMatthew Dillon */ 1436eb9f4c83SMatthew Dillon cmd |= AHCI_PREG_CMD_FRE; 1437eb9f4c83SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd); 1438eb9f4c83SMatthew Dillon if ((ap->ap_sc->sc_flags & AHCI_F_IGN_FR) == 0) 1439eb9f4c83SMatthew Dillon ahci_pwait_set(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_FR); 1440258223a3SMatthew Dillon 14411980eff3SMatthew Dillon /* 1442493d3201SMatthew Dillon * Make sure that all power management is disabled. 14431067474aSMatthew Dillon * 1444493d3201SMatthew Dillon * NOTE! AHCI_PREG_SCTL_DET_DISABLE seems to be highly unreliable 14454e21f4daSMatthew Dillon * on multiple chipsets and can brick the chipset or even 14464e21f4daSMatthew Dillon * the whole PC. Never use it. 14471980eff3SMatthew Dillon */ 14481980eff3SMatthew Dillon ap->ap_type = ATA_PORT_T_NONE; 1449258223a3SMatthew Dillon 1450f2dba700SMatthew Dillon retry: 1451f2dba700SMatthew Dillon /* 1452f2dba700SMatthew Dillon * Give the new power management state time to settle, then clear 1453f2dba700SMatthew Dillon * pending status. 1454f2dba700SMatthew Dillon */ 1455f2dba700SMatthew Dillon ahci_os_sleep(1000); 1456f2dba700SMatthew Dillon ahci_flush_tfd(ap); 1457f2dba700SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 14581980eff3SMatthew Dillon 14591980eff3SMatthew Dillon /* 1460493d3201SMatthew Dillon * Start transmitting COMRESET. The spec says that COMRESET must 1461493d3201SMatthew Dillon * be sent for at least 1ms but in actual fact numerous devices 1462493d3201SMatthew Dillon * appear to take much longer. Delay a whole second here. 1463493d3201SMatthew Dillon * 1464493d3201SMatthew Dillon * In addition, SATA-3 ports can take longer to train, so even 1465493d3201SMatthew Dillon * SATA-2 devices which would normally detect very quickly may 1466493d3201SMatthew Dillon * take longer when plugged into a SATA-3 port. 14671980eff3SMatthew Dillon */ 1468493d3201SMatthew Dillon r |= AHCI_PREG_SCTL_DET_INIT; 14698986d351SMatthew Dillon switch(AhciForceGen) { 14708986d351SMatthew Dillon case 0: 1471258223a3SMatthew Dillon r |= AHCI_PREG_SCTL_SPD_ANY; 14728986d351SMatthew Dillon break; 14738986d351SMatthew Dillon case 1: 14748986d351SMatthew Dillon r |= AHCI_PREG_SCTL_SPD_GEN1; 14758986d351SMatthew Dillon break; 14768986d351SMatthew Dillon case 2: 14778986d351SMatthew Dillon r |= AHCI_PREG_SCTL_SPD_GEN2; 14788986d351SMatthew Dillon break; 14798986d351SMatthew Dillon case 3: 14808986d351SMatthew Dillon r |= AHCI_PREG_SCTL_SPD_GEN3; 14818986d351SMatthew Dillon break; 14828986d351SMatthew Dillon default: 14838986d351SMatthew Dillon r |= AHCI_PREG_SCTL_SPD_GEN3; 14848986d351SMatthew Dillon break; 14858986d351SMatthew Dillon } 1486258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SCTL, r); 1487492bffafSMatthew Dillon ahci_os_sleep(1000); 1488493d3201SMatthew Dillon 1489492bffafSMatthew Dillon ap->ap_flags &= ~AP_F_HARSH_REINIT; 1490cf5f3a81SMatthew Dillon 1491cf5f3a81SMatthew Dillon /* 1492cf5f3a81SMatthew Dillon * Only SERR_DIAG_X needs to be cleared for TFD updates, but 1493cf5f3a81SMatthew Dillon * since we are hard-resetting the port we might as well clear 1494f2dba700SMatthew Dillon * the whole enchillada. Also be sure to clear any spurious BSY 1495f2dba700SMatthew Dillon * prior to clearing INIT. 1496493d3201SMatthew Dillon * 1497493d3201SMatthew Dillon * Wait 1 whole second after clearing INIT before checking 1498493d3201SMatthew Dillon * the device detection bits in an attempt to work around chipsets 1499493d3201SMatthew Dillon * which do not properly mask PCS/PRCS during low level init. 1500cf5f3a81SMatthew Dillon */ 1501cf5f3a81SMatthew Dillon ahci_flush_tfd(ap); 1502cf5f3a81SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 1503f2dba700SMatthew Dillon /* ahci_port_clo(ap);*/ 1504493d3201SMatthew Dillon ahci_os_sleep(10); 1505493d3201SMatthew Dillon 1506f2dba700SMatthew Dillon r &= ~AHCI_PREG_SCTL_SPD; 1507258223a3SMatthew Dillon r &= ~AHCI_PREG_SCTL_DET_INIT; 1508258223a3SMatthew Dillon r |= AHCI_PREG_SCTL_DET_NONE; 1509258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SCTL, r); 1510493d3201SMatthew Dillon ahci_os_sleep(1000); 1511258223a3SMatthew Dillon 15121980eff3SMatthew Dillon /* 1513*46d04d11SMatthew Dillon * Try to determine if there is a device on the port. This operation 1514*46d04d11SMatthew Dillon * typically runs in parallel on all ports belonging to an AHCI 1515*46d04d11SMatthew Dillon * controller. 15161980eff3SMatthew Dillon * 1517*46d04d11SMatthew Dillon * 3/10 of a second (loop = 300) is plenty for directly attached 1518*46d04d11SMatthew Dillon * devices, but not enough for some port multipliers, particularly 1519*46d04d11SMatthew Dillon * if powered-on cold. Since this operation runs in parallel, 1520*46d04d11SMatthew Dillon * give us 2 seconds to detect. 1521*46d04d11SMatthew Dillon * 1522*46d04d11SMatthew Dillon * NOTE: The 10-second hot-swap delay prior to the COMRESET is not 1523*46d04d11SMatthew Dillon * sufficient, since the first COMRESET after a cold power-on 1524*46d04d11SMatthew Dillon * of a port-multiplier can take extra time. 1525*46d04d11SMatthew Dillon * 15261980eff3SMatthew Dillon * If we fail clear PRCS (phy detect) since we may cycled 15271980eff3SMatthew Dillon * the phy and probably caused another PRCS interrupt. 15281980eff3SMatthew Dillon */ 1529*46d04d11SMatthew Dillon loop = 2000; 153076497a9cSMatthew Dillon while (loop > 0) { 15311980eff3SMatthew Dillon r = ahci_pread(ap, AHCI_PREG_SSTS); 15321980eff3SMatthew Dillon if (r & AHCI_PREG_SSTS_DET) 15331980eff3SMatthew Dillon break; 153476497a9cSMatthew Dillon loop -= ahci_os_softsleep(); 15351980eff3SMatthew Dillon } 15361980eff3SMatthew Dillon if (loop == 0) { 15371980eff3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_PRCS); 1538074579dfSMatthew Dillon if (bootverbose) { 15391980eff3SMatthew Dillon kprintf("%s: Port appears to be unplugged\n", 15401980eff3SMatthew Dillon PORTNAME(ap)); 1541074579dfSMatthew Dillon } 15423209f581SMatthew Dillon error = ENODEV; 154312feb904SMatthew Dillon goto done; 1544258223a3SMatthew Dillon } 1545258223a3SMatthew Dillon 1546cec85a37SMatthew Dillon /* 1547493d3201SMatthew Dillon * There is something on the port. Regardless of what happens 1548493d3201SMatthew Dillon * after this tell the caller to try to detect a port multiplier. 1549493d3201SMatthew Dillon * 1550493d3201SMatthew Dillon * Give the device 3 seconds to fully negotiate. 15511980eff3SMatthew Dillon */ 1552493d3201SMatthew Dillon *pmdetectp = 1; 1553493d3201SMatthew Dillon 155412feb904SMatthew Dillon if (ahci_pwait_eq(ap, 3000, AHCI_PREG_SSTS, 15551980eff3SMatthew Dillon AHCI_PREG_SSTS_DET, AHCI_PREG_SSTS_DET_DEV)) { 1556074579dfSMatthew Dillon if (bootverbose) { 15571980eff3SMatthew Dillon kprintf("%s: Device may be powered down\n", 15581980eff3SMatthew Dillon PORTNAME(ap)); 1559074579dfSMatthew Dillon } 15603209f581SMatthew Dillon error = ENODEV; 1561493d3201SMatthew Dillon goto done; 15621980eff3SMatthew Dillon } 15631980eff3SMatthew Dillon 156412feb904SMatthew Dillon /* 156512feb904SMatthew Dillon * We got something that definitely looks like a device. Give 156612feb904SMatthew Dillon * the device time to send us its first D2H FIS. Waiting for 156712feb904SMatthew Dillon * BSY to clear accomplishes this. 156812feb904SMatthew Dillon * 1569*46d04d11SMatthew Dillon * The target device might be hung in a BSY state depending on 1570*46d04d11SMatthew Dillon * the order things are power cycled. We want to retry the COMRESET 1571*46d04d11SMatthew Dillon * at least once if we find the device BSY for reliable operation. 1572*46d04d11SMatthew Dillon * 1573493d3201SMatthew Dillon * NOTE: A port multiplier may or may not clear BSY here, 1574*46d04d11SMatthew Dillon * particularly if it was previously configured and now 1575*46d04d11SMatthew Dillon * its cable has been unplugged and plugged back in, 1576*46d04d11SMatthew Dillon * and also depending on what is sitting in target 0 behind it. 1577f2dba700SMatthew Dillon * 1578f2dba700SMatthew Dillon * NOTE: Intel SSDs seem to have compatibility problems with Intel 1579f2dba700SMatthew Dillon * mobo's on cold boots and may leave BSY set. A single 1580f2dba700SMatthew Dillon * retry works around the problem. This is definitely a bug 1581f2dba700SMatthew Dillon * with the mobo and/or the SSD and does not appear to occur 1582f2dba700SMatthew Dillon * with other devices connected to the same port. 158312feb904SMatthew Dillon */ 1584c408a8b3SMatthew Dillon ahci_flush_tfd(ap); 1585f2dba700SMatthew Dillon if (ahci_pwait_clr_to(ap, 8000, AHCI_PREG_TFD, 15861980eff3SMatthew Dillon AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) { 1587f2dba700SMatthew Dillon kprintf("%s: Device BUSY: %b\n", 1588f2dba700SMatthew Dillon PORTNAME(ap), 1589f2dba700SMatthew Dillon ahci_pread(ap, AHCI_PREG_TFD), 1590f2dba700SMatthew Dillon AHCI_PFMT_TFD_STS); 1591f2dba700SMatthew Dillon if (retries == 0) { 1592f2dba700SMatthew Dillon kprintf("%s: Retrying\n", PORTNAME(ap)); 1593f2dba700SMatthew Dillon retries = 1; 1594f2dba700SMatthew Dillon goto retry; 1595f2dba700SMatthew Dillon } 159612feb904SMatthew Dillon error = EBUSY; 15971980eff3SMatthew Dillon } else { 1598*46d04d11SMatthew Dillon if (retries) 1599*46d04d11SMatthew Dillon kprintf("%s: Device Unbusied after retry\n", 1600*46d04d11SMatthew Dillon PORTNAME(ap)); 16013209f581SMatthew Dillon error = 0; 16021980eff3SMatthew Dillon } 1603258223a3SMatthew Dillon 160412feb904SMatthew Dillon done: 1605493d3201SMatthew Dillon ahci_flush_tfd(ap); 1606493d3201SMatthew Dillon return error; 1607493d3201SMatthew Dillon } 1608493d3201SMatthew Dillon 1609493d3201SMatthew Dillon 1610493d3201SMatthew Dillon /* 1611493d3201SMatthew Dillon * AHCI port reset, Section 10.4.2 1612493d3201SMatthew Dillon * 1613493d3201SMatthew Dillon * This function does a hard reset of the port. Note that the device 1614493d3201SMatthew Dillon * connected to the port could still end-up hung. 1615493d3201SMatthew Dillon */ 1616493d3201SMatthew Dillon int 1617493d3201SMatthew Dillon ahci_port_hardreset(struct ahci_port *ap, int hard) 1618493d3201SMatthew Dillon { 1619493d3201SMatthew Dillon u_int32_t data; 1620493d3201SMatthew Dillon int error; 1621493d3201SMatthew Dillon int pmdetect; 1622493d3201SMatthew Dillon 1623493d3201SMatthew Dillon if (bootverbose) 1624493d3201SMatthew Dillon kprintf("%s: START HARDRESET\n", PORTNAME(ap)); 1625493d3201SMatthew Dillon ap->ap_flags |= AP_F_IN_RESET; 1626493d3201SMatthew Dillon 1627493d3201SMatthew Dillon error = ahci_comreset(ap, &pmdetect); 1628493d3201SMatthew Dillon 1629493d3201SMatthew Dillon /* 1630493d3201SMatthew Dillon * We may be asked to perform a port multiplier check even if the 1631493d3201SMatthew Dillon * comreset failed. This typically occurs when the PM has nothing 1632493d3201SMatthew Dillon * in slot 0, which can cause BSY to remain set. 1633493d3201SMatthew Dillon * 1634493d3201SMatthew Dillon * If the PM detection is successful it will override (error), 1635493d3201SMatthew Dillon * otherwise (error) is retained. If an error does occur it 1636493d3201SMatthew Dillon * is possible that a normal device has blown up on us DUE to 1637493d3201SMatthew Dillon * the PM detection code, so re-run the comreset and assume 1638493d3201SMatthew Dillon * a normal device. 1639493d3201SMatthew Dillon */ 1640493d3201SMatthew Dillon if (pmdetect) { 1641493d3201SMatthew Dillon if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SPM) { 1642493d3201SMatthew Dillon error = ahci_pm_port_probe(ap, error); 1643493d3201SMatthew Dillon if (error) { 1644493d3201SMatthew Dillon error = ahci_comreset(ap, &pmdetect); 1645493d3201SMatthew Dillon } 1646493d3201SMatthew Dillon } 1647493d3201SMatthew Dillon } 1648493d3201SMatthew Dillon 164912feb904SMatthew Dillon /* 165012feb904SMatthew Dillon * Finish up. 165112feb904SMatthew Dillon */ 1652493d3201SMatthew Dillon ahci_os_sleep(500); 1653493d3201SMatthew Dillon 165412feb904SMatthew Dillon switch(error) { 165512feb904SMatthew Dillon case 0: 165612feb904SMatthew Dillon /* 165712feb904SMatthew Dillon * All good, make sure the port is running and set the 165812feb904SMatthew Dillon * probe state. Ignore the signature junk (it's unreliable) 165912feb904SMatthew Dillon * until we get to the softreset code. 166012feb904SMatthew Dillon */ 166112feb904SMatthew Dillon if (ahci_port_start(ap)) { 166212feb904SMatthew Dillon kprintf("%s: failed to start command DMA on port, " 166312feb904SMatthew Dillon "disabling\n", PORTNAME(ap)); 166412feb904SMatthew Dillon error = EBUSY; 1665493d3201SMatthew Dillon break; 166612feb904SMatthew Dillon } 1667f4553de1SMatthew Dillon if (ap->ap_type == ATA_PORT_T_PM) 1668f4553de1SMatthew Dillon ap->ap_probe = ATA_PROBE_GOOD; 1669f4553de1SMatthew Dillon else 1670f4553de1SMatthew Dillon ap->ap_probe = ATA_PROBE_NEED_SOFT_RESET; 167112feb904SMatthew Dillon break; 167212feb904SMatthew Dillon case ENODEV: 1673fd8bd957SMatthew Dillon /* 167412feb904SMatthew Dillon * Normal device probe failure 16751980eff3SMatthew Dillon */ 167612feb904SMatthew Dillon data = ahci_pread(ap, AHCI_PREG_SSTS); 16771980eff3SMatthew Dillon 167812feb904SMatthew Dillon switch(data & AHCI_PREG_SSTS_DET) { 167912feb904SMatthew Dillon case AHCI_PREG_SSTS_DET_DEV_NE: 168012feb904SMatthew Dillon kprintf("%s: Device not communicating\n", 16811980eff3SMatthew Dillon PORTNAME(ap)); 168212feb904SMatthew Dillon break; 168312feb904SMatthew Dillon case AHCI_PREG_SSTS_DET_PHYOFFLINE: 168412feb904SMatthew Dillon kprintf("%s: PHY offline\n", 168512feb904SMatthew Dillon PORTNAME(ap)); 168612feb904SMatthew Dillon break; 168712feb904SMatthew Dillon default: 168812feb904SMatthew Dillon kprintf("%s: No device detected\n", 168912feb904SMatthew Dillon PORTNAME(ap)); 169012feb904SMatthew Dillon break; 16911980eff3SMatthew Dillon } 169212feb904SMatthew Dillon ahci_port_hardstop(ap); 169312feb904SMatthew Dillon break; 169412feb904SMatthew Dillon default: 16951980eff3SMatthew Dillon /* 169612feb904SMatthew Dillon * Abnormal probe (EBUSY) 16971980eff3SMatthew Dillon */ 169812feb904SMatthew Dillon kprintf("%s: Device on port is bricked\n", 169912feb904SMatthew Dillon PORTNAME(ap)); 170012feb904SMatthew Dillon ahci_port_hardstop(ap); 170112feb904SMatthew Dillon #if 0 170212feb904SMatthew Dillon rc = ahci_port_reset(ap, atx, 0); 170312feb904SMatthew Dillon if (rc) { 170412feb904SMatthew Dillon kprintf("%s: Unable unbrick device\n", 170512feb904SMatthew Dillon PORTNAME(ap)); 17061980eff3SMatthew Dillon } else { 170712feb904SMatthew Dillon kprintf("%s: Successfully unbricked\n", 17083209f581SMatthew Dillon PORTNAME(ap)); 170912feb904SMatthew Dillon } 171012feb904SMatthew Dillon #endif 171112feb904SMatthew Dillon break; 17123209f581SMatthew Dillon } 17131067474aSMatthew Dillon 17141067474aSMatthew Dillon /* 171512feb904SMatthew Dillon * Clean up 17161067474aSMatthew Dillon */ 171712feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 171812feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_PCS | AHCI_PREG_IS_PRCS); 17193209f581SMatthew Dillon 172012feb904SMatthew Dillon ap->ap_flags &= ~AP_F_IN_RESET; 17211980eff3SMatthew Dillon 172212feb904SMatthew Dillon if (bootverbose) 172312feb904SMatthew Dillon kprintf("%s: END HARDRESET %d\n", PORTNAME(ap), error); 1724831bc9e3SMatthew Dillon return (error); 17251980eff3SMatthew Dillon } 17261980eff3SMatthew Dillon 17271980eff3SMatthew Dillon /* 1728cf5f3a81SMatthew Dillon * Hard-stop on hot-swap device removal. See 10.10.1 1729cf5f3a81SMatthew Dillon * 1730cf5f3a81SMatthew Dillon * Place the port in a mode that will allow it to detect hot-swap insertions. 1731cf5f3a81SMatthew Dillon * This is a bit imprecise because just setting-up SCTL to DET_INIT doesn't 1732cf5f3a81SMatthew Dillon * seem to do the job. 1733f17a0cedSMatthew Dillon * 1734f17a0cedSMatthew Dillon * FIS reception is left enabled but command processing is disabled. 1735f17a0cedSMatthew Dillon * Cycling FIS reception (FRE) can brick ports. 1736cf5f3a81SMatthew Dillon */ 1737cf5f3a81SMatthew Dillon void 1738cf5f3a81SMatthew Dillon ahci_port_hardstop(struct ahci_port *ap) 1739cf5f3a81SMatthew Dillon { 174076497a9cSMatthew Dillon struct ahci_ccb *ccb; 17411980eff3SMatthew Dillon struct ata_port *at; 1742cf5f3a81SMatthew Dillon u_int32_t r; 1743cf5f3a81SMatthew Dillon u_int32_t cmd; 174476497a9cSMatthew Dillon int slot; 17451980eff3SMatthew Dillon int i; 1746bb79834dSMatthew Dillon int serial; 1747cf5f3a81SMatthew Dillon 1748cf5f3a81SMatthew Dillon /* 1749cf5f3a81SMatthew Dillon * Stop the port. We can't modify things like SUD if the port 1750cf5f3a81SMatthew Dillon * is running. 1751cf5f3a81SMatthew Dillon */ 1752cf5f3a81SMatthew Dillon ap->ap_state = AP_S_FATAL_ERROR; 17531980eff3SMatthew Dillon ap->ap_probe = ATA_PROBE_FAILED; 17541980eff3SMatthew Dillon ap->ap_type = ATA_PORT_T_NONE; 1755cf5f3a81SMatthew Dillon ahci_port_stop(ap, 0); 1756cf5f3a81SMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD); 1757492bffafSMatthew Dillon cmd &= ~(AHCI_PREG_CMD_CLO | AHCI_PREG_CMD_PMA | AHCI_PREG_CMD_ICC); 1758492bffafSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd); 1759cf5f3a81SMatthew Dillon 1760cf5f3a81SMatthew Dillon /* 17611980eff3SMatthew Dillon * Clean up AT sub-ports on SATA port. 17621980eff3SMatthew Dillon */ 17631980eff3SMatthew Dillon for (i = 0; ap->ap_ata && i < AHCI_MAX_PMPORTS; ++i) { 1764b012a2caSMatthew Dillon at = ap->ap_ata[i]; 17651980eff3SMatthew Dillon at->at_type = ATA_PORT_T_NONE; 17663209f581SMatthew Dillon at->at_probe = ATA_PROBE_FAILED; 17671980eff3SMatthew Dillon } 17681980eff3SMatthew Dillon 17691980eff3SMatthew Dillon /* 1770cf5f3a81SMatthew Dillon * 10.10.1 place us in the Listen state. 1771cf5f3a81SMatthew Dillon * 17725502cf24SMatthew Dillon * 10.10.3 DET must be set to 0 and found to be 0 before 17735502cf24SMatthew Dillon * setting SUD to 0. 17745502cf24SMatthew Dillon * 17755502cf24SMatthew Dillon * Deactivating SUD only applies if the controller supports SUD, it 17765502cf24SMatthew Dillon * is a bit unclear what happens w/regards to detecting hotplug 17775502cf24SMatthew Dillon * if it doesn't. 1778eb9f4c83SMatthew Dillon * 1779eb9f4c83SMatthew Dillon * NOTE: AHCI_PREG_SCTL_SPM_* bits are not implemented by the spec 1780eb9f4c83SMatthew Dillon * and must be zero. 1781cf5f3a81SMatthew Dillon */ 1782eb9f4c83SMatthew Dillon r = ap->ap_sc->sc_ipm_disable; 17835502cf24SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SCTL, r); 17845502cf24SMatthew Dillon ahci_os_sleep(10); 1785eb9f4c83SMatthew Dillon 1786eb9f4c83SMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD); 1787cf5f3a81SMatthew Dillon cmd &= ~AHCI_PREG_CMD_SUD; 1788cf5f3a81SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd); 17895502cf24SMatthew Dillon ahci_os_sleep(10); 1790cf5f3a81SMatthew Dillon 1791cf5f3a81SMatthew Dillon /* 17925502cf24SMatthew Dillon * 10.10.1 17935502cf24SMatthew Dillon * 17945502cf24SMatthew Dillon * Transition su to the spin-up state. HBA shall send COMRESET and 17955502cf24SMatthew Dillon * begin initialization sequence (whatever that means). Presumably 17965502cf24SMatthew Dillon * this is edge-triggered. Following the spin-up state the HBA 17975502cf24SMatthew Dillon * will automatically transition to the Normal state. 1798cf5f3a81SMatthew Dillon * 1799cf5f3a81SMatthew Dillon * This only applies if the controller supports SUD. 18004e21f4daSMatthew Dillon * NEVER use AHCI_PREG_DET_DISABLE. 1801cf5f3a81SMatthew Dillon */ 18025502cf24SMatthew Dillon cmd |= AHCI_PREG_CMD_POD | 18035502cf24SMatthew Dillon AHCI_PREG_CMD_SUD | 18045502cf24SMatthew Dillon AHCI_PREG_CMD_ICC_ACTIVE; 1805cf5f3a81SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CMD, cmd); 1806eb9f4c83SMatthew Dillon ahci_pwait_clr(ap, AHCI_PREG_CMD, AHCI_PREG_CMD_ICC); 1807cf5f3a81SMatthew Dillon 1808cf5f3a81SMatthew Dillon /* 1809cf5f3a81SMatthew Dillon * Flush SERR_DIAG_X so the TFD can update. 1810cf5f3a81SMatthew Dillon */ 1811cf5f3a81SMatthew Dillon ahci_flush_tfd(ap); 1812cf5f3a81SMatthew Dillon 1813cf5f3a81SMatthew Dillon /* 181476497a9cSMatthew Dillon * Clean out pending ccbs 181576497a9cSMatthew Dillon */ 1816bb79834dSMatthew Dillon restart: 181776497a9cSMatthew Dillon while (ap->ap_active) { 181876497a9cSMatthew Dillon slot = ffs(ap->ap_active) - 1; 181976497a9cSMatthew Dillon ap->ap_active &= ~(1 << slot); 182076497a9cSMatthew Dillon --ap->ap_active_cnt; 182176497a9cSMatthew Dillon ccb = &ap->ap_ccbs[slot]; 182276497a9cSMatthew Dillon if (ccb->ccb_xa.flags & ATA_F_TIMEOUT_RUNNING) { 1823bb79834dSMatthew Dillon serial = ccb->ccb_xa.serial; 182446528d33SMatthew Dillon callout_stop_sync(&ccb->ccb_timeout); 1825bb79834dSMatthew Dillon if (serial != ccb->ccb_xa.serial) { 1826bb79834dSMatthew Dillon kprintf("%s: Warning: timeout race ccb %p\n", 1827bb79834dSMatthew Dillon PORTNAME(ap), ccb); 1828bb79834dSMatthew Dillon goto restart; 1829bb79834dSMatthew Dillon } 183076497a9cSMatthew Dillon ccb->ccb_xa.flags &= ~ATA_F_TIMEOUT_RUNNING; 183176497a9cSMatthew Dillon } 183246528d33SMatthew Dillon ap->ap_expired &= ~(1 << slot); 183376497a9cSMatthew Dillon ccb->ccb_xa.flags &= ~(ATA_F_TIMEOUT_DESIRED | 183476497a9cSMatthew Dillon ATA_F_TIMEOUT_EXPIRED); 183576497a9cSMatthew Dillon ccb->ccb_xa.state = ATA_S_TIMEOUT; 183676497a9cSMatthew Dillon ccb->ccb_done(ccb); 183776497a9cSMatthew Dillon ccb->ccb_xa.complete(&ccb->ccb_xa); 183876497a9cSMatthew Dillon } 183976497a9cSMatthew Dillon while (ap->ap_sactive) { 184076497a9cSMatthew Dillon slot = ffs(ap->ap_sactive) - 1; 184176497a9cSMatthew Dillon ap->ap_sactive &= ~(1 << slot); 184276497a9cSMatthew Dillon ccb = &ap->ap_ccbs[slot]; 184376497a9cSMatthew Dillon if (ccb->ccb_xa.flags & ATA_F_TIMEOUT_RUNNING) { 1844bb79834dSMatthew Dillon serial = ccb->ccb_xa.serial; 184546528d33SMatthew Dillon callout_stop_sync(&ccb->ccb_timeout); 1846bb79834dSMatthew Dillon if (serial != ccb->ccb_xa.serial) { 1847bb79834dSMatthew Dillon kprintf("%s: Warning: timeout race ccb %p\n", 1848bb79834dSMatthew Dillon PORTNAME(ap), ccb); 1849bb79834dSMatthew Dillon goto restart; 1850bb79834dSMatthew Dillon } 185176497a9cSMatthew Dillon ccb->ccb_xa.flags &= ~ATA_F_TIMEOUT_RUNNING; 185276497a9cSMatthew Dillon } 185346528d33SMatthew Dillon ap->ap_expired &= ~(1 << slot); 185476497a9cSMatthew Dillon ccb->ccb_xa.flags &= ~(ATA_F_TIMEOUT_DESIRED | 185576497a9cSMatthew Dillon ATA_F_TIMEOUT_EXPIRED); 185676497a9cSMatthew Dillon ccb->ccb_xa.state = ATA_S_TIMEOUT; 185776497a9cSMatthew Dillon ccb->ccb_done(ccb); 185876497a9cSMatthew Dillon ccb->ccb_xa.complete(&ccb->ccb_xa); 185976497a9cSMatthew Dillon } 186076497a9cSMatthew Dillon KKASSERT(ap->ap_active_cnt == 0); 186176497a9cSMatthew Dillon 186276497a9cSMatthew Dillon while ((ccb = TAILQ_FIRST(&ap->ap_ccb_pending)) != NULL) { 186376497a9cSMatthew Dillon TAILQ_REMOVE(&ap->ap_ccb_pending, ccb, ccb_entry); 186476497a9cSMatthew Dillon ccb->ccb_xa.state = ATA_S_TIMEOUT; 186576497a9cSMatthew Dillon ccb->ccb_xa.flags &= ~ATA_F_TIMEOUT_DESIRED; 186676497a9cSMatthew Dillon ccb->ccb_done(ccb); 186776497a9cSMatthew Dillon ccb->ccb_xa.complete(&ccb->ccb_xa); 186876497a9cSMatthew Dillon } 186976497a9cSMatthew Dillon 187076497a9cSMatthew Dillon /* 18715502cf24SMatthew Dillon * Hot-plug device detection should work at this point. e.g. on 18725502cf24SMatthew Dillon * AMD chipsets Spin-Up/Normal state is sufficient for hot-plug 18735502cf24SMatthew Dillon * detection and entering RESET (continuous COMRESET by setting INIT) 18745502cf24SMatthew Dillon * will actually prevent hot-plug detection from working properly. 1875cf5f3a81SMatthew Dillon * 18765502cf24SMatthew Dillon * There may be cases where this will fail to work, I have some 18775502cf24SMatthew Dillon * additional code to place the HBA in RESET (send continuous 18785502cf24SMatthew Dillon * COMRESET) and hopefully get DIAG.X or other events when something 18795502cf24SMatthew Dillon * is plugged in. Unfortunately this isn't universal and can 18805502cf24SMatthew Dillon * also prevent events from generating interrupts. 1881cf5f3a81SMatthew Dillon */ 18825502cf24SMatthew Dillon 18835502cf24SMatthew Dillon #if 0 18845502cf24SMatthew Dillon /* 18855502cf24SMatthew Dillon * Transition us to the Reset state. Theoretically we send a 18865502cf24SMatthew Dillon * continuous stream of COMRESETs in this state. 18875502cf24SMatthew Dillon */ 18885502cf24SMatthew Dillon r |= AHCI_PREG_SCTL_DET_INIT; 18895502cf24SMatthew Dillon if (AhciForceGen1 & (1 << ap->ap_num)) { 18905502cf24SMatthew Dillon kprintf("%s: Force 1.5Gbits\n", PORTNAME(ap)); 18915502cf24SMatthew Dillon r |= AHCI_PREG_SCTL_SPD_GEN1; 18925502cf24SMatthew Dillon } else { 18935502cf24SMatthew Dillon r |= AHCI_PREG_SCTL_SPD_ANY; 18945502cf24SMatthew Dillon } 18955502cf24SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SCTL, r); 18965502cf24SMatthew Dillon ahci_os_sleep(10); 18975502cf24SMatthew Dillon 18985502cf24SMatthew Dillon /* 18995502cf24SMatthew Dillon * Flush SERR_DIAG_X so the TFD can update. 19005502cf24SMatthew Dillon */ 19015502cf24SMatthew Dillon ahci_flush_tfd(ap); 19025502cf24SMatthew Dillon #endif 1903cf5f3a81SMatthew Dillon /* NOP */ 1904cf5f3a81SMatthew Dillon } 1905cf5f3a81SMatthew Dillon 1906cf5f3a81SMatthew Dillon /* 1907c408a8b3SMatthew Dillon * We can't loop on the X bit, a continuous COMINIT received will make 1908c408a8b3SMatthew Dillon * it loop forever. Just assume one event has built up and clear X 1909c408a8b3SMatthew Dillon * so the task file descriptor can update. 1910cf5f3a81SMatthew Dillon */ 1911cf5f3a81SMatthew Dillon void 1912cf5f3a81SMatthew Dillon ahci_flush_tfd(struct ahci_port *ap) 1913cf5f3a81SMatthew Dillon { 1914cf5f3a81SMatthew Dillon u_int32_t r; 1915cf5f3a81SMatthew Dillon 1916cf5f3a81SMatthew Dillon r = ahci_pread(ap, AHCI_PREG_SERR); 1917c408a8b3SMatthew Dillon if (r & AHCI_PREG_SERR_DIAG_X) 19181980eff3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, AHCI_PREG_SERR_DIAG_X); 1919cf5f3a81SMatthew Dillon } 1920cf5f3a81SMatthew Dillon 1921cf5f3a81SMatthew Dillon /* 1922fd8bd957SMatthew Dillon * Figure out what type of device is connected to the port, ATAPI or 1923fd8bd957SMatthew Dillon * DISK. 1924fd8bd957SMatthew Dillon */ 1925fd8bd957SMatthew Dillon int 19261980eff3SMatthew Dillon ahci_port_signature_detect(struct ahci_port *ap, struct ata_port *at) 1927fd8bd957SMatthew Dillon { 1928fd8bd957SMatthew Dillon u_int32_t sig; 1929fd8bd957SMatthew Dillon 1930fd8bd957SMatthew Dillon sig = ahci_pread(ap, AHCI_PREG_SIG); 1931074579dfSMatthew Dillon if (bootverbose) 1932*46d04d11SMatthew Dillon kprintf("%s: SIG %08x\n", ATANAME(ap, at), sig); 1933fd8bd957SMatthew Dillon if ((sig & 0xffff0000) == (SATA_SIGNATURE_ATAPI & 0xffff0000)) { 1934fd8bd957SMatthew Dillon return(ATA_PORT_T_ATAPI); 19351980eff3SMatthew Dillon } else if ((sig & 0xffff0000) == 19361980eff3SMatthew Dillon (SATA_SIGNATURE_PORT_MULTIPLIER & 0xffff0000)) { 19371980eff3SMatthew Dillon return(ATA_PORT_T_PM); 1938fd8bd957SMatthew Dillon } else { 1939fd8bd957SMatthew Dillon return(ATA_PORT_T_DISK); 1940fd8bd957SMatthew Dillon } 1941fd8bd957SMatthew Dillon } 1942fd8bd957SMatthew Dillon 1943fd8bd957SMatthew Dillon /* 1944fd8bd957SMatthew Dillon * Load the DMA descriptor table for a CCB's buffer. 1945fd8bd957SMatthew Dillon */ 1946258223a3SMatthew Dillon int 1947258223a3SMatthew Dillon ahci_load_prdt(struct ahci_ccb *ccb) 1948258223a3SMatthew Dillon { 1949258223a3SMatthew Dillon struct ahci_port *ap = ccb->ccb_port; 1950258223a3SMatthew Dillon struct ahci_softc *sc = ap->ap_sc; 1951258223a3SMatthew Dillon struct ata_xfer *xa = &ccb->ccb_xa; 1952258223a3SMatthew Dillon struct ahci_prdt *prdt = ccb->ccb_cmd_table->prdt; 1953258223a3SMatthew Dillon bus_dmamap_t dmap = ccb->ccb_dmamap; 1954258223a3SMatthew Dillon struct ahci_cmd_hdr *cmd_slot = ccb->ccb_cmd_hdr; 1955258223a3SMatthew Dillon int error; 1956258223a3SMatthew Dillon 1957258223a3SMatthew Dillon if (xa->datalen == 0) { 1958258223a3SMatthew Dillon ccb->ccb_cmd_hdr->prdtl = 0; 1959258223a3SMatthew Dillon return (0); 1960258223a3SMatthew Dillon } 1961258223a3SMatthew Dillon 1962258223a3SMatthew Dillon error = bus_dmamap_load(sc->sc_tag_data, dmap, 1963258223a3SMatthew Dillon xa->data, xa->datalen, 1964258223a3SMatthew Dillon ahci_load_prdt_callback, 1965258223a3SMatthew Dillon &prdt, 1966258223a3SMatthew Dillon ((xa->flags & ATA_F_NOWAIT) ? 1967258223a3SMatthew Dillon BUS_DMA_NOWAIT : BUS_DMA_WAITOK)); 1968258223a3SMatthew Dillon if (error != 0) { 1969258223a3SMatthew Dillon kprintf("%s: error %d loading dmamap\n", PORTNAME(ap), error); 1970258223a3SMatthew Dillon return (1); 1971258223a3SMatthew Dillon } 197212feb904SMatthew Dillon #if 0 1973258223a3SMatthew Dillon if (xa->flags & ATA_F_PIO) 1974258223a3SMatthew Dillon prdt->flags |= htole32(AHCI_PRDT_FLAG_INTR); 197512feb904SMatthew Dillon #endif 1976258223a3SMatthew Dillon 1977258223a3SMatthew Dillon cmd_slot->prdtl = htole16(prdt - ccb->ccb_cmd_table->prdt + 1); 1978258223a3SMatthew Dillon 1979b012a2caSMatthew Dillon if (xa->flags & ATA_F_READ) 1980b012a2caSMatthew Dillon bus_dmamap_sync(sc->sc_tag_data, dmap, BUS_DMASYNC_PREREAD); 1981b012a2caSMatthew Dillon if (xa->flags & ATA_F_WRITE) 1982b012a2caSMatthew Dillon bus_dmamap_sync(sc->sc_tag_data, dmap, BUS_DMASYNC_PREWRITE); 1983258223a3SMatthew Dillon 1984258223a3SMatthew Dillon return (0); 1985258223a3SMatthew Dillon } 1986258223a3SMatthew Dillon 1987258223a3SMatthew Dillon /* 1988258223a3SMatthew Dillon * Callback from BUSDMA system to load the segment list. The passed segment 1989258223a3SMatthew Dillon * list is a temporary structure. 1990258223a3SMatthew Dillon */ 1991258223a3SMatthew Dillon static 1992258223a3SMatthew Dillon void 1993258223a3SMatthew Dillon ahci_load_prdt_callback(void *info, bus_dma_segment_t *segs, int nsegs, 1994258223a3SMatthew Dillon int error) 1995258223a3SMatthew Dillon { 1996258223a3SMatthew Dillon struct ahci_prdt *prd = *(void **)info; 1997258223a3SMatthew Dillon u_int64_t addr; 1998258223a3SMatthew Dillon 1999258223a3SMatthew Dillon KKASSERT(nsegs <= AHCI_MAX_PRDT); 2000258223a3SMatthew Dillon 2001258223a3SMatthew Dillon while (nsegs) { 2002258223a3SMatthew Dillon addr = segs->ds_addr; 2003258223a3SMatthew Dillon prd->dba_hi = htole32((u_int32_t)(addr >> 32)); 2004258223a3SMatthew Dillon prd->dba_lo = htole32((u_int32_t)addr); 2005258223a3SMatthew Dillon prd->flags = htole32(segs->ds_len - 1); 2006258223a3SMatthew Dillon --nsegs; 2007258223a3SMatthew Dillon if (nsegs) 2008258223a3SMatthew Dillon ++prd; 2009258223a3SMatthew Dillon ++segs; 2010258223a3SMatthew Dillon } 2011258223a3SMatthew Dillon *(void **)info = prd; /* return last valid segment */ 2012258223a3SMatthew Dillon } 2013258223a3SMatthew Dillon 2014258223a3SMatthew Dillon void 2015258223a3SMatthew Dillon ahci_unload_prdt(struct ahci_ccb *ccb) 2016258223a3SMatthew Dillon { 2017258223a3SMatthew Dillon struct ahci_port *ap = ccb->ccb_port; 2018258223a3SMatthew Dillon struct ahci_softc *sc = ap->ap_sc; 2019258223a3SMatthew Dillon struct ata_xfer *xa = &ccb->ccb_xa; 2020258223a3SMatthew Dillon bus_dmamap_t dmap = ccb->ccb_dmamap; 2021258223a3SMatthew Dillon 2022258223a3SMatthew Dillon if (xa->datalen != 0) { 2023b012a2caSMatthew Dillon if (xa->flags & ATA_F_READ) { 2024258223a3SMatthew Dillon bus_dmamap_sync(sc->sc_tag_data, dmap, 2025b012a2caSMatthew Dillon BUS_DMASYNC_POSTREAD); 2026b012a2caSMatthew Dillon } 2027b012a2caSMatthew Dillon if (xa->flags & ATA_F_WRITE) { 2028b012a2caSMatthew Dillon bus_dmamap_sync(sc->sc_tag_data, dmap, 2029b012a2caSMatthew Dillon BUS_DMASYNC_POSTWRITE); 2030b012a2caSMatthew Dillon } 2031258223a3SMatthew Dillon bus_dmamap_unload(sc->sc_tag_data, dmap); 2032258223a3SMatthew Dillon 2033f7d09f74SMatthew Dillon /* 2034f7d09f74SMatthew Dillon * prdbc is only updated by hardware for non-NCQ commands. 2035f7d09f74SMatthew Dillon */ 2036f7d09f74SMatthew Dillon if (ccb->ccb_xa.flags & ATA_F_NCQ) { 2037f7d09f74SMatthew Dillon xa->resid = 0; 2038f7d09f74SMatthew Dillon } else { 203950a3ecb6SMatthew Dillon if (ccb->ccb_cmd_hdr->prdbc == 0 && 204050a3ecb6SMatthew Dillon ccb->ccb_xa.state == ATA_S_COMPLETE) { 2041f7d09f74SMatthew Dillon kprintf("%s: WARNING! Unload prdbc resid " 2042f7d09f74SMatthew Dillon "was zero! tag=%d\n", 204312feb904SMatthew Dillon ATANAME(ap, xa->at), ccb->ccb_slot); 204412feb904SMatthew Dillon } 2045258223a3SMatthew Dillon xa->resid = xa->datalen - 2046258223a3SMatthew Dillon le32toh(ccb->ccb_cmd_hdr->prdbc); 2047258223a3SMatthew Dillon } 2048258223a3SMatthew Dillon } 2049f7d09f74SMatthew Dillon } 2050258223a3SMatthew Dillon 20515f8c1efdSMatthew Dillon /* 20525f8c1efdSMatthew Dillon * Start a command and poll for completion. 20535f8c1efdSMatthew Dillon * 20543209f581SMatthew Dillon * timeout is in ms and only counts once the command gets on-chip. 20553209f581SMatthew Dillon * 2056831bc9e3SMatthew Dillon * Returns ATA_S_* state, compare against ATA_S_COMPLETE to determine 2057831bc9e3SMatthew Dillon * that no error occured. 2058831bc9e3SMatthew Dillon * 20595f8c1efdSMatthew Dillon * NOTE: If the caller specifies a NULL timeout function the caller is 20605f8c1efdSMatthew Dillon * responsible for clearing hardware state on failure, but we will 20615f8c1efdSMatthew Dillon * deal with removing the ccb from any pending queue. 20625f8c1efdSMatthew Dillon * 20635f8c1efdSMatthew Dillon * NOTE: NCQ should never be used with this function. 2064cf5f3a81SMatthew Dillon * 2065cf5f3a81SMatthew Dillon * NOTE: If the port is in a failed state and stopped we do not try 2066cf5f3a81SMatthew Dillon * to activate the ccb. 20675f8c1efdSMatthew Dillon */ 2068258223a3SMatthew Dillon int 2069831bc9e3SMatthew Dillon ahci_poll(struct ahci_ccb *ccb, int timeout, 2070831bc9e3SMatthew Dillon void (*timeout_fn)(struct ahci_ccb *)) 2071258223a3SMatthew Dillon { 2072258223a3SMatthew Dillon struct ahci_port *ap = ccb->ccb_port; 2073258223a3SMatthew Dillon 2074cf5f3a81SMatthew Dillon if (ccb->ccb_port->ap_state == AP_S_FATAL_ERROR) { 2075cf5f3a81SMatthew Dillon ccb->ccb_xa.state = ATA_S_ERROR; 2076831bc9e3SMatthew Dillon return(ccb->ccb_xa.state); 2077cf5f3a81SMatthew Dillon } 2078258223a3SMatthew Dillon crit_enter(); 207912feb904SMatthew Dillon #if 0 208012feb904SMatthew Dillon kprintf("%s: Start command %02x tag=%d\n", 208112feb904SMatthew Dillon ATANAME(ccb->ccb_port, ccb->ccb_xa.at), 208212feb904SMatthew Dillon ccb->ccb_xa.fis->command, ccb->ccb_slot); 208312feb904SMatthew Dillon #endif 2084258223a3SMatthew Dillon ahci_start(ccb); 20851980eff3SMatthew Dillon 2086258223a3SMatthew Dillon do { 2087f4553de1SMatthew Dillon ahci_port_intr(ap, 1); 2088831bc9e3SMatthew Dillon switch(ccb->ccb_xa.state) { 2089831bc9e3SMatthew Dillon case ATA_S_ONCHIP: 2090831bc9e3SMatthew Dillon timeout -= ahci_os_softsleep(); 2091f4553de1SMatthew Dillon break; 2092831bc9e3SMatthew Dillon case ATA_S_PENDING: 2093831bc9e3SMatthew Dillon ahci_os_softsleep(); 2094831bc9e3SMatthew Dillon ahci_check_active_timeouts(ap); 2095831bc9e3SMatthew Dillon break; 2096831bc9e3SMatthew Dillon default: 2097831bc9e3SMatthew Dillon crit_exit(); 2098831bc9e3SMatthew Dillon return (ccb->ccb_xa.state); 2099f4553de1SMatthew Dillon } 21003209f581SMatthew Dillon } while (timeout > 0); 21015f8c1efdSMatthew Dillon 2102492bffafSMatthew Dillon if ((ccb->ccb_xa.flags & ATA_F_SILENT) == 0) { 2103831bc9e3SMatthew Dillon kprintf("%s: Poll timeout slot %d CMD: %b TFD: 0x%b SERR: %b\n", 2104831bc9e3SMatthew Dillon ATANAME(ap, ccb->ccb_xa.at), ccb->ccb_slot, 2105831bc9e3SMatthew Dillon ahci_pread(ap, AHCI_PREG_CMD), AHCI_PFMT_CMD, 2106831bc9e3SMatthew Dillon ahci_pread(ap, AHCI_PREG_TFD), AHCI_PFMT_TFD_STS, 2107831bc9e3SMatthew Dillon ahci_pread(ap, AHCI_PREG_SERR), AHCI_PFMT_SERR); 2108492bffafSMatthew Dillon } 21095f8c1efdSMatthew Dillon 2110258223a3SMatthew Dillon timeout_fn(ccb); 2111831bc9e3SMatthew Dillon 2112258223a3SMatthew Dillon crit_exit(); 2113258223a3SMatthew Dillon 2114831bc9e3SMatthew Dillon return(ccb->ccb_xa.state); 2115831bc9e3SMatthew Dillon } 2116831bc9e3SMatthew Dillon 2117831bc9e3SMatthew Dillon /* 2118831bc9e3SMatthew Dillon * When polling we have to check if the currently active CCB(s) 2119831bc9e3SMatthew Dillon * have timed out as the callout will be deadlocked while we 2120831bc9e3SMatthew Dillon * hold the port lock. 2121831bc9e3SMatthew Dillon */ 2122831bc9e3SMatthew Dillon void 2123831bc9e3SMatthew Dillon ahci_check_active_timeouts(struct ahci_port *ap) 2124831bc9e3SMatthew Dillon { 2125831bc9e3SMatthew Dillon struct ahci_ccb *ccb; 2126831bc9e3SMatthew Dillon u_int32_t mask; 2127831bc9e3SMatthew Dillon int tag; 2128831bc9e3SMatthew Dillon 2129831bc9e3SMatthew Dillon mask = ap->ap_active | ap->ap_sactive; 2130831bc9e3SMatthew Dillon while (mask) { 2131831bc9e3SMatthew Dillon tag = ffs(mask) - 1; 2132831bc9e3SMatthew Dillon mask &= ~(1 << tag); 2133831bc9e3SMatthew Dillon ccb = &ap->ap_ccbs[tag]; 2134831bc9e3SMatthew Dillon if (ccb->ccb_xa.flags & ATA_F_TIMEOUT_EXPIRED) { 2135831bc9e3SMatthew Dillon ahci_ata_cmd_timeout(ccb); 2136831bc9e3SMatthew Dillon } 2137831bc9e3SMatthew Dillon } 2138258223a3SMatthew Dillon } 2139258223a3SMatthew Dillon 21403209f581SMatthew Dillon static 21413209f581SMatthew Dillon __inline 21423209f581SMatthew Dillon void 21433209f581SMatthew Dillon ahci_start_timeout(struct ahci_ccb *ccb) 21443209f581SMatthew Dillon { 21453209f581SMatthew Dillon if (ccb->ccb_xa.flags & ATA_F_TIMEOUT_DESIRED) { 21463209f581SMatthew Dillon ccb->ccb_xa.flags |= ATA_F_TIMEOUT_RUNNING; 21473209f581SMatthew Dillon callout_reset(&ccb->ccb_timeout, 21483209f581SMatthew Dillon (ccb->ccb_xa.timeout * hz + 999) / 1000, 21493209f581SMatthew Dillon ahci_ata_cmd_timeout_unserialized, ccb); 21503209f581SMatthew Dillon } 21513209f581SMatthew Dillon } 21523209f581SMatthew Dillon 2153258223a3SMatthew Dillon void 2154258223a3SMatthew Dillon ahci_start(struct ahci_ccb *ccb) 2155258223a3SMatthew Dillon { 2156258223a3SMatthew Dillon struct ahci_port *ap = ccb->ccb_port; 2157258223a3SMatthew Dillon struct ahci_softc *sc = ap->ap_sc; 2158258223a3SMatthew Dillon 2159258223a3SMatthew Dillon KKASSERT(ccb->ccb_xa.state == ATA_S_PENDING); 2160258223a3SMatthew Dillon 2161258223a3SMatthew Dillon /* Zero transferred byte count before transfer */ 2162258223a3SMatthew Dillon ccb->ccb_cmd_hdr->prdbc = 0; 2163258223a3SMatthew Dillon 2164258223a3SMatthew Dillon /* Sync command list entry and corresponding command table entry */ 2165258223a3SMatthew Dillon bus_dmamap_sync(sc->sc_tag_cmdh, 2166258223a3SMatthew Dillon AHCI_DMA_MAP(ap->ap_dmamem_cmd_list), 2167258223a3SMatthew Dillon BUS_DMASYNC_PREWRITE); 2168258223a3SMatthew Dillon bus_dmamap_sync(sc->sc_tag_cmdt, 2169258223a3SMatthew Dillon AHCI_DMA_MAP(ap->ap_dmamem_cmd_table), 2170258223a3SMatthew Dillon BUS_DMASYNC_PREWRITE); 2171258223a3SMatthew Dillon 2172258223a3SMatthew Dillon /* Prepare RFIS area for write by controller */ 2173258223a3SMatthew Dillon bus_dmamap_sync(sc->sc_tag_rfis, 2174258223a3SMatthew Dillon AHCI_DMA_MAP(ap->ap_dmamem_rfis), 2175258223a3SMatthew Dillon BUS_DMASYNC_PREREAD); 2176258223a3SMatthew Dillon 21771980eff3SMatthew Dillon /* 21784c339a5fSMatthew Dillon * There's no point trying to optimize this, it only shaves a few 21794c339a5fSMatthew Dillon * nanoseconds so just queue the command and call our generic issue. 21801980eff3SMatthew Dillon */ 21814c339a5fSMatthew Dillon ahci_issue_pending_commands(ap, ccb); 2182258223a3SMatthew Dillon } 2183258223a3SMatthew Dillon 2184831bc9e3SMatthew Dillon /* 2185831bc9e3SMatthew Dillon * While holding the port lock acquire exclusive access to the port. 2186831bc9e3SMatthew Dillon * 2187831bc9e3SMatthew Dillon * This is used when running the state machine to initialize and identify 2188831bc9e3SMatthew Dillon * targets over a port multiplier. Setting exclusive access prevents 2189831bc9e3SMatthew Dillon * ahci_port_intr() from activating any requests sitting on the pending 2190831bc9e3SMatthew Dillon * queue. 2191831bc9e3SMatthew Dillon */ 2192831bc9e3SMatthew Dillon void 2193831bc9e3SMatthew Dillon ahci_beg_exclusive_access(struct ahci_port *ap, struct ata_port *at) 2194831bc9e3SMatthew Dillon { 2195831bc9e3SMatthew Dillon KKASSERT((ap->ap_flags & AP_F_EXCLUSIVE_ACCESS) == 0); 2196831bc9e3SMatthew Dillon ap->ap_flags |= AP_F_EXCLUSIVE_ACCESS; 2197831bc9e3SMatthew Dillon while (ap->ap_active || ap->ap_sactive) { 2198831bc9e3SMatthew Dillon ahci_port_intr(ap, 1); 2199831bc9e3SMatthew Dillon ahci_os_softsleep(); 2200831bc9e3SMatthew Dillon } 2201831bc9e3SMatthew Dillon } 2202831bc9e3SMatthew Dillon 2203831bc9e3SMatthew Dillon void 2204831bc9e3SMatthew Dillon ahci_end_exclusive_access(struct ahci_port *ap, struct ata_port *at) 2205831bc9e3SMatthew Dillon { 2206831bc9e3SMatthew Dillon KKASSERT((ap->ap_flags & AP_F_EXCLUSIVE_ACCESS) != 0); 2207831bc9e3SMatthew Dillon ap->ap_flags &= ~AP_F_EXCLUSIVE_ACCESS; 22084c339a5fSMatthew Dillon ahci_issue_pending_commands(ap, NULL); 2209831bc9e3SMatthew Dillon } 2210831bc9e3SMatthew Dillon 22111980eff3SMatthew Dillon /* 22124c339a5fSMatthew Dillon * If ccb is not NULL enqueue and/or issue it. 22134c339a5fSMatthew Dillon * 22144c339a5fSMatthew Dillon * If ccb is NULL issue whatever we can from the queue. However, nothing 22154c339a5fSMatthew Dillon * new is issued if the exclusive access flag is set or expired ccb's are 22164c339a5fSMatthew Dillon * present. 22174c339a5fSMatthew Dillon * 22184c339a5fSMatthew Dillon * If existing commands are still active (ap_active/ap_sactive) we can only 22194c339a5fSMatthew Dillon * issue matching new commands. 22201980eff3SMatthew Dillon */ 22214c339a5fSMatthew Dillon void 22224c339a5fSMatthew Dillon ahci_issue_pending_commands(struct ahci_port *ap, struct ahci_ccb *ccb) 22234c339a5fSMatthew Dillon { 22244c339a5fSMatthew Dillon u_int32_t mask; 22254c339a5fSMatthew Dillon int limit; 22268119d5f5SMatthew Dillon struct ata_port *ccb_at; 2227258223a3SMatthew Dillon 22281980eff3SMatthew Dillon /* 22294c339a5fSMatthew Dillon * Enqueue the ccb. 22304c339a5fSMatthew Dillon * 22314c339a5fSMatthew Dillon * If just running the queue and in exclusive access mode we 22324c339a5fSMatthew Dillon * just return. Also in this case if there are any expired ccb's 22334c339a5fSMatthew Dillon * we want to clear the queue so the port can be safely stopped. 22344c339a5fSMatthew Dillon */ 22354c339a5fSMatthew Dillon if (ccb) { 22364c339a5fSMatthew Dillon TAILQ_INSERT_TAIL(&ap->ap_ccb_pending, ccb, ccb_entry); 22374c339a5fSMatthew Dillon } else if ((ap->ap_flags & AP_F_EXCLUSIVE_ACCESS) || ap->ap_expired) { 22384c339a5fSMatthew Dillon return; 22394c339a5fSMatthew Dillon } 22404c339a5fSMatthew Dillon 22414c339a5fSMatthew Dillon /* 22424c339a5fSMatthew Dillon * Pull the next ccb off the queue and run it if possible. 2243c1fd1d86SMatthew Dillon * 2244c1fd1d86SMatthew Dillon * The error CCB supercedes all normal queue operations and 2245c1fd1d86SMatthew Dillon * implies exclusive access while the error CCB is active. 22464c339a5fSMatthew Dillon */ 2247c1fd1d86SMatthew Dillon if (ccb != ap->ap_err_ccb) { 22484c339a5fSMatthew Dillon if ((ccb = TAILQ_FIRST(&ap->ap_ccb_pending)) == NULL) 22494c339a5fSMatthew Dillon return; 2250c1fd1d86SMatthew Dillon if (ap->ap_flags & AP_F_ERR_CCB_RESERVED) { 2251c1fd1d86SMatthew Dillon kprintf("DELAY CCB slot %d\n", ccb->ccb_slot); 2252c1fd1d86SMatthew Dillon return; 2253c1fd1d86SMatthew Dillon } 2254c1fd1d86SMatthew Dillon } 22554c339a5fSMatthew Dillon 225612feb904SMatthew Dillon /* 225712feb904SMatthew Dillon * Handle exclusivity requirements. 225812feb904SMatthew Dillon * 225912feb904SMatthew Dillon * ATA_F_EXCLUSIVE is used when we want to be the only command 226012feb904SMatthew Dillon * running. 226112feb904SMatthew Dillon * 226212feb904SMatthew Dillon * ATA_F_AUTOSENSE is used when we want the D2H rfis loaded 226312feb904SMatthew Dillon * back into the ccb on a normal (non-errored) command completion. 226412feb904SMatthew Dillon * For example, for PM requests to target 15. Because the AHCI 226512feb904SMatthew Dillon * spec does not stop the command processor and has only one rfis 226612feb904SMatthew Dillon * area (for non-FBSS anyway), AUTOSENSE currently implies EXCLUSIVE. 226712feb904SMatthew Dillon * Otherwise multiple completions can destroy the rfis data before 226812feb904SMatthew Dillon * we have a chance to copy it. 226912feb904SMatthew Dillon */ 227012feb904SMatthew Dillon if (ap->ap_active & ~ap->ap_expired) { 227112feb904SMatthew Dillon /* 227212feb904SMatthew Dillon * There may be multiple ccb's already running, 227312feb904SMatthew Dillon * if any are running and ap_run_flags sets 227412feb904SMatthew Dillon * one of these flags then we know only one is 227512feb904SMatthew Dillon * running. 227612feb904SMatthew Dillon * 227712feb904SMatthew Dillon * XXX Current AUTOSENSE code forces exclusivity 227812feb904SMatthew Dillon * to simplify the code. 227912feb904SMatthew Dillon */ 228012feb904SMatthew Dillon if (ap->ap_run_flags & 228112feb904SMatthew Dillon (ATA_F_EXCLUSIVE | ATA_F_AUTOSENSE)) { 228212feb904SMatthew Dillon return; 228312feb904SMatthew Dillon } 228412feb904SMatthew Dillon 228512feb904SMatthew Dillon if (ccb->ccb_xa.flags & 228612feb904SMatthew Dillon (ATA_F_EXCLUSIVE | ATA_F_AUTOSENSE)) { 228712feb904SMatthew Dillon return; 228812feb904SMatthew Dillon } 228912feb904SMatthew Dillon } 229012feb904SMatthew Dillon 22914c339a5fSMatthew Dillon if (ccb->ccb_xa.flags & ATA_F_NCQ) { 22924c339a5fSMatthew Dillon /* 22934c339a5fSMatthew Dillon * The next command is a NCQ command and can be issued as 22944c339a5fSMatthew Dillon * long as currently active commands are not standard. 22954c339a5fSMatthew Dillon */ 22964c339a5fSMatthew Dillon if (ap->ap_active) { 22974c339a5fSMatthew Dillon KKASSERT(ap->ap_active_cnt > 0); 22984c339a5fSMatthew Dillon return; 22994c339a5fSMatthew Dillon } 23004c339a5fSMatthew Dillon KKASSERT(ap->ap_active_cnt == 0); 23014c339a5fSMatthew Dillon 23024c339a5fSMatthew Dillon mask = 0; 23034c339a5fSMatthew Dillon do { 23044c339a5fSMatthew Dillon TAILQ_REMOVE(&ap->ap_ccb_pending, ccb, ccb_entry); 2305d16d3400SMatthew Dillon KKASSERT((mask & (1 << ccb->ccb_slot)) == 0); 23064c339a5fSMatthew Dillon mask |= 1 << ccb->ccb_slot; 2307d16d3400SMatthew Dillon KKASSERT(ccb->ccb_xa.state == ATA_S_PENDING); 2308d16d3400SMatthew Dillon KKASSERT(ccb == &ap->ap_ccbs[ccb->ccb_slot]); 23094c339a5fSMatthew Dillon ccb->ccb_xa.state = ATA_S_ONCHIP; 231012feb904SMatthew Dillon ahci_start_timeout(ccb); 231112feb904SMatthew Dillon ap->ap_run_flags = ccb->ccb_xa.flags; 23128119d5f5SMatthew Dillon 23138119d5f5SMatthew Dillon ccb_at = ccb->ccb_xa.at; 23148119d5f5SMatthew Dillon if (ap->ap_flags & AP_F_FBSS_ENABLED) { 23158119d5f5SMatthew Dillon ap->ap_sactive |= mask; 23168119d5f5SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SACT, mask); 23178119d5f5SMatthew Dillon if (ccb_at) { 23188119d5f5SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_FBS, 23198119d5f5SMatthew Dillon (ccb_at->at_target << 23208119d5f5SMatthew Dillon AHCI_PREG_FBS_DEV_SHIFT) | 23218119d5f5SMatthew Dillon AHCI_PREG_FBS_EN); 23228119d5f5SMatthew Dillon } else { 23238119d5f5SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_FBS, 23248119d5f5SMatthew Dillon AHCI_PREG_FBS_EN); 23258119d5f5SMatthew Dillon } 23268119d5f5SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CI, mask); 23278119d5f5SMatthew Dillon mask = 0; 23288119d5f5SMatthew Dillon } 23294c339a5fSMatthew Dillon ccb = TAILQ_FIRST(&ap->ap_ccb_pending); 233012feb904SMatthew Dillon } while (ccb && (ccb->ccb_xa.flags & ATA_F_NCQ) && 233112feb904SMatthew Dillon (ap->ap_run_flags & 233212feb904SMatthew Dillon (ATA_F_EXCLUSIVE | ATA_F_AUTOSENSE)) == 0); 23334c339a5fSMatthew Dillon 2334d16d3400SMatthew Dillon KKASSERT(((ap->ap_active | ap->ap_sactive) & mask) == 0); 2335d16d3400SMatthew Dillon 23368119d5f5SMatthew Dillon if (mask) { 23374c339a5fSMatthew Dillon ap->ap_sactive |= mask; 23384c339a5fSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SACT, mask); 23394c339a5fSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CI, mask); 23408119d5f5SMatthew Dillon } 23414c339a5fSMatthew Dillon } else { 23424c339a5fSMatthew Dillon /* 23434c339a5fSMatthew Dillon * The next command is a standard command and can be issued 23444c339a5fSMatthew Dillon * as long as currently active commands are not NCQ. 23454c339a5fSMatthew Dillon * 23464c339a5fSMatthew Dillon * We limit ourself to 1 command if we have a port multiplier, 23474c339a5fSMatthew Dillon * (at least without FBSS support), otherwise timeouts on 23484c339a5fSMatthew Dillon * one port can race completions on other ports (see 23494c339a5fSMatthew Dillon * ahci_ata_cmd_timeout() for more information). 23504c339a5fSMatthew Dillon * 23514c339a5fSMatthew Dillon * If not on a port multiplier generally allow up to 4 23524c339a5fSMatthew Dillon * standard commands to be enqueued. Remember that the 23534c339a5fSMatthew Dillon * command processor will still process them sequentially. 23541980eff3SMatthew Dillon */ 23551980eff3SMatthew Dillon if (ap->ap_sactive) 2356258223a3SMatthew Dillon return; 23578119d5f5SMatthew Dillon if (ap->ap_type == ATA_PORT_T_PM && 23588119d5f5SMatthew Dillon (ap->ap_flags & AP_F_FBSS_ENABLED) == 0) { 23594c339a5fSMatthew Dillon limit = 1; 23608119d5f5SMatthew Dillon } else if (ap->ap_sc->sc_ncmds > 4) { 23614c339a5fSMatthew Dillon limit = 4; 23628119d5f5SMatthew Dillon } else { 23634c339a5fSMatthew Dillon limit = 2; 23648119d5f5SMatthew Dillon } 2365258223a3SMatthew Dillon 23664c339a5fSMatthew Dillon while (ap->ap_active_cnt < limit && ccb && 23674c339a5fSMatthew Dillon (ccb->ccb_xa.flags & ATA_F_NCQ) == 0) { 23688119d5f5SMatthew Dillon ccb_at = ccb->ccb_xa.at; 23694c339a5fSMatthew Dillon TAILQ_REMOVE(&ap->ap_ccb_pending, ccb, ccb_entry); 2370d16d3400SMatthew Dillon KKASSERT(((ap->ap_active | ap->ap_sactive) & 2371d16d3400SMatthew Dillon (1 << ccb->ccb_slot)) == 0); 23724c339a5fSMatthew Dillon ap->ap_active |= 1 << ccb->ccb_slot; 2373258223a3SMatthew Dillon ap->ap_active_cnt++; 237412feb904SMatthew Dillon ap->ap_run_flags = ccb->ccb_xa.flags; 23754c339a5fSMatthew Dillon ccb->ccb_xa.state = ATA_S_ONCHIP; 237612feb904SMatthew Dillon ahci_start_timeout(ccb); 23778119d5f5SMatthew Dillon if (ap->ap_flags & AP_F_FBSS_ENABLED) { 23788119d5f5SMatthew Dillon if (ccb_at) { 23798119d5f5SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_FBS, 23808119d5f5SMatthew Dillon (ccb_at->at_target << 23818119d5f5SMatthew Dillon AHCI_PREG_FBS_DEV_SHIFT) | 23828119d5f5SMatthew Dillon AHCI_PREG_FBS_EN); 23838119d5f5SMatthew Dillon } else { 23848119d5f5SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_FBS, 23858119d5f5SMatthew Dillon AHCI_PREG_FBS_EN); 23868119d5f5SMatthew Dillon } 23878119d5f5SMatthew Dillon } 2388d16d3400SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CI, 1 << ccb->ccb_slot); 238922726f69SMatthew Dillon if ((ap->ap_run_flags & 239022726f69SMatthew Dillon (ATA_F_EXCLUSIVE | ATA_F_AUTOSENSE)) == 0) { 239122726f69SMatthew Dillon break; 239222726f69SMatthew Dillon } 23934c339a5fSMatthew Dillon ccb = TAILQ_FIRST(&ap->ap_ccb_pending); 239412feb904SMatthew Dillon if (ccb && (ccb->ccb_xa.flags & 239512feb904SMatthew Dillon (ATA_F_EXCLUSIVE | ATA_F_AUTOSENSE))) { 239612feb904SMatthew Dillon break; 239712feb904SMatthew Dillon } 23981980eff3SMatthew Dillon } 2399258223a3SMatthew Dillon } 2400258223a3SMatthew Dillon } 2401258223a3SMatthew Dillon 2402258223a3SMatthew Dillon void 2403258223a3SMatthew Dillon ahci_intr(void *arg) 2404258223a3SMatthew Dillon { 2405258223a3SMatthew Dillon struct ahci_softc *sc = arg; 2406f4553de1SMatthew Dillon struct ahci_port *ap; 240712feb904SMatthew Dillon u_int32_t is; 240812feb904SMatthew Dillon u_int32_t ack; 2409258223a3SMatthew Dillon int port; 2410258223a3SMatthew Dillon 2411f4553de1SMatthew Dillon /* 2412f4553de1SMatthew Dillon * Check if the master enable is up, and whether any interrupts are 2413f4553de1SMatthew Dillon * pending. 2414f4553de1SMatthew Dillon */ 2415f4553de1SMatthew Dillon if ((sc->sc_flags & AHCI_F_INT_GOOD) == 0) 2416f4553de1SMatthew Dillon return; 2417258223a3SMatthew Dillon is = ahci_read(sc, AHCI_REG_IS); 241812feb904SMatthew Dillon if (is == 0 || is == 0xffffffff) { 2419258223a3SMatthew Dillon return; 242012feb904SMatthew Dillon } 242112feb904SMatthew Dillon is &= sc->sc_portmask; 2422258223a3SMatthew Dillon 2423258223a3SMatthew Dillon #ifdef AHCI_COALESCE 2424258223a3SMatthew Dillon /* Check coalescing interrupt first */ 2425258223a3SMatthew Dillon if (is & sc->sc_ccc_mask) { 2426258223a3SMatthew Dillon DPRINTF(AHCI_D_INTR, "%s: command coalescing interrupt\n", 2427258223a3SMatthew Dillon DEVNAME(sc)); 2428258223a3SMatthew Dillon is &= ~sc->sc_ccc_mask; 2429258223a3SMatthew Dillon is |= sc->sc_ccc_ports_cur; 2430258223a3SMatthew Dillon } 2431258223a3SMatthew Dillon #endif 2432258223a3SMatthew Dillon 2433f4553de1SMatthew Dillon /* 2434f4553de1SMatthew Dillon * Process interrupts for each port in a non-blocking fashion. 243512feb904SMatthew Dillon * 24363d102df7SMatthew Dillon * The global IS bit is supposed to be forced on if any unmasked 24373d102df7SMatthew Dillon * port interrupt is pending, even if we clear it. 24383d102df7SMatthew Dillon * 24393d102df7SMatthew Dillon * However it would appear that it is simply latched on some parts, 24403d102df7SMatthew Dillon * which means we have to clear it BEFORE processing the status bits 24413d102df7SMatthew Dillon * to avoid races. 2442f4553de1SMatthew Dillon */ 24433d102df7SMatthew Dillon ahci_write(sc, AHCI_REG_IS, is); 244412feb904SMatthew Dillon for (ack = 0; is; is &= ~(1 << port)) { 2445258223a3SMatthew Dillon port = ffs(is) - 1; 244612feb904SMatthew Dillon ack |= 1 << port; 244712feb904SMatthew Dillon 2448f4553de1SMatthew Dillon ap = sc->sc_ports[port]; 244912feb904SMatthew Dillon if (ap == NULL) 245012feb904SMatthew Dillon continue; 245112feb904SMatthew Dillon 2452f4553de1SMatthew Dillon if (ahci_os_lock_port_nb(ap) == 0) { 2453f4553de1SMatthew Dillon ahci_port_intr(ap, 0); 2454f4553de1SMatthew Dillon ahci_os_unlock_port(ap); 2455f4553de1SMatthew Dillon } else { 2456f4553de1SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IE, 0); 2457f4553de1SMatthew Dillon ahci_os_signal_port_thread(ap, AP_SIGF_PORTINT); 2458f4553de1SMatthew Dillon } 2459f4553de1SMatthew Dillon } 2460258223a3SMatthew Dillon } 2461258223a3SMatthew Dillon 2462f4553de1SMatthew Dillon /* 2463f4553de1SMatthew Dillon * Core called from helper thread. 2464f4553de1SMatthew Dillon */ 24653209f581SMatthew Dillon void 2466f4553de1SMatthew Dillon ahci_port_thread_core(struct ahci_port *ap, int mask) 2467f4553de1SMatthew Dillon { 2468f4553de1SMatthew Dillon /* 2469f4553de1SMatthew Dillon * Process any expired timedouts. 2470f4553de1SMatthew Dillon */ 2471f4553de1SMatthew Dillon ahci_os_lock_port(ap); 2472f4553de1SMatthew Dillon if (mask & AP_SIGF_TIMEOUT) { 2473831bc9e3SMatthew Dillon ahci_check_active_timeouts(ap); 2474f4553de1SMatthew Dillon } 2475f4553de1SMatthew Dillon 2476f4553de1SMatthew Dillon /* 2477f4553de1SMatthew Dillon * Process port interrupts which require a higher level of 2478f4553de1SMatthew Dillon * intervention. 2479f4553de1SMatthew Dillon */ 2480f4553de1SMatthew Dillon if (mask & AP_SIGF_PORTINT) { 2481f4553de1SMatthew Dillon ahci_port_intr(ap, 1); 2482f4553de1SMatthew Dillon ahci_port_interrupt_enable(ap); 248312feb904SMatthew Dillon } else if (ap->ap_probe != ATA_PROBE_FAILED) { 248412feb904SMatthew Dillon ahci_port_intr(ap, 1); 248512feb904SMatthew Dillon ahci_port_interrupt_enable(ap); 2486f4553de1SMatthew Dillon } 2487d16d3400SMatthew Dillon ahci_os_unlock_port(ap); 2488f4553de1SMatthew Dillon } 2489f4553de1SMatthew Dillon 2490f4553de1SMatthew Dillon /* 2491f4553de1SMatthew Dillon * Core per-port interrupt handler. 2492f4553de1SMatthew Dillon * 2493f4553de1SMatthew Dillon * If blockable is 0 we cannot call ahci_os_sleep() at all and we can only 2494f4553de1SMatthew Dillon * deal with normal command completions which do not require blocking. 2495f4553de1SMatthew Dillon */ 2496f4553de1SMatthew Dillon void 2497f4553de1SMatthew Dillon ahci_port_intr(struct ahci_port *ap, int blockable) 2498258223a3SMatthew Dillon { 2499258223a3SMatthew Dillon struct ahci_softc *sc = ap->ap_sc; 25003209f581SMatthew Dillon u_int32_t is, ci_saved, ci_masked; 250122181ab7SMatthew Dillon int slot; 2502492bffafSMatthew Dillon int stopped = 0; 2503258223a3SMatthew Dillon struct ahci_ccb *ccb = NULL; 25041980eff3SMatthew Dillon struct ata_port *ccb_at = NULL; 2505258223a3SMatthew Dillon volatile u_int32_t *active; 2506f4553de1SMatthew Dillon const u_int32_t blockable_mask = AHCI_PREG_IS_TFES | 2507f4553de1SMatthew Dillon AHCI_PREG_IS_IFS | 2508f4553de1SMatthew Dillon AHCI_PREG_IS_PCS | 2509f4553de1SMatthew Dillon AHCI_PREG_IS_PRCS | 2510f4553de1SMatthew Dillon AHCI_PREG_IS_HBFS | 2511f4553de1SMatthew Dillon AHCI_PREG_IS_OFS | 2512f4553de1SMatthew Dillon AHCI_PREG_IS_UFS; 2513f4553de1SMatthew Dillon 2514492bffafSMatthew Dillon enum { NEED_NOTHING, NEED_REINIT, NEED_RESTART, 2515492bffafSMatthew Dillon NEED_HOTPLUG_INSERT, NEED_HOTPLUG_REMOVE } need = NEED_NOTHING; 2516258223a3SMatthew Dillon 2517f4553de1SMatthew Dillon /* 2518f4553de1SMatthew Dillon * All basic command completions are always processed. 2519f4553de1SMatthew Dillon */ 252012feb904SMatthew Dillon is = ahci_pread(ap, AHCI_PREG_IS); 2521cec07d75SMatthew Dillon if (is & AHCI_PREG_IS_DPS) 2522cec07d75SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, is & AHCI_PREG_IS_DPS); 2523258223a3SMatthew Dillon 2524f4553de1SMatthew Dillon /* 2525f4553de1SMatthew Dillon * If we can't block then we can't handle these here. Disable 2526f4553de1SMatthew Dillon * the interrupts in question so we don't live-lock, the helper 2527f4553de1SMatthew Dillon * thread will re-enable them. 2528f4553de1SMatthew Dillon * 2529f4553de1SMatthew Dillon * If the port is in a completely failed state we do not want 2530dbef6246SMatthew Dillon * to drop through to failed-command-processing if blockable is 0, 2531f4553de1SMatthew Dillon * just let the thread deal with it all. 2532dbef6246SMatthew Dillon * 2533dbef6246SMatthew Dillon * Otherwise we fall through and still handle DHRS and any commands 2534dbef6246SMatthew Dillon * which completed normally. Even if we are errored we haven't 2535dbef6246SMatthew Dillon * stopped the port yet so CI/SACT are still good. 2536f4553de1SMatthew Dillon */ 2537f4553de1SMatthew Dillon if (blockable == 0) { 2538f4553de1SMatthew Dillon if (ap->ap_state == AP_S_FATAL_ERROR) { 253912feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IE, 0); 2540f4553de1SMatthew Dillon ahci_os_signal_port_thread(ap, AP_SIGF_PORTINT); 2541f4553de1SMatthew Dillon return; 2542f4553de1SMatthew Dillon } 2543f4553de1SMatthew Dillon if (is & blockable_mask) { 254412feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IE, 0); 2545f4553de1SMatthew Dillon ahci_os_signal_port_thread(ap, AP_SIGF_PORTINT); 254612feb904SMatthew Dillon return; 2547f4553de1SMatthew Dillon } 2548f4553de1SMatthew Dillon } 2549f4553de1SMatthew Dillon 25503209f581SMatthew Dillon /* 2551f4553de1SMatthew Dillon * Either NCQ or non-NCQ commands will be active, never both. 25523209f581SMatthew Dillon */ 2553258223a3SMatthew Dillon if (ap->ap_sactive) { 2554258223a3SMatthew Dillon KKASSERT(ap->ap_active == 0); 2555258223a3SMatthew Dillon KKASSERT(ap->ap_active_cnt == 0); 2556258223a3SMatthew Dillon ci_saved = ahci_pread(ap, AHCI_PREG_SACT); 2557258223a3SMatthew Dillon active = &ap->ap_sactive; 2558258223a3SMatthew Dillon } else { 2559258223a3SMatthew Dillon ci_saved = ahci_pread(ap, AHCI_PREG_CI); 2560258223a3SMatthew Dillon active = &ap->ap_active; 2561258223a3SMatthew Dillon } 256212feb904SMatthew Dillon KKASSERT(!(ap->ap_sactive && ap->ap_active)); 2563d16d3400SMatthew Dillon KKASSERT((ci_saved & (ap->ap_sactive | ap->ap_active)) == ci_saved); 256412feb904SMatthew Dillon #if 0 256512feb904SMatthew Dillon kprintf("CHECK act=%08x/%08x sact=%08x/%08x\n", 256612feb904SMatthew Dillon ap->ap_active, ahci_pread(ap, AHCI_PREG_CI), 256712feb904SMatthew Dillon ap->ap_sactive, ahci_pread(ap, AHCI_PREG_SACT)); 256812feb904SMatthew Dillon #endif 2569258223a3SMatthew Dillon 2570492bffafSMatthew Dillon /* 2571492bffafSMatthew Dillon * Ignore AHCI_PREG_IS_PRCS when link power management is on 2572492bffafSMatthew Dillon */ 2573795adb22SMatthew Dillon if (ap->link_pwr_mgmt != AHCI_LINK_PWR_MGMT_NONE) { 2574795adb22SMatthew Dillon is &= ~AHCI_PREG_IS_PRCS; 2575795adb22SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, 2576795adb22SMatthew Dillon AHCI_PREG_SERR_DIAG_N | AHCI_PREG_SERR_DIAG_W); 2577795adb22SMatthew Dillon } 2578795adb22SMatthew Dillon 2579cf5f3a81SMatthew Dillon /* 2580f4553de1SMatthew Dillon * Command failed (blockable). 2581f4553de1SMatthew Dillon * 2582f4553de1SMatthew Dillon * See AHCI 1.1 spec 6.2.2.1 and 6.2.2.2. 25831980eff3SMatthew Dillon * 25841980eff3SMatthew Dillon * This stops command processing. 2585cf5f3a81SMatthew Dillon */ 2586492bffafSMatthew Dillon if (is & AHCI_PREG_IS_TFES) { 2587258223a3SMatthew Dillon u_int32_t tfd, serr; 2588258223a3SMatthew Dillon int err_slot; 2589258223a3SMatthew Dillon 259012feb904SMatthew Dillon process_error: 2591258223a3SMatthew Dillon tfd = ahci_pread(ap, AHCI_PREG_TFD); 2592258223a3SMatthew Dillon serr = ahci_pread(ap, AHCI_PREG_SERR); 2593258223a3SMatthew Dillon 2594cf5f3a81SMatthew Dillon /* 259512feb904SMatthew Dillon * Load the error slot and restart command processing. 259612feb904SMatthew Dillon * CLO if we need to. The error slot may not be valid. 259712feb904SMatthew Dillon * MUST BE DONE BEFORE CLEARING ST! 259812feb904SMatthew Dillon * 259912feb904SMatthew Dillon * Cycle ST. 260012feb904SMatthew Dillon * 260112feb904SMatthew Dillon * It is unclear but we may have to clear SERR to reenable 260212feb904SMatthew Dillon * error processing. 2603cf5f3a81SMatthew Dillon */ 260412feb904SMatthew Dillon err_slot = AHCI_PREG_CMD_CCS(ahci_pread(ap, AHCI_PREG_CMD)); 260512feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_TFES | 260612feb904SMatthew Dillon AHCI_PREG_IS_PSS | 260712feb904SMatthew Dillon AHCI_PREG_IS_DHRS | 260812feb904SMatthew Dillon AHCI_PREG_IS_SDBS); 260912feb904SMatthew Dillon is &= ~(AHCI_PREG_IS_TFES | AHCI_PREG_IS_PSS | 261012feb904SMatthew Dillon AHCI_PREG_IS_DHRS | AHCI_PREG_IS_SDBS); 261112feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, serr); 2612258223a3SMatthew Dillon ahci_port_stop(ap, 0); 261312feb904SMatthew Dillon ahci_os_hardsleep(10); 261412feb904SMatthew Dillon if (tfd & (AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) { 261512feb904SMatthew Dillon kprintf("%s: Issuing CLO\n", PORTNAME(ap)); 261612feb904SMatthew Dillon ahci_port_clo(ap); 261712feb904SMatthew Dillon } 2618492bffafSMatthew Dillon 2619492bffafSMatthew Dillon /* 2620492bffafSMatthew Dillon * We are now stopped and need a restart. If we have to 2621492bffafSMatthew Dillon * process a NCQ error we will temporarily start and then 2622492bffafSMatthew Dillon * stop the port again, so this condition holds. 2623492bffafSMatthew Dillon */ 2624492bffafSMatthew Dillon stopped = 1; 262522181ab7SMatthew Dillon need = NEED_RESTART; 2626258223a3SMatthew Dillon 262750a3ecb6SMatthew Dillon /* 262850a3ecb6SMatthew Dillon * ATAPI errors are fairly common from probing, just 262950a3ecb6SMatthew Dillon * report disk errors or if bootverbose is on. 263050a3ecb6SMatthew Dillon */ 263150a3ecb6SMatthew Dillon if (bootverbose || ap->ap_type != ATA_PORT_T_ATAPI) { 263212feb904SMatthew Dillon kprintf("%s: TFES slot %d ci_saved = %08x\n", 263312feb904SMatthew Dillon PORTNAME(ap), err_slot, ci_saved); 263450a3ecb6SMatthew Dillon } 2635258223a3SMatthew Dillon 26361980eff3SMatthew Dillon /* 263712feb904SMatthew Dillon * If we got an error on an error CCB just complete it 263812feb904SMatthew Dillon * with an error. ci_saved has the mask to restart 263912feb904SMatthew Dillon * (the err_ccb will be removed from it by finish_error). 26401980eff3SMatthew Dillon */ 264112feb904SMatthew Dillon if (ap->ap_flags & AP_F_ERR_CCB_RESERVED) { 264212feb904SMatthew Dillon err_slot = ap->ap_err_ccb->ccb_slot; 264312feb904SMatthew Dillon goto finish_error; 2644258223a3SMatthew Dillon } 2645258223a3SMatthew Dillon 26461980eff3SMatthew Dillon /* 264712feb904SMatthew Dillon * If NCQ commands were active get the error slot from 264812feb904SMatthew Dillon * the log page. NCQ is not supported for PM's so this 264912feb904SMatthew Dillon * is a direct-attached target. 26501980eff3SMatthew Dillon * 265112feb904SMatthew Dillon * Otherwise if no commands were active we have a problem. 265212feb904SMatthew Dillon * 265312feb904SMatthew Dillon * Otherwise if the error slot is bad we have a problem. 265412feb904SMatthew Dillon * 265512feb904SMatthew Dillon * Otherwise process the error for the slot. 26561980eff3SMatthew Dillon */ 265712feb904SMatthew Dillon if (ap->ap_sactive) { 2658492bffafSMatthew Dillon ahci_port_start(ap); 265912feb904SMatthew Dillon err_slot = ahci_port_read_ncq_error(ap, 0); 2660492bffafSMatthew Dillon ahci_port_stop(ap, 0); 266112feb904SMatthew Dillon } else if (ap->ap_active == 0) { 266212feb904SMatthew Dillon kprintf("%s: TFES with no commands pending\n", 266312feb904SMatthew Dillon PORTNAME(ap)); 266412feb904SMatthew Dillon err_slot = -1; 266512feb904SMatthew Dillon } else if (err_slot < 0 || err_slot >= ap->ap_sc->sc_ncmds) { 266612feb904SMatthew Dillon kprintf("%s: bad error slot %d\n", 2667258223a3SMatthew Dillon PORTNAME(ap), err_slot); 266812feb904SMatthew Dillon err_slot = -1; 2669258223a3SMatthew Dillon } else { 267012feb904SMatthew Dillon ccb = &ap->ap_ccbs[err_slot]; 267112feb904SMatthew Dillon 26724c339a5fSMatthew Dillon /* 267312feb904SMatthew Dillon * Validate the errored ccb. Note that ccb_at can 267412feb904SMatthew Dillon * be NULL for direct-attached ccb's. 267512feb904SMatthew Dillon * 267612feb904SMatthew Dillon * Copy received taskfile data from the RFIS. 26774c339a5fSMatthew Dillon */ 267812feb904SMatthew Dillon if (ccb->ccb_xa.state == ATA_S_ONCHIP) { 26798119d5f5SMatthew Dillon int fis_target; 26808119d5f5SMatthew Dillon uint32_t bytes; 26818119d5f5SMatthew Dillon intmax_t offset; 26828119d5f5SMatthew Dillon struct ata_fis_d2h *rfis; 26838119d5f5SMatthew Dillon 268412feb904SMatthew Dillon ccb_at = ccb->ccb_xa.at; 26858119d5f5SMatthew Dillon if (ccb_at && 26868119d5f5SMatthew Dillon (ap->ap_flags & AP_F_FBSS_ENABLED)) 26878119d5f5SMatthew Dillon fis_target = ccb_at->at_target; 26888119d5f5SMatthew Dillon else 26898119d5f5SMatthew Dillon fis_target = 0; 26908119d5f5SMatthew Dillon 26918119d5f5SMatthew Dillon memcpy(&ccb->ccb_xa.rfis, 26928119d5f5SMatthew Dillon ap->ap_rfis[fis_target].rfis, 269312feb904SMatthew Dillon sizeof(struct ata_fis_d2h)); 26948119d5f5SMatthew Dillon rfis = &ccb->ccb_xa.rfis; 26958119d5f5SMatthew Dillon 26968119d5f5SMatthew Dillon offset = (intmax_t)rfis->lba_low | 26978119d5f5SMatthew Dillon ((intmax_t)rfis->lba_mid << 8) | 26988119d5f5SMatthew Dillon ((intmax_t)rfis->lba_high << 16) | 26998119d5f5SMatthew Dillon ((intmax_t)rfis->lba_low_exp << 24) | 27008119d5f5SMatthew Dillon ((intmax_t)rfis->lba_mid_exp << 32) | 27018119d5f5SMatthew Dillon ((intmax_t)rfis->lba_high_exp << 40); 27028119d5f5SMatthew Dillon offset *= 512; 27038119d5f5SMatthew Dillon bytes = rfis->sector_count * 512; 27048119d5f5SMatthew Dillon 27058119d5f5SMatthew Dillon /* NOTE: expect type == 0x34 */ 27068119d5f5SMatthew Dillon kprintf("%s: TFES RFIS-%02x flg=%02x " 27078119d5f5SMatthew Dillon "st=%02x err=%02x dev=%02x " 27088119d5f5SMatthew Dillon "off=%jd/%d\n", 27098119d5f5SMatthew Dillon PORTNAME(ap), 27108119d5f5SMatthew Dillon rfis->type, 27118119d5f5SMatthew Dillon rfis->flags, 27128119d5f5SMatthew Dillon rfis->status, 27138119d5f5SMatthew Dillon rfis->error, 27148119d5f5SMatthew Dillon rfis->device, 27158119d5f5SMatthew Dillon offset, bytes); 271612feb904SMatthew Dillon } else { 271712feb904SMatthew Dillon kprintf("%s: Cannot copy rfis, CCB slot " 271812feb904SMatthew Dillon "%d is not on-chip (state=%d)\n", 271912feb904SMatthew Dillon ATANAME(ap, ccb->ccb_xa.at), 272012feb904SMatthew Dillon err_slot, ccb->ccb_xa.state); 272112feb904SMatthew Dillon err_slot = -1; 272212feb904SMatthew Dillon } 2723258223a3SMatthew Dillon } 2724258223a3SMatthew Dillon 2725258223a3SMatthew Dillon /* 272612feb904SMatthew Dillon * If we could not determine the errored slot then 272712feb904SMatthew Dillon * reset the port. 2728258223a3SMatthew Dillon */ 272912feb904SMatthew Dillon if (err_slot < 0) { 273012feb904SMatthew Dillon kprintf("%s: TFES: Unable to determine errored slot\n", 273112feb904SMatthew Dillon PORTNAME(ap)); 27321980eff3SMatthew Dillon if (ap->ap_flags & AP_F_IN_RESET) 27331980eff3SMatthew Dillon goto fatal; 2734258223a3SMatthew Dillon goto failall; 2735258223a3SMatthew Dillon } 2736258223a3SMatthew Dillon 273712feb904SMatthew Dillon /* 273812feb904SMatthew Dillon * Finish error on slot. We will restart ci_saved 273912feb904SMatthew Dillon * commands except the errored slot which we generate 274012feb904SMatthew Dillon * a failure for. 274112feb904SMatthew Dillon */ 274212feb904SMatthew Dillon finish_error: 274312feb904SMatthew Dillon ccb = &ap->ap_ccbs[err_slot]; 2744258223a3SMatthew Dillon ci_saved &= ~(1 << err_slot); 2745258223a3SMatthew Dillon KKASSERT(ccb->ccb_xa.state == ATA_S_ONCHIP); 2746258223a3SMatthew Dillon ccb->ccb_xa.state = ATA_S_ERROR; 27471980eff3SMatthew Dillon } else if (is & AHCI_PREG_IS_DHRS) { 27481980eff3SMatthew Dillon /* 2749f4553de1SMatthew Dillon * Command posted D2H register FIS to the rfis (non-blocking). 2750f4553de1SMatthew Dillon * 275112feb904SMatthew Dillon * A normal completion with an error may set DHRS instead 275212feb904SMatthew Dillon * of TFES. The CCS bits are only valid if ERR was set. 275312feb904SMatthew Dillon * If ERR is set command processing was probably stopped. 27548bf6a3ffSMatthew Dillon * 275512feb904SMatthew Dillon * If ERR was not set we can only copy-back data for 275612feb904SMatthew Dillon * exclusive-mode commands because otherwise we won't know 275712feb904SMatthew Dillon * which tag the rfis belonged to. 275812feb904SMatthew Dillon * 275912feb904SMatthew Dillon * err_slot must be read from the CCS before any other port 276012feb904SMatthew Dillon * action, such as stopping the port. 276112feb904SMatthew Dillon * 276212feb904SMatthew Dillon * WARNING! This is not well documented in the AHCI spec. 276312feb904SMatthew Dillon * It can be found in the state machine tables 276412feb904SMatthew Dillon * but not in the explanations. 27651980eff3SMatthew Dillon */ 276612feb904SMatthew Dillon u_int32_t tfd; 276712feb904SMatthew Dillon u_int32_t cmd; 27681980eff3SMatthew Dillon int err_slot; 27691980eff3SMatthew Dillon 277012feb904SMatthew Dillon tfd = ahci_pread(ap, AHCI_PREG_TFD); 277112feb904SMatthew Dillon cmd = ahci_pread(ap, AHCI_PREG_CMD); 277212feb904SMatthew Dillon 27733d102df7SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_DHRS); 2774eb9f4c83SMatthew Dillon 2775eb9f4c83SMatthew Dillon /* 2776eb9f4c83SMatthew Dillon * If command processing is turned off we can process the 2777eb9f4c83SMatthew Dillon * error immediately. Use the ST bit here instead of the 2778eb9f4c83SMatthew Dillon * CR bit in case the CR bit is not implemented via the 2779eb9f4c83SMatthew Dillon * F_IGN_CR quirk. 2780eb9f4c83SMatthew Dillon */ 278112feb904SMatthew Dillon if ((tfd & AHCI_PREG_TFD_STS_ERR) && 2782eb9f4c83SMatthew Dillon (cmd & AHCI_PREG_CMD_ST) == 0) { 27831980eff3SMatthew Dillon err_slot = AHCI_PREG_CMD_CCS( 27841980eff3SMatthew Dillon ahci_pread(ap, AHCI_PREG_CMD)); 27851980eff3SMatthew Dillon ccb = &ap->ap_ccbs[err_slot]; 278612feb904SMatthew Dillon kprintf("%s: DHRS tfd=%b err_slot=%d cmd=%02x\n", 278712feb904SMatthew Dillon PORTNAME(ap), 278812feb904SMatthew Dillon tfd, AHCI_PFMT_TFD_STS, 278912feb904SMatthew Dillon err_slot, ccb->ccb_xa.fis->command); 279012feb904SMatthew Dillon goto process_error; 2791258223a3SMatthew Dillon } 279212feb904SMatthew Dillon /* 279312feb904SMatthew Dillon * NO ELSE... copy back is in the normal command completion 279412feb904SMatthew Dillon * code and only if no error occured and ATA_F_AUTOSENSE 279512feb904SMatthew Dillon * was set. 279612feb904SMatthew Dillon */ 27971980eff3SMatthew Dillon } 27981980eff3SMatthew Dillon 27991980eff3SMatthew Dillon /* 2800f4553de1SMatthew Dillon * Device notification to us (non-blocking) 28011980eff3SMatthew Dillon * 280212feb904SMatthew Dillon * NOTE! On some parts notification bits can cause an IPMS 280312feb904SMatthew Dillon * interrupt instead of a SDBS interrupt. 2804cec07d75SMatthew Dillon * 280512feb904SMatthew Dillon * NOTE! On some parts (e.g. VBOX, probably intel ICHx), 280612feb904SMatthew Dillon * SDBS notifies us of the completion of a NCQ command 280712feb904SMatthew Dillon * and DBS does not. 28081980eff3SMatthew Dillon */ 280912feb904SMatthew Dillon if (is & (AHCI_PREG_IS_SDBS | AHCI_PREG_IS_IPMS)) { 28101980eff3SMatthew Dillon u_int32_t data; 28111980eff3SMatthew Dillon 281212feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, 281312feb904SMatthew Dillon AHCI_PREG_IS_SDBS | AHCI_PREG_IS_IPMS); 281412feb904SMatthew Dillon if (sc->sc_cap & AHCI_REG_CAP_SSNTF) { 28151980eff3SMatthew Dillon data = ahci_pread(ap, AHCI_PREG_SNTF); 2816cec07d75SMatthew Dillon if (data) { 281712feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, 281812feb904SMatthew Dillon AHCI_PREG_IS_SDBS); 281912feb904SMatthew Dillon kprintf("%s: NOTIFY %08x\n", 282012feb904SMatthew Dillon PORTNAME(ap), data); 282112feb904SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, 282212feb904SMatthew Dillon AHCI_PREG_SERR_DIAG_N); 28233209f581SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SNTF, data); 28243209f581SMatthew Dillon ahci_cam_changed(ap, NULL, -1); 28251980eff3SMatthew Dillon } 28261980eff3SMatthew Dillon } 282712feb904SMatthew Dillon is &= ~(AHCI_PREG_IS_SDBS | AHCI_PREG_IS_IPMS); 282812feb904SMatthew Dillon } 28293209f581SMatthew Dillon 28303209f581SMatthew Dillon /* 2831492bffafSMatthew Dillon * Spurious IFS errors (blockable) - when AP_F_IGNORE_IFS is set. 2832f4553de1SMatthew Dillon * 28333209f581SMatthew Dillon * Spurious IFS errors can occur while we are doing a reset 2834492bffafSMatthew Dillon * sequence through a PM, probably due to an unexpected FIS 2835492bffafSMatthew Dillon * being received during the PM target reset sequence. Chipsets 2836492bffafSMatthew Dillon * are supposed to mask these events but some do not. 2837492bffafSMatthew Dillon * 2838492bffafSMatthew Dillon * Try to recover from the condition. 28393209f581SMatthew Dillon */ 28403209f581SMatthew Dillon if ((is & AHCI_PREG_IS_IFS) && (ap->ap_flags & AP_F_IGNORE_IFS)) { 28411980eff3SMatthew Dillon u_int32_t serr = ahci_pread(ap, AHCI_PREG_SERR); 28423209f581SMatthew Dillon if ((ap->ap_flags & AP_F_IFS_IGNORED) == 0) { 2843492bffafSMatthew Dillon kprintf("%s: IFS during PM probe (ignored) " 2844492bffafSMatthew Dillon "IS=%b, SERR=%b\n", 28451980eff3SMatthew Dillon PORTNAME(ap), 28461980eff3SMatthew Dillon is, AHCI_PFMT_IS, 28471980eff3SMatthew Dillon serr, AHCI_PFMT_SERR); 28483209f581SMatthew Dillon ap->ap_flags |= AP_F_IFS_IGNORED; 28493209f581SMatthew Dillon } 2850492bffafSMatthew Dillon 2851492bffafSMatthew Dillon /* 2852492bffafSMatthew Dillon * Try to clear the error condition. The IFS error killed 2853492bffafSMatthew Dillon * the port so stop it so we can restart it. 2854492bffafSMatthew Dillon */ 28551980eff3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, AHCI_PREG_IS_IFS); 28563d102df7SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 28571980eff3SMatthew Dillon is &= ~AHCI_PREG_IS_IFS; 2858492bffafSMatthew Dillon need = NEED_RESTART; 285912feb904SMatthew Dillon goto failall; 28601980eff3SMatthew Dillon } 2861258223a3SMatthew Dillon 2862258223a3SMatthew Dillon /* 2863f4553de1SMatthew Dillon * Port change (hot-plug) (blockable). 2864258223a3SMatthew Dillon * 2865492bffafSMatthew Dillon * A PRCS interrupt can occur: 2866492bffafSMatthew Dillon * (1) On hot-unplug / normal-unplug (phy lost) 2867492bffafSMatthew Dillon * (2) Sometimes on hot-plug too. 2868258223a3SMatthew Dillon * 2869492bffafSMatthew Dillon * A PCS interrupt can occur in a number of situations: 2870492bffafSMatthew Dillon * (1) On hot-plug once communication is established 2871492bffafSMatthew Dillon * (2) On hot-unplug sometimes. 2872492bffafSMatthew Dillon * (3) For chipsets with badly written firmware it can occur 2873492bffafSMatthew Dillon * during INIT/RESET sequences due to the device reset. 2874492bffafSMatthew Dillon * (4) For chipsets with badly written firmware it can occur 2875492bffafSMatthew Dillon * when it thinks an unsolicited COMRESET is received 2876492bffafSMatthew Dillon * during a INIT/RESET sequence, even though we actually 2877492bffafSMatthew Dillon * did request it. 2878258223a3SMatthew Dillon * 287922181ab7SMatthew Dillon * XXX We can then check the CPS (Cold Presence State) bit, if 288022181ab7SMatthew Dillon * supported, to determine if a device is plugged in or not and do 288122181ab7SMatthew Dillon * the right thing. 288222181ab7SMatthew Dillon * 2883492bffafSMatthew Dillon * PCS interrupts are cleared by clearing DIAG_X. If this occurs 2884492bffafSMatthew Dillon * command processing is automatically stopped (CR goes inactive) 2885492bffafSMatthew Dillon * and the port must be stopped and restarted. 2886492bffafSMatthew Dillon * 2887492bffafSMatthew Dillon * WARNING: AMD parts (e.g. 880G chipset, probably others) can 2888492bffafSMatthew Dillon * generate PCS on initialization even when device is 2889492bffafSMatthew Dillon * already connected up. It is unclear why this happens. 2890492bffafSMatthew Dillon * Depending on the state of the device detect this can 2891492bffafSMatthew Dillon * cause us to go into harsh reinit or hot-plug insertion 2892492bffafSMatthew Dillon * mode. 2893492bffafSMatthew Dillon * 2894492bffafSMatthew Dillon * WARNING: PCS errors can be repetitive (e.g. unsolicited COMRESET 2895492bffafSMatthew Dillon * continues to flow in from the device), we must clear the 2896492bffafSMatthew Dillon * interrupt in all cases and enforce a delay to prevent 2897492bffafSMatthew Dillon * a livelock and give the port time to settle down. 2898492bffafSMatthew Dillon * Only print something if we aren't in INIT/HARD-RESET. 2899258223a3SMatthew Dillon */ 2900258223a3SMatthew Dillon if (is & (AHCI_PREG_IS_PCS | AHCI_PREG_IS_PRCS)) { 29013d102df7SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, 29023d102df7SMatthew Dillon is & (AHCI_PREG_IS_PCS | AHCI_PREG_IS_PRCS)); 2903492bffafSMatthew Dillon /* 2904492bffafSMatthew Dillon * Try to clear the error. Because of the repetitiveness 2905492bffafSMatthew Dillon * of this interrupt avoid any harsh action if the port is 2906492bffafSMatthew Dillon * already in the init or hard-reset probe state. 2907492bffafSMatthew Dillon */ 2908492bffafSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SERR, -1); 2909492bffafSMatthew Dillon /* (AHCI_PREG_SERR_DIAG_N | AHCI_PREG_SERR_DIAG_X) */ 2910492bffafSMatthew Dillon 2911493d3201SMatthew Dillon /* 2912493d3201SMatthew Dillon * Ignore PCS/PRCS errors during probes (but still clear the 2913493d3201SMatthew Dillon * interrupt to avoid a livelock). The AMD 880/890/SB850 2914493d3201SMatthew Dillon * chipsets do not mask PCS/PRCS internally during reset 2915493d3201SMatthew Dillon * sequences. 2916493d3201SMatthew Dillon */ 29175502cf24SMatthew Dillon if (ap->ap_flags & AP_F_IN_RESET) 2918493d3201SMatthew Dillon goto skip_pcs; 2919493d3201SMatthew Dillon 2920492bffafSMatthew Dillon if (ap->ap_probe == ATA_PROBE_NEED_INIT || 2921492bffafSMatthew Dillon ap->ap_probe == ATA_PROBE_NEED_HARD_RESET) { 2922cec07d75SMatthew Dillon is &= ~(AHCI_PREG_IS_PCS | AHCI_PREG_IS_PRCS); 2923492bffafSMatthew Dillon need = NEED_NOTHING; 2924492bffafSMatthew Dillon ahci_os_sleep(1000); 2925492bffafSMatthew Dillon goto failall; 2926492bffafSMatthew Dillon } 2927492bffafSMatthew Dillon kprintf("%s: Transient Errors: %b (%d)\n", 2928492bffafSMatthew Dillon PORTNAME(ap), is, AHCI_PFMT_IS, ap->ap_probe); 2929492bffafSMatthew Dillon is &= ~(AHCI_PREG_IS_PCS | AHCI_PREG_IS_PRCS); 2930492bffafSMatthew Dillon ahci_os_sleep(200); 2931492bffafSMatthew Dillon 2932492bffafSMatthew Dillon /* 2933492bffafSMatthew Dillon * Stop the port and figure out what to do next. 2934492bffafSMatthew Dillon */ 293522181ab7SMatthew Dillon ahci_port_stop(ap, 0); 2936492bffafSMatthew Dillon stopped = 1; 29370be9576aSMatthew Dillon 2938258223a3SMatthew Dillon switch (ahci_pread(ap, AHCI_PREG_SSTS) & AHCI_PREG_SSTS_DET) { 2939258223a3SMatthew Dillon case AHCI_PREG_SSTS_DET_DEV: 2940492bffafSMatthew Dillon /* 2941492bffafSMatthew Dillon * Device detect 2942492bffafSMatthew Dillon */ 294312feb904SMatthew Dillon if (ap->ap_probe == ATA_PROBE_FAILED) { 294422181ab7SMatthew Dillon need = NEED_HOTPLUG_INSERT; 294522181ab7SMatthew Dillon goto fatal; 2946258223a3SMatthew Dillon } 294722181ab7SMatthew Dillon need = NEED_RESTART; 2948258223a3SMatthew Dillon break; 2949492bffafSMatthew Dillon case AHCI_PREG_SSTS_DET_DEV_NE: 2950492bffafSMatthew Dillon /* 2951492bffafSMatthew Dillon * Device not communicating. AMD parts seem to 2952492bffafSMatthew Dillon * like to throw this error on initialization 2953492bffafSMatthew Dillon * for no reason that I can fathom. 2954492bffafSMatthew Dillon */ 2955492bffafSMatthew Dillon kprintf("%s: Device present but not communicating, " 2956492bffafSMatthew Dillon "attempting port restart\n", 2957492bffafSMatthew Dillon PORTNAME(ap)); 2958492bffafSMatthew Dillon need = NEED_REINIT; 2959492bffafSMatthew Dillon goto fatal; 2960258223a3SMatthew Dillon default: 29610be9576aSMatthew Dillon if (ap->ap_probe != ATA_PROBE_FAILED) { 296222181ab7SMatthew Dillon need = NEED_HOTPLUG_REMOVE; 296322181ab7SMatthew Dillon goto fatal; 2964258223a3SMatthew Dillon } 296522181ab7SMatthew Dillon need = NEED_RESTART; 2966258223a3SMatthew Dillon break; 2967258223a3SMatthew Dillon } 2968493d3201SMatthew Dillon skip_pcs: 2969493d3201SMatthew Dillon ; 2970258223a3SMatthew Dillon } 2971258223a3SMatthew Dillon 297222181ab7SMatthew Dillon /* 2973f4553de1SMatthew Dillon * Check for remaining errors - they are fatal. (blockable) 297422181ab7SMatthew Dillon */ 2975258223a3SMatthew Dillon if (is & (AHCI_PREG_IS_TFES | AHCI_PREG_IS_HBFS | AHCI_PREG_IS_IFS | 2976258223a3SMatthew Dillon AHCI_PREG_IS_OFS | AHCI_PREG_IS_UFS)) { 2977cec07d75SMatthew Dillon u_int32_t serr; 2978cec07d75SMatthew Dillon 2979cec07d75SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, 2980cec07d75SMatthew Dillon is & (AHCI_PREG_IS_TFES | AHCI_PREG_IS_HBFS | 2981cec07d75SMatthew Dillon AHCI_PREG_IS_IFS | AHCI_PREG_IS_OFS | 2982cec07d75SMatthew Dillon AHCI_PREG_IS_UFS)); 2983cec07d75SMatthew Dillon serr = ahci_pread(ap, AHCI_PREG_SERR); 2984831bc9e3SMatthew Dillon kprintf("%s: Unrecoverable errors (IS: %b, SERR: %b), " 29854444122dSMatthew Dillon "disabling port.\n", 29864444122dSMatthew Dillon PORTNAME(ap), 29874444122dSMatthew Dillon is, AHCI_PFMT_IS, 29881980eff3SMatthew Dillon serr, AHCI_PFMT_SERR 29894444122dSMatthew Dillon ); 2990831bc9e3SMatthew Dillon is &= ~(AHCI_PREG_IS_TFES | AHCI_PREG_IS_HBFS | 2991831bc9e3SMatthew Dillon AHCI_PREG_IS_IFS | AHCI_PREG_IS_OFS | 2992831bc9e3SMatthew Dillon AHCI_PREG_IS_UFS); 2993492bffafSMatthew Dillon 2994492bffafSMatthew Dillon /* 2995492bffafSMatthew Dillon * Fail all commands but then what? For now try to 2996492bffafSMatthew Dillon * reinitialize the port. 2997492bffafSMatthew Dillon */ 2998492bffafSMatthew Dillon need = NEED_REINIT; 2999258223a3SMatthew Dillon goto fatal; 3000258223a3SMatthew Dillon } 3001258223a3SMatthew Dillon 300222181ab7SMatthew Dillon /* 300322181ab7SMatthew Dillon * Fail all outstanding commands if we know the port won't recover. 30041980eff3SMatthew Dillon * 30051980eff3SMatthew Dillon * We may have a ccb_at if the failed command is known and was 30061980eff3SMatthew Dillon * being sent to a device over a port multiplier (PM). In this 30071980eff3SMatthew Dillon * case if the port itself has not completely failed we fail just 30081980eff3SMatthew Dillon * the commands related to that target. 300912feb904SMatthew Dillon * 301012feb904SMatthew Dillon * ci_saved contains the mask of active commands as of when the 301112feb904SMatthew Dillon * error occured, prior to any port stops. 301222181ab7SMatthew Dillon */ 3013258223a3SMatthew Dillon if (ap->ap_state == AP_S_FATAL_ERROR) { 3014258223a3SMatthew Dillon fatal: 3015258223a3SMatthew Dillon ap->ap_state = AP_S_FATAL_ERROR; 301612feb904SMatthew Dillon failall: 3017492bffafSMatthew Dillon ahci_port_stop(ap, 0); 3018492bffafSMatthew Dillon stopped = 1; 3019258223a3SMatthew Dillon 30201980eff3SMatthew Dillon /* 3021492bffafSMatthew Dillon * Error all the active slots not already errored. 30221980eff3SMatthew Dillon */ 302312feb904SMatthew Dillon ci_masked = ci_saved & *active & ~ap->ap_expired; 3024492bffafSMatthew Dillon if (ci_masked) { 3025492bffafSMatthew Dillon kprintf("%s: Failing all commands: %08x\n", 3026492bffafSMatthew Dillon PORTNAME(ap), ci_masked); 3027492bffafSMatthew Dillon } 3028492bffafSMatthew Dillon 3029258223a3SMatthew Dillon while (ci_masked) { 3030258223a3SMatthew Dillon slot = ffs(ci_masked) - 1; 3031258223a3SMatthew Dillon ccb = &ap->ap_ccbs[slot]; 303212feb904SMatthew Dillon ccb->ccb_xa.state = ATA_S_TIMEOUT; 303312feb904SMatthew Dillon ap->ap_expired |= 1 << slot; 303412feb904SMatthew Dillon ci_saved &= ~(1 << slot); 303512feb904SMatthew Dillon ci_masked &= ~(1 << slot); 30361980eff3SMatthew Dillon } 3037258223a3SMatthew Dillon 303812feb904SMatthew Dillon /* 303912feb904SMatthew Dillon * Clear bits in ci_saved (cause completions to be run) 304012feb904SMatthew Dillon * for all slots which are not active. 304112feb904SMatthew Dillon */ 3042258223a3SMatthew Dillon ci_saved &= ~*active; 3043258223a3SMatthew Dillon 3044258223a3SMatthew Dillon /* 3045258223a3SMatthew Dillon * Don't restart the port if our problems were deemed fatal. 3046258223a3SMatthew Dillon * 3047258223a3SMatthew Dillon * Also acknowlege all fatal interrupt sources to prevent 3048258223a3SMatthew Dillon * a livelock. 3049258223a3SMatthew Dillon */ 3050258223a3SMatthew Dillon if (ap->ap_state == AP_S_FATAL_ERROR) { 305122181ab7SMatthew Dillon if (need == NEED_RESTART) 305222181ab7SMatthew Dillon need = NEED_NOTHING; 3053258223a3SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_IS, 3054258223a3SMatthew Dillon AHCI_PREG_IS_TFES | AHCI_PREG_IS_HBFS | 3055258223a3SMatthew Dillon AHCI_PREG_IS_IFS | AHCI_PREG_IS_OFS | 3056258223a3SMatthew Dillon AHCI_PREG_IS_UFS); 3057258223a3SMatthew Dillon } 3058258223a3SMatthew Dillon } 3059258223a3SMatthew Dillon 3060258223a3SMatthew Dillon /* 3061492bffafSMatthew Dillon * If we are stopped the AHCI chipset is supposed to have cleared 3062492bffafSMatthew Dillon * CI and SACT. Did it? If it didn't we try very hard to clear 3063492bffafSMatthew Dillon * the fields otherwise we may end up completing CCBs which are 3064492bffafSMatthew Dillon * actually still active. 3065492bffafSMatthew Dillon * 3066492bffafSMatthew Dillon * IFS errors on (at least) AMD chipsets create this confusion. 3067492bffafSMatthew Dillon */ 3068492bffafSMatthew Dillon if (stopped) { 3069492bffafSMatthew Dillon u_int32_t mask; 3070492bffafSMatthew Dillon if ((mask = ahci_pactive(ap)) != 0) { 3071492bffafSMatthew Dillon kprintf("%s: chipset failed to clear " 3072492bffafSMatthew Dillon "active cmds %08x\n", 3073492bffafSMatthew Dillon PORTNAME(ap), mask); 3074492bffafSMatthew Dillon ahci_port_start(ap); 3075492bffafSMatthew Dillon ahci_port_stop(ap, 0); 3076492bffafSMatthew Dillon if ((mask = ahci_pactive(ap)) != 0) { 3077492bffafSMatthew Dillon kprintf("%s: unable to prod the chip into " 3078492bffafSMatthew Dillon "clearing active cmds %08x\n", 3079492bffafSMatthew Dillon PORTNAME(ap), mask); 3080492bffafSMatthew Dillon /* what do we do now? */ 3081492bffafSMatthew Dillon } 3082492bffafSMatthew Dillon } 3083492bffafSMatthew Dillon } 3084492bffafSMatthew Dillon 3085492bffafSMatthew Dillon /* 3086f4553de1SMatthew Dillon * CCB completion (non blocking). 3087f4553de1SMatthew Dillon * 3088258223a3SMatthew Dillon * CCB completion is detected by noticing its slot's bit in CI has 3089258223a3SMatthew Dillon * changed to zero some time after we activated it. 3090258223a3SMatthew Dillon * If we are polling, we may only be interested in particular slot(s). 3091cf5f3a81SMatthew Dillon * 3092cf5f3a81SMatthew Dillon * Any active bits not saved are completed within the restrictions 3093cf5f3a81SMatthew Dillon * imposed by the caller. 3094258223a3SMatthew Dillon */ 30953209f581SMatthew Dillon ci_masked = ~ci_saved & *active; 3096258223a3SMatthew Dillon while (ci_masked) { 3097258223a3SMatthew Dillon slot = ffs(ci_masked) - 1; 3098258223a3SMatthew Dillon ccb = &ap->ap_ccbs[slot]; 3099258223a3SMatthew Dillon ci_masked &= ~(1 << slot); 3100258223a3SMatthew Dillon 3101258223a3SMatthew Dillon DPRINTF(AHCI_D_INTR, "%s: slot %d is complete%s\n", 3102258223a3SMatthew Dillon PORTNAME(ap), slot, ccb->ccb_xa.state == ATA_S_ERROR ? 3103258223a3SMatthew Dillon " (error)" : ""); 3104258223a3SMatthew Dillon 3105258223a3SMatthew Dillon bus_dmamap_sync(sc->sc_tag_cmdh, 3106258223a3SMatthew Dillon AHCI_DMA_MAP(ap->ap_dmamem_cmd_list), 3107258223a3SMatthew Dillon BUS_DMASYNC_POSTWRITE); 3108258223a3SMatthew Dillon 3109258223a3SMatthew Dillon bus_dmamap_sync(sc->sc_tag_cmdt, 3110258223a3SMatthew Dillon AHCI_DMA_MAP(ap->ap_dmamem_cmd_table), 3111258223a3SMatthew Dillon BUS_DMASYNC_POSTWRITE); 3112258223a3SMatthew Dillon 3113258223a3SMatthew Dillon bus_dmamap_sync(sc->sc_tag_rfis, 3114258223a3SMatthew Dillon AHCI_DMA_MAP(ap->ap_dmamem_rfis), 3115258223a3SMatthew Dillon BUS_DMASYNC_POSTREAD); 3116258223a3SMatthew Dillon 3117258223a3SMatthew Dillon *active &= ~(1 << ccb->ccb_slot); 31181980eff3SMatthew Dillon if (active == &ap->ap_active) { 31191980eff3SMatthew Dillon KKASSERT(ap->ap_active_cnt > 0); 31201980eff3SMatthew Dillon --ap->ap_active_cnt; 31211980eff3SMatthew Dillon } 31224c339a5fSMatthew Dillon 31234c339a5fSMatthew Dillon /* 31244c339a5fSMatthew Dillon * Complete the ccb. If the ccb was marked expired it 31254c339a5fSMatthew Dillon * was probably already removed from the command processor, 31264c339a5fSMatthew Dillon * so don't take the clear ci_saved bit as meaning the 31274c339a5fSMatthew Dillon * command actually succeeded, it didn't. 31284c339a5fSMatthew Dillon */ 31294c339a5fSMatthew Dillon if (ap->ap_expired & (1 << ccb->ccb_slot)) { 313076497a9cSMatthew Dillon ap->ap_expired &= ~(1 << ccb->ccb_slot); 31314c339a5fSMatthew Dillon ccb->ccb_xa.state = ATA_S_TIMEOUT; 3132258223a3SMatthew Dillon ccb->ccb_done(ccb); 31334c339a5fSMatthew Dillon ccb->ccb_xa.complete(&ccb->ccb_xa); 31344c339a5fSMatthew Dillon } else { 313512feb904SMatthew Dillon if (ccb->ccb_xa.state == ATA_S_ONCHIP) { 31364c339a5fSMatthew Dillon ccb->ccb_xa.state = ATA_S_COMPLETE; 313712feb904SMatthew Dillon if (ccb->ccb_xa.flags & ATA_F_AUTOSENSE) { 31388119d5f5SMatthew Dillon int fis_target; 31398119d5f5SMatthew Dillon 31408119d5f5SMatthew Dillon ccb_at = ccb->ccb_xa.at; 31418119d5f5SMatthew Dillon if (ccb_at && 31428119d5f5SMatthew Dillon (ap->ap_flags & AP_F_FBSS_ENABLED)) 31438119d5f5SMatthew Dillon fis_target = ccb_at->at_target; 31448119d5f5SMatthew Dillon else 31458119d5f5SMatthew Dillon fis_target = 0; 314612feb904SMatthew Dillon memcpy(&ccb->ccb_xa.rfis, 31478119d5f5SMatthew Dillon ap->ap_rfis[fis_target].rfis, 314812feb904SMatthew Dillon sizeof(struct ata_fis_d2h)); 314912feb904SMatthew Dillon if (ccb->ccb_xa.state == ATA_S_TIMEOUT) 315012feb904SMatthew Dillon ccb->ccb_xa.state = ATA_S_ERROR; 315112feb904SMatthew Dillon } 315212feb904SMatthew Dillon } 31534c339a5fSMatthew Dillon ccb->ccb_done(ccb); 31544c339a5fSMatthew Dillon } 3155258223a3SMatthew Dillon } 3156258223a3SMatthew Dillon 3157f4553de1SMatthew Dillon /* 3158f4553de1SMatthew Dillon * Cleanup. Will not be set if non-blocking. 3159f4553de1SMatthew Dillon */ 316022181ab7SMatthew Dillon switch(need) { 3161f3de36f7SMatthew Dillon case NEED_NOTHING: 3162f3de36f7SMatthew Dillon /* 3163f3de36f7SMatthew Dillon * If operating normally and not stopped the interrupt was 3164f3de36f7SMatthew Dillon * probably just a normal completion and we may be able to 3165f3de36f7SMatthew Dillon * issue more commands. 3166f3de36f7SMatthew Dillon */ 3167f3de36f7SMatthew Dillon if (stopped == 0 && ap->ap_state != AP_S_FATAL_ERROR) 3168f3de36f7SMatthew Dillon ahci_issue_pending_commands(ap, NULL); 3169f3de36f7SMatthew Dillon break; 317022181ab7SMatthew Dillon case NEED_RESTART: 317122181ab7SMatthew Dillon /* 317222181ab7SMatthew Dillon * A recoverable error occured and we can restart outstanding 317322181ab7SMatthew Dillon * commands on the port. 317422181ab7SMatthew Dillon */ 317512feb904SMatthew Dillon ci_saved &= ~ap->ap_expired; 3176258223a3SMatthew Dillon if (ci_saved) { 317712feb904SMatthew Dillon kprintf("%s: Restart %08x\n", PORTNAME(ap), ci_saved); 31784c339a5fSMatthew Dillon ahci_issue_saved_commands(ap, ci_saved); 3179258223a3SMatthew Dillon } 3180492bffafSMatthew Dillon 3181492bffafSMatthew Dillon /* 3182492bffafSMatthew Dillon * Potentially issue new commands if not in a failed 3183492bffafSMatthew Dillon * state. 3184492bffafSMatthew Dillon */ 3185492bffafSMatthew Dillon if (ap->ap_state != AP_S_FATAL_ERROR) { 3186492bffafSMatthew Dillon ahci_port_start(ap); 3187492bffafSMatthew Dillon ahci_issue_pending_commands(ap, NULL); 3188492bffafSMatthew Dillon } 3189492bffafSMatthew Dillon break; 3190492bffafSMatthew Dillon case NEED_REINIT: 3191492bffafSMatthew Dillon /* 3192492bffafSMatthew Dillon * Something horrible happened to the port and we 3193492bffafSMatthew Dillon * need to reinitialize it. 3194492bffafSMatthew Dillon */ 3195492bffafSMatthew Dillon kprintf("%s: REINIT - Attempting to reinitialize the port " 3196492bffafSMatthew Dillon "after it had a horrible accident\n", 3197492bffafSMatthew Dillon PORTNAME(ap)); 3198492bffafSMatthew Dillon ap->ap_flags |= AP_F_IN_RESET; 3199492bffafSMatthew Dillon ap->ap_flags |= AP_F_HARSH_REINIT; 3200492bffafSMatthew Dillon ap->ap_probe = ATA_PROBE_NEED_INIT; 3201492bffafSMatthew Dillon ahci_cam_changed(ap, NULL, -1); 320222181ab7SMatthew Dillon break; 320322181ab7SMatthew Dillon case NEED_HOTPLUG_INSERT: 320422181ab7SMatthew Dillon /* 3205cf5f3a81SMatthew Dillon * A hot-plug insertion event has occured and all 3206cf5f3a81SMatthew Dillon * outstanding commands have already been revoked. 32071980eff3SMatthew Dillon * 32081980eff3SMatthew Dillon * Don't recurse if this occurs while we are 32091980eff3SMatthew Dillon * resetting the port. 321022181ab7SMatthew Dillon */ 32111980eff3SMatthew Dillon if ((ap->ap_flags & AP_F_IN_RESET) == 0) { 321222181ab7SMatthew Dillon kprintf("%s: HOTPLUG - Device inserted\n", 321322181ab7SMatthew Dillon PORTNAME(ap)); 32143209f581SMatthew Dillon ap->ap_probe = ATA_PROBE_NEED_INIT; 32153209f581SMatthew Dillon ahci_cam_changed(ap, NULL, -1); 32161980eff3SMatthew Dillon } 321722181ab7SMatthew Dillon break; 321822181ab7SMatthew Dillon case NEED_HOTPLUG_REMOVE: 3219cf5f3a81SMatthew Dillon /* 3220cf5f3a81SMatthew Dillon * A hot-plug removal event has occured and all 3221cf5f3a81SMatthew Dillon * outstanding commands have already been revoked. 32221980eff3SMatthew Dillon * 32231980eff3SMatthew Dillon * Don't recurse if this occurs while we are 32241980eff3SMatthew Dillon * resetting the port. 3225cf5f3a81SMatthew Dillon */ 32261980eff3SMatthew Dillon if ((ap->ap_flags & AP_F_IN_RESET) == 0) { 322722181ab7SMatthew Dillon kprintf("%s: HOTPLUG - Device removed\n", 322822181ab7SMatthew Dillon PORTNAME(ap)); 3229cf5f3a81SMatthew Dillon ahci_port_hardstop(ap); 32303209f581SMatthew Dillon /* ap_probe set to failed */ 32313209f581SMatthew Dillon ahci_cam_changed(ap, NULL, -1); 32321980eff3SMatthew Dillon } 323322181ab7SMatthew Dillon break; 323422181ab7SMatthew Dillon default: 323522181ab7SMatthew Dillon break; 3236258223a3SMatthew Dillon } 3237258223a3SMatthew Dillon } 3238258223a3SMatthew Dillon 3239258223a3SMatthew Dillon struct ahci_ccb * 3240258223a3SMatthew Dillon ahci_get_ccb(struct ahci_port *ap) 3241258223a3SMatthew Dillon { 3242258223a3SMatthew Dillon struct ahci_ccb *ccb; 3243258223a3SMatthew Dillon 3244258223a3SMatthew Dillon lockmgr(&ap->ap_ccb_lock, LK_EXCLUSIVE); 3245258223a3SMatthew Dillon ccb = TAILQ_FIRST(&ap->ap_ccb_free); 3246258223a3SMatthew Dillon if (ccb != NULL) { 3247d16d3400SMatthew Dillon KKASSERT((ap->ap_sactive & (1 << ccb->ccb_slot)) == 0); 3248258223a3SMatthew Dillon KKASSERT(ccb->ccb_xa.state == ATA_S_PUT); 3249258223a3SMatthew Dillon TAILQ_REMOVE(&ap->ap_ccb_free, ccb, ccb_entry); 3250258223a3SMatthew Dillon ccb->ccb_xa.state = ATA_S_SETUP; 3251492bffafSMatthew Dillon ccb->ccb_xa.flags = 0; 32521980eff3SMatthew Dillon ccb->ccb_xa.at = NULL; 3253258223a3SMatthew Dillon } 3254258223a3SMatthew Dillon lockmgr(&ap->ap_ccb_lock, LK_RELEASE); 3255258223a3SMatthew Dillon 3256258223a3SMatthew Dillon return (ccb); 3257258223a3SMatthew Dillon } 3258258223a3SMatthew Dillon 3259258223a3SMatthew Dillon void 3260258223a3SMatthew Dillon ahci_put_ccb(struct ahci_ccb *ccb) 3261258223a3SMatthew Dillon { 3262258223a3SMatthew Dillon struct ahci_port *ap = ccb->ccb_port; 3263258223a3SMatthew Dillon 3264d16d3400SMatthew Dillon KKASSERT(ccb->ccb_xa.state != ATA_S_PUT); 3265d16d3400SMatthew Dillon KKASSERT((ap->ap_sactive & (1 << ccb->ccb_slot)) == 0); 3266258223a3SMatthew Dillon lockmgr(&ap->ap_ccb_lock, LK_EXCLUSIVE); 3267dcdc0770SMatthew Dillon ccb->ccb_xa.state = ATA_S_PUT; 3268bb79834dSMatthew Dillon ++ccb->ccb_xa.serial; 3269258223a3SMatthew Dillon TAILQ_INSERT_TAIL(&ap->ap_ccb_free, ccb, ccb_entry); 3270258223a3SMatthew Dillon lockmgr(&ap->ap_ccb_lock, LK_RELEASE); 3271258223a3SMatthew Dillon } 3272258223a3SMatthew Dillon 3273258223a3SMatthew Dillon struct ahci_ccb * 3274258223a3SMatthew Dillon ahci_get_err_ccb(struct ahci_port *ap) 3275258223a3SMatthew Dillon { 3276258223a3SMatthew Dillon struct ahci_ccb *err_ccb; 3277258223a3SMatthew Dillon u_int32_t sact; 3278b012a2caSMatthew Dillon u_int32_t ci; 3279258223a3SMatthew Dillon 3280258223a3SMatthew Dillon /* No commands may be active on the chip. */ 3281b012a2caSMatthew Dillon 3282b012a2caSMatthew Dillon if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SNCQ) { 3283258223a3SMatthew Dillon sact = ahci_pread(ap, AHCI_PREG_SACT); 3284192ee1d0SMatthew Dillon if (sact != 0) { 3285192ee1d0SMatthew Dillon kprintf("%s: ahci_get_err_ccb but SACT %08x != 0?\n", 3286192ee1d0SMatthew Dillon PORTNAME(ap), sact); 3287192ee1d0SMatthew Dillon } 3288b012a2caSMatthew Dillon } 3289b012a2caSMatthew Dillon ci = ahci_pread(ap, AHCI_PREG_CI); 3290b012a2caSMatthew Dillon if (ci) { 3291b012a2caSMatthew Dillon kprintf("%s: ahci_get_err_ccb: ci not 0 (%08x)\n", 3292b012a2caSMatthew Dillon ap->ap_name, ci); 3293b012a2caSMatthew Dillon } 3294b012a2caSMatthew Dillon KKASSERT(ci == 0); 3295baef7501SMatthew Dillon KKASSERT((ap->ap_flags & AP_F_ERR_CCB_RESERVED) == 0); 3296baef7501SMatthew Dillon ap->ap_flags |= AP_F_ERR_CCB_RESERVED; 3297258223a3SMatthew Dillon 3298258223a3SMatthew Dillon /* Save outstanding command state. */ 3299258223a3SMatthew Dillon ap->ap_err_saved_active = ap->ap_active; 3300258223a3SMatthew Dillon ap->ap_err_saved_active_cnt = ap->ap_active_cnt; 3301258223a3SMatthew Dillon ap->ap_err_saved_sactive = ap->ap_sactive; 3302258223a3SMatthew Dillon 3303258223a3SMatthew Dillon /* 3304258223a3SMatthew Dillon * Pretend we have no commands outstanding, so that completions won't 3305258223a3SMatthew Dillon * run prematurely. 3306258223a3SMatthew Dillon */ 3307258223a3SMatthew Dillon ap->ap_active = ap->ap_active_cnt = ap->ap_sactive = 0; 3308258223a3SMatthew Dillon 3309258223a3SMatthew Dillon /* 3310258223a3SMatthew Dillon * Grab a CCB to use for error recovery. This should never fail, as 3311258223a3SMatthew Dillon * we ask atascsi to reserve one for us at init time. 3312258223a3SMatthew Dillon */ 33131067474aSMatthew Dillon err_ccb = ap->ap_err_ccb; 3314258223a3SMatthew Dillon KKASSERT(err_ccb != NULL); 3315258223a3SMatthew Dillon err_ccb->ccb_xa.flags = 0; 3316258223a3SMatthew Dillon err_ccb->ccb_done = ahci_empty_done; 3317258223a3SMatthew Dillon 3318258223a3SMatthew Dillon return err_ccb; 3319258223a3SMatthew Dillon } 3320258223a3SMatthew Dillon 3321258223a3SMatthew Dillon void 3322258223a3SMatthew Dillon ahci_put_err_ccb(struct ahci_ccb *ccb) 3323258223a3SMatthew Dillon { 3324258223a3SMatthew Dillon struct ahci_port *ap = ccb->ccb_port; 3325258223a3SMatthew Dillon u_int32_t sact; 33265f8c1efdSMatthew Dillon u_int32_t ci; 3327258223a3SMatthew Dillon 3328baef7501SMatthew Dillon KKASSERT((ap->ap_flags & AP_F_ERR_CCB_RESERVED) != 0); 3329baef7501SMatthew Dillon 33305f8c1efdSMatthew Dillon /* 33315f8c1efdSMatthew Dillon * No commands may be active on the chip 33325f8c1efdSMatthew Dillon */ 3333b012a2caSMatthew Dillon if (ap->ap_sc->sc_cap & AHCI_REG_CAP_SNCQ) { 3334258223a3SMatthew Dillon sact = ahci_pread(ap, AHCI_PREG_SACT); 33355f8c1efdSMatthew Dillon if (sact) { 3336ed20d0e3SSascha Wildner panic("ahci_port_err_ccb(%d) but SACT %08x != 0", 33375f8c1efdSMatthew Dillon ccb->ccb_slot, sact); 3338258223a3SMatthew Dillon } 3339b012a2caSMatthew Dillon } 33405f8c1efdSMatthew Dillon ci = ahci_pread(ap, AHCI_PREG_CI); 33415f8c1efdSMatthew Dillon if (ci) { 3342cf5f3a81SMatthew Dillon panic("ahci_put_err_ccb(%d) but CI %08x != 0 " 3343cf5f3a81SMatthew Dillon "(act=%08x sact=%08x)\n", 3344cf5f3a81SMatthew Dillon ccb->ccb_slot, ci, 3345cf5f3a81SMatthew Dillon ap->ap_active, ap->ap_sactive); 33465f8c1efdSMatthew Dillon } 3347258223a3SMatthew Dillon 33481067474aSMatthew Dillon KKASSERT(ccb == ap->ap_err_ccb); 3349258223a3SMatthew Dillon 3350258223a3SMatthew Dillon /* Restore outstanding command state */ 3351258223a3SMatthew Dillon ap->ap_sactive = ap->ap_err_saved_sactive; 3352258223a3SMatthew Dillon ap->ap_active_cnt = ap->ap_err_saved_active_cnt; 3353258223a3SMatthew Dillon ap->ap_active = ap->ap_err_saved_active; 3354258223a3SMatthew Dillon 3355baef7501SMatthew Dillon ap->ap_flags &= ~AP_F_ERR_CCB_RESERVED; 3356258223a3SMatthew Dillon } 3357258223a3SMatthew Dillon 33581980eff3SMatthew Dillon /* 33591980eff3SMatthew Dillon * Read log page to get NCQ error. 33601980eff3SMatthew Dillon * 33611980eff3SMatthew Dillon * NOTE: NCQ not currently supported on port multipliers. XXX 33621980eff3SMatthew Dillon */ 3363258223a3SMatthew Dillon int 336412feb904SMatthew Dillon ahci_port_read_ncq_error(struct ahci_port *ap, int target) 3365258223a3SMatthew Dillon { 336612feb904SMatthew Dillon struct ata_log_page_10h *log; 3367258223a3SMatthew Dillon struct ahci_ccb *ccb; 3368e1014452SMatthew Dillon struct ahci_ccb *ccb2; 3369258223a3SMatthew Dillon struct ahci_cmd_hdr *cmd_slot; 3370258223a3SMatthew Dillon struct ata_fis_h2d *fis; 337112feb904SMatthew Dillon int err_slot; 3372258223a3SMatthew Dillon 337312feb904SMatthew Dillon if (bootverbose) { 337412feb904SMatthew Dillon kprintf("%s: READ LOG PAGE target %d\n", PORTNAME(ap), 337512feb904SMatthew Dillon target); 337612feb904SMatthew Dillon } 3377258223a3SMatthew Dillon 337812feb904SMatthew Dillon /* 337912feb904SMatthew Dillon * Prep error CCB for READ LOG EXT, page 10h, 1 sector. 338012feb904SMatthew Dillon * 338112feb904SMatthew Dillon * Getting err_ccb clears active/sactive/active_cnt, putting 338212feb904SMatthew Dillon * it back restores the fields. 338312feb904SMatthew Dillon */ 3384258223a3SMatthew Dillon ccb = ahci_get_err_ccb(ap); 338512feb904SMatthew Dillon ccb->ccb_xa.flags = ATA_F_READ | ATA_F_POLL; 3386258223a3SMatthew Dillon ccb->ccb_xa.data = ap->ap_err_scratch; 3387258223a3SMatthew Dillon ccb->ccb_xa.datalen = 512; 338812feb904SMatthew Dillon ccb->ccb_xa.complete = ahci_dummy_done; 3389b012a2caSMatthew Dillon ccb->ccb_xa.at = ap->ap_ata[target]; 3390258223a3SMatthew Dillon 3391258223a3SMatthew Dillon fis = (struct ata_fis_h2d *)ccb->ccb_cmd_table->cfis; 339212feb904SMatthew Dillon bzero(fis, sizeof(*fis)); 3393258223a3SMatthew Dillon fis->type = ATA_FIS_TYPE_H2D; 339412feb904SMatthew Dillon fis->flags = ATA_H2D_FLAGS_CMD | target; 3395258223a3SMatthew Dillon fis->command = ATA_C_READ_LOG_EXT; 3396258223a3SMatthew Dillon fis->lba_low = 0x10; /* queued error log page (10h) */ 3397258223a3SMatthew Dillon fis->sector_count = 1; /* number of sectors (1) */ 3398258223a3SMatthew Dillon fis->sector_count_exp = 0; 3399258223a3SMatthew Dillon fis->lba_mid = 0; /* starting offset */ 3400258223a3SMatthew Dillon fis->lba_mid_exp = 0; 3401258223a3SMatthew Dillon fis->device = 0; 3402258223a3SMatthew Dillon 340312feb904SMatthew Dillon cmd_slot = ccb->ccb_cmd_hdr; 3404258223a3SMatthew Dillon cmd_slot->flags = htole16(5); /* FIS length: 5 DWORDS */ 3405258223a3SMatthew Dillon 3406258223a3SMatthew Dillon if (ahci_load_prdt(ccb) != 0) { 340712feb904SMatthew Dillon err_slot = -1; 3408258223a3SMatthew Dillon goto err; 3409258223a3SMatthew Dillon } 3410258223a3SMatthew Dillon 3411258223a3SMatthew Dillon ccb->ccb_xa.state = ATA_S_PENDING; 341212feb904SMatthew Dillon if (ahci_poll(ccb, 1000, ahci_quick_timeout) != ATA_S_COMPLETE) { 341312feb904SMatthew Dillon err_slot = -1; 3414258223a3SMatthew Dillon ahci_unload_prdt(ccb); 341512feb904SMatthew Dillon goto err; 341612feb904SMatthew Dillon } 341712feb904SMatthew Dillon ahci_unload_prdt(ccb); 3418258223a3SMatthew Dillon 341912feb904SMatthew Dillon /* 342012feb904SMatthew Dillon * Success, extract failed register set and tags from the scratch 342112feb904SMatthew Dillon * space. 342212feb904SMatthew Dillon */ 3423258223a3SMatthew Dillon log = (struct ata_log_page_10h *)ap->ap_err_scratch; 3424258223a3SMatthew Dillon if (log->err_regs.type & ATA_LOG_10H_TYPE_NOTQUEUED) { 3425258223a3SMatthew Dillon /* Not queued bit was set - wasn't an NCQ error? */ 342612feb904SMatthew Dillon kprintf("%s: read NCQ error page, but not an NCQ error?\n", 3427258223a3SMatthew Dillon PORTNAME(ap)); 342812feb904SMatthew Dillon err_slot = -1; 3429258223a3SMatthew Dillon } else { 3430258223a3SMatthew Dillon /* Copy back the log record as a D2H register FIS. */ 343112feb904SMatthew Dillon err_slot = log->err_regs.type & ATA_LOG_10H_TYPE_TAG_MASK; 3432258223a3SMatthew Dillon 3433e1014452SMatthew Dillon ccb2 = &ap->ap_ccbs[err_slot]; 3434e1014452SMatthew Dillon if (ccb2->ccb_xa.state == ATA_S_ONCHIP) { 343512feb904SMatthew Dillon kprintf("%s: read NCQ error page slot=%d\n", 3436e1014452SMatthew Dillon ATANAME(ap, ccb2->ccb_xa.at), 343712feb904SMatthew Dillon err_slot); 3438e1014452SMatthew Dillon memcpy(&ccb2->ccb_xa.rfis, &log->err_regs, 3439258223a3SMatthew Dillon sizeof(struct ata_fis_d2h)); 3440e1014452SMatthew Dillon ccb2->ccb_xa.rfis.type = ATA_FIS_TYPE_D2H; 3441e1014452SMatthew Dillon ccb2->ccb_xa.rfis.flags = 0; 344212feb904SMatthew Dillon } else { 344312feb904SMatthew Dillon kprintf("%s: read NCQ error page slot=%d, " 344412feb904SMatthew Dillon "slot does not match any cmds\n", 3445e1014452SMatthew Dillon ATANAME(ccb2->ccb_port, ccb2->ccb_xa.at), 344612feb904SMatthew Dillon err_slot); 344712feb904SMatthew Dillon err_slot = -1; 3448258223a3SMatthew Dillon } 3449258223a3SMatthew Dillon } 345012feb904SMatthew Dillon err: 345112feb904SMatthew Dillon ahci_put_err_ccb(ccb); 345212feb904SMatthew Dillon kprintf("%s: DONE log page target %d err_slot=%d\n", 345312feb904SMatthew Dillon PORTNAME(ap), target, err_slot); 345412feb904SMatthew Dillon return (err_slot); 3455258223a3SMatthew Dillon } 3456258223a3SMatthew Dillon 3457258223a3SMatthew Dillon /* 3458258223a3SMatthew Dillon * Allocate memory for various structures DMAd by hardware. The maximum 3459258223a3SMatthew Dillon * number of segments for these tags is 1 so the DMA memory will have a 3460258223a3SMatthew Dillon * single physical base address. 3461258223a3SMatthew Dillon */ 3462258223a3SMatthew Dillon struct ahci_dmamem * 3463258223a3SMatthew Dillon ahci_dmamem_alloc(struct ahci_softc *sc, bus_dma_tag_t tag) 3464258223a3SMatthew Dillon { 3465258223a3SMatthew Dillon struct ahci_dmamem *adm; 3466258223a3SMatthew Dillon int error; 3467258223a3SMatthew Dillon 3468258223a3SMatthew Dillon adm = kmalloc(sizeof(*adm), M_DEVBUF, M_INTWAIT | M_ZERO); 3469258223a3SMatthew Dillon 3470258223a3SMatthew Dillon error = bus_dmamem_alloc(tag, (void **)&adm->adm_kva, 3471258223a3SMatthew Dillon BUS_DMA_ZERO, &adm->adm_map); 3472258223a3SMatthew Dillon if (error == 0) { 3473258223a3SMatthew Dillon adm->adm_tag = tag; 3474258223a3SMatthew Dillon error = bus_dmamap_load(tag, adm->adm_map, 3475258223a3SMatthew Dillon adm->adm_kva, 3476258223a3SMatthew Dillon bus_dma_tag_getmaxsize(tag), 3477258223a3SMatthew Dillon ahci_dmamem_saveseg, &adm->adm_busaddr, 3478258223a3SMatthew Dillon 0); 3479258223a3SMatthew Dillon } 3480258223a3SMatthew Dillon if (error) { 3481258223a3SMatthew Dillon if (adm->adm_map) { 3482258223a3SMatthew Dillon bus_dmamap_destroy(tag, adm->adm_map); 3483258223a3SMatthew Dillon adm->adm_map = NULL; 3484258223a3SMatthew Dillon adm->adm_tag = NULL; 3485258223a3SMatthew Dillon adm->adm_kva = NULL; 3486258223a3SMatthew Dillon } 3487258223a3SMatthew Dillon kfree(adm, M_DEVBUF); 3488258223a3SMatthew Dillon adm = NULL; 3489258223a3SMatthew Dillon } 3490258223a3SMatthew Dillon return (adm); 3491258223a3SMatthew Dillon } 3492258223a3SMatthew Dillon 3493258223a3SMatthew Dillon static 3494258223a3SMatthew Dillon void 3495258223a3SMatthew Dillon ahci_dmamem_saveseg(void *info, bus_dma_segment_t *segs, int nsegs, int error) 3496258223a3SMatthew Dillon { 3497258223a3SMatthew Dillon KKASSERT(error == 0); 3498258223a3SMatthew Dillon KKASSERT(nsegs == 1); 3499258223a3SMatthew Dillon *(bus_addr_t *)info = segs->ds_addr; 3500258223a3SMatthew Dillon } 3501258223a3SMatthew Dillon 3502258223a3SMatthew Dillon 3503258223a3SMatthew Dillon void 3504258223a3SMatthew Dillon ahci_dmamem_free(struct ahci_softc *sc, struct ahci_dmamem *adm) 3505258223a3SMatthew Dillon { 3506258223a3SMatthew Dillon if (adm->adm_map) { 3507258223a3SMatthew Dillon bus_dmamap_unload(adm->adm_tag, adm->adm_map); 3508258223a3SMatthew Dillon bus_dmamap_destroy(adm->adm_tag, adm->adm_map); 3509258223a3SMatthew Dillon adm->adm_map = NULL; 3510258223a3SMatthew Dillon adm->adm_tag = NULL; 3511258223a3SMatthew Dillon adm->adm_kva = NULL; 3512258223a3SMatthew Dillon } 3513258223a3SMatthew Dillon kfree(adm, M_DEVBUF); 3514258223a3SMatthew Dillon } 3515258223a3SMatthew Dillon 3516258223a3SMatthew Dillon u_int32_t 3517258223a3SMatthew Dillon ahci_read(struct ahci_softc *sc, bus_size_t r) 3518258223a3SMatthew Dillon { 3519258223a3SMatthew Dillon bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4, 3520258223a3SMatthew Dillon BUS_SPACE_BARRIER_READ); 3521258223a3SMatthew Dillon return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, r)); 3522258223a3SMatthew Dillon } 3523258223a3SMatthew Dillon 3524258223a3SMatthew Dillon void 3525258223a3SMatthew Dillon ahci_write(struct ahci_softc *sc, bus_size_t r, u_int32_t v) 3526258223a3SMatthew Dillon { 3527258223a3SMatthew Dillon bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v); 3528258223a3SMatthew Dillon bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4, 3529258223a3SMatthew Dillon BUS_SPACE_BARRIER_WRITE); 3530258223a3SMatthew Dillon } 3531258223a3SMatthew Dillon 3532258223a3SMatthew Dillon u_int32_t 3533258223a3SMatthew Dillon ahci_pread(struct ahci_port *ap, bus_size_t r) 3534258223a3SMatthew Dillon { 3535258223a3SMatthew Dillon bus_space_barrier(ap->ap_sc->sc_iot, ap->ap_ioh, r, 4, 3536258223a3SMatthew Dillon BUS_SPACE_BARRIER_READ); 3537258223a3SMatthew Dillon return (bus_space_read_4(ap->ap_sc->sc_iot, ap->ap_ioh, r)); 3538258223a3SMatthew Dillon } 3539258223a3SMatthew Dillon 3540258223a3SMatthew Dillon void 3541258223a3SMatthew Dillon ahci_pwrite(struct ahci_port *ap, bus_size_t r, u_int32_t v) 3542258223a3SMatthew Dillon { 3543258223a3SMatthew Dillon bus_space_write_4(ap->ap_sc->sc_iot, ap->ap_ioh, r, v); 3544258223a3SMatthew Dillon bus_space_barrier(ap->ap_sc->sc_iot, ap->ap_ioh, r, 4, 3545258223a3SMatthew Dillon BUS_SPACE_BARRIER_WRITE); 3546258223a3SMatthew Dillon } 3547258223a3SMatthew Dillon 3548831bc9e3SMatthew Dillon /* 3549831bc9e3SMatthew Dillon * Wait up to (timeout) milliseconds for the masked port register to 3550831bc9e3SMatthew Dillon * match the target. 3551831bc9e3SMatthew Dillon * 3552831bc9e3SMatthew Dillon * Timeout is in milliseconds. 3553831bc9e3SMatthew Dillon */ 3554258223a3SMatthew Dillon int 3555cec85a37SMatthew Dillon ahci_pwait_eq(struct ahci_port *ap, int timeout, 3556cec85a37SMatthew Dillon bus_size_t r, u_int32_t mask, u_int32_t target) 3557258223a3SMatthew Dillon { 3558831bc9e3SMatthew Dillon int t; 3559258223a3SMatthew Dillon 3560831bc9e3SMatthew Dillon /* 3561831bc9e3SMatthew Dillon * Loop hard up to 100uS 3562831bc9e3SMatthew Dillon */ 3563831bc9e3SMatthew Dillon for (t = 0; t < 100; ++t) { 3564258223a3SMatthew Dillon if ((ahci_pread(ap, r) & mask) == target) 3565258223a3SMatthew Dillon return (0); 3566831bc9e3SMatthew Dillon ahci_os_hardsleep(1); /* us */ 3567258223a3SMatthew Dillon } 3568258223a3SMatthew Dillon 3569831bc9e3SMatthew Dillon do { 3570831bc9e3SMatthew Dillon timeout -= ahci_os_softsleep(); 3571831bc9e3SMatthew Dillon if ((ahci_pread(ap, r) & mask) == target) 3572831bc9e3SMatthew Dillon return (0); 3573831bc9e3SMatthew Dillon } while (timeout > 0); 3574831bc9e3SMatthew Dillon return (1); 3575831bc9e3SMatthew Dillon } 3576831bc9e3SMatthew Dillon 3577831bc9e3SMatthew Dillon int 3578831bc9e3SMatthew Dillon ahci_wait_ne(struct ahci_softc *sc, bus_size_t r, u_int32_t mask, 3579831bc9e3SMatthew Dillon u_int32_t target) 3580831bc9e3SMatthew Dillon { 3581831bc9e3SMatthew Dillon int t; 3582831bc9e3SMatthew Dillon 3583831bc9e3SMatthew Dillon /* 3584831bc9e3SMatthew Dillon * Loop hard up to 100uS 3585831bc9e3SMatthew Dillon */ 3586831bc9e3SMatthew Dillon for (t = 0; t < 100; ++t) { 3587831bc9e3SMatthew Dillon if ((ahci_read(sc, r) & mask) != target) 3588831bc9e3SMatthew Dillon return (0); 3589831bc9e3SMatthew Dillon ahci_os_hardsleep(1); /* us */ 3590831bc9e3SMatthew Dillon } 3591831bc9e3SMatthew Dillon 3592831bc9e3SMatthew Dillon /* 3593831bc9e3SMatthew Dillon * And one millisecond the slow way 3594831bc9e3SMatthew Dillon */ 3595831bc9e3SMatthew Dillon t = 1000; 3596831bc9e3SMatthew Dillon do { 3597831bc9e3SMatthew Dillon t -= ahci_os_softsleep(); 3598831bc9e3SMatthew Dillon if ((ahci_read(sc, r) & mask) != target) 3599831bc9e3SMatthew Dillon return (0); 3600831bc9e3SMatthew Dillon } while (t > 0); 3601831bc9e3SMatthew Dillon 3602258223a3SMatthew Dillon return (1); 3603258223a3SMatthew Dillon } 3604258223a3SMatthew Dillon 3605831bc9e3SMatthew Dillon 36061980eff3SMatthew Dillon /* 36071980eff3SMatthew Dillon * Acquire an ata transfer. 36081980eff3SMatthew Dillon * 36091980eff3SMatthew Dillon * Pass a NULL at for direct-attached transfers, and a non-NULL at for 36101980eff3SMatthew Dillon * targets that go through the port multiplier. 36111980eff3SMatthew Dillon */ 3612258223a3SMatthew Dillon struct ata_xfer * 36131980eff3SMatthew Dillon ahci_ata_get_xfer(struct ahci_port *ap, struct ata_port *at) 3614258223a3SMatthew Dillon { 3615258223a3SMatthew Dillon struct ahci_ccb *ccb; 3616258223a3SMatthew Dillon 3617258223a3SMatthew Dillon ccb = ahci_get_ccb(ap); 3618258223a3SMatthew Dillon if (ccb == NULL) { 3619258223a3SMatthew Dillon DPRINTF(AHCI_D_XFER, "%s: ahci_ata_get_xfer: NULL ccb\n", 3620258223a3SMatthew Dillon PORTNAME(ap)); 3621258223a3SMatthew Dillon return (NULL); 3622258223a3SMatthew Dillon } 3623258223a3SMatthew Dillon 3624258223a3SMatthew Dillon DPRINTF(AHCI_D_XFER, "%s: ahci_ata_get_xfer got slot %d\n", 3625258223a3SMatthew Dillon PORTNAME(ap), ccb->ccb_slot); 3626258223a3SMatthew Dillon 36272cc2e845SMatthew Dillon bzero(ccb->ccb_xa.fis, sizeof(*ccb->ccb_xa.fis)); 36281980eff3SMatthew Dillon ccb->ccb_xa.at = at; 3629258223a3SMatthew Dillon ccb->ccb_xa.fis->type = ATA_FIS_TYPE_H2D; 3630258223a3SMatthew Dillon 3631258223a3SMatthew Dillon return (&ccb->ccb_xa); 3632258223a3SMatthew Dillon } 3633258223a3SMatthew Dillon 3634258223a3SMatthew Dillon void 3635258223a3SMatthew Dillon ahci_ata_put_xfer(struct ata_xfer *xa) 3636258223a3SMatthew Dillon { 3637258223a3SMatthew Dillon struct ahci_ccb *ccb = (struct ahci_ccb *)xa; 3638258223a3SMatthew Dillon 3639258223a3SMatthew Dillon DPRINTF(AHCI_D_XFER, "ahci_ata_put_xfer slot %d\n", ccb->ccb_slot); 3640258223a3SMatthew Dillon 3641258223a3SMatthew Dillon ahci_put_ccb(ccb); 3642258223a3SMatthew Dillon } 3643258223a3SMatthew Dillon 3644258223a3SMatthew Dillon int 3645258223a3SMatthew Dillon ahci_ata_cmd(struct ata_xfer *xa) 3646258223a3SMatthew Dillon { 3647258223a3SMatthew Dillon struct ahci_ccb *ccb = (struct ahci_ccb *)xa; 3648258223a3SMatthew Dillon struct ahci_cmd_hdr *cmd_slot; 3649258223a3SMatthew Dillon 3650258223a3SMatthew Dillon KKASSERT(xa->state == ATA_S_SETUP); 3651258223a3SMatthew Dillon 3652258223a3SMatthew Dillon if (ccb->ccb_port->ap_state == AP_S_FATAL_ERROR) 3653258223a3SMatthew Dillon goto failcmd; 3654258223a3SMatthew Dillon ccb->ccb_done = ahci_ata_cmd_done; 3655258223a3SMatthew Dillon 3656258223a3SMatthew Dillon cmd_slot = ccb->ccb_cmd_hdr; 3657258223a3SMatthew Dillon cmd_slot->flags = htole16(5); /* FIS length (in DWORDs) */ 36581980eff3SMatthew Dillon if (ccb->ccb_xa.at) { 36591980eff3SMatthew Dillon cmd_slot->flags |= htole16(ccb->ccb_xa.at->at_target << 36601980eff3SMatthew Dillon AHCI_CMD_LIST_FLAG_PMP_SHIFT); 36611980eff3SMatthew Dillon } 3662258223a3SMatthew Dillon 3663258223a3SMatthew Dillon if (xa->flags & ATA_F_WRITE) 3664258223a3SMatthew Dillon cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_W); 3665258223a3SMatthew Dillon 3666258223a3SMatthew Dillon if (xa->flags & ATA_F_PACKET) 3667258223a3SMatthew Dillon cmd_slot->flags |= htole16(AHCI_CMD_LIST_FLAG_A); 3668258223a3SMatthew Dillon 3669258223a3SMatthew Dillon if (ahci_load_prdt(ccb) != 0) 3670258223a3SMatthew Dillon goto failcmd; 3671258223a3SMatthew Dillon 3672258223a3SMatthew Dillon xa->state = ATA_S_PENDING; 3673258223a3SMatthew Dillon 3674831bc9e3SMatthew Dillon if (xa->flags & ATA_F_POLL) 3675831bc9e3SMatthew Dillon return (ahci_poll(ccb, xa->timeout, ahci_ata_cmd_timeout)); 3676258223a3SMatthew Dillon 3677258223a3SMatthew Dillon crit_enter(); 3678f4553de1SMatthew Dillon KKASSERT((xa->flags & ATA_F_TIMEOUT_EXPIRED) == 0); 36793209f581SMatthew Dillon xa->flags |= ATA_F_TIMEOUT_DESIRED; 3680258223a3SMatthew Dillon ahci_start(ccb); 3681258223a3SMatthew Dillon crit_exit(); 3682831bc9e3SMatthew Dillon return (xa->state); 3683258223a3SMatthew Dillon 3684258223a3SMatthew Dillon failcmd: 3685258223a3SMatthew Dillon crit_enter(); 3686258223a3SMatthew Dillon xa->state = ATA_S_ERROR; 3687258223a3SMatthew Dillon xa->complete(xa); 3688258223a3SMatthew Dillon crit_exit(); 3689831bc9e3SMatthew Dillon return (ATA_S_ERROR); 3690258223a3SMatthew Dillon } 3691258223a3SMatthew Dillon 3692258223a3SMatthew Dillon void 3693258223a3SMatthew Dillon ahci_ata_cmd_done(struct ahci_ccb *ccb) 3694258223a3SMatthew Dillon { 3695258223a3SMatthew Dillon struct ata_xfer *xa = &ccb->ccb_xa; 3696bb79834dSMatthew Dillon int serial; 3697258223a3SMatthew Dillon 3698831bc9e3SMatthew Dillon /* 3699bb79834dSMatthew Dillon * NOTE: Callout does not lock port and may race us modifying 3700831bc9e3SMatthew Dillon * the flags, so make sure its stopped. 3701bb79834dSMatthew Dillon * 3702bb79834dSMatthew Dillon * A callout race can clean up the ccb. A change in the 3703bb79834dSMatthew Dillon * serial number should catch this condition. 3704831bc9e3SMatthew Dillon */ 3705258223a3SMatthew Dillon if (xa->flags & ATA_F_TIMEOUT_RUNNING) { 3706bb79834dSMatthew Dillon serial = ccb->ccb_xa.serial; 370746528d33SMatthew Dillon callout_stop_sync(&ccb->ccb_timeout); 3708bb79834dSMatthew Dillon if (serial != ccb->ccb_xa.serial) { 3709bb79834dSMatthew Dillon kprintf("%s: Warning: timeout race ccb %p\n", 3710bb79834dSMatthew Dillon PORTNAME(ccb->ccb_port), ccb); 3711bb79834dSMatthew Dillon return; 3712bb79834dSMatthew Dillon } 37138dc94ed9SMatthew Dillon xa->flags &= ~ATA_F_TIMEOUT_RUNNING; 3714258223a3SMatthew Dillon } 3715f4553de1SMatthew Dillon xa->flags &= ~(ATA_F_TIMEOUT_DESIRED | ATA_F_TIMEOUT_EXPIRED); 371646528d33SMatthew Dillon ccb->ccb_port->ap_expired &= ~(1 << ccb->ccb_slot); 3717258223a3SMatthew Dillon 371846528d33SMatthew Dillon KKASSERT(xa->state != ATA_S_ONCHIP && xa->state != ATA_S_PUT); 3719258223a3SMatthew Dillon ahci_unload_prdt(ccb); 3720258223a3SMatthew Dillon 3721258223a3SMatthew Dillon if (xa->state != ATA_S_TIMEOUT) 3722258223a3SMatthew Dillon xa->complete(xa); 3723258223a3SMatthew Dillon } 3724258223a3SMatthew Dillon 3725f4553de1SMatthew Dillon /* 3726f4553de1SMatthew Dillon * Timeout from callout, MPSAFE - nothing can mess with the CCB's flags 3727f4553de1SMatthew Dillon * while the callout is runing. 3728f4553de1SMatthew Dillon * 3729f4553de1SMatthew Dillon * We can't safely get the port lock here or delay, we could block 3730f4553de1SMatthew Dillon * the callout thread. 3731f4553de1SMatthew Dillon */ 3732258223a3SMatthew Dillon static void 3733258223a3SMatthew Dillon ahci_ata_cmd_timeout_unserialized(void *arg) 3734258223a3SMatthew Dillon { 3735258223a3SMatthew Dillon struct ahci_ccb *ccb = arg; 3736258223a3SMatthew Dillon struct ahci_port *ap = ccb->ccb_port; 3737258223a3SMatthew Dillon 373846528d33SMatthew Dillon KKASSERT(ccb->ccb_xa.flags & ATA_F_TIMEOUT_RUNNING); 3739f4553de1SMatthew Dillon ccb->ccb_xa.flags &= ~ATA_F_TIMEOUT_RUNNING; 3740f4553de1SMatthew Dillon ccb->ccb_xa.flags |= ATA_F_TIMEOUT_EXPIRED; 3741f4553de1SMatthew Dillon ahci_os_signal_port_thread(ap, AP_SIGF_TIMEOUT); 3742258223a3SMatthew Dillon } 3743258223a3SMatthew Dillon 37444c339a5fSMatthew Dillon /* 37454c339a5fSMatthew Dillon * Timeout code, typically called when the port command processor is running. 37464c339a5fSMatthew Dillon * 37474c339a5fSMatthew Dillon * We have to be very very careful here. We cannot stop the port unless 37484c339a5fSMatthew Dillon * CR is already clear or the only active commands remaining are timed-out 37494c339a5fSMatthew Dillon * ones. Otherwise stopping the port will race the command processor and 37504c339a5fSMatthew Dillon * we can lose events. While we can theoretically just restart everything 37514c339a5fSMatthew Dillon * that could result in a double-issue which will not work for ATAPI commands. 37524c339a5fSMatthew Dillon */ 37531980eff3SMatthew Dillon void 3754831bc9e3SMatthew Dillon ahci_ata_cmd_timeout(struct ahci_ccb *ccb) 3755258223a3SMatthew Dillon { 3756258223a3SMatthew Dillon struct ata_xfer *xa = &ccb->ccb_xa; 3757258223a3SMatthew Dillon struct ahci_port *ap = ccb->ccb_port; 37584c339a5fSMatthew Dillon struct ata_port *at; 3759492bffafSMatthew Dillon u_int32_t ci_saved; 3760492bffafSMatthew Dillon u_int32_t mask; 37614c339a5fSMatthew Dillon int slot; 3762258223a3SMatthew Dillon 37634c339a5fSMatthew Dillon at = ccb->ccb_xa.at; 37644c339a5fSMatthew Dillon 37654c339a5fSMatthew Dillon kprintf("%s: CMD TIMEOUT state=%d slot=%d\n" 37663d102df7SMatthew Dillon "\tglb-status 0x%08x\n" 37674c339a5fSMatthew Dillon "\tcmd-reg 0x%b\n" 37683d102df7SMatthew Dillon "\tport_status 0x%b\n" 37694c339a5fSMatthew Dillon "\tsactive=%08x active=%08x expired=%08x\n" 377008fb24a7SMatthew Dillon "\t sact=%08x ci=%08x\n" 377108fb24a7SMatthew Dillon "\t STS=%b\n", 37724c339a5fSMatthew Dillon ATANAME(ap, at), 37734c339a5fSMatthew Dillon ccb->ccb_xa.state, ccb->ccb_slot, 37743d102df7SMatthew Dillon ahci_read(ap->ap_sc, AHCI_REG_IS), 3775258223a3SMatthew Dillon ahci_pread(ap, AHCI_PREG_CMD), AHCI_PFMT_CMD, 37763d102df7SMatthew Dillon ahci_pread(ap, AHCI_PREG_IS), AHCI_PFMT_IS, 37774c339a5fSMatthew Dillon ap->ap_sactive, ap->ap_active, ap->ap_expired, 3778258223a3SMatthew Dillon ahci_pread(ap, AHCI_PREG_SACT), 377908fb24a7SMatthew Dillon ahci_pread(ap, AHCI_PREG_CI), 378008fb24a7SMatthew Dillon ahci_pread(ap, AHCI_PREG_TFD), AHCI_PFMT_TFD_STS 378108fb24a7SMatthew Dillon ); 378208fb24a7SMatthew Dillon 3783258223a3SMatthew Dillon 37849e145b23SMatthew Dillon /* 37859e145b23SMatthew Dillon * NOTE: Timeout will not be running if the command was polled. 37863209f581SMatthew Dillon * If we got here at least one of these flags should be set. 37879e145b23SMatthew Dillon */ 37883209f581SMatthew Dillon KKASSERT(xa->flags & (ATA_F_POLL | ATA_F_TIMEOUT_DESIRED | 37893209f581SMatthew Dillon ATA_F_TIMEOUT_RUNNING)); 3790f4553de1SMatthew Dillon xa->flags &= ~(ATA_F_TIMEOUT_RUNNING | ATA_F_TIMEOUT_EXPIRED); 3791258223a3SMatthew Dillon 3792258223a3SMatthew Dillon if (ccb->ccb_xa.state == ATA_S_PENDING) { 3793258223a3SMatthew Dillon TAILQ_REMOVE(&ap->ap_ccb_pending, ccb, ccb_entry); 37944c339a5fSMatthew Dillon ccb->ccb_xa.state = ATA_S_TIMEOUT; 37954c339a5fSMatthew Dillon ccb->ccb_done(ccb); 37964c339a5fSMatthew Dillon xa->complete(xa); 37974c339a5fSMatthew Dillon ahci_issue_pending_commands(ap, NULL); 37984c339a5fSMatthew Dillon return; 37994c339a5fSMatthew Dillon } 38004c339a5fSMatthew Dillon if (ccb->ccb_xa.state != ATA_S_ONCHIP) { 38014c339a5fSMatthew Dillon kprintf("%s: Unexpected state during timeout: %d\n", 38024c339a5fSMatthew Dillon ATANAME(ap, at), ccb->ccb_xa.state); 38034c339a5fSMatthew Dillon return; 38044c339a5fSMatthew Dillon } 38054c339a5fSMatthew Dillon 38064c339a5fSMatthew Dillon /* 38074c339a5fSMatthew Dillon * Ok, we can only get this command off the chip if CR is inactive 38084c339a5fSMatthew Dillon * or if the only commands running on the chip are all expired. 38094c339a5fSMatthew Dillon * Otherwise we have to wait until the port is in a safe state. 3810eb9f4c83SMatthew Dillon * Use the ST bit here instead of the CR bit in case the CR bit is 3811eb9f4c83SMatthew Dillon * not implemented via the F_IGN_CR quirk. 38124c339a5fSMatthew Dillon * 38134c339a5fSMatthew Dillon * Do not set state here, it will cause polls to return when the 38144c339a5fSMatthew Dillon * ccb is not yet off the chip. 38154c339a5fSMatthew Dillon */ 38164c339a5fSMatthew Dillon ap->ap_expired |= 1 << ccb->ccb_slot; 38174c339a5fSMatthew Dillon 3818eb9f4c83SMatthew Dillon if ((ahci_pread(ap, AHCI_PREG_CMD) & AHCI_PREG_CMD_ST) && 38194c339a5fSMatthew Dillon (ap->ap_active | ap->ap_sactive) != ap->ap_expired) { 38204c339a5fSMatthew Dillon /* 38214c339a5fSMatthew Dillon * If using FBSS or NCQ we can't safely stop the port 38224c339a5fSMatthew Dillon * right now. 38234c339a5fSMatthew Dillon */ 38244c339a5fSMatthew Dillon kprintf("%s: Deferred timeout until its safe, slot %d\n", 38254c339a5fSMatthew Dillon ATANAME(ap, at), ccb->ccb_slot); 38264c339a5fSMatthew Dillon return; 38274c339a5fSMatthew Dillon } 38284c339a5fSMatthew Dillon 38294c339a5fSMatthew Dillon /* 38304c339a5fSMatthew Dillon * We can safely stop the port and process all expired ccb's, 38314c339a5fSMatthew Dillon * which will include our current ccb. 38324c339a5fSMatthew Dillon */ 38334c339a5fSMatthew Dillon ci_saved = (ap->ap_sactive) ? ahci_pread(ap, AHCI_PREG_SACT) : 38344c339a5fSMatthew Dillon ahci_pread(ap, AHCI_PREG_CI); 38354c339a5fSMatthew Dillon ahci_port_stop(ap, 0); 38364c339a5fSMatthew Dillon 38374c339a5fSMatthew Dillon while (ap->ap_expired) { 38384c339a5fSMatthew Dillon slot = ffs(ap->ap_expired) - 1; 38394c339a5fSMatthew Dillon ap->ap_expired &= ~(1 << slot); 38404c339a5fSMatthew Dillon ci_saved &= ~(1 << slot); 38414c339a5fSMatthew Dillon ccb = &ap->ap_ccbs[slot]; 38424c339a5fSMatthew Dillon ccb->ccb_xa.state = ATA_S_TIMEOUT; 38434c339a5fSMatthew Dillon if (ccb->ccb_xa.flags & ATA_F_NCQ) { 38444c339a5fSMatthew Dillon KKASSERT(ap->ap_sactive & (1 << slot)); 38454c339a5fSMatthew Dillon ap->ap_sactive &= ~(1 << slot); 38464c339a5fSMatthew Dillon } else { 38474c339a5fSMatthew Dillon KKASSERT(ap->ap_active & (1 << slot)); 38484c339a5fSMatthew Dillon ap->ap_active &= ~(1 << slot); 38491980eff3SMatthew Dillon --ap->ap_active_cnt; 38501980eff3SMatthew Dillon } 3851258223a3SMatthew Dillon ccb->ccb_done(ccb); 38524c339a5fSMatthew Dillon ccb->ccb_xa.complete(&ccb->ccb_xa); 3853258223a3SMatthew Dillon } 38544c339a5fSMatthew Dillon /* ccb invalid now */ 3855258223a3SMatthew Dillon 38564c339a5fSMatthew Dillon /* 38574c339a5fSMatthew Dillon * We can safely CLO the port to clear any BSY/DRQ, a case which 38584c339a5fSMatthew Dillon * can occur with port multipliers. This will unbrick the port 38594c339a5fSMatthew Dillon * and allow commands to other targets behind the PM continue. 38604c339a5fSMatthew Dillon * (FBSS). 38614c339a5fSMatthew Dillon * 38624c339a5fSMatthew Dillon * Finally, once the port has been restarted we can issue any 38634c339a5fSMatthew Dillon * previously saved pending commands, and run the port interrupt 38644c339a5fSMatthew Dillon * code to handle any completions which may have occured when 38654c339a5fSMatthew Dillon * we saved CI. 38664c339a5fSMatthew Dillon */ 38674c339a5fSMatthew Dillon if (ahci_pread(ap, AHCI_PREG_TFD) & 38684c339a5fSMatthew Dillon (AHCI_PREG_TFD_STS_BSY | AHCI_PREG_TFD_STS_DRQ)) { 38694c339a5fSMatthew Dillon kprintf("%s: Warning, issuing CLO after timeout\n", 38704c339a5fSMatthew Dillon ATANAME(ap, at)); 3871131be210SMatthew Dillon ahci_port_clo(ap); 38724c339a5fSMatthew Dillon } 3873131be210SMatthew Dillon ahci_port_start(ap); 3874492bffafSMatthew Dillon 3875492bffafSMatthew Dillon /* 3876492bffafSMatthew Dillon * We absolutely must make sure the chipset cleared activity on 3877492bffafSMatthew Dillon * all slots. This sometimes might not happen due to races with 3878492bffafSMatthew Dillon * a chipset interrupt which stops the port before we can manage 3879492bffafSMatthew Dillon * to. For some reason some chipsets don't clear the active 3880492bffafSMatthew Dillon * commands when we turn off CMD_ST after the chip has stopped 3881492bffafSMatthew Dillon * operations itself. 3882492bffafSMatthew Dillon */ 3883492bffafSMatthew Dillon if (ahci_pactive(ap) != 0) { 3884492bffafSMatthew Dillon ahci_port_stop(ap, 0); 3885492bffafSMatthew Dillon ahci_port_start(ap); 3886492bffafSMatthew Dillon if ((mask = ahci_pactive(ap)) != 0) { 3887492bffafSMatthew Dillon kprintf("%s: quick-timeout: chipset failed " 3888492bffafSMatthew Dillon "to clear active cmds %08x\n", 3889492bffafSMatthew Dillon PORTNAME(ap), mask); 3890492bffafSMatthew Dillon } 3891492bffafSMatthew Dillon } 38924c339a5fSMatthew Dillon ahci_issue_saved_commands(ap, ci_saved & ~ap->ap_expired); 38934c339a5fSMatthew Dillon ahci_issue_pending_commands(ap, NULL); 38944c339a5fSMatthew Dillon ahci_port_intr(ap, 0); 38954c339a5fSMatthew Dillon } 38964c339a5fSMatthew Dillon 3897cf5f3a81SMatthew Dillon /* 38984c339a5fSMatthew Dillon * Issue a previously saved set of commands 3899cf5f3a81SMatthew Dillon */ 39004c339a5fSMatthew Dillon void 39014c339a5fSMatthew Dillon ahci_issue_saved_commands(struct ahci_port *ap, u_int32_t ci_saved) 39024c339a5fSMatthew Dillon { 39038119d5f5SMatthew Dillon if (ci_saved && (ap->ap_flags & AP_F_FBSS_ENABLED) == 0) { 39044c339a5fSMatthew Dillon KKASSERT(!((ap->ap_active & ci_saved) && 39054c339a5fSMatthew Dillon (ap->ap_sactive & ci_saved))); 39064c339a5fSMatthew Dillon KKASSERT((ci_saved & ap->ap_expired) == 0); 39074c339a5fSMatthew Dillon if (ap->ap_sactive & ci_saved) 39084c339a5fSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SACT, ci_saved); 39094c339a5fSMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CI, ci_saved); 39108119d5f5SMatthew Dillon } else if (ci_saved) { 39118119d5f5SMatthew Dillon struct ata_port *ccb_at; 39128119d5f5SMatthew Dillon int i; 39138119d5f5SMatthew Dillon int fis_target; 39148119d5f5SMatthew Dillon 39158119d5f5SMatthew Dillon for (i = 0; i < 32; ++i) { 39168119d5f5SMatthew Dillon if ((ci_saved & (1 << i)) == 0) 39178119d5f5SMatthew Dillon continue; 39188119d5f5SMatthew Dillon ccb_at = ap->ap_ccbs[i].ccb_xa.at; 39198119d5f5SMatthew Dillon if (ccb_at) 39208119d5f5SMatthew Dillon fis_target = ccb_at->at_target; 39218119d5f5SMatthew Dillon else 39228119d5f5SMatthew Dillon fis_target = 0; 39238119d5f5SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_FBS, 39248119d5f5SMatthew Dillon (fis_target << 39258119d5f5SMatthew Dillon AHCI_PREG_FBS_DEV_SHIFT) | 39268119d5f5SMatthew Dillon AHCI_PREG_FBS_EN); 39278119d5f5SMatthew Dillon if (ap->ap_sactive & (1 << i)) 39288119d5f5SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_SACT, (1 << i)); 39298119d5f5SMatthew Dillon ahci_pwrite(ap, AHCI_PREG_CI, 1 << i); 39308119d5f5SMatthew Dillon } 3931131be210SMatthew Dillon } 3932258223a3SMatthew Dillon } 3933258223a3SMatthew Dillon 3934831bc9e3SMatthew Dillon /* 3935831bc9e3SMatthew Dillon * Used by the softreset, pmprobe, and read_ncq_error only, in very 3936831bc9e3SMatthew Dillon * specialized, controlled circumstances. 3937831bc9e3SMatthew Dillon * 3938831bc9e3SMatthew Dillon * Only one command may be pending. 3939831bc9e3SMatthew Dillon */ 3940831bc9e3SMatthew Dillon void 3941831bc9e3SMatthew Dillon ahci_quick_timeout(struct ahci_ccb *ccb) 3942831bc9e3SMatthew Dillon { 3943831bc9e3SMatthew Dillon struct ahci_port *ap = ccb->ccb_port; 3944492bffafSMatthew Dillon u_int32_t mask; 3945831bc9e3SMatthew Dillon 3946831bc9e3SMatthew Dillon switch (ccb->ccb_xa.state) { 3947831bc9e3SMatthew Dillon case ATA_S_PENDING: 3948831bc9e3SMatthew Dillon TAILQ_REMOVE(&ap->ap_ccb_pending, ccb, ccb_entry); 3949831bc9e3SMatthew Dillon ccb->ccb_xa.state = ATA_S_TIMEOUT; 3950831bc9e3SMatthew Dillon break; 3951831bc9e3SMatthew Dillon case ATA_S_ONCHIP: 3952492bffafSMatthew Dillon /* 3953492bffafSMatthew Dillon * We have to clear the command on-chip. 3954492bffafSMatthew Dillon */ 3955831bc9e3SMatthew Dillon KKASSERT(ap->ap_active == (1 << ccb->ccb_slot) && 3956831bc9e3SMatthew Dillon ap->ap_sactive == 0); 3957831bc9e3SMatthew Dillon ahci_port_stop(ap, 0); 3958831bc9e3SMatthew Dillon ahci_port_start(ap); 3959492bffafSMatthew Dillon if (ahci_pactive(ap) != 0) { 3960492bffafSMatthew Dillon ahci_port_stop(ap, 0); 3961492bffafSMatthew Dillon ahci_port_start(ap); 3962492bffafSMatthew Dillon if ((mask = ahci_pactive(ap)) != 0) { 3963492bffafSMatthew Dillon kprintf("%s: quick-timeout: chipset failed " 3964492bffafSMatthew Dillon "to clear active cmds %08x\n", 3965492bffafSMatthew Dillon PORTNAME(ap), mask); 3966492bffafSMatthew Dillon } 3967492bffafSMatthew Dillon } 3968831bc9e3SMatthew Dillon 3969831bc9e3SMatthew Dillon ccb->ccb_xa.state = ATA_S_TIMEOUT; 3970831bc9e3SMatthew Dillon ap->ap_active &= ~(1 << ccb->ccb_slot); 3971831bc9e3SMatthew Dillon KKASSERT(ap->ap_active_cnt > 0); 3972831bc9e3SMatthew Dillon --ap->ap_active_cnt; 3973831bc9e3SMatthew Dillon break; 3974831bc9e3SMatthew Dillon default: 3975831bc9e3SMatthew Dillon panic("%s: ahci_quick_timeout: ccb in bad state %d", 3976831bc9e3SMatthew Dillon ATANAME(ap, ccb->ccb_xa.at), ccb->ccb_xa.state); 3977831bc9e3SMatthew Dillon } 3978831bc9e3SMatthew Dillon } 3979831bc9e3SMatthew Dillon 398012feb904SMatthew Dillon static void 398112feb904SMatthew Dillon ahci_dummy_done(struct ata_xfer *xa) 398212feb904SMatthew Dillon { 398312feb904SMatthew Dillon } 398412feb904SMatthew Dillon 398512feb904SMatthew Dillon static void 3986258223a3SMatthew Dillon ahci_empty_done(struct ahci_ccb *ccb) 3987258223a3SMatthew Dillon { 3988258223a3SMatthew Dillon } 3989795adb22SMatthew Dillon 3990795adb22SMatthew Dillon int 3991492bffafSMatthew Dillon ahci_set_feature(struct ahci_port *ap, struct ata_port *atx, 3992492bffafSMatthew Dillon int feature, int enable) 3993795adb22SMatthew Dillon { 3994795adb22SMatthew Dillon struct ata_port *at; 3995795adb22SMatthew Dillon struct ata_xfer *xa; 3996795adb22SMatthew Dillon int error; 3997795adb22SMatthew Dillon 3998795adb22SMatthew Dillon at = atx ? atx : ap->ap_ata[0]; 3999795adb22SMatthew Dillon 4000795adb22SMatthew Dillon xa = ahci_ata_get_xfer(ap, atx); 4001795adb22SMatthew Dillon 4002795adb22SMatthew Dillon xa->fis->type = ATA_FIS_TYPE_H2D; 4003795adb22SMatthew Dillon xa->fis->flags = ATA_H2D_FLAGS_CMD | at->at_target; 4004795adb22SMatthew Dillon xa->fis->command = ATA_C_SET_FEATURES; 4005750495d0SImre Vadász xa->fis->features = enable ? ATA_SF_SATAFT_ENA : ATA_SF_SATAFT_DIS; 4006795adb22SMatthew Dillon xa->fis->sector_count = feature; 4007795adb22SMatthew Dillon xa->fis->control = ATA_FIS_CONTROL_4BIT; 4008795adb22SMatthew Dillon 4009795adb22SMatthew Dillon xa->complete = ahci_dummy_done; 4010795adb22SMatthew Dillon xa->datalen = 0; 4011795adb22SMatthew Dillon xa->flags = ATA_F_POLL; 4012795adb22SMatthew Dillon xa->timeout = 1000; 4013795adb22SMatthew Dillon 4014795adb22SMatthew Dillon if (ahci_ata_cmd(xa) == ATA_S_COMPLETE) 4015795adb22SMatthew Dillon error = 0; 4016795adb22SMatthew Dillon else 4017795adb22SMatthew Dillon error = EIO; 4018795adb22SMatthew Dillon ahci_ata_put_xfer(xa); 4019795adb22SMatthew Dillon return(error); 4020795adb22SMatthew Dillon } 4021