Deleted Added
sdiff udiff text old ( 123361 ) new ( 124403 )
full compact
1/*-
2 * Copyright (c) 1998 - 2004 S�ren Schmidt <sos@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer,
10 * without modification, immediately at the beginning of the file.
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. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: head/sys/dev/ata/ata-pci.c 124403 2004-01-11 22:08:34Z sos $");
31
32#include "opt_ata.h"
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/kernel.h>
36#include <sys/module.h>
37#include <sys/bus.h>
38#include <sys/malloc.h>
39#include <sys/sema.h>
40#include <sys/taskqueue.h>
41#include <machine/stdarg.h>
42#include <machine/resource.h>
43#include <machine/bus.h>
44#ifdef __alpha__
45#include <machine/md_var.h>
46#endif
47#include <sys/rman.h>
48#include <dev/pci/pcivar.h>
49#include <dev/pci/pcireg.h>
50#include <dev/ata/ata-all.h>
51#include <dev/ata/ata-pci.h>
52
53/* local vars */
54static MALLOC_DEFINE(M_ATAPCI, "ATA PCI", "ATA driver PCI");
55
56/* misc defines */
57#define IOMASK 0xfffffffc
58
59/* prototypes */
60static int ata_pci_allocate(device_t, struct ata_channel *);
61static void ata_pci_dmainit(struct ata_channel *);
62static void ata_pci_locknoop(struct ata_channel *, int);
63
64static int
65ata_pci_probe(device_t dev)
66{
67 if (pci_get_class(dev) != PCIC_STORAGE)
68 return ENXIO;
69
70 switch (pci_get_vendor(dev)) {
71 case ATA_ACARD_ID:
72 if (!ata_acard_ident(dev))
73 return 0;
74 break;
75 case ATA_ACER_LABS_ID:
76 if (!ata_ali_ident(dev))
77 return 0;
78 break;
79 case ATA_AMD_ID:
80 if (!ata_amd_ident(dev))
81 return 0;
82 break;
83 case ATA_CYRIX_ID:
84 if (!ata_cyrix_ident(dev))
85 return 0;
86 break;
87 case ATA_CYPRESS_ID:
88 if (!ata_cypress_ident(dev))
89 return 0;
90 break;
91 case ATA_HIGHPOINT_ID:
92 if (!ata_highpoint_ident(dev))
93 return 0;
94 break;
95 case ATA_INTEL_ID:
96 if (!ata_intel_ident(dev))
97 return 0;
98 break;
99 case ATA_NATIONAL_ID:
100 if (!ata_national_ident(dev))
101 return 0;
102 break;
103 case ATA_NVIDIA_ID:
104 if (!ata_nvidia_ident(dev))
105 return 0;
106 break;
107 case ATA_PROMISE_ID:
108 if (!ata_promise_ident(dev))
109 return 0;
110 break;
111 case ATA_SERVERWORKS_ID:
112 if (!ata_serverworks_ident(dev))
113 return 0;
114 break;
115 case ATA_SILICON_IMAGE_ID:
116 if (!ata_sii_ident(dev))
117 return 0;
118 break;
119 case ATA_SIS_ID:
120 if (!ata_sis_ident(dev))
121 return 0;
122 break;
123 case ATA_VIA_ID:
124 if (!ata_via_ident(dev))
125 return 0;
126 break;
127 case 0x16ca:
128 if (pci_get_devid(dev) == 0x000116ca) {
129 ata_generic_ident(dev);
130 device_set_desc(dev, "Cenatek Rocket Drive controller");
131 return 0;
132 }
133 break;
134 case 0x1042:
135 if (pci_get_devid(dev)==0x10001042 || pci_get_devid(dev)==0x10011042) {
136 ata_generic_ident(dev);
137 device_set_desc(dev,
138 "RZ 100? ATA controller !WARNING! buggy HW data loss possible");
139 return 0;
140 }
141 break;
142 }
143
144 /* unknown chipset, try generic DMA if it seems possible */
145 if ((pci_get_class(dev) == PCIC_STORAGE) &&
146 (pci_get_subclass(dev) == PCIS_STORAGE_IDE))
147 return ata_generic_ident(dev);
148
149 return ENXIO;
150}
151
152static int
153ata_pci_attach(device_t dev)
154{
155 struct ata_pci_controller *ctlr = device_get_softc(dev);
156 u_int8_t class, subclass;
157 u_int32_t type, cmd;
158 int unit;
159
160 /* set up vendor-specific stuff */
161 type = pci_get_devid(dev);
162 class = pci_get_class(dev);
163 subclass = pci_get_subclass(dev);
164 cmd = pci_read_config(dev, PCIR_COMMAND, 2);
165
166 if (!(cmd & PCIM_CMD_PORTEN)) {
167 device_printf(dev, "ATA channel disabled by BIOS\n");
168 return 0;
169 }
170
171 /* do chipset specific setups only needed once */
172 if (ATA_MASTERDEV(dev) || pci_read_config(dev, 0x18, 4) & IOMASK)
173 ctlr->channels = 2;
174 else
175 ctlr->channels = 1;
176 ctlr->allocate = ata_pci_allocate;
177 ctlr->dmainit = ata_pci_dmainit;
178 ctlr->locking = ata_pci_locknoop;
179
180#ifdef __sparc64__
181 if (!(cmd & PCIM_CMD_BUSMASTEREN)) {
182 pci_write_config(dev, PCIR_COMMAND, cmd | PCIM_CMD_BUSMASTEREN, 2);
183 cmd = pci_read_config(dev, PCIR_COMMAND, 2);
184 }
185#endif
186 /* if busmastering configured get the I/O resource */
187 if ((cmd & PCIM_CMD_BUSMASTEREN) == PCIM_CMD_BUSMASTEREN) {
188 int rid = ATA_BMADDR_RID;
189
190 ctlr->r_io1 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
191 0, ~0, 1, RF_ACTIVE);
192 }
193
194 ctlr->chipinit(dev);
195
196 /* attach all channels on this controller */
197 for (unit = 0; unit < ctlr->channels; unit++)
198 device_add_child(dev, "ata", ATA_MASTERDEV(dev) ?
199 unit : devclass_find_free_unit(ata_devclass, 2));
200
201 return bus_generic_attach(dev);
202}
203
204
205static int
206ata_pci_print_child(device_t dev, device_t child)
207{
208 struct ata_channel *ch = device_get_softc(child);
209 int retval = 0;
210
211 retval += bus_print_child_header(dev, child);
212 retval += printf(": at 0x%lx", rman_get_start(ch->r_io[ATA_IDX_ADDR].res));
213
214 if (ATA_MASTERDEV(dev))
215 retval += printf(" irq %d", 14 + ch->unit);
216
217 retval += bus_print_child_footer(dev, child);
218
219 return retval;
220}
221
222static struct resource *
223ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid,
224 u_long start, u_long end, u_long count, u_int flags)
225{
226 struct ata_pci_controller *controller = device_get_softc(dev);
227 int unit = ((struct ata_channel *)device_get_softc(child))->unit;
228 struct resource *res = NULL;
229 int myrid;
230
231 if (type == SYS_RES_IOPORT) {
232 switch (*rid) {
233 case ATA_IOADDR_RID:
234 if (ATA_MASTERDEV(dev)) {
235 myrid = 0;
236 start = (unit ? ATA_SECONDARY : ATA_PRIMARY);
237 end = start + ATA_IOSIZE - 1;
238 count = ATA_IOSIZE;
239 res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
240 SYS_RES_IOPORT, &myrid,
241 start, end, count, flags);
242 }
243 else {
244 myrid = 0x10 + 8 * unit;
245 res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
246 SYS_RES_IOPORT, &myrid,
247 start, end, count, flags);
248 }
249 break;
250
251 case ATA_ALTADDR_RID:
252 if (ATA_MASTERDEV(dev)) {
253 myrid = 0;
254 start = (unit ? ATA_SECONDARY : ATA_PRIMARY) + ATA_ALTOFFSET;
255 end = start + ATA_ALTIOSIZE - 1;
256 count = ATA_ALTIOSIZE;
257 res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
258 SYS_RES_IOPORT, &myrid,
259 start, end, count, flags);
260 }
261 else {
262 myrid = 0x14 + 8 * unit;
263 res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
264 SYS_RES_IOPORT, &myrid,
265 start, end, count, flags);
266 if (res) {
267 start = rman_get_start(res) + 2;
268 end = start + ATA_ALTIOSIZE - 1;
269 count = ATA_ALTIOSIZE;
270 BUS_RELEASE_RESOURCE(device_get_parent(dev), dev,
271 SYS_RES_IOPORT, myrid, res);
272 res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
273 SYS_RES_IOPORT, &myrid,
274 start, end, count, flags);
275 }
276 }
277 break;
278 }
279 return res;
280 }
281
282 if (type == SYS_RES_IRQ && *rid == ATA_IRQ_RID) {
283 if (ATA_MASTERDEV(dev)) {
284#ifdef __alpha__
285 return alpha_platform_alloc_ide_intr(unit);
286#else
287 int irq = (unit == 0 ? 14 : 15);
288
289 return BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
290 SYS_RES_IRQ, rid, irq, irq, 1, flags);
291#endif
292 }
293 else {
294 return controller->r_irq;
295 }
296 }
297 return 0;
298}
299
300static int
301ata_pci_release_resource(device_t dev, device_t child, int type, int rid,
302 struct resource *r)
303{
304 int unit = ((struct ata_channel *)device_get_softc(child))->unit;
305
306 if (type == SYS_RES_IOPORT) {
307 switch (rid) {
308 case ATA_IOADDR_RID:
309 if (ATA_MASTERDEV(dev))
310 return BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
311 SYS_RES_IOPORT, 0x0, r);
312 else
313 return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev,
314 SYS_RES_IOPORT, 0x10 + 8 * unit, r);
315 break;
316
317 case ATA_ALTADDR_RID:
318 if (ATA_MASTERDEV(dev))
319 return BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
320 SYS_RES_IOPORT, 0x0, r);
321 else
322 return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev,
323 SYS_RES_IOPORT, 0x14 + 8 * unit, r);
324 break;
325 default:
326 return ENOENT;
327 }
328 }
329 if (type == SYS_RES_IRQ) {
330 if (rid != ATA_IRQ_RID)
331 return ENOENT;
332
333 if (ATA_MASTERDEV(dev)) {
334#ifdef __alpha__
335 return alpha_platform_release_ide_intr(unit, r);
336#else
337 return BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
338 SYS_RES_IRQ, rid, r);
339#endif
340 }
341 else
342 return 0;
343 }
344 return EINVAL;
345}
346
347static int
348ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq,
349 int flags, driver_intr_t *function, void *argument,
350 void **cookiep)
351{
352 if (ATA_MASTERDEV(dev)) {
353#ifdef __alpha__
354 return alpha_platform_setup_ide_intr(child, irq, function, argument,
355 cookiep);
356#else
357 return BUS_SETUP_INTR(device_get_parent(dev), child, irq,
358 flags, function, argument, cookiep);
359#endif
360 }
361 else {
362 struct ata_pci_controller *controller = device_get_softc(dev);
363 int unit = ((struct ata_channel *)device_get_softc(child))->unit;
364
365 controller->interrupt[unit].function = function;
366 controller->interrupt[unit].argument = argument;
367 *cookiep = controller;
368 return 0;
369 }
370}
371
372static int
373ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq,
374 void *cookie)
375{
376 if (ATA_MASTERDEV(dev)) {
377#ifdef __alpha__
378 return alpha_platform_teardown_ide_intr(child, irq, cookie);
379#else
380 return BUS_TEARDOWN_INTR(device_get_parent(dev), child, irq, cookie);
381#endif
382 }
383 else {
384 struct ata_pci_controller *controller = device_get_softc(dev);
385 int unit = ((struct ata_channel *)device_get_softc(child))->unit;
386
387 controller->interrupt[unit].function = NULL;
388 controller->interrupt[unit].argument = NULL;
389 return 0;
390 }
391}
392
393static int
394ata_pci_allocate(device_t dev, struct ata_channel *ch)
395{
396 struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
397 struct resource *io = NULL, *altio = NULL;
398 int i, rid;
399
400 rid = ATA_IOADDR_RID;
401 io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
402 0, ~0, ATA_IOSIZE, RF_ACTIVE);
403 if (!io)
404 return ENXIO;
405
406 rid = ATA_ALTADDR_RID;
407 altio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
408 0, ~0, ATA_ALTIOSIZE, RF_ACTIVE);
409 if (!altio) {
410 bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, io);
411 return ENXIO;
412 }
413
414 for (i = ATA_DATA; i <= ATA_STATUS; i ++) {
415 ch->r_io[i].res = io;
416 ch->r_io[i].offset = i;
417 }
418 ch->r_io[ATA_ALTSTAT].res = altio;
419 ch->r_io[ATA_ALTSTAT].offset = 0;
420 ch->r_io[ATA_IDX_ADDR].res = io;
421
422 if (ctlr->r_io1) {
423 for (i = ATA_BMCMD_PORT; i <= ATA_BMDTP_PORT; i++) {
424 ch->r_io[i].res = ctlr->r_io1;
425 ch->r_io[i].offset = (i - ATA_BMCMD_PORT)+(ch->unit * ATA_BMIOSIZE);
426 }
427
428 /* if simplex controller, only allow DMA on primary channel */
429 ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_IDX_INB(ch, ATA_BMSTAT_PORT) &
430 (ATA_BMSTAT_DMA_MASTER | ATA_BMSTAT_DMA_SLAVE));
431 if (ch->unit > 0 &&
432 (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_DMA_SIMPLEX))
433 device_printf(dev, "simplex device, DMA on primary only\n");
434 else
435 ctlr->dmainit(ch);
436 }
437 return 0;
438}
439
440static int
441ata_pci_dmastart(struct ata_channel *ch)
442{
443 ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) |
444 (ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR)));
445 ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->mdmatab);
446 ATA_IDX_OUTB(ch, ATA_BMCMD_PORT,
447 ((ch->dma->flags & ATA_DMA_READ) ? ATA_BMCMD_WRITE_READ : 0) |
448 ATA_BMCMD_START_STOP);
449 return 0;
450}
451
452static int
453ata_pci_dmastop(struct ata_channel *ch)
454{
455 int error;
456
457 error = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK;
458 ATA_IDX_OUTB(ch, ATA_BMCMD_PORT,
459 ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP);
460 ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR);
461 return error;
462}
463
464static void
465ata_pci_dmainit(struct ata_channel *ch)
466{
467 ata_dmainit(ch);
468 if (ch->dma) {
469 ch->dma->start = ata_pci_dmastart;
470 ch->dma->stop = ata_pci_dmastop;
471 }
472}
473
474static void
475ata_pci_locknoop(struct ata_channel *ch, int flags)
476{
477}
478
479static device_method_t ata_pci_methods[] = {
480 /* device interface */
481 DEVMETHOD(device_probe, ata_pci_probe),
482 DEVMETHOD(device_attach, ata_pci_attach),
483 DEVMETHOD(device_shutdown, bus_generic_shutdown),
484 DEVMETHOD(device_suspend, bus_generic_suspend),
485 DEVMETHOD(device_resume, bus_generic_resume),
486
487 /* bus methods */
488 DEVMETHOD(bus_print_child, ata_pci_print_child),
489 DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource),
490 DEVMETHOD(bus_release_resource, ata_pci_release_resource),
491 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
492 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
493 DEVMETHOD(bus_setup_intr, ata_pci_setup_intr),
494 DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr),
495 { 0, 0 }
496};
497
498static driver_t ata_pci_driver = {
499 "atapci",
500 ata_pci_methods,
501 sizeof(struct ata_pci_controller),
502};
503
504static devclass_t ata_pci_devclass;
505
506DRIVER_MODULE(atapci, pci, ata_pci_driver, ata_pci_devclass, 0, 0);
507
508static int
509ata_pcisub_probe(device_t dev)
510{
511 struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
512 struct ata_channel *ch = device_get_softc(dev);
513 device_t *children;
514 int count, error, i;
515
516 /* find channel number on this controller */
517 device_get_children(device_get_parent(dev), &children, &count);
518 for (i = 0; i < count; i++) {
519 if (children[i] == dev)
520 ch->unit = i;
521 }
522 free(children, M_TEMP);
523
524 if ((error = ctlr->allocate(dev, ch)))
525 return error;
526
527 ch->device[MASTER].setmode = ctlr->setmode;
528 ch->device[SLAVE].setmode = ctlr->setmode;
529 ch->locking = ctlr->locking;
530 return ata_probe(dev);
531}
532
533static device_method_t ata_pcisub_methods[] = {
534 /* device interface */
535 DEVMETHOD(device_probe, ata_pcisub_probe),
536 DEVMETHOD(device_attach, ata_attach),
537 DEVMETHOD(device_detach, ata_detach),
538 DEVMETHOD(device_suspend, ata_suspend),
539 DEVMETHOD(device_resume, ata_resume),
540 { 0, 0 }
541};
542
543static driver_t ata_pcisub_driver = {
544 "ata",
545 ata_pcisub_methods,
546 sizeof(struct ata_channel),
547};
548
549DRIVER_MODULE(ata, atapci, ata_pcisub_driver, ata_devclass, 0, 0);