kernel - unwind kthread_create() mplock
[dragonfly.git] / sys / dev / disk / ahci / ahci_dragonfly.c
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 AhciForceGen1 = 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         {0, 0}
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, 0, 0);
86
87 /*
88  * Device bus method procedures
89  */
90 static int
91 ahci_probe (device_t dev)
92 {
93         const struct ahci_device *ad;
94
95         if (kgetenv("hint.ahci.disabled"))
96                 return(ENXIO);
97         if (kgetenv("hint.ahci.force150"))
98                 AhciForceGen1 = -1;
99         if (kgetenv("hint.ahci.nofeatures"))
100                 AhciNoFeatures = -1;
101
102         ad = ahci_lookup_device(dev);
103         if (ad) {
104                 device_set_desc(dev, ad->name);
105                 return(-5);     /* higher priority the NATA */
106         }
107         return(ENXIO);
108 }
109
110 static int
111 ahci_attach (device_t dev)
112 {
113         struct ahci_softc *sc = device_get_softc(dev);
114         char name[16];
115         int error;
116
117         sc->sc_ad = ahci_lookup_device(dev);
118         if (sc->sc_ad == NULL)
119                 return(ENXIO);
120
121         sysctl_ctx_init(&sc->sysctl_ctx);
122         ksnprintf(name, sizeof(name), "%s%d",
123                 device_get_name(dev), device_get_unit(dev));
124         sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
125                                 SYSCTL_STATIC_CHILDREN(_hw),
126                                 OID_AUTO, name, CTLFLAG_RD, 0, "");
127
128         error = sc->sc_ad->ad_attach(dev);
129         if (error) {
130                 sysctl_ctx_free(&sc->sysctl_ctx);
131                 sc->sysctl_tree = NULL;
132         }
133         return (error);
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->sysctl_tree) {
143                 sysctl_ctx_free(&sc->sysctl_ctx);
144                 sc->sysctl_tree = NULL;
145         }
146         if (sc->sc_ad) {
147                 error = sc->sc_ad->ad_detach(dev);
148                 sc->sc_ad = NULL;
149         }
150         return(error);
151 }
152
153 static int
154 ahci_sysctl_link_pwr_mgmt (SYSCTL_HANDLER_ARGS)
155 {
156         struct ahci_port *ap = arg1;
157         int error, link_pwr_mgmt;
158
159         link_pwr_mgmt = ap->link_pwr_mgmt;
160         error = sysctl_handle_int(oidp, &link_pwr_mgmt, 0, req);
161         if (error || req->newptr == NULL)
162                 return error;
163
164         ahci_port_link_pwr_mgmt(ap, link_pwr_mgmt);
165         return 0;
166 }
167
168 static int
169 ahci_sysctl_link_pwr_state (SYSCTL_HANDLER_ARGS)
170 {
171         struct ahci_port *ap = arg1;
172         const char *state_names[] = {"unknown", "active", "partial", "slumber"};
173         char buf[16];
174         int state;
175
176         state = ahci_port_link_pwr_state(ap);
177         if (state < 0 || state >= sizeof(state_names) / sizeof(state_names[0]))
178                 state = 0;
179
180         ksnprintf(buf, sizeof(buf), "%s", state_names[state]);
181         return sysctl_handle_string(oidp, buf, sizeof(buf), req);
182 }
183
184 #if 0
185
186 static int
187 ahci_shutdown (device_t dev)
188 {
189         return (0);
190 }
191
192 static int
193 ahci_suspend (device_t dev)
194 {
195         return (0);
196 }
197
198 static int
199 ahci_resume (device_t dev)
200 {
201         return (0);
202 }
203
204 #endif
205
206 /*
207  * Sleep (ms) milliseconds, error on the side of caution.
208  */
209 void
210 ahci_os_sleep(int ms)
211 {
212         int ticks;
213
214         ticks = hz * ms / 1000 + 1;
215         tsleep(&ticks, 0, "ahslp", ticks);
216 }
217
218 /*
219  * Sleep for a minimum interval and return the number of milliseconds
220  * that was.  The minimum value returned is 1
221  */
222 int
223 ahci_os_softsleep(void)
224 {
225         if (hz >= 1000) {
226                 tsleep(&ticks, 0, "ahslp", hz / 1000);
227                 return(1);
228         } else {
229                 tsleep(&ticks, 0, "ahslp", 1);
230                 return(1000 / hz);
231         }
232 }
233
234 void
235 ahci_os_hardsleep(int us)
236 {
237         DELAY(us);
238 }
239
240 /*
241  * Create the OS-specific port helper thread and per-port lock.
242  */
243 void
244 ahci_os_start_port(struct ahci_port *ap)
245 {
246         char name[16];
247
248         atomic_set_int(&ap->ap_signal, AP_SIGF_INIT | AP_SIGF_THREAD_SYNC);
249         lockinit(&ap->ap_lock, "ahcipo", 0, 0);
250         lockinit(&ap->ap_sim_lock, "ahcicam", 0, LK_CANRECURSE);
251         lockinit(&ap->ap_sig_lock, "ahport", 0, 0);
252         sysctl_ctx_init(&ap->sysctl_ctx);
253         ksnprintf(name, sizeof(name), "%d", ap->ap_num);
254         ap->sysctl_tree = SYSCTL_ADD_NODE(&ap->sysctl_ctx,
255                                 SYSCTL_CHILDREN(ap->ap_sc->sysctl_tree),
256                                 OID_AUTO, name, CTLFLAG_RD, 0, "");
257
258         if ((ap->ap_sc->sc_cap & AHCI_REG_CAP_SALP) &&
259             (ap->ap_sc->sc_cap & (AHCI_REG_CAP_PSC | AHCI_REG_CAP_SSC))) {
260                 SYSCTL_ADD_PROC(&ap->sysctl_ctx,
261                         SYSCTL_CHILDREN(ap->sysctl_tree), OID_AUTO,
262                         "link_pwr_mgmt", CTLTYPE_INT | CTLFLAG_RW, ap, 0,
263                         ahci_sysctl_link_pwr_mgmt, "I",
264                         "Link power management policy "
265                         "(0 = disabled, 1 = medium, 2 = aggressive)");
266                 SYSCTL_ADD_PROC(&ap->sysctl_ctx,
267                         SYSCTL_CHILDREN(ap->sysctl_tree), OID_AUTO,
268                         "link_pwr_state", CTLTYPE_STRING | CTLFLAG_RD, ap, 0,
269                         ahci_sysctl_link_pwr_state, "A",
270                         "Link power management state");
271
272         }
273
274         kthread_create(ahci_port_thread, ap, &ap->ap_thread,
275                        "%s", PORTNAME(ap));
276 }
277
278 /*
279  * Stop the OS-specific port helper thread and kill the per-port lock.
280  */
281 void
282 ahci_os_stop_port(struct ahci_port *ap)
283 {
284         if (ap->sysctl_tree) {
285                 sysctl_ctx_free(&ap->sysctl_ctx);
286                 ap->sysctl_tree = NULL;
287         }
288
289         if (ap->ap_thread) {
290                 ahci_os_signal_port_thread(ap, AP_SIGF_STOP);
291                 ahci_os_sleep(10);
292                 if (ap->ap_thread) {
293                         kprintf("%s: Waiting for thread to terminate\n",
294                                 PORTNAME(ap));
295                         while (ap->ap_thread)
296                                 ahci_os_sleep(100);
297                         kprintf("%s: thread terminated\n",
298                                 PORTNAME(ap));
299                 }
300         }
301         lockuninit(&ap->ap_lock);
302 }
303
304 /*
305  * Add (mask) to the set of bits being sent to the per-port thread helper
306  * and wake the helper up if necessary.
307  */
308 void
309 ahci_os_signal_port_thread(struct ahci_port *ap, int mask)
310 {
311         lockmgr(&ap->ap_sig_lock, LK_EXCLUSIVE);
312         atomic_set_int(&ap->ap_signal, mask);
313         wakeup(&ap->ap_thread);
314         lockmgr(&ap->ap_sig_lock, LK_RELEASE);
315 }
316
317 /*
318  * Unconditionally lock the port structure for access.
319  */
320 void
321 ahci_os_lock_port(struct ahci_port *ap)
322 {
323         lockmgr(&ap->ap_lock, LK_EXCLUSIVE);
324 }
325
326 /*
327  * Conditionally lock the port structure for access.
328  *
329  * Returns 0 on success, non-zero on failure.
330  */
331 int
332 ahci_os_lock_port_nb(struct ahci_port *ap)
333 {
334         return (lockmgr(&ap->ap_lock, LK_EXCLUSIVE | LK_NOWAIT));
335 }
336
337 /*
338  * Unlock a previously locked port.
339  */
340 void
341 ahci_os_unlock_port(struct ahci_port *ap)
342 {
343         lockmgr(&ap->ap_lock, LK_RELEASE);
344 }
345
346 /*
347  * Per-port thread helper.  This helper thread is responsible for
348  * atomically retrieving and clearing the signal mask and calling
349  * the machine-independant driver core.
350  *
351  * MPSAFE
352  */
353 static
354 void
355 ahci_port_thread(void *arg)
356 {
357         struct ahci_port *ap = arg;
358         int mask;
359
360         /*
361          * The helper thread is responsible for the initial port init,
362          * so all the ports can be inited in parallel.
363          *
364          * We also run the state machine which should do all probes.
365          * Since CAM is not attached yet we will not get out-of-order
366          * SCSI attachments.
367          */
368         ahci_os_lock_port(ap);
369         ahci_port_init(ap);
370         atomic_clear_int(&ap->ap_signal, AP_SIGF_THREAD_SYNC);
371         wakeup(&ap->ap_signal);
372         ahci_port_state_machine(ap, 1);
373         ahci_os_unlock_port(ap);
374         atomic_clear_int(&ap->ap_signal, AP_SIGF_INIT);
375         wakeup(&ap->ap_signal);
376
377         /*
378          * Then loop on the helper core.
379          */
380         mask = ap->ap_signal;
381         while ((mask & AP_SIGF_STOP) == 0) {
382                 atomic_clear_int(&ap->ap_signal, mask);
383                 ahci_port_thread_core(ap, mask);
384                 lockmgr(&ap->ap_sig_lock, LK_EXCLUSIVE);
385                 if (ap->ap_signal == 0) {
386                         lksleep(&ap->ap_thread, &ap->ap_sig_lock, 0,
387                                 "ahport", 0);
388                 }
389                 lockmgr(&ap->ap_sig_lock, LK_RELEASE);
390                 mask = ap->ap_signal;
391         }
392         ap->ap_thread = NULL;
393 }