1 /* 2 * (MPSAFE) 3 * 4 * Copyright (c) 2009 The DragonFly Project. All rights reserved. 5 * 6 * This code is derived from software contributed to The DragonFly Project 7 * by Matthew Dillon <dillon@backplane.com> 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 3. Neither the name of The DragonFly Project nor the names of its 20 * contributors may be used to endorse or promote products derived 21 * from this software without specific, prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 /* 37 * Primary device and CAM interface to OpenBSD AHCI driver, for DragonFly 38 */ 39 40 #include "ahci.h" 41 42 u_int32_t AhciForceGen = 0; 43 u_int32_t AhciNoFeatures = 0; 44 45 /* 46 * Device bus methods 47 */ 48 49 static int ahci_probe (device_t dev); 50 static int ahci_attach (device_t dev); 51 static int ahci_detach (device_t dev); 52 static int ahci_sysctl_link_pwr_mgmt (SYSCTL_HANDLER_ARGS); 53 #if 0 54 static int ahci_shutdown (device_t dev); 55 static int ahci_suspend (device_t dev); 56 static int ahci_resume (device_t dev); 57 #endif 58 59 static void ahci_port_thread(void *arg); 60 61 static device_method_t ahci_methods[] = { 62 DEVMETHOD(device_probe, ahci_probe), 63 DEVMETHOD(device_attach, ahci_attach), 64 DEVMETHOD(device_detach, ahci_detach), 65 #if 0 66 DEVMETHOD(device_shutdown, ahci_shutdown), 67 DEVMETHOD(device_suspend, ahci_suspend), 68 DEVMETHOD(device_resume, ahci_resume), 69 #endif 70 71 DEVMETHOD(bus_print_child, bus_generic_print_child), 72 DEVMETHOD(bus_driver_added, bus_generic_driver_added), 73 DEVMETHOD_END 74 }; 75 76 static devclass_t ahci_devclass; 77 78 static driver_t ahci_driver = { 79 "ahci", 80 ahci_methods, 81 sizeof(struct ahci_softc) 82 }; 83 84 MODULE_DEPEND(ahci, cam, 1, 1, 1); 85 DRIVER_MODULE(ahci, pci, ahci_driver, ahci_devclass, NULL, NULL); 86 MODULE_VERSION(ahci, 1); 87 88 /* 89 * Device bus method procedures 90 */ 91 static int 92 ahci_probe (device_t dev) 93 { 94 const struct ahci_device *ad; 95 96 if (kgetenv("hint.ahci.disabled")) 97 return(ENXIO); 98 99 ad = ahci_lookup_device(dev); 100 if (ad) { 101 device_set_desc(dev, ad->name); 102 return(-5); /* higher priority the NATA */ 103 } 104 return(ENXIO); 105 } 106 107 static int 108 ahci_attach (device_t dev) 109 { 110 struct ahci_softc *sc = device_get_softc(dev); 111 112 sc->sc_ad = ahci_lookup_device(dev); 113 if (sc->sc_ad == NULL) 114 return(ENXIO); 115 116 /* 117 * Some chipsets do not properly implement the AHCI spec and may 118 * require the link speed to be specifically requested. 119 */ 120 if (kgetenv("hint.ahci.force150")) 121 AhciForceGen = 1; 122 if (kgetenv("hint.ahci.force300")) 123 AhciForceGen = 2; 124 if (kgetenv("hint.ahci.force600")) 125 AhciForceGen = 3; 126 127 if (kgetenv("hint.ahci.nofeatures")) 128 AhciNoFeatures = -1; 129 130 if (kgetenv("hint.ahci.forcefbss")) 131 sc->sc_flags |= AHCI_F_FORCE_FBSS; 132 133 return (sc->sc_ad->ad_attach(dev)); 134 } 135 136 static int 137 ahci_detach (device_t dev) 138 { 139 struct ahci_softc *sc = device_get_softc(dev); 140 int error = 0; 141 142 if (sc->sc_ad) { 143 error = sc->sc_ad->ad_detach(dev); 144 sc->sc_ad = NULL; 145 } 146 return(error); 147 } 148 149 static int 150 ahci_sysctl_link_pwr_mgmt (SYSCTL_HANDLER_ARGS) 151 { 152 struct ahci_port *ap = arg1; 153 int error, link_pwr_mgmt; 154 155 link_pwr_mgmt = ap->link_pwr_mgmt; 156 error = sysctl_handle_int(oidp, &link_pwr_mgmt, 0, req); 157 if (error || req->newptr == NULL) 158 return error; 159 160 ahci_port_link_pwr_mgmt(ap, link_pwr_mgmt); 161 return 0; 162 } 163 164 static int 165 ahci_sysctl_link_pwr_state (SYSCTL_HANDLER_ARGS) 166 { 167 struct ahci_port *ap = arg1; 168 const char *state_names[] = 169 {"unknown", "active", "partial", "slumber", "devsleep"}; 170 char buf[16]; 171 int state; 172 173 state = ahci_port_link_pwr_state(ap); 174 if (state < 0 || state >= NELEM(state_names)) 175 state = 0; 176 177 ksnprintf(buf, sizeof(buf), "%s", state_names[state]); 178 return sysctl_handle_string(oidp, buf, sizeof(buf), req); 179 } 180 181 #if 0 182 183 static int 184 ahci_shutdown (device_t dev) 185 { 186 return (0); 187 } 188 189 static int 190 ahci_suspend (device_t dev) 191 { 192 return (0); 193 } 194 195 static int 196 ahci_resume (device_t dev) 197 { 198 return (0); 199 } 200 201 #endif 202 203 /* 204 * Sleep (ms) milliseconds, error on the side of caution. 205 */ 206 void 207 ahci_os_sleep(int ms) 208 { 209 int ticks; 210 211 ticks = hz * ms / 1000 + 1; 212 tsleep(&ticks, 0, "ahslp", ticks); 213 } 214 215 /* 216 * Sleep for a minimum interval and return the number of milliseconds 217 * that was. The minimum value returned is 1 218 */ 219 int 220 ahci_os_softsleep(void) 221 { 222 if (hz >= 1000) { 223 tsleep(&ticks, 0, "ahslp", hz / 1000); 224 return(1); 225 } else { 226 tsleep(&ticks, 0, "ahslp", 1); 227 return(1000 / hz); 228 } 229 } 230 231 void 232 ahci_os_hardsleep(int us) 233 { 234 DELAY(us); 235 } 236 237 /* 238 * Create the OS-specific port helper thread and per-port lock. 239 */ 240 void 241 ahci_os_start_port(struct ahci_port *ap) 242 { 243 struct sysctl_oid *soid; 244 char name[16]; 245 246 atomic_set_int(&ap->ap_signal, AP_SIGF_INIT | AP_SIGF_THREAD_SYNC); 247 lockinit(&ap->ap_lock, "ahcipo", 0, LK_CANRECURSE); 248 lockinit(&ap->ap_sim_lock, "ahcicam", 0, LK_CANRECURSE); 249 lockinit(&ap->ap_sig_lock, "ahport", 0, 0); 250 sysctl_ctx_init(&ap->sysctl_ctx); 251 ksnprintf(name, sizeof(name), "%d", ap->ap_num); 252 soid = device_get_sysctl_tree(ap->ap_sc->sc_dev); 253 ap->sysctl_tree = SYSCTL_ADD_NODE(&ap->sysctl_ctx, 254 SYSCTL_CHILDREN(soid), 255 OID_AUTO, name, CTLFLAG_RD, 0, ""); 256 257 if ((ap->ap_sc->sc_cap & AHCI_REG_CAP_SALP) && 258 (ap->ap_sc->sc_cap & (AHCI_REG_CAP_PSC | AHCI_REG_CAP_SSC))) { 259 SYSCTL_ADD_PROC(&ap->sysctl_ctx, 260 SYSCTL_CHILDREN(ap->sysctl_tree), OID_AUTO, 261 "link_pwr_mgmt", CTLTYPE_INT | CTLFLAG_RW, ap, 0, 262 ahci_sysctl_link_pwr_mgmt, "I", 263 "Link power management policy " 264 "(0 = disabled, 1 = medium, 2 = aggressive)"); 265 SYSCTL_ADD_PROC(&ap->sysctl_ctx, 266 SYSCTL_CHILDREN(ap->sysctl_tree), OID_AUTO, 267 "link_pwr_state", CTLTYPE_STRING | CTLFLAG_RD, ap, 0, 268 ahci_sysctl_link_pwr_state, "A", 269 "Link power management state"); 270 271 } 272 273 kthread_create(ahci_port_thread, ap, &ap->ap_thread, 274 "%s", PORTNAME(ap)); 275 } 276 277 /* 278 * Stop the OS-specific port helper thread and kill the per-port lock. 279 */ 280 void 281 ahci_os_stop_port(struct ahci_port *ap) 282 { 283 if (ap->sysctl_tree) { 284 sysctl_ctx_free(&ap->sysctl_ctx); 285 ap->sysctl_tree = NULL; 286 } 287 288 if (ap->ap_thread) { 289 ahci_os_signal_port_thread(ap, AP_SIGF_STOP); 290 ahci_os_sleep(10); 291 if (ap->ap_thread) { 292 kprintf("%s: Waiting for thread to terminate\n", 293 PORTNAME(ap)); 294 while (ap->ap_thread) 295 ahci_os_sleep(100); 296 kprintf("%s: thread terminated\n", 297 PORTNAME(ap)); 298 } 299 } 300 lockuninit(&ap->ap_lock); 301 } 302 303 /* 304 * Add (mask) to the set of bits being sent to the per-port thread helper 305 * and wake the helper up if necessary. 306 */ 307 void 308 ahci_os_signal_port_thread(struct ahci_port *ap, int mask) 309 { 310 lockmgr(&ap->ap_sig_lock, LK_EXCLUSIVE); 311 atomic_set_int(&ap->ap_signal, mask); 312 lockmgr(&ap->ap_sig_lock, LK_RELEASE); 313 wakeup(&ap->ap_thread); 314 } 315 316 /* 317 * Unconditionally lock the port structure for access. 318 */ 319 void 320 ahci_os_lock_port(struct ahci_port *ap) 321 { 322 lockmgr(&ap->ap_lock, LK_EXCLUSIVE); 323 } 324 325 /* 326 * Conditionally lock the port structure for access. 327 * 328 * Returns 0 on success, non-zero on failure. 329 */ 330 int 331 ahci_os_lock_port_nb(struct ahci_port *ap) 332 { 333 return (lockmgr(&ap->ap_lock, LK_EXCLUSIVE | LK_NOWAIT)); 334 } 335 336 /* 337 * Unlock a previously locked port. 338 */ 339 void 340 ahci_os_unlock_port(struct ahci_port *ap) 341 { 342 lockmgr(&ap->ap_lock, LK_RELEASE); 343 } 344 345 /* 346 * Per-port thread helper. This helper thread is responsible for 347 * atomically retrieving and clearing the signal mask and calling 348 * the machine-independant driver core. 349 * 350 * MPSAFE 351 */ 352 static 353 void 354 ahci_port_thread(void *arg) 355 { 356 struct ahci_port *ap = arg; 357 int mask; 358 359 /* 360 * Sets us up as an interrupt support thread, meaning we are 361 * given a higher priority and we can preempt normal threads. 362 */ 363 lwkt_set_interrupt_support_thread(); 364 365 /* 366 * The helper thread is responsible for the initial port init, 367 * so all the ports can be inited in parallel. 368 * 369 * We also run the state machine which should do all probes. 370 * Since CAM is not attached yet we will not get out-of-order 371 * SCSI attachments. 372 */ 373 ahci_os_lock_port(ap); 374 ahci_port_init(ap); 375 atomic_clear_int(&ap->ap_signal, AP_SIGF_THREAD_SYNC); 376 wakeup(&ap->ap_signal); 377 ahci_port_state_machine(ap, 1); 378 atomic_clear_int(&ap->ap_signal, AP_SIGF_INIT); 379 380 /* 381 * If attaching synchronous wakeup the frontend (device attach code), 382 * otherwise attach asynchronously. We haven't probed anything yet 383 * so the ahci_cam_attach() won't try to probe. 384 */ 385 if (ahci_synchronous_boot) { 386 wakeup(&ap->ap_signal); 387 } else { 388 if (ahci_cam_attach(ap) == 0) 389 ahci_cam_changed(ap, NULL, -1); 390 } 391 ahci_os_unlock_port(ap); 392 393 /* 394 * Then loop on the helper core. 395 */ 396 mask = ap->ap_signal; 397 while ((mask & AP_SIGF_STOP) == 0) { 398 ahci_port_thread_core(ap, mask); 399 lockmgr(&ap->ap_sig_lock, LK_EXCLUSIVE); 400 if (ap->ap_signal == 0) { 401 lksleep(&ap->ap_thread, &ap->ap_sig_lock, 0, 402 "ahport", 0); 403 } 404 mask = ap->ap_signal; 405 atomic_clear_int(&ap->ap_signal, mask); 406 lockmgr(&ap->ap_sig_lock, LK_RELEASE); 407 } 408 ap->ap_thread = NULL; 409 } 410