FreeBSD/Linux Kernel Cross Reference
sys/dev/ata/ata.c
1 /* $NetBSD: ata.c,v 1.27.2.2 2005/05/24 19:54:47 riz Exp $ */
2
3 /*
4 * Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Manuel Bouyer.
17 * 4. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.27.2.2 2005/05/24 19:54:47 riz Exp $");
34
35 #ifndef WDCDEBUG
36 #define WDCDEBUG
37 #endif /* WDCDEBUG */
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
43 #include <sys/device.h>
44 #include <sys/proc.h>
45 #include <sys/kthread.h>
46 #include <sys/errno.h>
47
48 #include <machine/intr.h>
49 #include <machine/bus.h>
50
51 #include <dev/ata/atareg.h>
52 #include <dev/ata/atavar.h>
53 #include <dev/ic/wdcreg.h>
54 #include <dev/ic/wdcvar.h>
55
56 #include "locators.h"
57
58 #define DEBUG_FUNCS 0x08
59 #define DEBUG_PROBE 0x10
60 #define DEBUG_DETACH 0x20
61 #ifdef WDCDEBUG
62 extern int wdcdebug_mask; /* init'ed in wdc.c */
63 #define WDCDEBUG_PRINT(args, level) \
64 if (wdcdebug_mask & (level)) \
65 printf args
66 #else
67 #define WDCDEBUG_PRINT(args, level)
68 #endif
69
70 /*****************************************************************************
71 * ATA bus layer.
72 *
73 * ATA controllers attach an atabus instance, which handles probing the bus
74 * for drives, etc.
75 *****************************************************************************/
76
77 /*
78 * atabusprint:
79 *
80 * Autoconfiguration print routine used by ATA controllers when
81 * attaching an atabus instance.
82 */
83 int
84 atabusprint(void *aux, const char *pnp)
85 {
86 struct wdc_channel *chan = aux;
87
88 if (pnp)
89 aprint_normal("atabus at %s", pnp);
90 aprint_normal(" channel %d", chan->ch_channel);
91
92 return (UNCONF);
93 }
94
95 /*
96 * ataprint:
97 *
98 * Autoconfiguration print routine.
99 */
100 int
101 ataprint(void *aux, const char *pnp)
102 {
103 struct ata_device *adev = aux;
104
105 if (pnp)
106 aprint_normal("wd at %s", pnp);
107 aprint_normal(" drive %d", adev->adev_drv_data->drive);
108
109 return (UNCONF);
110 }
111
112 /*
113 * atabus_thread:
114 *
115 * Worker thread for the ATA bus.
116 */
117 static void
118 atabus_thread(void *arg)
119 {
120 struct atabus_softc *sc = arg;
121 struct wdc_channel *chp = sc->sc_chan;
122 struct ata_xfer *xfer;
123 int s;
124
125 s = splbio();
126 chp->ch_flags |= WDCF_TH_RUN;
127 splx(s);
128
129 /* Configure the devices on the bus. */
130 atabusconfig(sc);
131
132 s = splbio();
133 for (;;) {
134 if ((chp->ch_flags & (WDCF_TH_RESET | WDCF_SHUTDOWN)) == 0 &&
135 ((chp->ch_flags & WDCF_ACTIVE) == 0 ||
136 chp->ch_queue->queue_freeze == 0)) {
137 chp->ch_flags &= ~WDCF_TH_RUN;
138 (void) tsleep(&chp->ch_thread, PRIBIO, "atath", 0);
139 chp->ch_flags |= WDCF_TH_RUN;
140 }
141 if (chp->ch_flags & WDCF_SHUTDOWN)
142 break;
143 if (chp->ch_flags & WDCF_TH_RESET) {
144 int drive;
145
146 (void) wdcreset(chp, RESET_SLEEP);
147 for (drive = 0; drive < 2; drive++)
148 chp->ch_drive[drive].state = 0;
149 chp->ch_flags &= ~WDCF_TH_RESET;
150 chp->ch_queue->queue_freeze--;
151 wdcstart(chp);
152 } else if ((chp->ch_flags & WDCF_ACTIVE) != 0 &&
153 chp->ch_queue->queue_freeze == 1) {
154 /*
155 * Caller has bumped queue_freeze, decrease it.
156 */
157 chp->ch_queue->queue_freeze--;
158 xfer = TAILQ_FIRST(&chp->ch_queue->queue_xfer);
159 KASSERT(xfer != NULL);
160 (*xfer->c_start)(chp, xfer);
161 } else if (chp->ch_queue->queue_freeze > 1)
162 panic("ata_thread: queue_freeze");
163 }
164 splx(s);
165 chp->ch_thread = NULL;
166 wakeup((void *)&chp->ch_flags);
167 kthread_exit(0);
168 }
169
170 /*
171 * atabus_create_thread:
172 *
173 * Helper routine to create the ATA bus worker thread.
174 */
175 static void
176 atabus_create_thread(void *arg)
177 {
178 struct atabus_softc *sc = arg;
179 struct wdc_channel *chp = sc->sc_chan;
180 int error;
181
182 if ((error = kthread_create1(atabus_thread, sc, &chp->ch_thread,
183 "%s", sc->sc_dev.dv_xname)) != 0)
184 aprint_error("%s: unable to create kernel thread: error %d\n",
185 sc->sc_dev.dv_xname, error);
186 }
187
188 /*
189 * atabus_match:
190 *
191 * Autoconfiguration match routine.
192 */
193 static int
194 atabus_match(struct device *parent, struct cfdata *cf, void *aux)
195 {
196 struct wdc_channel *chp = aux;
197
198 if (chp == NULL)
199 return (0);
200
201 if (cf->cf_loc[ATACF_CHANNEL] != chp->ch_channel &&
202 cf->cf_loc[ATACF_CHANNEL] != ATACF_CHANNEL_DEFAULT)
203 return (0);
204
205 return (1);
206 }
207
208 /*
209 * atabus_attach:
210 *
211 * Autoconfiguration attach routine.
212 */
213 static void
214 atabus_attach(struct device *parent, struct device *self, void *aux)
215 {
216 struct atabus_softc *sc = (void *) self;
217 struct wdc_channel *chp = aux;
218 struct atabus_initq *initq;
219
220 sc->sc_chan = chp;
221
222 aprint_normal("\n");
223 aprint_naive("\n");
224
225 initq = malloc(sizeof(*initq), M_DEVBUF, M_WAITOK);
226 initq->atabus_sc = sc;
227 TAILQ_INSERT_TAIL(&atabus_initq_head, initq, atabus_initq);
228 config_pending_incr();
229 kthread_create(atabus_create_thread, sc);
230 }
231
232 /*
233 * atabus_activate:
234 *
235 * Autoconfiguration activation routine.
236 */
237 static int
238 atabus_activate(struct device *self, enum devact act)
239 {
240 struct atabus_softc *sc = (void *) self;
241 struct wdc_channel *chp = sc->sc_chan;
242 struct device *dev = NULL;
243 int s, i, error = 0;
244
245 s = splbio();
246 switch (act) {
247 case DVACT_ACTIVATE:
248 error = EOPNOTSUPP;
249 break;
250
251 case DVACT_DEACTIVATE:
252 /*
253 * We might deactivate the children of atapibus twice
254 * (once bia atapibus, once directly), but since the
255 * generic autoconfiguration code maintains the DVF_ACTIVE
256 * flag, it's safe.
257 */
258 if ((dev = chp->atapibus) != NULL) {
259 error = config_deactivate(dev);
260 if (error)
261 goto out;
262 }
263
264 for (i = 0; i < 2; i++) {
265 if ((dev = chp->ch_drive[i].drv_softc) != NULL) {
266 WDCDEBUG_PRINT(("atabus_activate: %s: "
267 "deactivating %s\n", sc->sc_dev.dv_xname,
268 dev->dv_xname),
269 DEBUG_DETACH);
270 error = config_deactivate(dev);
271 if (error)
272 goto out;
273 }
274 }
275 break;
276 }
277 out:
278 splx(s);
279
280 #ifdef WDCDEBUG
281 if (dev != NULL && error != 0)
282 WDCDEBUG_PRINT(("atabus_activate: %s: "
283 "error %d deactivating %s\n", sc->sc_dev.dv_xname,
284 error, dev->dv_xname), DEBUG_DETACH);
285 #endif /* WDCDEBUG */
286
287 return (error);
288 }
289
290 /*
291 * atabus_detach:
292 *
293 * Autoconfiguration detach routine.
294 */
295 static int
296 atabus_detach(struct device *self, int flags)
297 {
298 struct atabus_softc *sc = (void *) self;
299 struct wdc_channel *chp = sc->sc_chan;
300 struct device *dev = NULL;
301 int i, error = 0;
302
303 /* Shutdown the channel. */
304 /* XXX NEED AN INTERLOCK HERE. */
305 chp->ch_flags |= WDCF_SHUTDOWN;
306 wakeup(&chp->ch_thread);
307 while (chp->ch_thread != NULL)
308 (void) tsleep((void *)&chp->ch_flags, PRIBIO, "atadown", 0);
309
310 /*
311 * Detach atapibus and its children.
312 */
313 if ((dev = chp->atapibus) != NULL) {
314 WDCDEBUG_PRINT(("atabus_detach: %s: detaching %s\n",
315 sc->sc_dev.dv_xname, dev->dv_xname), DEBUG_DETACH);
316 error = config_detach(dev, flags);
317 if (error)
318 goto out;
319 }
320
321 /*
322 * Detach our other children.
323 */
324 for (i = 0; i < 2; i++) {
325 if (chp->ch_drive[i].drive_flags & DRIVE_ATAPI)
326 continue;
327 if ((dev = chp->ch_drive[i].drv_softc) != NULL) {
328 WDCDEBUG_PRINT(("atabus_detach: %s: detaching %s\n",
329 sc->sc_dev.dv_xname, dev->dv_xname),
330 DEBUG_DETACH);
331 error = config_detach(dev, flags);
332 if (error)
333 goto out;
334 }
335 }
336
337 wdc_kill_pending(chp);
338 out:
339 #ifdef WDCDEBUG
340 if (dev != NULL && error != 0)
341 WDCDEBUG_PRINT(("atabus_detach: %s: error %d detaching %s\n",
342 sc->sc_dev.dv_xname, error, dev->dv_xname),
343 DEBUG_DETACH);
344 #endif /* WDCDEBUG */
345
346 return (error);
347 }
348
349 CFATTACH_DECL(atabus, sizeof(struct atabus_softc),
350 atabus_match, atabus_attach, atabus_detach, atabus_activate);
351
352 /*****************************************************************************
353 * Common ATA bus operations.
354 *****************************************************************************/
355
356 /* Get the disk's parameters */
357 int
358 ata_get_params(struct ata_drive_datas *drvp, u_int8_t flags,
359 struct ataparams *prms)
360 {
361 char tb[DEV_BSIZE];
362 struct wdc_command wdc_c;
363
364 #if BYTE_ORDER == LITTLE_ENDIAN
365 int i;
366 u_int16_t *p;
367 #endif
368
369 WDCDEBUG_PRINT(("ata_get_parms\n"), DEBUG_FUNCS);
370
371 memset(tb, 0, DEV_BSIZE);
372 memset(prms, 0, sizeof(struct ataparams));
373 memset(&wdc_c, 0, sizeof(struct wdc_command));
374
375 if (drvp->drive_flags & DRIVE_ATA) {
376 wdc_c.r_command = WDCC_IDENTIFY;
377 wdc_c.r_st_bmask = WDCS_DRDY;
378 wdc_c.r_st_pmask = 0;
379 wdc_c.timeout = 3000; /* 3s */
380 } else if (drvp->drive_flags & DRIVE_ATAPI) {
381 wdc_c.r_command = ATAPI_IDENTIFY_DEVICE;
382 wdc_c.r_st_bmask = 0;
383 wdc_c.r_st_pmask = 0;
384 wdc_c.timeout = 10000; /* 10s */
385 } else {
386 WDCDEBUG_PRINT(("ata_get_parms: no disks\n"),
387 DEBUG_FUNCS|DEBUG_PROBE);
388 return CMD_ERR;
389 }
390 wdc_c.flags = AT_READ | flags;
391 wdc_c.data = tb;
392 wdc_c.bcount = DEV_BSIZE;
393 if (wdc_exec_command(drvp, &wdc_c) != WDC_COMPLETE) {
394 WDCDEBUG_PRINT(("ata_get_parms: wdc_exec_command failed\n"),
395 DEBUG_FUNCS|DEBUG_PROBE);
396 return CMD_AGAIN;
397 }
398 if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
399 WDCDEBUG_PRINT(("ata_get_parms: wdc_c.flags=0x%x\n",
400 wdc_c.flags), DEBUG_FUNCS|DEBUG_PROBE);
401 return CMD_ERR;
402 } else {
403 /* if we didn't read any data something is wrong */
404 if ((wdc_c.flags & AT_XFDONE) == 0)
405 return CMD_ERR;
406 /* Read in parameter block. */
407 memcpy(prms, tb, sizeof(struct ataparams));
408 #if BYTE_ORDER == LITTLE_ENDIAN
409 /*
410 * Shuffle string byte order.
411 * ATAPI Mitsumi and NEC drives don't need this.
412 */
413 if ((prms->atap_config & WDC_CFG_ATAPI_MASK) ==
414 WDC_CFG_ATAPI &&
415 ((prms->atap_model[0] == 'N' &&
416 prms->atap_model[1] == 'E') ||
417 (prms->atap_model[0] == 'F' &&
418 prms->atap_model[1] == 'X')))
419 return 0;
420 for (i = 0; i < sizeof(prms->atap_model); i += 2) {
421 p = (u_short *)(prms->atap_model + i);
422 *p = ntohs(*p);
423 }
424 for (i = 0; i < sizeof(prms->atap_serial); i += 2) {
425 p = (u_short *)(prms->atap_serial + i);
426 *p = ntohs(*p);
427 }
428 for (i = 0; i < sizeof(prms->atap_revision); i += 2) {
429 p = (u_short *)(prms->atap_revision + i);
430 *p = ntohs(*p);
431 }
432 #endif
433 return CMD_OK;
434 }
435 }
436
437 int
438 ata_set_mode(struct ata_drive_datas *drvp, u_int8_t mode, u_int8_t flags)
439 {
440 struct wdc_command wdc_c;
441
442 WDCDEBUG_PRINT(("ata_set_mode=0x%x\n", mode), DEBUG_FUNCS);
443 memset(&wdc_c, 0, sizeof(struct wdc_command));
444
445 wdc_c.r_command = SET_FEATURES;
446 wdc_c.r_st_bmask = 0;
447 wdc_c.r_st_pmask = 0;
448 wdc_c.r_precomp = WDSF_SET_MODE;
449 wdc_c.r_count = mode;
450 wdc_c.flags = flags;
451 wdc_c.timeout = 1000; /* 1s */
452 if (wdc_exec_command(drvp, &wdc_c) != WDC_COMPLETE)
453 return CMD_AGAIN;
454 if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
455 return CMD_ERR;
456 }
457 return CMD_OK;
458 }
459
460 void
461 ata_dmaerr(struct ata_drive_datas *drvp, int flags)
462 {
463 /*
464 * Downgrade decision: if we get NERRS_MAX in NXFER.
465 * We start with n_dmaerrs set to NERRS_MAX-1 so that the
466 * first error within the first NXFER ops will immediatly trigger
467 * a downgrade.
468 * If we got an error and n_xfers is bigger than NXFER reset counters.
469 */
470 drvp->n_dmaerrs++;
471 if (drvp->n_dmaerrs >= NERRS_MAX && drvp->n_xfers <= NXFER) {
472 wdc_downgrade_mode(drvp, flags);
473 drvp->n_dmaerrs = NERRS_MAX-1;
474 drvp->n_xfers = 0;
475 return;
476 }
477 if (drvp->n_xfers > NXFER) {
478 drvp->n_dmaerrs = 1; /* just got an error */
479 drvp->n_xfers = 1; /* restart counting from this error */
480 }
481 }
Cache object: c6dd7c16485b69a11085cf91135eae4f
|