1258223a3SMatthew Dillon /* 2fb00c6edSMatthew Dillon * (MPSAFE) 3fb00c6edSMatthew Dillon * 4258223a3SMatthew Dillon * Copyright (c) 2009 The DragonFly Project. All rights reserved. 5258223a3SMatthew Dillon * 6258223a3SMatthew Dillon * This code is derived from software contributed to The DragonFly Project 7258223a3SMatthew Dillon * by Matthew Dillon <dillon@backplane.com> 8258223a3SMatthew Dillon * 9258223a3SMatthew Dillon * Redistribution and use in source and binary forms, with or without 10258223a3SMatthew Dillon * modification, are permitted provided that the following conditions 11258223a3SMatthew Dillon * are met: 12258223a3SMatthew Dillon * 13258223a3SMatthew Dillon * 1. Redistributions of source code must retain the above copyright 14258223a3SMatthew Dillon * notice, this list of conditions and the following disclaimer. 15258223a3SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright 16258223a3SMatthew Dillon * notice, this list of conditions and the following disclaimer in 17258223a3SMatthew Dillon * the documentation and/or other materials provided with the 18258223a3SMatthew Dillon * distribution. 19258223a3SMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its 20258223a3SMatthew Dillon * contributors may be used to endorse or promote products derived 21258223a3SMatthew Dillon * from this software without specific, prior written permission. 22258223a3SMatthew Dillon * 23258223a3SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24258223a3SMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25258223a3SMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26258223a3SMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27258223a3SMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28258223a3SMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 29258223a3SMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30258223a3SMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 31258223a3SMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32258223a3SMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 33258223a3SMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34258223a3SMatthew Dillon * SUCH DAMAGE. 35258223a3SMatthew Dillon */ 36258223a3SMatthew Dillon /* 37258223a3SMatthew Dillon * Primary device and CAM interface to OpenBSD AHCI driver, for DragonFly 38258223a3SMatthew Dillon */ 39258223a3SMatthew Dillon 40258223a3SMatthew Dillon #include "ahci.h" 41258223a3SMatthew Dillon 428986d351SMatthew Dillon u_int32_t AhciForceGen = 0; 43afa796d2SMatthew Dillon u_int32_t AhciNoFeatures = 0; 44afa796d2SMatthew Dillon 45258223a3SMatthew Dillon /* 46258223a3SMatthew Dillon * Device bus methods 47258223a3SMatthew Dillon */ 48258223a3SMatthew Dillon 49258223a3SMatthew Dillon static int ahci_probe (device_t dev); 50258223a3SMatthew Dillon static int ahci_attach (device_t dev); 51258223a3SMatthew Dillon static int ahci_detach (device_t dev); 52795adb22SMatthew Dillon static int ahci_sysctl_link_pwr_mgmt (SYSCTL_HANDLER_ARGS); 53258223a3SMatthew Dillon #if 0 54258223a3SMatthew Dillon static int ahci_shutdown (device_t dev); 55258223a3SMatthew Dillon static int ahci_suspend (device_t dev); 56258223a3SMatthew Dillon static int ahci_resume (device_t dev); 57258223a3SMatthew Dillon #endif 58258223a3SMatthew Dillon 59f4553de1SMatthew Dillon static void ahci_port_thread(void *arg); 60f4553de1SMatthew Dillon 61258223a3SMatthew Dillon static device_method_t ahci_methods[] = { 62258223a3SMatthew Dillon DEVMETHOD(device_probe, ahci_probe), 63258223a3SMatthew Dillon DEVMETHOD(device_attach, ahci_attach), 64258223a3SMatthew Dillon DEVMETHOD(device_detach, ahci_detach), 65258223a3SMatthew Dillon #if 0 66258223a3SMatthew Dillon DEVMETHOD(device_shutdown, ahci_shutdown), 67258223a3SMatthew Dillon DEVMETHOD(device_suspend, ahci_suspend), 68258223a3SMatthew Dillon DEVMETHOD(device_resume, ahci_resume), 69258223a3SMatthew Dillon #endif 70258223a3SMatthew Dillon 71258223a3SMatthew Dillon DEVMETHOD(bus_print_child, bus_generic_print_child), 72258223a3SMatthew Dillon DEVMETHOD(bus_driver_added, bus_generic_driver_added), 73d3c9c58eSSascha Wildner DEVMETHOD_END 74258223a3SMatthew Dillon }; 75258223a3SMatthew Dillon 76258223a3SMatthew Dillon static devclass_t ahci_devclass; 77258223a3SMatthew Dillon 78258223a3SMatthew Dillon static driver_t ahci_driver = { 79258223a3SMatthew Dillon "ahci", 80258223a3SMatthew Dillon ahci_methods, 81258223a3SMatthew Dillon sizeof(struct ahci_softc) 82258223a3SMatthew Dillon }; 83258223a3SMatthew Dillon 84258223a3SMatthew Dillon MODULE_DEPEND(ahci, cam, 1, 1, 1); 85aa2b9d05SSascha Wildner DRIVER_MODULE(ahci, pci, ahci_driver, ahci_devclass, NULL, NULL); 868097e19fSSascha Wildner MODULE_VERSION(ahci, 1); 87258223a3SMatthew Dillon 88258223a3SMatthew Dillon /* 89258223a3SMatthew Dillon * Device bus method procedures 90258223a3SMatthew Dillon */ 91258223a3SMatthew Dillon static int 92258223a3SMatthew Dillon ahci_probe (device_t dev) 93258223a3SMatthew Dillon { 94258223a3SMatthew Dillon const struct ahci_device *ad; 95258223a3SMatthew Dillon 96c45a2365SMatthew Dillon if (kgetenv("hint.ahci.disabled")) 97c45a2365SMatthew Dillon return(ENXIO); 98c45a2365SMatthew Dillon 99258223a3SMatthew Dillon ad = ahci_lookup_device(dev); 100258223a3SMatthew Dillon if (ad) { 101258223a3SMatthew Dillon device_set_desc(dev, ad->name); 102258223a3SMatthew Dillon return(-5); /* higher priority the NATA */ 103258223a3SMatthew Dillon } 104258223a3SMatthew Dillon return(ENXIO); 105258223a3SMatthew Dillon } 106258223a3SMatthew Dillon 107258223a3SMatthew Dillon static int 108258223a3SMatthew Dillon ahci_attach (device_t dev) 109258223a3SMatthew Dillon { 110258223a3SMatthew Dillon struct ahci_softc *sc = device_get_softc(dev); 111258223a3SMatthew Dillon 112258223a3SMatthew Dillon sc->sc_ad = ahci_lookup_device(dev); 113258223a3SMatthew Dillon if (sc->sc_ad == NULL) 114258223a3SMatthew Dillon return(ENXIO); 115f17a0cedSMatthew Dillon 1168986d351SMatthew Dillon /* 1178986d351SMatthew Dillon * Some chipsets do not properly implement the AHCI spec and may 1188986d351SMatthew Dillon * require the link speed to be specifically requested. 1198986d351SMatthew Dillon */ 1208986d351SMatthew Dillon if (kgetenv("hint.ahci.force150")) 1218986d351SMatthew Dillon AhciForceGen = 1; 1228986d351SMatthew Dillon if (kgetenv("hint.ahci.force300")) 1238986d351SMatthew Dillon AhciForceGen = 2; 1248986d351SMatthew Dillon if (kgetenv("hint.ahci.force600")) 1258986d351SMatthew Dillon AhciForceGen = 3; 1268986d351SMatthew Dillon 1278986d351SMatthew Dillon if (kgetenv("hint.ahci.nofeatures")) 1288986d351SMatthew Dillon AhciNoFeatures = -1; 1298986d351SMatthew Dillon 1304b450139SMatthew Dillon if (kgetenv("hint.ahci.forcefbss")) 1314b450139SMatthew Dillon sc->sc_flags |= AHCI_F_FORCE_FBSS; 1324b450139SMatthew Dillon 13326595b18SSascha Wildner return (sc->sc_ad->ad_attach(dev)); 134258223a3SMatthew Dillon } 135258223a3SMatthew Dillon 136258223a3SMatthew Dillon static int 137258223a3SMatthew Dillon ahci_detach (device_t dev) 138258223a3SMatthew Dillon { 139258223a3SMatthew Dillon struct ahci_softc *sc = device_get_softc(dev); 140258223a3SMatthew Dillon int error = 0; 141258223a3SMatthew Dillon 142258223a3SMatthew Dillon if (sc->sc_ad) { 143258223a3SMatthew Dillon error = sc->sc_ad->ad_detach(dev); 144258223a3SMatthew Dillon sc->sc_ad = NULL; 145258223a3SMatthew Dillon } 146258223a3SMatthew Dillon return(error); 147258223a3SMatthew Dillon } 148258223a3SMatthew Dillon 149f17a0cedSMatthew Dillon static int 150795adb22SMatthew Dillon ahci_sysctl_link_pwr_mgmt (SYSCTL_HANDLER_ARGS) 151f17a0cedSMatthew Dillon { 152f17a0cedSMatthew Dillon struct ahci_port *ap = arg1; 153f17a0cedSMatthew Dillon int error, link_pwr_mgmt; 154f17a0cedSMatthew Dillon 155f17a0cedSMatthew Dillon link_pwr_mgmt = ap->link_pwr_mgmt; 156f17a0cedSMatthew Dillon error = sysctl_handle_int(oidp, &link_pwr_mgmt, 0, req); 157f17a0cedSMatthew Dillon if (error || req->newptr == NULL) 158f17a0cedSMatthew Dillon return error; 159f17a0cedSMatthew Dillon 160f17a0cedSMatthew Dillon ahci_port_link_pwr_mgmt(ap, link_pwr_mgmt); 161f17a0cedSMatthew Dillon return 0; 162f17a0cedSMatthew Dillon } 163f17a0cedSMatthew Dillon 164795adb22SMatthew Dillon static int 165795adb22SMatthew Dillon ahci_sysctl_link_pwr_state (SYSCTL_HANDLER_ARGS) 166795adb22SMatthew Dillon { 167795adb22SMatthew Dillon struct ahci_port *ap = arg1; 168*d90e4fd1SImre Vadász const char *state_names[] = 169*d90e4fd1SImre Vadász {"unknown", "active", "partial", "slumber", "devsleep"}; 170795adb22SMatthew Dillon char buf[16]; 171795adb22SMatthew Dillon int state; 172795adb22SMatthew Dillon 173795adb22SMatthew Dillon state = ahci_port_link_pwr_state(ap); 174c157ff7aSSascha Wildner if (state < 0 || state >= NELEM(state_names)) 175795adb22SMatthew Dillon state = 0; 176795adb22SMatthew Dillon 177795adb22SMatthew Dillon ksnprintf(buf, sizeof(buf), "%s", state_names[state]); 178795adb22SMatthew Dillon return sysctl_handle_string(oidp, buf, sizeof(buf), req); 179795adb22SMatthew Dillon } 180795adb22SMatthew Dillon 181258223a3SMatthew Dillon #if 0 182258223a3SMatthew Dillon 183258223a3SMatthew Dillon static int 184258223a3SMatthew Dillon ahci_shutdown (device_t dev) 185258223a3SMatthew Dillon { 186258223a3SMatthew Dillon return (0); 187258223a3SMatthew Dillon } 188258223a3SMatthew Dillon 189258223a3SMatthew Dillon static int 190258223a3SMatthew Dillon ahci_suspend (device_t dev) 191258223a3SMatthew Dillon { 192258223a3SMatthew Dillon return (0); 193258223a3SMatthew Dillon } 194258223a3SMatthew Dillon 195258223a3SMatthew Dillon static int 196258223a3SMatthew Dillon ahci_resume (device_t dev) 197258223a3SMatthew Dillon { 198258223a3SMatthew Dillon return (0); 199258223a3SMatthew Dillon } 200258223a3SMatthew Dillon 201258223a3SMatthew Dillon #endif 2023209f581SMatthew Dillon 203831bc9e3SMatthew Dillon /* 204831bc9e3SMatthew Dillon * Sleep (ms) milliseconds, error on the side of caution. 205831bc9e3SMatthew Dillon */ 2063209f581SMatthew Dillon void 2073209f581SMatthew Dillon ahci_os_sleep(int ms) 2083209f581SMatthew Dillon { 2093209f581SMatthew Dillon int ticks; 2103209f581SMatthew Dillon 2113209f581SMatthew Dillon ticks = hz * ms / 1000 + 1; 2123209f581SMatthew Dillon tsleep(&ticks, 0, "ahslp", ticks); 2133209f581SMatthew Dillon } 214831bc9e3SMatthew Dillon 215831bc9e3SMatthew Dillon /* 216831bc9e3SMatthew Dillon * Sleep for a minimum interval and return the number of milliseconds 217831bc9e3SMatthew Dillon * that was. The minimum value returned is 1 218831bc9e3SMatthew Dillon */ 219831bc9e3SMatthew Dillon int 220831bc9e3SMatthew Dillon ahci_os_softsleep(void) 221831bc9e3SMatthew Dillon { 222831bc9e3SMatthew Dillon if (hz >= 1000) { 223831bc9e3SMatthew Dillon tsleep(&ticks, 0, "ahslp", hz / 1000); 224831bc9e3SMatthew Dillon return(1); 225831bc9e3SMatthew Dillon } else { 226831bc9e3SMatthew Dillon tsleep(&ticks, 0, "ahslp", 1); 227831bc9e3SMatthew Dillon return(1000 / hz); 228831bc9e3SMatthew Dillon } 229831bc9e3SMatthew Dillon } 230831bc9e3SMatthew Dillon 231831bc9e3SMatthew Dillon void 232831bc9e3SMatthew Dillon ahci_os_hardsleep(int us) 233831bc9e3SMatthew Dillon { 234831bc9e3SMatthew Dillon DELAY(us); 2353209f581SMatthew Dillon } 236f4553de1SMatthew Dillon 237f4553de1SMatthew Dillon /* 238f4553de1SMatthew Dillon * Create the OS-specific port helper thread and per-port lock. 239f4553de1SMatthew Dillon */ 240f4553de1SMatthew Dillon void 241f4553de1SMatthew Dillon ahci_os_start_port(struct ahci_port *ap) 242f4553de1SMatthew Dillon { 24326595b18SSascha Wildner struct sysctl_oid *soid; 244f17a0cedSMatthew Dillon char name[16]; 245f17a0cedSMatthew Dillon 246e8cf3f55SMatthew Dillon atomic_set_int(&ap->ap_signal, AP_SIGF_INIT | AP_SIGF_THREAD_SYNC); 247d16d3400SMatthew Dillon lockinit(&ap->ap_lock, "ahcipo", 0, LK_CANRECURSE); 248fb00c6edSMatthew Dillon lockinit(&ap->ap_sim_lock, "ahcicam", 0, LK_CANRECURSE); 249fb00c6edSMatthew Dillon lockinit(&ap->ap_sig_lock, "ahport", 0, 0); 250f17a0cedSMatthew Dillon sysctl_ctx_init(&ap->sysctl_ctx); 251f17a0cedSMatthew Dillon ksnprintf(name, sizeof(name), "%d", ap->ap_num); 25226595b18SSascha Wildner soid = device_get_sysctl_tree(ap->ap_sc->sc_dev); 253f17a0cedSMatthew Dillon ap->sysctl_tree = SYSCTL_ADD_NODE(&ap->sysctl_ctx, 25426595b18SSascha Wildner SYSCTL_CHILDREN(soid), 255f17a0cedSMatthew Dillon OID_AUTO, name, CTLFLAG_RD, 0, ""); 256f17a0cedSMatthew Dillon 257f17a0cedSMatthew Dillon if ((ap->ap_sc->sc_cap & AHCI_REG_CAP_SALP) && 258f17a0cedSMatthew Dillon (ap->ap_sc->sc_cap & (AHCI_REG_CAP_PSC | AHCI_REG_CAP_SSC))) { 259f17a0cedSMatthew Dillon SYSCTL_ADD_PROC(&ap->sysctl_ctx, 260f17a0cedSMatthew Dillon SYSCTL_CHILDREN(ap->sysctl_tree), OID_AUTO, 261f17a0cedSMatthew Dillon "link_pwr_mgmt", CTLTYPE_INT | CTLFLAG_RW, ap, 0, 262795adb22SMatthew Dillon ahci_sysctl_link_pwr_mgmt, "I", 263795adb22SMatthew Dillon "Link power management policy " 264f17a0cedSMatthew Dillon "(0 = disabled, 1 = medium, 2 = aggressive)"); 265795adb22SMatthew Dillon SYSCTL_ADD_PROC(&ap->sysctl_ctx, 266795adb22SMatthew Dillon SYSCTL_CHILDREN(ap->sysctl_tree), OID_AUTO, 267795adb22SMatthew Dillon "link_pwr_state", CTLTYPE_STRING | CTLFLAG_RD, ap, 0, 268795adb22SMatthew Dillon ahci_sysctl_link_pwr_state, "A", 269795adb22SMatthew Dillon "Link power management state"); 270f17a0cedSMatthew Dillon 271f17a0cedSMatthew Dillon } 272f17a0cedSMatthew Dillon 273f4553de1SMatthew Dillon kthread_create(ahci_port_thread, ap, &ap->ap_thread, 274f4553de1SMatthew Dillon "%s", PORTNAME(ap)); 275f4553de1SMatthew Dillon } 276f4553de1SMatthew Dillon 277f4553de1SMatthew Dillon /* 278f4553de1SMatthew Dillon * Stop the OS-specific port helper thread and kill the per-port lock. 279f4553de1SMatthew Dillon */ 280f4553de1SMatthew Dillon void 281f4553de1SMatthew Dillon ahci_os_stop_port(struct ahci_port *ap) 282f4553de1SMatthew Dillon { 283f17a0cedSMatthew Dillon if (ap->sysctl_tree) { 284f17a0cedSMatthew Dillon sysctl_ctx_free(&ap->sysctl_ctx); 285f17a0cedSMatthew Dillon ap->sysctl_tree = NULL; 286f17a0cedSMatthew Dillon } 287f17a0cedSMatthew Dillon 288f4553de1SMatthew Dillon if (ap->ap_thread) { 289f4553de1SMatthew Dillon ahci_os_signal_port_thread(ap, AP_SIGF_STOP); 290f4553de1SMatthew Dillon ahci_os_sleep(10); 291f4553de1SMatthew Dillon if (ap->ap_thread) { 292f4553de1SMatthew Dillon kprintf("%s: Waiting for thread to terminate\n", 293f4553de1SMatthew Dillon PORTNAME(ap)); 294f4553de1SMatthew Dillon while (ap->ap_thread) 295f4553de1SMatthew Dillon ahci_os_sleep(100); 296f4553de1SMatthew Dillon kprintf("%s: thread terminated\n", 297f4553de1SMatthew Dillon PORTNAME(ap)); 298f4553de1SMatthew Dillon } 299f4553de1SMatthew Dillon } 300f4553de1SMatthew Dillon lockuninit(&ap->ap_lock); 301f4553de1SMatthew Dillon } 302f4553de1SMatthew Dillon 303f4553de1SMatthew Dillon /* 304f4553de1SMatthew Dillon * Add (mask) to the set of bits being sent to the per-port thread helper 305f4553de1SMatthew Dillon * and wake the helper up if necessary. 306f4553de1SMatthew Dillon */ 307f4553de1SMatthew Dillon void 308f4553de1SMatthew Dillon ahci_os_signal_port_thread(struct ahci_port *ap, int mask) 309f4553de1SMatthew Dillon { 310fb00c6edSMatthew Dillon lockmgr(&ap->ap_sig_lock, LK_EXCLUSIVE); 311f4553de1SMatthew Dillon atomic_set_int(&ap->ap_signal, mask); 312fb00c6edSMatthew Dillon lockmgr(&ap->ap_sig_lock, LK_RELEASE); 3133d102df7SMatthew Dillon wakeup(&ap->ap_thread); 314f4553de1SMatthew Dillon } 315f4553de1SMatthew Dillon 316f4553de1SMatthew Dillon /* 317f4553de1SMatthew Dillon * Unconditionally lock the port structure for access. 318f4553de1SMatthew Dillon */ 319f4553de1SMatthew Dillon void 320f4553de1SMatthew Dillon ahci_os_lock_port(struct ahci_port *ap) 321f4553de1SMatthew Dillon { 322f4553de1SMatthew Dillon lockmgr(&ap->ap_lock, LK_EXCLUSIVE); 323f4553de1SMatthew Dillon } 324f4553de1SMatthew Dillon 325f4553de1SMatthew Dillon /* 326f4553de1SMatthew Dillon * Conditionally lock the port structure for access. 327f4553de1SMatthew Dillon * 328f4553de1SMatthew Dillon * Returns 0 on success, non-zero on failure. 329f4553de1SMatthew Dillon */ 330f4553de1SMatthew Dillon int 331f4553de1SMatthew Dillon ahci_os_lock_port_nb(struct ahci_port *ap) 332f4553de1SMatthew Dillon { 333f4553de1SMatthew Dillon return (lockmgr(&ap->ap_lock, LK_EXCLUSIVE | LK_NOWAIT)); 334f4553de1SMatthew Dillon } 335f4553de1SMatthew Dillon 336f4553de1SMatthew Dillon /* 337f4553de1SMatthew Dillon * Unlock a previously locked port. 338f4553de1SMatthew Dillon */ 339f4553de1SMatthew Dillon void 340f4553de1SMatthew Dillon ahci_os_unlock_port(struct ahci_port *ap) 341f4553de1SMatthew Dillon { 342f4553de1SMatthew Dillon lockmgr(&ap->ap_lock, LK_RELEASE); 343f4553de1SMatthew Dillon } 344f4553de1SMatthew Dillon 345f4553de1SMatthew Dillon /* 346f4553de1SMatthew Dillon * Per-port thread helper. This helper thread is responsible for 347f4553de1SMatthew Dillon * atomically retrieving and clearing the signal mask and calling 348f4553de1SMatthew Dillon * the machine-independant driver core. 349cd8ab232SMatthew Dillon * 350cd8ab232SMatthew Dillon * MPSAFE 351f4553de1SMatthew Dillon */ 352f4553de1SMatthew Dillon static 353f4553de1SMatthew Dillon void 354f4553de1SMatthew Dillon ahci_port_thread(void *arg) 355f4553de1SMatthew Dillon { 356f4553de1SMatthew Dillon struct ahci_port *ap = arg; 357f4553de1SMatthew Dillon int mask; 358f4553de1SMatthew Dillon 359f4553de1SMatthew Dillon /* 360e6546af9SMatthew Dillon * Sets us up as an interrupt support thread, meaning we are 361e6546af9SMatthew Dillon * given a higher priority and we can preempt normal threads. 362e6546af9SMatthew Dillon */ 363e6546af9SMatthew Dillon lwkt_set_interrupt_support_thread(); 364e6546af9SMatthew Dillon 365e6546af9SMatthew Dillon /* 366f4553de1SMatthew Dillon * The helper thread is responsible for the initial port init, 367f4553de1SMatthew Dillon * so all the ports can be inited in parallel. 368f4553de1SMatthew Dillon * 369f4553de1SMatthew Dillon * We also run the state machine which should do all probes. 370f4553de1SMatthew Dillon * Since CAM is not attached yet we will not get out-of-order 371f4553de1SMatthew Dillon * SCSI attachments. 372f4553de1SMatthew Dillon */ 373f4553de1SMatthew Dillon ahci_os_lock_port(ap); 37412feb904SMatthew Dillon ahci_port_init(ap); 375e8cf3f55SMatthew Dillon atomic_clear_int(&ap->ap_signal, AP_SIGF_THREAD_SYNC); 376e8cf3f55SMatthew Dillon wakeup(&ap->ap_signal); 377831bc9e3SMatthew Dillon ahci_port_state_machine(ap, 1); 378f4553de1SMatthew Dillon ahci_os_unlock_port(ap); 379f4553de1SMatthew Dillon atomic_clear_int(&ap->ap_signal, AP_SIGF_INIT); 380f4553de1SMatthew Dillon wakeup(&ap->ap_signal); 381f4553de1SMatthew Dillon 382f4553de1SMatthew Dillon /* 383f4553de1SMatthew Dillon * Then loop on the helper core. 384f4553de1SMatthew Dillon */ 385f4553de1SMatthew Dillon mask = ap->ap_signal; 386f4553de1SMatthew Dillon while ((mask & AP_SIGF_STOP) == 0) { 3876bac9ae4SMatthew Dillon ahci_port_thread_core(ap, mask); 388fb00c6edSMatthew Dillon lockmgr(&ap->ap_sig_lock, LK_EXCLUSIVE); 389fb00c6edSMatthew Dillon if (ap->ap_signal == 0) { 390fb00c6edSMatthew Dillon lksleep(&ap->ap_thread, &ap->ap_sig_lock, 0, 391fb00c6edSMatthew Dillon "ahport", 0); 392fb00c6edSMatthew Dillon } 393f4553de1SMatthew Dillon mask = ap->ap_signal; 3943d102df7SMatthew Dillon atomic_clear_int(&ap->ap_signal, mask); 3953d102df7SMatthew Dillon lockmgr(&ap->ap_sig_lock, LK_RELEASE); 396f4553de1SMatthew Dillon } 397f4553de1SMatthew Dillon ap->ap_thread = NULL; 398f4553de1SMatthew Dillon } 399