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