1331c488dSSøren Schmidt /*- 2f601b4ebSSøren Schmidt * Copyright (c) 1998,1999,2000,2001 S�ren Schmidt <sos@FreeBSD.org> 3331c488dSSøren Schmidt * All rights reserved. 4331c488dSSøren Schmidt * 5331c488dSSøren Schmidt * Redistribution and use in source and binary forms, with or without 6331c488dSSøren Schmidt * modification, are permitted provided that the following conditions 7331c488dSSøren Schmidt * are met: 8331c488dSSøren Schmidt * 1. Redistributions of source code must retain the above copyright 9331c488dSSøren Schmidt * notice, this list of conditions and the following disclaimer, 10331c488dSSøren Schmidt * without modification, immediately at the beginning of the file. 11331c488dSSøren Schmidt * 2. Redistributions in binary form must reproduce the above copyright 12331c488dSSøren Schmidt * notice, this list of conditions and the following disclaimer in the 13331c488dSSøren Schmidt * documentation and/or other materials provided with the distribution. 14331c488dSSøren Schmidt * 3. The name of the author may not be used to endorse or promote products 15331c488dSSøren Schmidt * derived from this software without specific prior written permission. 16331c488dSSøren Schmidt * 17331c488dSSøren Schmidt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18331c488dSSøren Schmidt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19331c488dSSøren Schmidt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20331c488dSSøren Schmidt * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21331c488dSSøren Schmidt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22331c488dSSøren Schmidt * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23331c488dSSøren Schmidt * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24331c488dSSøren Schmidt * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25331c488dSSøren Schmidt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26331c488dSSøren Schmidt * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27331c488dSSøren Schmidt * 28331c488dSSøren Schmidt * $FreeBSD$ 29331c488dSSøren Schmidt */ 30331c488dSSøren Schmidt 31331c488dSSøren Schmidt #include <sys/param.h> 32331c488dSSøren Schmidt #include <sys/systm.h> 33331c488dSSøren Schmidt #include <sys/kernel.h> 34331c488dSSøren Schmidt #include <sys/disk.h> 35331c488dSSøren Schmidt #include <sys/module.h> 36331c488dSSøren Schmidt #include <sys/bus.h> 37331c488dSSøren Schmidt #include <sys/bio.h> 38331c488dSSøren Schmidt #include <sys/malloc.h> 39331c488dSSøren Schmidt #include <sys/devicestat.h> 40331c488dSSøren Schmidt #include <sys/sysctl.h> 41331c488dSSøren Schmidt #include <machine/stdarg.h> 42331c488dSSøren Schmidt #include <machine/resource.h> 43331c488dSSøren Schmidt #include <machine/bus.h> 44331c488dSSøren Schmidt #ifdef __alpha__ 45331c488dSSøren Schmidt #include <machine/md_var.h> 46331c488dSSøren Schmidt #endif 47331c488dSSøren Schmidt #include <sys/rman.h> 48331c488dSSøren Schmidt #include <pci/pcivar.h> 49331c488dSSøren Schmidt #include <pci/pcireg.h> 50331c488dSSøren Schmidt #include <dev/ata/ata-all.h> 51331c488dSSøren Schmidt 5272c2f499SSøren Schmidt /* device structures */ 53331c488dSSøren Schmidt struct ata_pci_softc { 54331c488dSSøren Schmidt struct resource *bmio; 55331c488dSSøren Schmidt int bmaddr; 56331c488dSSøren Schmidt struct resource *irq; 57331c488dSSøren Schmidt int irqcnt; 58331c488dSSøren Schmidt }; 59331c488dSSøren Schmidt 6072c2f499SSøren Schmidt /* prototypes */ 6172c2f499SSøren Schmidt void ata_via686b(device_t); 6272c2f499SSøren Schmidt 6372c2f499SSøren Schmidt /* misc defines */ 6472c2f499SSøren Schmidt #define IOMASK 0xfffffffc 6572c2f499SSøren Schmidt #define ATA_MASTERDEV(dev) ((pci_get_progif(dev) & 0x80) && \ 6672c2f499SSøren Schmidt (pci_get_progif(dev) & 0x05) != 0x05) 6772c2f499SSøren Schmidt 68331c488dSSøren Schmidt int 6972c2f499SSøren Schmidt ata_find_dev(device_t dev, u_int32_t devid, u_int32_t revid) 70331c488dSSøren Schmidt { 71331c488dSSøren Schmidt device_t *children, child; 72331c488dSSøren Schmidt int nchildren, i; 73331c488dSSøren Schmidt 74331c488dSSøren Schmidt if (device_get_children(device_get_parent(dev), &children, &nchildren)) 75331c488dSSøren Schmidt return 0; 76331c488dSSøren Schmidt 77331c488dSSøren Schmidt for (i = 0; i < nchildren; i++) { 78331c488dSSøren Schmidt child = children[i]; 79331c488dSSøren Schmidt 80331c488dSSøren Schmidt /* check that it's on the same silicon and the device we want */ 81331c488dSSøren Schmidt if (pci_get_slot(dev) == pci_get_slot(child) && 8272c2f499SSøren Schmidt pci_get_devid(child) == devid && pci_get_revid(child) >= revid) { 83331c488dSSøren Schmidt free(children, M_TEMP); 84331c488dSSøren Schmidt return 1; 85331c488dSSøren Schmidt } 86331c488dSSøren Schmidt } 87331c488dSSøren Schmidt free(children, M_TEMP); 88331c488dSSøren Schmidt return 0; 89331c488dSSøren Schmidt } 90331c488dSSøren Schmidt 9172c2f499SSøren Schmidt void 9272c2f499SSøren Schmidt ata_via686b(device_t dev) 9372c2f499SSøren Schmidt { 9472c2f499SSøren Schmidt device_t *children, child; 9572c2f499SSøren Schmidt int nchildren, i; 9672c2f499SSøren Schmidt 9772c2f499SSøren Schmidt if (device_get_children(device_get_parent(dev), &children, &nchildren)) 9872c2f499SSøren Schmidt return; 9972c2f499SSøren Schmidt 10072c2f499SSøren Schmidt for (i = 0; i < nchildren; i++) { 10172c2f499SSøren Schmidt child = children[i]; 10272c2f499SSøren Schmidt 10372c2f499SSøren Schmidt if (pci_get_devid(child) == 0x03051106 || /* VIA KT133 */ 10472c2f499SSøren Schmidt pci_get_devid(child) == 0x03911106) { /* VIA KX133 */ 10572c2f499SSøren Schmidt pci_write_config(child, 0x75, 0x83, 1); 10672c2f499SSøren Schmidt pci_write_config(child, 0x76, 10772c2f499SSøren Schmidt (pci_read_config(child, 0x76, 1) & 0xdf) | 0xd0,1); 10872c2f499SSøren Schmidt device_printf(dev, "VIA '686b southbridge fix applied\n"); 10972c2f499SSøren Schmidt break; 11072c2f499SSøren Schmidt } 11172c2f499SSøren Schmidt } 11272c2f499SSøren Schmidt free(children, M_TEMP); 11372c2f499SSøren Schmidt } 11472c2f499SSøren Schmidt 115331c488dSSøren Schmidt static const char * 116331c488dSSøren Schmidt ata_pci_match(device_t dev) 117331c488dSSøren Schmidt { 118331c488dSSøren Schmidt if (pci_get_class(dev) != PCIC_STORAGE) 119331c488dSSøren Schmidt return NULL; 120331c488dSSøren Schmidt 121331c488dSSøren Schmidt switch (pci_get_devid(dev)) { 122331c488dSSøren Schmidt /* supported chipsets */ 123331c488dSSøren Schmidt case 0x12308086: 124331c488dSSøren Schmidt return "Intel PIIX ATA controller"; 125331c488dSSøren Schmidt 126331c488dSSøren Schmidt case 0x70108086: 127331c488dSSøren Schmidt return "Intel PIIX3 ATA controller"; 128331c488dSSøren Schmidt 129331c488dSSøren Schmidt case 0x71118086: 130331c488dSSøren Schmidt case 0x71998086: 131331c488dSSøren Schmidt return "Intel PIIX4 ATA33 controller"; 132331c488dSSøren Schmidt 133331c488dSSøren Schmidt case 0x24218086: 134331c488dSSøren Schmidt return "Intel ICH0 ATA33 controller"; 135331c488dSSøren Schmidt 136331c488dSSøren Schmidt case 0x24118086: 137331c488dSSøren Schmidt return "Intel ICH ATA66 controller"; 138331c488dSSøren Schmidt 139b952dabaSSøren Schmidt case 0x244a8086: 140331c488dSSøren Schmidt case 0x244b8086: 141331c488dSSøren Schmidt return "Intel ICH2 ATA100 controller"; 142331c488dSSøren Schmidt 143331c488dSSøren Schmidt case 0x522910b9: 144331c488dSSøren Schmidt if (pci_get_revid(dev) < 0x20) 145331c488dSSøren Schmidt return "AcerLabs Aladdin ATA controller"; 146331c488dSSøren Schmidt else 147331c488dSSøren Schmidt return "AcerLabs Aladdin ATA33 controller"; 148331c488dSSøren Schmidt 149331c488dSSøren Schmidt case 0x05711106: 150331c488dSSøren Schmidt if (ata_find_dev(dev, 0x05861106, 0x02)) 151331c488dSSøren Schmidt return "VIA 82C586 ATA33 controller"; 152331c488dSSøren Schmidt if (ata_find_dev(dev, 0x05861106, 0)) 153331c488dSSøren Schmidt return "VIA 82C586 ATA controller"; 154331c488dSSøren Schmidt if (ata_find_dev(dev, 0x05961106, 0x12)) 155331c488dSSøren Schmidt return "VIA 82C596 ATA66 controller"; 156331c488dSSøren Schmidt if (ata_find_dev(dev, 0x05961106, 0)) 157331c488dSSøren Schmidt return "VIA 82C596 ATA33 controller"; 158b4fa8260SSøren Schmidt if (ata_find_dev(dev, 0x06861106, 0x40) || 159b4fa8260SSøren Schmidt ata_find_dev(dev, 0x30741106, 0)) 160331c488dSSøren Schmidt return "VIA 82C686 ATA100 controller"; 161331c488dSSøren Schmidt if (ata_find_dev(dev, 0x06861106, 0)) 162331c488dSSøren Schmidt return "VIA 82C686 ATA66 controller"; 163331c488dSSøren Schmidt return "VIA Apollo ATA controller"; 164331c488dSSøren Schmidt 165331c488dSSøren Schmidt case 0x55131039: 166331c488dSSøren Schmidt return "SiS 5591 ATA33 controller"; 167331c488dSSøren Schmidt 168331c488dSSøren Schmidt case 0x06491095: 169331c488dSSøren Schmidt return "CMD 649 ATA100 controller"; 170331c488dSSøren Schmidt 171331c488dSSøren Schmidt case 0x06481095: 172331c488dSSøren Schmidt return "CMD 648 ATA66 controller"; 173331c488dSSøren Schmidt 174331c488dSSøren Schmidt case 0x06461095: 175331c488dSSøren Schmidt return "CMD 646 ATA controller"; 176331c488dSSøren Schmidt 177331c488dSSøren Schmidt case 0xc6931080: 178331c488dSSøren Schmidt if (pci_get_subclass(dev) == PCIS_STORAGE_IDE) 179331c488dSSøren Schmidt return "Cypress 82C693 ATA controller"; 180331c488dSSøren Schmidt break; 181331c488dSSøren Schmidt 182331c488dSSøren Schmidt case 0x01021078: 183331c488dSSøren Schmidt return "Cyrix 5530 ATA33 controller"; 184331c488dSSøren Schmidt 185331c488dSSøren Schmidt case 0x74091022: 186331c488dSSøren Schmidt return "AMD 756 ATA66 controller"; 187331c488dSSøren Schmidt 188ef9988d0SSøren Schmidt case 0x74111022: 189ef9988d0SSøren Schmidt return "AMD 766 ATA100 controller"; 190ef9988d0SSøren Schmidt 191331c488dSSøren Schmidt case 0x02111166: 192331c488dSSøren Schmidt return "ServerWorks ROSB4 ATA33 controller"; 193331c488dSSøren Schmidt 194331c488dSSøren Schmidt case 0x4d33105a: 195331c488dSSøren Schmidt return "Promise ATA33 controller"; 196331c488dSSøren Schmidt 197331c488dSSøren Schmidt case 0x4d38105a: 198331c488dSSøren Schmidt return "Promise ATA66 controller"; 199331c488dSSøren Schmidt 200331c488dSSøren Schmidt case 0x0d30105a: 201331c488dSSøren Schmidt case 0x4d30105a: 202a8ae5362SSøren Schmidt return "Promise ATA100 controller"; 203a8ae5362SSøren Schmidt 2047aa30182SSøren Schmidt case 0x4d68105a: 205468fe0fdSSøren Schmidt case 0x6268105a: 206a8ae5362SSøren Schmidt return "Promise TX2 ATA100 controller"; 207331c488dSSøren Schmidt 208331c488dSSøren Schmidt case 0x00041103: 209331c488dSSøren Schmidt switch (pci_get_revid(dev)) { 210331c488dSSøren Schmidt case 0x00: 211331c488dSSøren Schmidt case 0x01: 212331c488dSSøren Schmidt return "HighPoint HPT366 ATA66 controller"; 213331c488dSSøren Schmidt case 0x02: 214331c488dSSøren Schmidt return "HighPoint HPT368 ATA66 controller"; 215331c488dSSøren Schmidt case 0x03: 216331c488dSSøren Schmidt case 0x04: 217331c488dSSøren Schmidt return "HighPoint HPT370 ATA100 controller"; 218331c488dSSøren Schmidt default: 219331c488dSSøren Schmidt return "Unknown revision HighPoint ATA controller"; 220331c488dSSøren Schmidt } 221331c488dSSøren Schmidt 222331c488dSSøren Schmidt /* unsupported but known chipsets, generic DMA only */ 223331c488dSSøren Schmidt case 0x10001042: 224331c488dSSøren Schmidt case 0x10011042: 225331c488dSSøren Schmidt return "RZ 100? ATA controller !WARNING! buggy chip data loss possible"; 226331c488dSSøren Schmidt 227331c488dSSøren Schmidt case 0x06401095: 228331c488dSSøren Schmidt return "CMD 640 ATA controller !WARNING! buggy chip data loss possible"; 229331c488dSSøren Schmidt 230331c488dSSøren Schmidt /* unknown chipsets, try generic DMA if it seems possible */ 231331c488dSSøren Schmidt default: 232331c488dSSøren Schmidt if (pci_get_class(dev) == PCIC_STORAGE && 233331c488dSSøren Schmidt (pci_get_subclass(dev) == PCIS_STORAGE_IDE)) 234331c488dSSøren Schmidt return "Generic PCI ATA controller"; 235331c488dSSøren Schmidt } 236331c488dSSøren Schmidt return NULL; 237331c488dSSøren Schmidt } 238331c488dSSøren Schmidt 239331c488dSSøren Schmidt static int 240331c488dSSøren Schmidt ata_pci_probe(device_t dev) 241331c488dSSøren Schmidt { 242331c488dSSøren Schmidt const char *desc = ata_pci_match(dev); 243331c488dSSøren Schmidt 244331c488dSSøren Schmidt if (desc) { 245331c488dSSøren Schmidt device_set_desc(dev, desc); 246331c488dSSøren Schmidt return 0; 247331c488dSSøren Schmidt } 248331c488dSSøren Schmidt else 249331c488dSSøren Schmidt return ENXIO; 250331c488dSSøren Schmidt } 251331c488dSSøren Schmidt 252331c488dSSøren Schmidt static int 253331c488dSSøren Schmidt ata_pci_add_child(device_t dev, int unit) 254331c488dSSøren Schmidt { 255331c488dSSøren Schmidt device_t child; 256331c488dSSøren Schmidt 257331c488dSSøren Schmidt /* check if this is located at one of the std addresses */ 258331c488dSSøren Schmidt if (ATA_MASTERDEV(dev)) { 259331c488dSSøren Schmidt if (!(child = device_add_child(dev, "ata", unit))) 260331c488dSSøren Schmidt return ENOMEM; 261331c488dSSøren Schmidt } 262331c488dSSøren Schmidt else { 263331c488dSSøren Schmidt if (!(child = device_add_child(dev, "ata", 2))) 264331c488dSSøren Schmidt return ENOMEM; 265331c488dSSøren Schmidt } 266331c488dSSøren Schmidt return 0; 267331c488dSSøren Schmidt } 268331c488dSSøren Schmidt 269331c488dSSøren Schmidt static int 270331c488dSSøren Schmidt ata_pci_attach(device_t dev) 271331c488dSSøren Schmidt { 272331c488dSSøren Schmidt struct ata_pci_softc *sc = device_get_softc(dev); 273331c488dSSøren Schmidt u_int8_t class, subclass; 274331c488dSSøren Schmidt u_int32_t type, cmd; 275331c488dSSøren Schmidt int rid; 276331c488dSSøren Schmidt 277331c488dSSøren Schmidt /* set up vendor-specific stuff */ 278331c488dSSøren Schmidt type = pci_get_devid(dev); 279331c488dSSøren Schmidt class = pci_get_class(dev); 280331c488dSSøren Schmidt subclass = pci_get_subclass(dev); 281331c488dSSøren Schmidt cmd = pci_read_config(dev, PCIR_COMMAND, 4); 282331c488dSSøren Schmidt 283f74abb9bSSøren Schmidt if (!(cmd & PCIM_CMD_PORTEN)) { 284f74abb9bSSøren Schmidt device_printf(dev, "ATA channel disabled by BIOS\n"); 285f74abb9bSSøren Schmidt return 0; 286f74abb9bSSøren Schmidt } 287f74abb9bSSøren Schmidt 288331c488dSSøren Schmidt /* is busmastering supported ? */ 289331c488dSSøren Schmidt if ((cmd & (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN)) == 290331c488dSSøren Schmidt (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN)) { 291331c488dSSøren Schmidt 292331c488dSSøren Schmidt /* is there a valid port range to connect to ? */ 293331c488dSSøren Schmidt rid = 0x20; 294331c488dSSøren Schmidt sc->bmio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 295331c488dSSøren Schmidt 0, ~0, 1, RF_ACTIVE); 296331c488dSSøren Schmidt if (!sc->bmio) 297331c488dSSøren Schmidt device_printf(dev, "Busmastering DMA not configured\n"); 298331c488dSSøren Schmidt } 299331c488dSSøren Schmidt else 300331c488dSSøren Schmidt device_printf(dev, "Busmastering DMA not supported\n"); 301331c488dSSøren Schmidt 302331c488dSSøren Schmidt /* do extra chipset specific setups */ 303331c488dSSøren Schmidt switch (type) { 304331c488dSSøren Schmidt case 0x522910b9: /* Aladdin need to activate the ATAPI FIFO */ 305331c488dSSøren Schmidt pci_write_config(dev, 0x53, 306331c488dSSøren Schmidt (pci_read_config(dev, 0x53, 1) & ~0x01) | 0x02, 1); 307331c488dSSøren Schmidt break; 308331c488dSSøren Schmidt 309a8ae5362SSøren Schmidt case 0x4d38105a: /* Promise 66 & 100 (before TX2) need the clock changed */ 310331c488dSSøren Schmidt case 0x4d30105a: 311331c488dSSøren Schmidt case 0x0d30105a: 312331c488dSSøren Schmidt ATA_OUTB(sc->bmio, 0x11, ATA_INB(sc->bmio, 0x11) | 0x0a); 313331c488dSSøren Schmidt /* FALLTHROUGH */ 314331c488dSSøren Schmidt 315a8ae5362SSøren Schmidt case 0x4d33105a: /* Promise (before TX2) need burst mode turned on */ 316331c488dSSøren Schmidt ATA_OUTB(sc->bmio, 0x1f, ATA_INB(sc->bmio, 0x1f) | 0x01); 317331c488dSSøren Schmidt break; 318331c488dSSøren Schmidt 319331c488dSSøren Schmidt case 0x00041103: /* HighPoint */ 320331c488dSSøren Schmidt switch (pci_get_revid(dev)) { 321331c488dSSøren Schmidt case 0x00: 322331c488dSSøren Schmidt case 0x01: 323331c488dSSøren Schmidt /* turn off interrupt prediction */ 324331c488dSSøren Schmidt pci_write_config(dev, 0x51, 325331c488dSSøren Schmidt (pci_read_config(dev, 0x51, 1) & ~0x80), 1); 326331c488dSSøren Schmidt break; 327331c488dSSøren Schmidt 328331c488dSSøren Schmidt case 0x02: 329331c488dSSøren Schmidt case 0x03: 330331c488dSSøren Schmidt case 0x04: 331331c488dSSøren Schmidt /* turn off interrupt prediction */ 332331c488dSSøren Schmidt pci_write_config(dev, 0x51, 333331c488dSSøren Schmidt (pci_read_config(dev, 0x51, 1) & ~0x02), 1); 334331c488dSSøren Schmidt pci_write_config(dev, 0x55, 335331c488dSSøren Schmidt (pci_read_config(dev, 0x55, 1) & ~0x02), 1); 336331c488dSSøren Schmidt /* turn on interrupts */ 337331c488dSSøren Schmidt pci_write_config(dev, 0x5a, 338331c488dSSøren Schmidt (pci_read_config(dev, 0x5a, 1) & ~0x10), 1); 339331c488dSSøren Schmidt 340331c488dSSøren Schmidt } 341331c488dSSøren Schmidt break; 342331c488dSSøren Schmidt 34372c2f499SSøren Schmidt case 0x05711106: /* VIA 82C586, '596, '686 default setup */ 34472c2f499SSøren Schmidt /* prepare for ATA-66 on the 82C686a and rev 0x12 and newer 82C596's */ 34572c2f499SSøren Schmidt if ((ata_find_dev(dev, 0x06861106, 0) && 34672c2f499SSøren Schmidt !ata_find_dev(dev, 0x06861106, 0x40)) || 34772c2f499SSøren Schmidt ata_find_dev(dev, 0x05961106, 0x12)) 34872c2f499SSøren Schmidt pci_write_config(dev, 0x50, 0x030b030b, 4); 34972c2f499SSøren Schmidt 35072c2f499SSøren Schmidt /* the '686b might need the data corruption fix */ 35172c2f499SSøren Schmidt if (ata_find_dev(dev, 0x06861106, 0x40)) 35272c2f499SSøren Schmidt ata_via686b(dev); 35372c2f499SSøren Schmidt 35472c2f499SSøren Schmidt /* FALLTHROUGH */ 35572c2f499SSøren Schmidt 35672c2f499SSøren Schmidt case 0x74091022: /* AMD 756 default setup */ 35772c2f499SSøren Schmidt case 0x74111022: /* AMD 766 default setup */ 358331c488dSSøren Schmidt 359331c488dSSøren Schmidt /* set prefetch, postwrite */ 360331c488dSSøren Schmidt pci_write_config(dev, 0x41, pci_read_config(dev, 0x41, 1) | 0xf0, 1); 361331c488dSSøren Schmidt 362331c488dSSøren Schmidt /* set fifo configuration half'n'half */ 363331c488dSSøren Schmidt pci_write_config(dev, 0x43, 364331c488dSSøren Schmidt (pci_read_config(dev, 0x43, 1) & 0x90) | 0x2a, 1); 365331c488dSSøren Schmidt 366331c488dSSøren Schmidt /* set status register read retry */ 367331c488dSSøren Schmidt pci_write_config(dev, 0x44, pci_read_config(dev, 0x44, 1) | 0x08, 1); 368331c488dSSøren Schmidt 369331c488dSSøren Schmidt /* set DMA read & end-of-sector fifo flush */ 370331c488dSSøren Schmidt pci_write_config(dev, 0x46, 371331c488dSSøren Schmidt (pci_read_config(dev, 0x46, 1) & 0x0c) | 0xf0, 1); 372331c488dSSøren Schmidt 373331c488dSSøren Schmidt /* set sector size */ 374331c488dSSøren Schmidt pci_write_config(dev, 0x60, DEV_BSIZE, 2); 375331c488dSSøren Schmidt pci_write_config(dev, 0x68, DEV_BSIZE, 2); 376331c488dSSøren Schmidt break; 377331c488dSSøren Schmidt 378331c488dSSøren Schmidt case 0x10001042: /* RZ 100? known bad, no DMA */ 379331c488dSSøren Schmidt case 0x10011042: 380331c488dSSøren Schmidt case 0x06401095: /* CMD 640 known bad, no DMA */ 381331c488dSSøren Schmidt sc->bmio = NULL; 382331c488dSSøren Schmidt device_printf(dev, "Busmastering DMA disabled\n"); 383331c488dSSøren Schmidt } 384331c488dSSøren Schmidt 385331c488dSSøren Schmidt if (sc->bmio) { 386331c488dSSøren Schmidt sc->bmaddr = rman_get_start(sc->bmio); 387331c488dSSøren Schmidt BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, 388331c488dSSøren Schmidt SYS_RES_IOPORT, rid, sc->bmio); 389331c488dSSøren Schmidt sc->bmio = NULL; 390331c488dSSøren Schmidt } 391331c488dSSøren Schmidt 392331c488dSSøren Schmidt /* 393331c488dSSøren Schmidt * the Cypress chip is a mess, it contains two ATA functions, but 394331c488dSSøren Schmidt * both channels are visible on the first one. 395331c488dSSøren Schmidt * simply ignore the second function for now, as the right 396331c488dSSøren Schmidt * solution (ignoring the second channel on the first function) 397331c488dSSøren Schmidt * doesn't work with the crappy ATA interrupt setup on the alpha. 398331c488dSSøren Schmidt */ 399331c488dSSøren Schmidt if (pci_get_devid(dev) == 0xc6931080 && pci_get_function(dev) > 1) 400331c488dSSøren Schmidt return 0; 401331c488dSSøren Schmidt 402331c488dSSøren Schmidt ata_pci_add_child(dev, 0); 403331c488dSSøren Schmidt 404331c488dSSøren Schmidt if (ATA_MASTERDEV(dev) || pci_read_config(dev, 0x18, 4) & IOMASK) 405331c488dSSøren Schmidt ata_pci_add_child(dev, 1); 406331c488dSSøren Schmidt 407331c488dSSøren Schmidt return bus_generic_attach(dev); 408331c488dSSøren Schmidt } 409331c488dSSøren Schmidt 410331c488dSSøren Schmidt static int 411331c488dSSøren Schmidt ata_pci_intr(struct ata_softc *scp) 412331c488dSSøren Schmidt { 413331c488dSSøren Schmidt u_int8_t dmastat; 414331c488dSSøren Schmidt 415331c488dSSøren Schmidt /* 416331c488dSSøren Schmidt * since we might share the IRQ with another device, and in some 417331c488dSSøren Schmidt * cases with our twin channel, we only want to process interrupts 418331c488dSSøren Schmidt * that we know this channel generated. 419331c488dSSøren Schmidt */ 420331c488dSSøren Schmidt switch (scp->chiptype) { 421331c488dSSøren Schmidt case 0x00041103: /* HighPoint HPT366/368/370 */ 422331c488dSSøren Schmidt if (((dmastat = ata_dmastatus(scp)) & 423331c488dSSøren Schmidt (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != ATA_BMSTAT_INTERRUPT) 424331c488dSSøren Schmidt return 1; 425331c488dSSøren Schmidt ATA_OUTB(scp->r_bmio, ATA_BMSTAT_PORT, dmastat | ATA_BMSTAT_INTERRUPT); 426331c488dSSøren Schmidt DELAY(1); 427331c488dSSøren Schmidt return 0; 428331c488dSSøren Schmidt 429331c488dSSøren Schmidt case 0x06481095: /* CMD 648 */ 430331c488dSSøren Schmidt case 0x06491095: /* CMD 649 */ 431331c488dSSøren Schmidt if (!(pci_read_config(device_get_parent(scp->dev), 0x71, 1) & 432331c488dSSøren Schmidt (scp->channel ? 0x08 : 0x04))) 433331c488dSSøren Schmidt return 1; 434331c488dSSøren Schmidt break; 435331c488dSSøren Schmidt 436331c488dSSøren Schmidt case 0x4d33105a: /* Promise Ultra/Fasttrak 33 */ 437331c488dSSøren Schmidt case 0x4d38105a: /* Promise Ultra/Fasttrak 66 */ 438331c488dSSøren Schmidt case 0x4d30105a: /* Promise Ultra/Fasttrak 100 */ 439331c488dSSøren Schmidt case 0x0d30105a: /* Promise OEM ATA100 */ 4407aa30182SSøren Schmidt case 0x4d68105a: /* Promise TX2 ATA100 */ 441468fe0fdSSøren Schmidt case 0x6268105a: /* Promise TX2v2 ATA100 */ 442331c488dSSøren Schmidt if (!(ATA_INL(scp->r_bmio, (scp->channel ? 0x14 : 0x1c)) & 443331c488dSSøren Schmidt (scp->channel ? 0x00004000 : 0x00000400))) 444331c488dSSøren Schmidt return 1; 445331c488dSSøren Schmidt break; 446331c488dSSøren Schmidt } 447331c488dSSøren Schmidt 448331c488dSSøren Schmidt if (scp->flags & ATA_DMA_ACTIVE) { 449331c488dSSøren Schmidt if (!((dmastat = ata_dmastatus(scp)) & ATA_BMSTAT_INTERRUPT)) 450331c488dSSøren Schmidt return 1; 451331c488dSSøren Schmidt ATA_OUTB(scp->r_bmio, ATA_BMSTAT_PORT, dmastat | ATA_BMSTAT_INTERRUPT); 452331c488dSSøren Schmidt DELAY(1); 453331c488dSSøren Schmidt } 454331c488dSSøren Schmidt return 0; 455331c488dSSøren Schmidt } 456331c488dSSøren Schmidt 457331c488dSSøren Schmidt static int 458331c488dSSøren Schmidt ata_pci_print_child(device_t dev, device_t child) 459331c488dSSøren Schmidt { 460331c488dSSøren Schmidt struct ata_softc *scp = device_get_softc(child); 461331c488dSSøren Schmidt int retval = 0; 462331c488dSSøren Schmidt 463331c488dSSøren Schmidt retval += bus_print_child_header(dev, child); 464331c488dSSøren Schmidt retval += printf(": at 0x%lx", rman_get_start(scp->r_io)); 465331c488dSSøren Schmidt 466331c488dSSøren Schmidt if (ATA_MASTERDEV(dev)) 467331c488dSSøren Schmidt retval += printf(" irq %d", 14 + scp->channel); 468331c488dSSøren Schmidt 469331c488dSSøren Schmidt retval += bus_print_child_footer(dev, child); 470331c488dSSøren Schmidt 471331c488dSSøren Schmidt return retval; 472331c488dSSøren Schmidt } 473331c488dSSøren Schmidt 474331c488dSSøren Schmidt static struct resource * 475331c488dSSøren Schmidt ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid, 476331c488dSSøren Schmidt u_long start, u_long end, u_long count, u_int flags) 477331c488dSSøren Schmidt { 478331c488dSSøren Schmidt struct ata_pci_softc *sc = device_get_softc(dev); 479331c488dSSøren Schmidt struct resource *res = NULL; 480331c488dSSøren Schmidt int channel = ((struct ata_softc *)device_get_softc(child))->channel; 481331c488dSSøren Schmidt int myrid; 482331c488dSSøren Schmidt 483331c488dSSøren Schmidt if (type == SYS_RES_IOPORT) { 484331c488dSSøren Schmidt switch (*rid) { 485331c488dSSøren Schmidt case ATA_IOADDR_RID: 486331c488dSSøren Schmidt if (ATA_MASTERDEV(dev)) { 487331c488dSSøren Schmidt myrid = 0; 488331c488dSSøren Schmidt start = (channel ? ATA_SECONDARY : ATA_PRIMARY); 489331c488dSSøren Schmidt end = start + ATA_IOSIZE - 1; 490331c488dSSøren Schmidt count = ATA_IOSIZE; 491331c488dSSøren Schmidt res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 492331c488dSSøren Schmidt SYS_RES_IOPORT, &myrid, 493331c488dSSøren Schmidt start, end, count, flags); 494331c488dSSøren Schmidt } 495331c488dSSøren Schmidt else { 496331c488dSSøren Schmidt myrid = 0x10 + 8 * channel; 497331c488dSSøren Schmidt res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, 498331c488dSSøren Schmidt SYS_RES_IOPORT, &myrid, 499331c488dSSøren Schmidt start, end, count, flags); 500331c488dSSøren Schmidt } 501331c488dSSøren Schmidt break; 502331c488dSSøren Schmidt 503331c488dSSøren Schmidt case ATA_ALTADDR_RID: 504331c488dSSøren Schmidt if (ATA_MASTERDEV(dev)) { 505331c488dSSøren Schmidt myrid = 0; 506331c488dSSøren Schmidt start = (channel ? ATA_SECONDARY : ATA_PRIMARY) + ATA_ALTOFFSET; 507331c488dSSøren Schmidt end = start + ATA_ALTIOSIZE - 1; 508331c488dSSøren Schmidt count = ATA_ALTIOSIZE; 509331c488dSSøren Schmidt res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 510331c488dSSøren Schmidt SYS_RES_IOPORT, &myrid, 511331c488dSSøren Schmidt start, end, count, flags); 512331c488dSSøren Schmidt } 513331c488dSSøren Schmidt else { 514331c488dSSøren Schmidt myrid = 0x14 + 8 * channel; 515331c488dSSøren Schmidt res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, 516331c488dSSøren Schmidt SYS_RES_IOPORT, &myrid, 517331c488dSSøren Schmidt start, end, count, flags); 518331c488dSSøren Schmidt if (res) { 519331c488dSSøren Schmidt start = rman_get_start(res) + 2; 520b5a5e99dSSøren Schmidt end = rman_get_start(res) + ATA_ALTIOSIZE - 1; 521331c488dSSøren Schmidt count = ATA_ALTIOSIZE; 522331c488dSSøren Schmidt BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, 523331c488dSSøren Schmidt SYS_RES_IOPORT, myrid, res); 524331c488dSSøren Schmidt res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, 525331c488dSSøren Schmidt SYS_RES_IOPORT, &myrid, 526331c488dSSøren Schmidt start, end, count, flags); 527331c488dSSøren Schmidt } 528331c488dSSøren Schmidt } 529331c488dSSøren Schmidt break; 530331c488dSSøren Schmidt 531331c488dSSøren Schmidt case ATA_BMADDR_RID: 532331c488dSSøren Schmidt if (sc->bmaddr) { 533331c488dSSøren Schmidt myrid = 0x20; 534331c488dSSøren Schmidt start = (channel == 0 ? sc->bmaddr : sc->bmaddr + ATA_BMIOSIZE); 535331c488dSSøren Schmidt end = start + ATA_BMIOSIZE - 1; 536331c488dSSøren Schmidt count = ATA_BMIOSIZE; 537331c488dSSøren Schmidt res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 538331c488dSSøren Schmidt SYS_RES_IOPORT, &myrid, 539331c488dSSøren Schmidt start, end, count, flags); 540331c488dSSøren Schmidt } 541331c488dSSøren Schmidt } 542331c488dSSøren Schmidt return res; 543331c488dSSøren Schmidt } 544331c488dSSøren Schmidt 545331c488dSSøren Schmidt if (type == SYS_RES_IRQ && *rid == ATA_IRQ_RID) { 546331c488dSSøren Schmidt if (ATA_MASTERDEV(dev)) { 547331c488dSSøren Schmidt #ifdef __alpha__ 548331c488dSSøren Schmidt return alpha_platform_alloc_ide_intr(channel); 549331c488dSSøren Schmidt #else 550331c488dSSøren Schmidt int irq = (channel == 0 ? 14 : 15); 551331c488dSSøren Schmidt 552331c488dSSøren Schmidt return BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 553468fe0fdSSøren Schmidt SYS_RES_IRQ, rid, irq, irq, 1, flags); 554331c488dSSøren Schmidt #endif 555331c488dSSøren Schmidt } 556331c488dSSøren Schmidt else { 557b5a5e99dSSøren Schmidt /* primary and secondary channels share interrupt, keep track */ 558331c488dSSøren Schmidt if (!sc->irq) 559331c488dSSøren Schmidt sc->irq = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, 560331c488dSSøren Schmidt SYS_RES_IRQ, rid, 0, ~0, 1, flags); 561b5a5e99dSSøren Schmidt sc->irqcnt++; 562331c488dSSøren Schmidt return sc->irq; 563331c488dSSøren Schmidt } 564331c488dSSøren Schmidt } 565331c488dSSøren Schmidt return 0; 566331c488dSSøren Schmidt } 567331c488dSSøren Schmidt 568331c488dSSøren Schmidt static int 569331c488dSSøren Schmidt ata_pci_release_resource(device_t dev, device_t child, int type, int rid, 570331c488dSSøren Schmidt struct resource *r) 571331c488dSSøren Schmidt { 572331c488dSSøren Schmidt struct ata_pci_softc *sc = device_get_softc(dev); 573331c488dSSøren Schmidt int channel = ((struct ata_softc *)device_get_softc(child))->channel; 574331c488dSSøren Schmidt 575331c488dSSøren Schmidt if (type == SYS_RES_IOPORT) { 576331c488dSSøren Schmidt switch (rid) { 577331c488dSSøren Schmidt case ATA_IOADDR_RID: 578331c488dSSøren Schmidt if (ATA_MASTERDEV(dev)) 579b5a5e99dSSøren Schmidt return BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 580b5a5e99dSSøren Schmidt SYS_RES_IOPORT, 0x0, r); 581331c488dSSøren Schmidt else 582b5a5e99dSSøren Schmidt return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, 583b5a5e99dSSøren Schmidt SYS_RES_IOPORT, 0x10+8*channel, r); 584331c488dSSøren Schmidt break; 585331c488dSSøren Schmidt 586331c488dSSøren Schmidt case ATA_ALTADDR_RID: 587331c488dSSøren Schmidt if (ATA_MASTERDEV(dev)) 588b5a5e99dSSøren Schmidt return BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 589b5a5e99dSSøren Schmidt SYS_RES_IOPORT, 0x0, r); 590331c488dSSøren Schmidt else 591b5a5e99dSSøren Schmidt return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, 592b5a5e99dSSøren Schmidt SYS_RES_IOPORT, 0x14+8*channel, r); 593331c488dSSøren Schmidt break; 594331c488dSSøren Schmidt 595331c488dSSøren Schmidt case ATA_BMADDR_RID: 596b5a5e99dSSøren Schmidt return BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 597b5a5e99dSSøren Schmidt SYS_RES_IOPORT, 0x20, r); 598331c488dSSøren Schmidt default: 599331c488dSSøren Schmidt return ENOENT; 600331c488dSSøren Schmidt } 601331c488dSSøren Schmidt } 602331c488dSSøren Schmidt if (type == SYS_RES_IRQ) { 603331c488dSSøren Schmidt if (rid != ATA_IRQ_RID) 604331c488dSSøren Schmidt return ENOENT; 605331c488dSSøren Schmidt 606331c488dSSøren Schmidt if (ATA_MASTERDEV(dev)) { 607331c488dSSøren Schmidt #ifdef __alpha__ 608331c488dSSøren Schmidt return alpha_platform_release_ide_intr(channel, r); 609331c488dSSøren Schmidt #else 610b5a5e99dSSøren Schmidt return BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 611b5a5e99dSSøren Schmidt SYS_RES_IRQ, rid, r); 612331c488dSSøren Schmidt #endif 613331c488dSSøren Schmidt } 614331c488dSSøren Schmidt else { 615b5a5e99dSSøren Schmidt /* primary and secondary channels share interrupt, keep track */ 616331c488dSSøren Schmidt if (--sc->irqcnt) 617331c488dSSøren Schmidt return 0; 618b5a5e99dSSøren Schmidt sc->irq = 0; 619b5a5e99dSSøren Schmidt return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, 620b5a5e99dSSøren Schmidt SYS_RES_IRQ, rid, r); 621331c488dSSøren Schmidt } 622331c488dSSøren Schmidt } 623331c488dSSøren Schmidt return EINVAL; 624331c488dSSøren Schmidt } 625331c488dSSøren Schmidt 626331c488dSSøren Schmidt static int 627331c488dSSøren Schmidt ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq, 628331c488dSSøren Schmidt int flags, driver_intr_t *intr, void *arg, 629331c488dSSøren Schmidt void **cookiep) 630331c488dSSøren Schmidt { 631331c488dSSøren Schmidt if (ATA_MASTERDEV(dev)) { 632331c488dSSøren Schmidt #ifdef __alpha__ 633331c488dSSøren Schmidt return alpha_platform_setup_ide_intr(child, irq, intr, arg, cookiep); 634331c488dSSøren Schmidt #else 635331c488dSSøren Schmidt return BUS_SETUP_INTR(device_get_parent(dev), child, irq, 636331c488dSSøren Schmidt flags, intr, arg, cookiep); 637331c488dSSøren Schmidt #endif 638331c488dSSøren Schmidt } 639331c488dSSøren Schmidt else 640331c488dSSøren Schmidt return BUS_SETUP_INTR(device_get_parent(dev), dev, irq, 641331c488dSSøren Schmidt flags, intr, arg, cookiep); 642331c488dSSøren Schmidt } 643331c488dSSøren Schmidt 644331c488dSSøren Schmidt static int 645331c488dSSøren Schmidt ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, 646331c488dSSøren Schmidt void *cookie) 647331c488dSSøren Schmidt { 648331c488dSSøren Schmidt if (ATA_MASTERDEV(dev)) { 649331c488dSSøren Schmidt #ifdef __alpha__ 650331c488dSSøren Schmidt return alpha_platform_teardown_ide_intr(child, irq, cookie); 651331c488dSSøren Schmidt #else 652331c488dSSøren Schmidt return BUS_TEARDOWN_INTR(device_get_parent(dev), child, irq, cookie); 653331c488dSSøren Schmidt #endif 654331c488dSSøren Schmidt } 655331c488dSSøren Schmidt else 656331c488dSSøren Schmidt return BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie); 657331c488dSSøren Schmidt } 658331c488dSSøren Schmidt 659331c488dSSøren Schmidt static device_method_t ata_pci_methods[] = { 660331c488dSSøren Schmidt /* device interface */ 661331c488dSSøren Schmidt DEVMETHOD(device_probe, ata_pci_probe), 662331c488dSSøren Schmidt DEVMETHOD(device_attach, ata_pci_attach), 663331c488dSSøren Schmidt DEVMETHOD(device_shutdown, bus_generic_shutdown), 664331c488dSSøren Schmidt DEVMETHOD(device_suspend, bus_generic_suspend), 665331c488dSSøren Schmidt DEVMETHOD(device_resume, bus_generic_resume), 666331c488dSSøren Schmidt 667331c488dSSøren Schmidt /* bus methods */ 668331c488dSSøren Schmidt DEVMETHOD(bus_print_child, ata_pci_print_child), 669331c488dSSøren Schmidt DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource), 670331c488dSSøren Schmidt DEVMETHOD(bus_release_resource, ata_pci_release_resource), 671331c488dSSøren Schmidt DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 672331c488dSSøren Schmidt DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 673331c488dSSøren Schmidt DEVMETHOD(bus_setup_intr, ata_pci_setup_intr), 674331c488dSSøren Schmidt DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr), 675331c488dSSøren Schmidt { 0, 0 } 676331c488dSSøren Schmidt }; 677331c488dSSøren Schmidt 678331c488dSSøren Schmidt static driver_t ata_pci_driver = { 679331c488dSSøren Schmidt "atapci", 680331c488dSSøren Schmidt ata_pci_methods, 681331c488dSSøren Schmidt sizeof(struct ata_pci_softc), 682331c488dSSøren Schmidt }; 683331c488dSSøren Schmidt 684331c488dSSøren Schmidt static devclass_t ata_pci_devclass; 685331c488dSSøren Schmidt 686331c488dSSøren Schmidt DRIVER_MODULE(atapci, pci, ata_pci_driver, ata_pci_devclass, 0, 0); 687331c488dSSøren Schmidt 688331c488dSSøren Schmidt static int 689331c488dSSøren Schmidt ata_pcisub_probe(device_t dev) 690331c488dSSøren Schmidt { 691331c488dSSøren Schmidt struct ata_softc *scp = device_get_softc(dev); 692331c488dSSøren Schmidt device_t *children; 693331c488dSSøren Schmidt int count, i; 694331c488dSSøren Schmidt 695331c488dSSøren Schmidt /* find channel number on this controller */ 696331c488dSSøren Schmidt device_get_children(device_get_parent(dev), &children, &count); 697331c488dSSøren Schmidt for (i = 0; i < count; i++) { 698331c488dSSøren Schmidt if (children[i] == dev) 699331c488dSSøren Schmidt scp->channel = i; 700331c488dSSøren Schmidt } 701331c488dSSøren Schmidt free(children, M_TEMP); 702331c488dSSøren Schmidt scp->chiptype = pci_get_devid(device_get_parent(dev)); 703331c488dSSøren Schmidt scp->intr_func = ata_pci_intr; 704331c488dSSøren Schmidt return ata_probe(dev); 705331c488dSSøren Schmidt } 706331c488dSSøren Schmidt 707331c488dSSøren Schmidt static device_method_t ata_pcisub_methods[] = { 708331c488dSSøren Schmidt /* device interface */ 709331c488dSSøren Schmidt DEVMETHOD(device_probe, ata_pcisub_probe), 710331c488dSSøren Schmidt DEVMETHOD(device_attach, ata_attach), 711331c488dSSøren Schmidt DEVMETHOD(device_detach, ata_detach), 712331c488dSSøren Schmidt DEVMETHOD(device_resume, ata_resume), 713331c488dSSøren Schmidt { 0, 0 } 714331c488dSSøren Schmidt }; 715331c488dSSøren Schmidt 716331c488dSSøren Schmidt static driver_t ata_pcisub_driver = { 717331c488dSSøren Schmidt "ata", 718331c488dSSøren Schmidt ata_pcisub_methods, 719331c488dSSøren Schmidt sizeof(struct ata_softc), 720331c488dSSøren Schmidt }; 721331c488dSSøren Schmidt 722331c488dSSøren Schmidt DRIVER_MODULE(ata, atapci, ata_pcisub_driver, ata_devclass, 0, 0); 723