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 42*8986d351SMatthew 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), 73258223a3SMatthew Dillon {0, 0} 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); 85258223a3SMatthew Dillon DRIVER_MODULE(ahci, pci, ahci_driver, ahci_devclass, 0, 0); 86258223a3SMatthew Dillon 87258223a3SMatthew Dillon /* 88258223a3SMatthew Dillon * Device bus method procedures 89258223a3SMatthew Dillon */ 90258223a3SMatthew Dillon static int 91258223a3SMatthew Dillon ahci_probe (device_t dev) 92258223a3SMatthew Dillon { 93258223a3SMatthew Dillon const struct ahci_device *ad; 94258223a3SMatthew Dillon 95c45a2365SMatthew Dillon if (kgetenv("hint.ahci.disabled")) 96c45a2365SMatthew Dillon return(ENXIO); 97c45a2365SMatthew Dillon 98258223a3SMatthew Dillon ad = ahci_lookup_device(dev); 99258223a3SMatthew Dillon if (ad) { 100258223a3SMatthew Dillon device_set_desc(dev, ad->name); 101258223a3SMatthew Dillon return(-5); /* higher priority the NATA */ 102258223a3SMatthew Dillon } 103258223a3SMatthew Dillon return(ENXIO); 104258223a3SMatthew Dillon } 105258223a3SMatthew Dillon 106258223a3SMatthew Dillon static int 107258223a3SMatthew Dillon ahci_attach (device_t dev) 108258223a3SMatthew Dillon { 109258223a3SMatthew Dillon struct ahci_softc *sc = device_get_softc(dev); 110f17a0cedSMatthew Dillon char name[16]; 111258223a3SMatthew Dillon int error; 112258223a3SMatthew Dillon 113258223a3SMatthew Dillon sc->sc_ad = ahci_lookup_device(dev); 114258223a3SMatthew Dillon if (sc->sc_ad == NULL) 115258223a3SMatthew Dillon return(ENXIO); 116f17a0cedSMatthew Dillon 117*8986d351SMatthew Dillon /* 118*8986d351SMatthew Dillon * Some chipsets do not properly implement the AHCI spec and may 119*8986d351SMatthew Dillon * require the link speed to be specifically requested. 120*8986d351SMatthew Dillon */ 121*8986d351SMatthew Dillon if (kgetenv("hint.ahci.force150")) 122*8986d351SMatthew Dillon AhciForceGen = 1; 123*8986d351SMatthew Dillon if (kgetenv("hint.ahci.force300")) 124*8986d351SMatthew Dillon AhciForceGen = 2; 125*8986d351SMatthew Dillon if (kgetenv("hint.ahci.force600")) 126*8986d351SMatthew Dillon AhciForceGen = 3; 127*8986d351SMatthew Dillon 128*8986d351SMatthew Dillon if (kgetenv("hint.ahci.nofeatures")) 129*8986d351SMatthew Dillon AhciNoFeatures = -1; 130*8986d351SMatthew Dillon 131f17a0cedSMatthew Dillon sysctl_ctx_init(&sc->sysctl_ctx); 132f17a0cedSMatthew Dillon ksnprintf(name, sizeof(name), "%s%d", 133f17a0cedSMatthew Dillon device_get_name(dev), device_get_unit(dev)); 134f17a0cedSMatthew Dillon sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 135f17a0cedSMatthew Dillon SYSCTL_STATIC_CHILDREN(_hw), 136f17a0cedSMatthew Dillon OID_AUTO, name, CTLFLAG_RD, 0, ""); 137f17a0cedSMatthew Dillon 138258223a3SMatthew Dillon error = sc->sc_ad->ad_attach(dev); 139f17a0cedSMatthew Dillon if (error) { 140f17a0cedSMatthew Dillon sysctl_ctx_free(&sc->sysctl_ctx); 141f17a0cedSMatthew Dillon sc->sysctl_tree = NULL; 142f17a0cedSMatthew Dillon } 143258223a3SMatthew Dillon return (error); 144258223a3SMatthew Dillon } 145258223a3SMatthew Dillon 146258223a3SMatthew Dillon static int 147258223a3SMatthew Dillon ahci_detach (device_t dev) 148258223a3SMatthew Dillon { 149258223a3SMatthew Dillon struct ahci_softc *sc = device_get_softc(dev); 150258223a3SMatthew Dillon int error = 0; 151258223a3SMatthew Dillon 152f17a0cedSMatthew Dillon if (sc->sysctl_tree) { 153f17a0cedSMatthew Dillon sysctl_ctx_free(&sc->sysctl_ctx); 154f17a0cedSMatthew Dillon sc->sysctl_tree = NULL; 155f17a0cedSMatthew Dillon } 156258223a3SMatthew Dillon if (sc->sc_ad) { 157258223a3SMatthew Dillon error = sc->sc_ad->ad_detach(dev); 158258223a3SMatthew Dillon sc->sc_ad = NULL; 159258223a3SMatthew Dillon } 160258223a3SMatthew Dillon return(error); 161258223a3SMatthew Dillon } 162258223a3SMatthew Dillon 163f17a0cedSMatthew Dillon static int 164795adb22SMatthew Dillon ahci_sysctl_link_pwr_mgmt (SYSCTL_HANDLER_ARGS) 165f17a0cedSMatthew Dillon { 166f17a0cedSMatthew Dillon struct ahci_port *ap = arg1; 167f17a0cedSMatthew Dillon int error, link_pwr_mgmt; 168f17a0cedSMatthew Dillon 169f17a0cedSMatthew Dillon link_pwr_mgmt = ap->link_pwr_mgmt; 170f17a0cedSMatthew Dillon error = sysctl_handle_int(oidp, &link_pwr_mgmt, 0, req); 171f17a0cedSMatthew Dillon if (error || req->newptr == NULL) 172f17a0cedSMatthew Dillon return error; 173f17a0cedSMatthew Dillon 174f17a0cedSMatthew Dillon ahci_port_link_pwr_mgmt(ap, link_pwr_mgmt); 175f17a0cedSMatthew Dillon return 0; 176f17a0cedSMatthew Dillon } 177f17a0cedSMatthew Dillon 178795adb22SMatthew Dillon static int 179795adb22SMatthew Dillon ahci_sysctl_link_pwr_state (SYSCTL_HANDLER_ARGS) 180795adb22SMatthew Dillon { 181795adb22SMatthew Dillon struct ahci_port *ap = arg1; 182795adb22SMatthew Dillon const char *state_names[] = {"unknown", "active", "partial", "slumber"}; 183795adb22SMatthew Dillon char buf[16]; 184795adb22SMatthew Dillon int state; 185795adb22SMatthew Dillon 186795adb22SMatthew Dillon state = ahci_port_link_pwr_state(ap); 187c157ff7aSSascha Wildner if (state < 0 || state >= NELEM(state_names)) 188795adb22SMatthew Dillon state = 0; 189795adb22SMatthew Dillon 190795adb22SMatthew Dillon ksnprintf(buf, sizeof(buf), "%s", state_names[state]); 191795adb22SMatthew Dillon return sysctl_handle_string(oidp, buf, sizeof(buf), req); 192795adb22SMatthew Dillon } 193795adb22SMatthew Dillon 194258223a3SMatthew Dillon #if 0 195258223a3SMatthew Dillon 196258223a3SMatthew Dillon static int 197258223a3SMatthew Dillon ahci_shutdown (device_t dev) 198258223a3SMatthew Dillon { 199258223a3SMatthew Dillon return (0); 200258223a3SMatthew Dillon } 201258223a3SMatthew Dillon 202258223a3SMatthew Dillon static int 203258223a3SMatthew Dillon ahci_suspend (device_t dev) 204258223a3SMatthew Dillon { 205258223a3SMatthew Dillon return (0); 206258223a3SMatthew Dillon } 207258223a3SMatthew Dillon 208258223a3SMatthew Dillon static int 209258223a3SMatthew Dillon ahci_resume (device_t dev) 210258223a3SMatthew Dillon { 211258223a3SMatthew Dillon return (0); 212258223a3SMatthew Dillon } 213258223a3SMatthew Dillon 214258223a3SMatthew Dillon #endif 2153209f581SMatthew Dillon 216831bc9e3SMatthew Dillon /* 217831bc9e3SMatthew Dillon * Sleep (ms) milliseconds, error on the side of caution. 218831bc9e3SMatthew Dillon */ 2193209f581SMatthew Dillon void 2203209f581SMatthew Dillon ahci_os_sleep(int ms) 2213209f581SMatthew Dillon { 2223209f581SMatthew Dillon int ticks; 2233209f581SMatthew Dillon 2243209f581SMatthew Dillon ticks = hz * ms / 1000 + 1; 2253209f581SMatthew Dillon tsleep(&ticks, 0, "ahslp", ticks); 2263209f581SMatthew Dillon } 227831bc9e3SMatthew Dillon 228831bc9e3SMatthew Dillon /* 229831bc9e3SMatthew Dillon * Sleep for a minimum interval and return the number of milliseconds 230831bc9e3SMatthew Dillon * that was. The minimum value returned is 1 231831bc9e3SMatthew Dillon */ 232831bc9e3SMatthew Dillon int 233831bc9e3SMatthew Dillon ahci_os_softsleep(void) 234831bc9e3SMatthew Dillon { 235831bc9e3SMatthew Dillon if (hz >= 1000) { 236831bc9e3SMatthew Dillon tsleep(&ticks, 0, "ahslp", hz / 1000); 237831bc9e3SMatthew Dillon return(1); 238831bc9e3SMatthew Dillon } else { 239831bc9e3SMatthew Dillon tsleep(&ticks, 0, "ahslp", 1); 240831bc9e3SMatthew Dillon return(1000 / hz); 241831bc9e3SMatthew Dillon } 242831bc9e3SMatthew Dillon } 243831bc9e3SMatthew Dillon 244831bc9e3SMatthew Dillon void 245831bc9e3SMatthew Dillon ahci_os_hardsleep(int us) 246831bc9e3SMatthew Dillon { 247831bc9e3SMatthew Dillon DELAY(us); 2483209f581SMatthew Dillon } 249f4553de1SMatthew Dillon 250f4553de1SMatthew Dillon /* 251f4553de1SMatthew Dillon * Create the OS-specific port helper thread and per-port lock. 252f4553de1SMatthew Dillon */ 253f4553de1SMatthew Dillon void 254f4553de1SMatthew Dillon ahci_os_start_port(struct ahci_port *ap) 255f4553de1SMatthew Dillon { 256f17a0cedSMatthew Dillon char name[16]; 257f17a0cedSMatthew Dillon 258e8cf3f55SMatthew Dillon atomic_set_int(&ap->ap_signal, AP_SIGF_INIT | AP_SIGF_THREAD_SYNC); 259f4553de1SMatthew Dillon lockinit(&ap->ap_lock, "ahcipo", 0, 0); 260fb00c6edSMatthew Dillon lockinit(&ap->ap_sim_lock, "ahcicam", 0, LK_CANRECURSE); 261fb00c6edSMatthew Dillon lockinit(&ap->ap_sig_lock, "ahport", 0, 0); 262f17a0cedSMatthew Dillon sysctl_ctx_init(&ap->sysctl_ctx); 263f17a0cedSMatthew Dillon ksnprintf(name, sizeof(name), "%d", ap->ap_num); 264f17a0cedSMatthew Dillon ap->sysctl_tree = SYSCTL_ADD_NODE(&ap->sysctl_ctx, 265f17a0cedSMatthew Dillon SYSCTL_CHILDREN(ap->ap_sc->sysctl_tree), 266f17a0cedSMatthew Dillon OID_AUTO, name, CTLFLAG_RD, 0, ""); 267f17a0cedSMatthew Dillon 268f17a0cedSMatthew Dillon if ((ap->ap_sc->sc_cap & AHCI_REG_CAP_SALP) && 269f17a0cedSMatthew Dillon (ap->ap_sc->sc_cap & (AHCI_REG_CAP_PSC | AHCI_REG_CAP_SSC))) { 270f17a0cedSMatthew Dillon SYSCTL_ADD_PROC(&ap->sysctl_ctx, 271f17a0cedSMatthew Dillon SYSCTL_CHILDREN(ap->sysctl_tree), OID_AUTO, 272f17a0cedSMatthew Dillon "link_pwr_mgmt", CTLTYPE_INT | CTLFLAG_RW, ap, 0, 273795adb22SMatthew Dillon ahci_sysctl_link_pwr_mgmt, "I", 274795adb22SMatthew Dillon "Link power management policy " 275f17a0cedSMatthew Dillon "(0 = disabled, 1 = medium, 2 = aggressive)"); 276795adb22SMatthew Dillon SYSCTL_ADD_PROC(&ap->sysctl_ctx, 277795adb22SMatthew Dillon SYSCTL_CHILDREN(ap->sysctl_tree), OID_AUTO, 278795adb22SMatthew Dillon "link_pwr_state", CTLTYPE_STRING | CTLFLAG_RD, ap, 0, 279795adb22SMatthew Dillon ahci_sysctl_link_pwr_state, "A", 280795adb22SMatthew Dillon "Link power management state"); 281f17a0cedSMatthew Dillon 282f17a0cedSMatthew Dillon } 283f17a0cedSMatthew Dillon 284f4553de1SMatthew Dillon kthread_create(ahci_port_thread, ap, &ap->ap_thread, 285f4553de1SMatthew Dillon "%s", PORTNAME(ap)); 286f4553de1SMatthew Dillon } 287f4553de1SMatthew Dillon 288f4553de1SMatthew Dillon /* 289f4553de1SMatthew Dillon * Stop the OS-specific port helper thread and kill the per-port lock. 290f4553de1SMatthew Dillon */ 291f4553de1SMatthew Dillon void 292f4553de1SMatthew Dillon ahci_os_stop_port(struct ahci_port *ap) 293f4553de1SMatthew Dillon { 294f17a0cedSMatthew Dillon if (ap->sysctl_tree) { 295f17a0cedSMatthew Dillon sysctl_ctx_free(&ap->sysctl_ctx); 296f17a0cedSMatthew Dillon ap->sysctl_tree = NULL; 297f17a0cedSMatthew Dillon } 298f17a0cedSMatthew Dillon 299f4553de1SMatthew Dillon if (ap->ap_thread) { 300f4553de1SMatthew Dillon ahci_os_signal_port_thread(ap, AP_SIGF_STOP); 301f4553de1SMatthew Dillon ahci_os_sleep(10); 302f4553de1SMatthew Dillon if (ap->ap_thread) { 303f4553de1SMatthew Dillon kprintf("%s: Waiting for thread to terminate\n", 304f4553de1SMatthew Dillon PORTNAME(ap)); 305f4553de1SMatthew Dillon while (ap->ap_thread) 306f4553de1SMatthew Dillon ahci_os_sleep(100); 307f4553de1SMatthew Dillon kprintf("%s: thread terminated\n", 308f4553de1SMatthew Dillon PORTNAME(ap)); 309f4553de1SMatthew Dillon } 310f4553de1SMatthew Dillon } 311f4553de1SMatthew Dillon lockuninit(&ap->ap_lock); 312f4553de1SMatthew Dillon } 313f4553de1SMatthew Dillon 314f4553de1SMatthew Dillon /* 315f4553de1SMatthew Dillon * Add (mask) to the set of bits being sent to the per-port thread helper 316f4553de1SMatthew Dillon * and wake the helper up if necessary. 317f4553de1SMatthew Dillon */ 318f4553de1SMatthew Dillon void 319f4553de1SMatthew Dillon ahci_os_signal_port_thread(struct ahci_port *ap, int mask) 320f4553de1SMatthew Dillon { 321fb00c6edSMatthew Dillon lockmgr(&ap->ap_sig_lock, LK_EXCLUSIVE); 322f4553de1SMatthew Dillon atomic_set_int(&ap->ap_signal, mask); 323f4553de1SMatthew Dillon wakeup(&ap->ap_thread); 324fb00c6edSMatthew Dillon lockmgr(&ap->ap_sig_lock, LK_RELEASE); 325f4553de1SMatthew Dillon } 326f4553de1SMatthew Dillon 327f4553de1SMatthew Dillon /* 328f4553de1SMatthew Dillon * Unconditionally lock the port structure for access. 329f4553de1SMatthew Dillon */ 330f4553de1SMatthew Dillon void 331f4553de1SMatthew Dillon ahci_os_lock_port(struct ahci_port *ap) 332f4553de1SMatthew Dillon { 333f4553de1SMatthew Dillon lockmgr(&ap->ap_lock, LK_EXCLUSIVE); 334f4553de1SMatthew Dillon } 335f4553de1SMatthew Dillon 336f4553de1SMatthew Dillon /* 337f4553de1SMatthew Dillon * Conditionally lock the port structure for access. 338f4553de1SMatthew Dillon * 339f4553de1SMatthew Dillon * Returns 0 on success, non-zero on failure. 340f4553de1SMatthew Dillon */ 341f4553de1SMatthew Dillon int 342f4553de1SMatthew Dillon ahci_os_lock_port_nb(struct ahci_port *ap) 343f4553de1SMatthew Dillon { 344f4553de1SMatthew Dillon return (lockmgr(&ap->ap_lock, LK_EXCLUSIVE | LK_NOWAIT)); 345f4553de1SMatthew Dillon } 346f4553de1SMatthew Dillon 347f4553de1SMatthew Dillon /* 348f4553de1SMatthew Dillon * Unlock a previously locked port. 349f4553de1SMatthew Dillon */ 350f4553de1SMatthew Dillon void 351f4553de1SMatthew Dillon ahci_os_unlock_port(struct ahci_port *ap) 352f4553de1SMatthew Dillon { 353f4553de1SMatthew Dillon lockmgr(&ap->ap_lock, LK_RELEASE); 354f4553de1SMatthew Dillon } 355f4553de1SMatthew Dillon 356f4553de1SMatthew Dillon /* 357f4553de1SMatthew Dillon * Per-port thread helper. This helper thread is responsible for 358f4553de1SMatthew Dillon * atomically retrieving and clearing the signal mask and calling 359f4553de1SMatthew Dillon * the machine-independant driver core. 360cd8ab232SMatthew Dillon * 361cd8ab232SMatthew Dillon * MPSAFE 362f4553de1SMatthew Dillon */ 363f4553de1SMatthew Dillon static 364f4553de1SMatthew Dillon void 365f4553de1SMatthew Dillon ahci_port_thread(void *arg) 366f4553de1SMatthew Dillon { 367f4553de1SMatthew Dillon struct ahci_port *ap = arg; 368f4553de1SMatthew Dillon int mask; 369f4553de1SMatthew Dillon 370f4553de1SMatthew Dillon /* 371f4553de1SMatthew Dillon * The helper thread is responsible for the initial port init, 372f4553de1SMatthew Dillon * so all the ports can be inited in parallel. 373f4553de1SMatthew Dillon * 374f4553de1SMatthew Dillon * We also run the state machine which should do all probes. 375f4553de1SMatthew Dillon * Since CAM is not attached yet we will not get out-of-order 376f4553de1SMatthew Dillon * SCSI attachments. 377f4553de1SMatthew Dillon */ 378f4553de1SMatthew Dillon ahci_os_lock_port(ap); 37912feb904SMatthew Dillon ahci_port_init(ap); 380e8cf3f55SMatthew Dillon atomic_clear_int(&ap->ap_signal, AP_SIGF_THREAD_SYNC); 381e8cf3f55SMatthew Dillon wakeup(&ap->ap_signal); 382831bc9e3SMatthew Dillon ahci_port_state_machine(ap, 1); 383f4553de1SMatthew Dillon ahci_os_unlock_port(ap); 384f4553de1SMatthew Dillon atomic_clear_int(&ap->ap_signal, AP_SIGF_INIT); 385f4553de1SMatthew Dillon wakeup(&ap->ap_signal); 386f4553de1SMatthew Dillon 387f4553de1SMatthew Dillon /* 388f4553de1SMatthew Dillon * Then loop on the helper core. 389f4553de1SMatthew Dillon */ 390f4553de1SMatthew Dillon mask = ap->ap_signal; 391f4553de1SMatthew Dillon while ((mask & AP_SIGF_STOP) == 0) { 392f4553de1SMatthew Dillon atomic_clear_int(&ap->ap_signal, mask); 393f4553de1SMatthew Dillon ahci_port_thread_core(ap, mask); 394fb00c6edSMatthew Dillon lockmgr(&ap->ap_sig_lock, LK_EXCLUSIVE); 395fb00c6edSMatthew Dillon if (ap->ap_signal == 0) { 396fb00c6edSMatthew Dillon lksleep(&ap->ap_thread, &ap->ap_sig_lock, 0, 397fb00c6edSMatthew Dillon "ahport", 0); 398fb00c6edSMatthew Dillon } 399fb00c6edSMatthew Dillon lockmgr(&ap->ap_sig_lock, LK_RELEASE); 400f4553de1SMatthew Dillon mask = ap->ap_signal; 401f4553de1SMatthew Dillon } 402f4553de1SMatthew Dillon ap->ap_thread = NULL; 403f4553de1SMatthew Dillon } 404