1331c488dSSøren Schmidt /*- 2e2bf77c5SSøren Schmidt * Copyright (c) 1998 - 2006 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 * 15331c488dSSøren Schmidt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16331c488dSSøren Schmidt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17331c488dSSøren Schmidt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18331c488dSSøren Schmidt * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19331c488dSSøren Schmidt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20331c488dSSøren Schmidt * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21331c488dSSøren Schmidt * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22331c488dSSøren Schmidt * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23331c488dSSøren Schmidt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24331c488dSSøren Schmidt * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25331c488dSSøren Schmidt */ 26331c488dSSøren Schmidt 27aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 28aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 29aad970f1SDavid E. O'Brien 307800211bSSøren Schmidt #include "opt_ata.h" 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/module.h> 358ca4df32SSøren Schmidt #include <sys/ata.h> 36331c488dSSøren Schmidt #include <sys/bus.h> 370a3a1935SSøren Schmidt #include <sys/conf.h> 38331c488dSSøren Schmidt #include <sys/malloc.h> 39a7a120f6SSøren Schmidt #include <sys/sema.h> 405fdbb0d2SSøren Schmidt #include <sys/taskqueue.h> 415df3ca78SSøren Schmidt #include <vm/uma.h> 42331c488dSSøren Schmidt #include <machine/stdarg.h> 43331c488dSSøren Schmidt #include <machine/resource.h> 44331c488dSSøren Schmidt #include <machine/bus.h> 45331c488dSSøren Schmidt #ifdef __alpha__ 46331c488dSSøren Schmidt #include <machine/md_var.h> 47331c488dSSøren Schmidt #endif 48331c488dSSøren Schmidt #include <sys/rman.h> 494fbd232cSWarner Losh #include <dev/pci/pcivar.h> 504fbd232cSWarner Losh #include <dev/pci/pcireg.h> 51331c488dSSøren Schmidt #include <dev/ata/ata-all.h> 52bb5bdd38SSøren Schmidt #include <dev/ata/ata-pci.h> 538ca4df32SSøren Schmidt #include <ata_if.h> 54331c488dSSøren Schmidt 55bb5bdd38SSøren Schmidt /* local vars */ 565bb84bc8SRobert Watson static MALLOC_DEFINE(M_ATAPCI, "ata_pci", "ATA driver PCI"); 57331c488dSSøren Schmidt 5872c2f499SSøren Schmidt /* misc defines */ 5972c2f499SSøren Schmidt #define IOMASK 0xfffffffc 607af3abd8SSøren Schmidt #define ATA_PROBE_OK -10 6172c2f499SSøren Schmidt 624ee3fbe8SSøren Schmidt int 634ee3fbe8SSøren Schmidt ata_legacy(device_t dev) 644ee3fbe8SSøren Schmidt { 654ee3fbe8SSøren Schmidt return ((pci_read_config(dev, PCIR_PROGIF, 1)&PCIP_STORAGE_IDE_MASTERDEV) && 664ee3fbe8SSøren Schmidt ((pci_read_config(dev, PCIR_PROGIF, 1) & 674ee3fbe8SSøren Schmidt (PCIP_STORAGE_IDE_MODEPRIM | PCIP_STORAGE_IDE_MODESEC)) != 684ee3fbe8SSøren Schmidt (PCIP_STORAGE_IDE_MODEPRIM | PCIP_STORAGE_IDE_MODESEC))); 694ee3fbe8SSøren Schmidt } 704ee3fbe8SSøren Schmidt 718ca4df32SSøren Schmidt int 72331c488dSSøren Schmidt ata_pci_probe(device_t dev) 73331c488dSSøren Schmidt { 74bb5bdd38SSøren Schmidt if (pci_get_class(dev) != PCIC_STORAGE) 75331c488dSSøren Schmidt return ENXIO; 76331c488dSSøren Schmidt 77bb5bdd38SSøren Schmidt switch (pci_get_vendor(dev)) { 78bb5bdd38SSøren Schmidt case ATA_ACARD_ID: 7945f13b84SSøren Schmidt if (!ata_acard_ident(dev)) 807af3abd8SSøren Schmidt return ATA_PROBE_OK; 8145f13b84SSøren Schmidt break; 82bb5bdd38SSøren Schmidt case ATA_ACER_LABS_ID: 8345f13b84SSøren Schmidt if (!ata_ali_ident(dev)) 847af3abd8SSøren Schmidt return ATA_PROBE_OK; 8545f13b84SSøren Schmidt break; 86bb5bdd38SSøren Schmidt case ATA_AMD_ID: 8745f13b84SSøren Schmidt if (!ata_amd_ident(dev)) 887af3abd8SSøren Schmidt return ATA_PROBE_OK; 8945f13b84SSøren Schmidt break; 907ebce023SSøren Schmidt case ATA_ATI_ID: 917ebce023SSøren Schmidt if (!ata_ati_ident(dev)) 927af3abd8SSøren Schmidt return ATA_PROBE_OK; 937ebce023SSøren Schmidt break; 94bb5bdd38SSøren Schmidt case ATA_CYRIX_ID: 9545f13b84SSøren Schmidt if (!ata_cyrix_ident(dev)) 967af3abd8SSøren Schmidt return ATA_PROBE_OK; 9745f13b84SSøren Schmidt break; 98bb5bdd38SSøren Schmidt case ATA_CYPRESS_ID: 9945f13b84SSøren Schmidt if (!ata_cypress_ident(dev)) 1007af3abd8SSøren Schmidt return ATA_PROBE_OK; 10145f13b84SSøren Schmidt break; 102bb5bdd38SSøren Schmidt case ATA_HIGHPOINT_ID: 10345f13b84SSøren Schmidt if (!ata_highpoint_ident(dev)) 1047af3abd8SSøren Schmidt return ATA_PROBE_OK; 10545f13b84SSøren Schmidt break; 106bb5bdd38SSøren Schmidt case ATA_INTEL_ID: 10745f13b84SSøren Schmidt if (!ata_intel_ident(dev)) 1087af3abd8SSøren Schmidt return ATA_PROBE_OK; 10945f13b84SSøren Schmidt break; 11088bdf804SSøren Schmidt case ATA_ITE_ID: 11188bdf804SSøren Schmidt if (!ata_ite_ident(dev)) 1127af3abd8SSøren Schmidt return ATA_PROBE_OK; 11388bdf804SSøren Schmidt break; 114797c12eeSSøren Schmidt case ATA_JMICRON_ID: 115797c12eeSSøren Schmidt if (!ata_jmicron_ident(dev)) 116797c12eeSSøren Schmidt return ATA_PROBE_OK; 117797c12eeSSøren Schmidt break; 1184b55f0c7SSøren Schmidt case ATA_MARVELL_ID: 1194b55f0c7SSøren Schmidt if (!ata_marvell_ident(dev)) 1207af3abd8SSøren Schmidt return ATA_PROBE_OK; 1214b55f0c7SSøren Schmidt break; 122a5cd71eeSSøren Schmidt case ATA_NATIONAL_ID: 123a5cd71eeSSøren Schmidt if (!ata_national_ident(dev)) 1247af3abd8SSøren Schmidt return ATA_PROBE_OK; 125a5cd71eeSSøren Schmidt break; 126bb5bdd38SSøren Schmidt case ATA_NVIDIA_ID: 12745f13b84SSøren Schmidt if (!ata_nvidia_ident(dev)) 1287af3abd8SSøren Schmidt return ATA_PROBE_OK; 12945f13b84SSøren Schmidt break; 130bb5bdd38SSøren Schmidt case ATA_PROMISE_ID: 13145f13b84SSøren Schmidt if (!ata_promise_ident(dev)) 1327af3abd8SSøren Schmidt return ATA_PROBE_OK; 13345f13b84SSøren Schmidt break; 134bb5bdd38SSøren Schmidt case ATA_SERVERWORKS_ID: 13545f13b84SSøren Schmidt if (!ata_serverworks_ident(dev)) 1367af3abd8SSøren Schmidt return ATA_PROBE_OK; 13745f13b84SSøren Schmidt break; 138bb5bdd38SSøren Schmidt case ATA_SILICON_IMAGE_ID: 13945f13b84SSøren Schmidt if (!ata_sii_ident(dev)) 1407af3abd8SSøren Schmidt return ATA_PROBE_OK; 14145f13b84SSøren Schmidt break; 142bb5bdd38SSøren Schmidt case ATA_SIS_ID: 14345f13b84SSøren Schmidt if (!ata_sis_ident(dev)) 1447af3abd8SSøren Schmidt return ATA_PROBE_OK; 14545f13b84SSøren Schmidt break; 146bb5bdd38SSøren Schmidt case ATA_VIA_ID: 14745f13b84SSøren Schmidt if (!ata_via_ident(dev)) 1487af3abd8SSøren Schmidt return ATA_PROBE_OK; 14945f13b84SSøren Schmidt break; 15088bdf804SSøren Schmidt case ATA_CENATEK_ID: 15188bdf804SSøren Schmidt if (pci_get_devid(dev) == ATA_CENATEK_ROCKET) { 152566cf07aSSøren Schmidt ata_generic_ident(dev); 153bb5bdd38SSøren Schmidt device_set_desc(dev, "Cenatek Rocket Drive controller"); 1547af3abd8SSøren Schmidt return ATA_PROBE_OK; 155331c488dSSøren Schmidt } 15645f13b84SSøren Schmidt break; 15788bdf804SSøren Schmidt case ATA_MICRON_ID: 15888bdf804SSøren Schmidt if (pci_get_devid(dev) == ATA_MICRON_RZ1000 || 15988bdf804SSøren Schmidt pci_get_devid(dev) == ATA_MICRON_RZ1001) { 160566cf07aSSøren Schmidt ata_generic_ident(dev); 161bb5bdd38SSøren Schmidt device_set_desc(dev, 16288bdf804SSøren Schmidt "RZ 100? ATA controller !WARNING! data loss/corruption risk"); 1637af3abd8SSøren Schmidt return ATA_PROBE_OK; 164bb5bdd38SSøren Schmidt } 16545f13b84SSøren Schmidt break; 16645f13b84SSøren Schmidt } 167bb5bdd38SSøren Schmidt 168bb5bdd38SSøren Schmidt /* unknown chipset, try generic DMA if it seems possible */ 16945f13b84SSøren Schmidt if ((pci_get_class(dev) == PCIC_STORAGE) && 1707af3abd8SSøren Schmidt (pci_get_subclass(dev) == PCIS_STORAGE_IDE)) { 1717af3abd8SSøren Schmidt if (!ata_generic_ident(dev)) 1727af3abd8SSøren Schmidt return ATA_PROBE_OK; 1737af3abd8SSøren Schmidt } 174bb5bdd38SSøren Schmidt return ENXIO; 175bb5bdd38SSøren Schmidt } 176331c488dSSøren Schmidt 1778ca4df32SSøren Schmidt int 178331c488dSSøren Schmidt ata_pci_attach(device_t dev) 179331c488dSSøren Schmidt { 180566cf07aSSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(dev); 181498e5543SSøren Schmidt u_int32_t cmd; 1821b7cfe44SSøren Schmidt int unit; 183331c488dSSøren Schmidt 184566cf07aSSøren Schmidt /* do chipset specific setups only needed once */ 1856230b63cSSøren Schmidt if (ata_legacy(dev) || pci_read_config(dev, PCIR_BAR(2), 4) & IOMASK) 186566cf07aSSøren Schmidt ctlr->channels = 2; 187566cf07aSSøren Schmidt else 188566cf07aSSøren Schmidt ctlr->channels = 1; 189566cf07aSSøren Schmidt ctlr->allocate = ata_pci_allocate; 190566cf07aSSøren Schmidt ctlr->dmainit = ata_pci_dmainit; 1918ca4df32SSøren Schmidt ctlr->dev = dev; 192566cf07aSSøren Schmidt 193498e5543SSøren Schmidt /* if needed try to enable busmastering */ 194498e5543SSøren Schmidt cmd = pci_read_config(dev, PCIR_COMMAND, 2); 1957800211bSSøren Schmidt if (!(cmd & PCIM_CMD_BUSMASTEREN)) { 1967800211bSSøren Schmidt pci_write_config(dev, PCIR_COMMAND, cmd | PCIM_CMD_BUSMASTEREN, 2); 1977800211bSSøren Schmidt cmd = pci_read_config(dev, PCIR_COMMAND, 2); 1987800211bSSøren Schmidt } 199331c488dSSøren Schmidt 200498e5543SSøren Schmidt /* if busmastering mode "stuck" use it */ 201498e5543SSøren Schmidt if ((cmd & PCIM_CMD_BUSMASTEREN) == PCIM_CMD_BUSMASTEREN) { 202498e5543SSøren Schmidt ctlr->r_type1 = SYS_RES_IOPORT; 203498e5543SSøren Schmidt ctlr->r_rid1 = ATA_BMADDR_RID; 2045f96beb9SNate Lawson ctlr->r_res1 = bus_alloc_resource_any(dev, ctlr->r_type1, &ctlr->r_rid1, 2055f96beb9SNate Lawson RF_ACTIVE); 206331c488dSSøren Schmidt } 207331c488dSSøren Schmidt 208f5f55db3SSøren Schmidt if (ctlr->chipinit(dev)) 209f5f55db3SSøren Schmidt return ENXIO; 210c2833977SSøren Schmidt 211566cf07aSSøren Schmidt /* attach all channels on this controller */ 2126230b63cSSøren Schmidt for (unit = 0; unit < ctlr->channels; unit++) { 2136230b63cSSøren Schmidt if (unit == 0 && (pci_get_progif(dev) & 0x81) == 0x80) { 2146230b63cSSøren Schmidt device_add_child(dev, "ata", unit); 2156230b63cSSøren Schmidt continue; 2166230b63cSSøren Schmidt } 2176230b63cSSøren Schmidt if (unit == 1 && (pci_get_progif(dev) & 0x84) == 0x80) { 2186230b63cSSøren Schmidt device_add_child(dev, "ata", unit); 2196230b63cSSøren Schmidt continue; 2206230b63cSSøren Schmidt } 2216230b63cSSøren Schmidt device_add_child(dev, "ata", devclass_find_free_unit(ata_devclass, 2)); 2226230b63cSSøren Schmidt } 2238ca4df32SSøren Schmidt bus_generic_attach(dev); 2248ca4df32SSøren Schmidt return 0; 225f2972d7eSSøren Schmidt } 226498e5543SSøren Schmidt 2278ca4df32SSøren Schmidt int 228498e5543SSøren Schmidt ata_pci_detach(device_t dev) 229498e5543SSøren Schmidt { 230498e5543SSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(dev); 2318ca4df32SSøren Schmidt device_t *children; 2328ca4df32SSøren Schmidt int nchildren, i; 233498e5543SSøren Schmidt 2348ca4df32SSøren Schmidt /* detach & delete all children */ 2358ca4df32SSøren Schmidt if (!device_get_children(dev, &children, &nchildren)) { 2368ca4df32SSøren Schmidt for (i = 0; i < nchildren; i++) 2378ca4df32SSøren Schmidt device_delete_child(dev, children[i]); 2388ca4df32SSøren Schmidt free(children, M_TEMP); 239331c488dSSøren Schmidt } 240331c488dSSøren Schmidt 241498e5543SSøren Schmidt if (ctlr->r_irq) { 242498e5543SSøren Schmidt bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle); 243498e5543SSøren Schmidt bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ctlr->r_irq); 244498e5543SSøren Schmidt } 245498e5543SSøren Schmidt if (ctlr->r_res2) 246498e5543SSøren Schmidt bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2); 247498e5543SSøren Schmidt if (ctlr->r_res1) 248498e5543SSøren Schmidt bus_release_resource(dev, ctlr->r_type1, ctlr->r_rid1, ctlr->r_res1); 249498e5543SSøren Schmidt 250498e5543SSøren Schmidt return 0; 251498e5543SSøren Schmidt } 252331c488dSSøren Schmidt 2538ca4df32SSøren Schmidt struct resource * 254331c488dSSøren Schmidt ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid, 255331c488dSSøren Schmidt u_long start, u_long end, u_long count, u_int flags) 256331c488dSSøren Schmidt { 2576ddce903SSøren Schmidt struct ata_pci_controller *controller = device_get_softc(dev); 2586ddce903SSøren Schmidt int unit = ((struct ata_channel *)device_get_softc(child))->unit; 259bb5bdd38SSøren Schmidt struct resource *res = NULL; 260331c488dSSøren Schmidt int myrid; 261331c488dSSøren Schmidt 262331c488dSSøren Schmidt if (type == SYS_RES_IOPORT) { 263331c488dSSøren Schmidt switch (*rid) { 264331c488dSSøren Schmidt case ATA_IOADDR_RID: 2654ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 2666ddce903SSøren Schmidt start = (unit ? ATA_SECONDARY : ATA_PRIMARY); 267331c488dSSøren Schmidt count = ATA_IOSIZE; 268f2972d7eSSøren Schmidt end = start + count - 1; 269331c488dSSøren Schmidt } 2706230b63cSSøren Schmidt myrid = PCIR_BAR(0) + (unit << 3); 271331c488dSSøren Schmidt res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, 272331c488dSSøren Schmidt SYS_RES_IOPORT, &myrid, 273331c488dSSøren Schmidt start, end, count, flags); 274331c488dSSøren Schmidt break; 275331c488dSSøren Schmidt 2760e1eb682SSøren Schmidt case ATA_CTLADDR_RID: 2774ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 2780e1eb682SSøren Schmidt start = (unit ? ATA_SECONDARY : ATA_PRIMARY) + ATA_CTLOFFSET; 2790e1eb682SSøren Schmidt count = ATA_CTLIOSIZE; 280f2972d7eSSøren Schmidt end = start + count - 1; 281331c488dSSøren Schmidt } 2826230b63cSSøren Schmidt myrid = PCIR_BAR(1) + (unit << 3); 283331c488dSSøren Schmidt res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, 284331c488dSSøren Schmidt SYS_RES_IOPORT, &myrid, 285331c488dSSøren Schmidt start, end, count, flags); 286331c488dSSøren Schmidt break; 287331c488dSSøren Schmidt } 288331c488dSSøren Schmidt } 289331c488dSSøren Schmidt if (type == SYS_RES_IRQ && *rid == ATA_IRQ_RID) { 2904ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 291331c488dSSøren Schmidt #ifdef __alpha__ 292bbccd832SSøren Schmidt res = alpha_platform_alloc_ide_intr(unit); 293331c488dSSøren Schmidt #else 2946ddce903SSøren Schmidt int irq = (unit == 0 ? 14 : 15); 295331c488dSSøren Schmidt 296bbccd832SSøren Schmidt res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 297468fe0fdSSøren Schmidt SYS_RES_IRQ, rid, irq, irq, 1, flags); 298331c488dSSøren Schmidt #endif 299331c488dSSøren Schmidt } 300bbccd832SSøren Schmidt else 301bbccd832SSøren Schmidt res = controller->r_irq; 302331c488dSSøren Schmidt } 303bbccd832SSøren Schmidt return res; 304331c488dSSøren Schmidt } 305331c488dSSøren Schmidt 3068ca4df32SSøren Schmidt int 307331c488dSSøren Schmidt ata_pci_release_resource(device_t dev, device_t child, int type, int rid, 308331c488dSSøren Schmidt struct resource *r) 309331c488dSSøren Schmidt { 3106ddce903SSøren Schmidt int unit = ((struct ata_channel *)device_get_softc(child))->unit; 311331c488dSSøren Schmidt 312331c488dSSøren Schmidt if (type == SYS_RES_IOPORT) { 313331c488dSSøren Schmidt switch (rid) { 314331c488dSSøren Schmidt case ATA_IOADDR_RID: 315b5a5e99dSSøren Schmidt return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, 3166230b63cSSøren Schmidt SYS_RES_IOPORT, 3176230b63cSSøren Schmidt PCIR_BAR(0) + (unit << 3), r); 318331c488dSSøren Schmidt break; 319331c488dSSøren Schmidt 3200e1eb682SSøren Schmidt case ATA_CTLADDR_RID: 321b5a5e99dSSøren Schmidt return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, 3226230b63cSSøren Schmidt SYS_RES_IOPORT, 3236230b63cSSøren Schmidt PCIR_BAR(1) + (unit << 3), r); 324331c488dSSøren Schmidt break; 325331c488dSSøren Schmidt default: 326331c488dSSøren Schmidt return ENOENT; 327331c488dSSøren Schmidt } 328331c488dSSøren Schmidt } 329331c488dSSøren Schmidt if (type == SYS_RES_IRQ) { 330331c488dSSøren Schmidt if (rid != ATA_IRQ_RID) 331331c488dSSøren Schmidt return ENOENT; 332331c488dSSøren Schmidt 3334ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 334331c488dSSøren Schmidt #ifdef __alpha__ 3356ddce903SSøren Schmidt return alpha_platform_release_ide_intr(unit, r); 336331c488dSSøren Schmidt #else 337b5a5e99dSSøren Schmidt return BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 338b5a5e99dSSøren Schmidt SYS_RES_IRQ, rid, r); 339331c488dSSøren Schmidt #endif 340331c488dSSøren Schmidt } 341bb5bdd38SSøren Schmidt else 342331c488dSSøren Schmidt return 0; 343331c488dSSøren Schmidt } 344331c488dSSøren Schmidt return EINVAL; 345331c488dSSøren Schmidt } 346331c488dSSøren Schmidt 3478ca4df32SSøren Schmidt int 348331c488dSSøren Schmidt ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq, 349bb5bdd38SSøren Schmidt int flags, driver_intr_t *function, void *argument, 350331c488dSSøren Schmidt void **cookiep) 351331c488dSSøren Schmidt { 3524ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 353331c488dSSøren Schmidt #ifdef __alpha__ 354bb5bdd38SSøren Schmidt return alpha_platform_setup_ide_intr(child, irq, function, argument, 355bb5bdd38SSøren Schmidt cookiep); 356331c488dSSøren Schmidt #else 357331c488dSSøren Schmidt return BUS_SETUP_INTR(device_get_parent(dev), child, irq, 358bb5bdd38SSøren Schmidt flags, function, argument, cookiep); 359331c488dSSøren Schmidt #endif 360331c488dSSøren Schmidt } 361bb5bdd38SSøren Schmidt else { 362bb5bdd38SSøren Schmidt struct ata_pci_controller *controller = device_get_softc(dev); 363bb5bdd38SSøren Schmidt int unit = ((struct ata_channel *)device_get_softc(child))->unit; 364bb5bdd38SSøren Schmidt 365bb5bdd38SSøren Schmidt controller->interrupt[unit].function = function; 366bb5bdd38SSøren Schmidt controller->interrupt[unit].argument = argument; 367bb5bdd38SSøren Schmidt *cookiep = controller; 368bb5bdd38SSøren Schmidt return 0; 369bb5bdd38SSøren Schmidt } 370331c488dSSøren Schmidt } 371331c488dSSøren Schmidt 3728ca4df32SSøren Schmidt int 373331c488dSSøren Schmidt ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, 374331c488dSSøren Schmidt void *cookie) 375331c488dSSøren Schmidt { 3764ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 377331c488dSSøren Schmidt #ifdef __alpha__ 378331c488dSSøren Schmidt return alpha_platform_teardown_ide_intr(child, irq, cookie); 379331c488dSSøren Schmidt #else 380331c488dSSøren Schmidt return BUS_TEARDOWN_INTR(device_get_parent(dev), child, irq, cookie); 381331c488dSSøren Schmidt #endif 382331c488dSSøren Schmidt } 3832e6c2a10SSøren Schmidt else { 3842e6c2a10SSøren Schmidt struct ata_pci_controller *controller = device_get_softc(dev); 3852e6c2a10SSøren Schmidt int unit = ((struct ata_channel *)device_get_softc(child))->unit; 3862e6c2a10SSøren Schmidt 3872e6c2a10SSøren Schmidt controller->interrupt[unit].function = NULL; 3882e6c2a10SSøren Schmidt controller->interrupt[unit].argument = NULL; 389bb5bdd38SSøren Schmidt return 0; 390331c488dSSøren Schmidt } 3912e6c2a10SSøren Schmidt } 392331c488dSSøren Schmidt 393b0a7e6a5SSøren Schmidt int 394bbccd832SSøren Schmidt ata_pci_allocate(device_t dev) 395566cf07aSSøren Schmidt { 396566cf07aSSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); 397bbccd832SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 3980e1eb682SSøren Schmidt struct resource *io = NULL, *ctlio = NULL; 399566cf07aSSøren Schmidt int i, rid; 400566cf07aSSøren Schmidt 401566cf07aSSøren Schmidt rid = ATA_IOADDR_RID; 402ecd6c15dSSøren Schmidt if (!(io = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE))) 403566cf07aSSøren Schmidt return ENXIO; 404566cf07aSSøren Schmidt 4050e1eb682SSøren Schmidt rid = ATA_CTLADDR_RID; 406ecd6c15dSSøren Schmidt if (!(ctlio = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,RF_ACTIVE))){ 407566cf07aSSøren Schmidt bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, io); 408566cf07aSSøren Schmidt return ENXIO; 409566cf07aSSøren Schmidt } 410566cf07aSSøren Schmidt 4110e1eb682SSøren Schmidt for (i = ATA_DATA; i <= ATA_COMMAND; i ++) { 412566cf07aSSøren Schmidt ch->r_io[i].res = io; 413566cf07aSSøren Schmidt ch->r_io[i].offset = i; 414566cf07aSSøren Schmidt } 4150e1eb682SSøren Schmidt ch->r_io[ATA_CONTROL].res = ctlio; 4160e1eb682SSøren Schmidt ch->r_io[ATA_CONTROL].offset = ata_legacy(device_get_parent(dev)) ? 0 : 2; 4171b39bd24SSøren Schmidt ch->r_io[ATA_IDX_ADDR].res = io; 4180068f98fSSøren Schmidt ata_default_registers(dev); 419498e5543SSøren Schmidt if (ctlr->r_res1) { 420566cf07aSSøren Schmidt for (i = ATA_BMCMD_PORT; i <= ATA_BMDTP_PORT; i++) { 421498e5543SSøren Schmidt ch->r_io[i].res = ctlr->r_res1; 422566cf07aSSøren Schmidt ch->r_io[i].offset = (i - ATA_BMCMD_PORT) + (ch->unit*ATA_BMIOSIZE); 423566cf07aSSøren Schmidt } 424566cf07aSSøren Schmidt } 425f2972d7eSSøren Schmidt 426f5f55db3SSøren Schmidt ata_pci_hw(dev); 427566cf07aSSøren Schmidt return 0; 428566cf07aSSøren Schmidt } 429566cf07aSSøren Schmidt 430f5f55db3SSøren Schmidt void 431f5f55db3SSøren Schmidt ata_pci_hw(device_t dev) 432f5f55db3SSøren Schmidt { 433f5f55db3SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 434f5f55db3SSøren Schmidt 435f5f55db3SSøren Schmidt ata_generic_hw(dev); 436f5f55db3SSøren Schmidt ch->hw.status = ata_pci_status; 437f5f55db3SSøren Schmidt } 438f5f55db3SSøren Schmidt 439f5f55db3SSøren Schmidt int 440f5f55db3SSøren Schmidt ata_pci_status(device_t dev) 441f5f55db3SSøren Schmidt { 442f5f55db3SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 443f5f55db3SSøren Schmidt 4440a3a1935SSøren Schmidt if ((dumping || !ata_legacy(device_get_parent(dev))) && 445634c3776SSøren Schmidt ch->dma && ((ch->flags & ATA_ALWAYS_DMASTAT) || 446f5f55db3SSøren Schmidt (ch->dma->flags & ATA_DMA_ACTIVE))) { 447f5f55db3SSøren Schmidt int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; 448f5f55db3SSøren Schmidt 449f5f55db3SSøren Schmidt if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != 450f5f55db3SSøren Schmidt ATA_BMSTAT_INTERRUPT) 451f5f55db3SSøren Schmidt return 0; 452f5f55db3SSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); 453f5f55db3SSøren Schmidt DELAY(1); 454f5f55db3SSøren Schmidt } 455f5f55db3SSøren Schmidt if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) { 456f5f55db3SSøren Schmidt DELAY(100); 457f5f55db3SSøren Schmidt if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) 458f5f55db3SSøren Schmidt return 0; 459f5f55db3SSøren Schmidt } 460f5f55db3SSøren Schmidt return 1; 461f5f55db3SSøren Schmidt } 462f5f55db3SSøren Schmidt 463566cf07aSSøren Schmidt static int 4640068f98fSSøren Schmidt ata_pci_dmastart(device_t dev) 465566cf07aSSøren Schmidt { 466eeda55ceSSøren Schmidt struct ata_channel *ch = device_get_softc(device_get_parent(dev)); 4670068f98fSSøren Schmidt 468566cf07aSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) | 469566cf07aSSøren Schmidt (ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR))); 4708ca4df32SSøren Schmidt ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->sg_bus); 471c5b2c44cSSøren Schmidt ch->dma->flags |= ATA_DMA_ACTIVE; 472566cf07aSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, 47345bf968aSSøren Schmidt (ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_WRITE_READ) | 47480344be5SSøren Schmidt ((ch->dma->flags & ATA_DMA_READ) ? ATA_BMCMD_WRITE_READ : 0) | 47580344be5SSøren Schmidt ATA_BMCMD_START_STOP); 476566cf07aSSøren Schmidt return 0; 477566cf07aSSøren Schmidt } 478566cf07aSSøren Schmidt 479566cf07aSSøren Schmidt static int 4800068f98fSSøren Schmidt ata_pci_dmastop(device_t dev) 481566cf07aSSøren Schmidt { 482eeda55ceSSøren Schmidt struct ata_channel *ch = device_get_softc(device_get_parent(dev)); 483566cf07aSSøren Schmidt int error; 484566cf07aSSøren Schmidt 485566cf07aSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, 486566cf07aSSøren Schmidt ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP); 4877e6d7588SSøren Schmidt ch->dma->flags &= ~ATA_DMA_ACTIVE; 488c5b2c44cSSøren Schmidt error = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; 489566cf07aSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR); 4905fdbb0d2SSøren Schmidt return error; 491566cf07aSSøren Schmidt } 492566cf07aSSøren Schmidt 4936419d0b0SSøren Schmidt static void 494eeda55ceSSøren Schmidt ata_pci_dmareset(device_t dev) 495eeda55ceSSøren Schmidt { 496eeda55ceSSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 497eeda55ceSSøren Schmidt 498eeda55ceSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, 499eeda55ceSSøren Schmidt ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP); 500eeda55ceSSøren Schmidt ch->dma->flags &= ~ATA_DMA_ACTIVE; 501eeda55ceSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR); 502eeda55ceSSøren Schmidt ch->dma->unload(dev); 503eeda55ceSSøren Schmidt } 504eeda55ceSSøren Schmidt 505e3989d3eSSøren Schmidt void 5060068f98fSSøren Schmidt ata_pci_dmainit(device_t dev) 507566cf07aSSøren Schmidt { 5080068f98fSSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 5090068f98fSSøren Schmidt 5100068f98fSSøren Schmidt ata_dmainit(dev); 5116419d0b0SSøren Schmidt if (ch->dma) { 512566cf07aSSøren Schmidt ch->dma->start = ata_pci_dmastart; 513566cf07aSSøren Schmidt ch->dma->stop = ata_pci_dmastop; 514eeda55ceSSøren Schmidt ch->dma->reset = ata_pci_dmareset; 5156419d0b0SSøren Schmidt } 516566cf07aSSøren Schmidt } 517566cf07aSSøren Schmidt 518331c488dSSøren Schmidt static device_method_t ata_pci_methods[] = { 519331c488dSSøren Schmidt /* device interface */ 520331c488dSSøren Schmidt DEVMETHOD(device_probe, ata_pci_probe), 521331c488dSSøren Schmidt DEVMETHOD(device_attach, ata_pci_attach), 522498e5543SSøren Schmidt DEVMETHOD(device_detach, ata_pci_detach), 523331c488dSSøren Schmidt DEVMETHOD(device_shutdown, bus_generic_shutdown), 524331c488dSSøren Schmidt DEVMETHOD(device_suspend, bus_generic_suspend), 525331c488dSSøren Schmidt DEVMETHOD(device_resume, bus_generic_resume), 526331c488dSSøren Schmidt 527331c488dSSøren Schmidt /* bus methods */ 528331c488dSSøren Schmidt DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource), 529331c488dSSøren Schmidt DEVMETHOD(bus_release_resource, ata_pci_release_resource), 530331c488dSSøren Schmidt DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 531331c488dSSøren Schmidt DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 532331c488dSSøren Schmidt DEVMETHOD(bus_setup_intr, ata_pci_setup_intr), 533331c488dSSøren Schmidt DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr), 5348ca4df32SSøren Schmidt 535331c488dSSøren Schmidt { 0, 0 } 536331c488dSSøren Schmidt }; 537331c488dSSøren Schmidt 5388ca4df32SSøren Schmidt devclass_t atapci_devclass; 5398ca4df32SSøren Schmidt 540331c488dSSøren Schmidt static driver_t ata_pci_driver = { 541331c488dSSøren Schmidt "atapci", 542331c488dSSøren Schmidt ata_pci_methods, 5436ddce903SSøren Schmidt sizeof(struct ata_pci_controller), 544331c488dSSøren Schmidt }; 545331c488dSSøren Schmidt 5468ca4df32SSøren Schmidt DRIVER_MODULE(atapci, pci, ata_pci_driver, atapci_devclass, 0, 0); 5478ca4df32SSøren Schmidt MODULE_VERSION(atapci, 1); 5488ca4df32SSøren Schmidt MODULE_DEPEND(atapci, ata, 1, 1, 1); 549331c488dSSøren Schmidt 550331c488dSSøren Schmidt static int 5515a5b148dSSøren Schmidt ata_pcichannel_probe(device_t dev) 552331c488dSSøren Schmidt { 5536ddce903SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 554331c488dSSøren Schmidt device_t *children; 555d53fc3e4SSøren Schmidt int count, i; 5568ca4df32SSøren Schmidt char buffer[32]; 557331c488dSSøren Schmidt 558498e5543SSøren Schmidt /* take care of green memory */ 559498e5543SSøren Schmidt bzero(ch, sizeof(struct ata_channel)); 560498e5543SSøren Schmidt 561331c488dSSøren Schmidt /* find channel number on this controller */ 562331c488dSSøren Schmidt device_get_children(device_get_parent(dev), &children, &count); 563331c488dSSøren Schmidt for (i = 0; i < count; i++) { 564331c488dSSøren Schmidt if (children[i] == dev) 5656ddce903SSøren Schmidt ch->unit = i; 566331c488dSSøren Schmidt } 567331c488dSSøren Schmidt free(children, M_TEMP); 5688ba4488cSSøren Schmidt 5698ca4df32SSøren Schmidt sprintf(buffer, "ATA channel %d", ch->unit); 5708ca4df32SSøren Schmidt device_set_desc_copy(dev, buffer); 5718ca4df32SSøren Schmidt 572d53fc3e4SSøren Schmidt return ata_probe(dev); 573d53fc3e4SSøren Schmidt } 574d53fc3e4SSøren Schmidt 575d53fc3e4SSøren Schmidt static int 5765a5b148dSSøren Schmidt ata_pcichannel_attach(device_t dev) 577d53fc3e4SSøren Schmidt { 578d53fc3e4SSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); 579d53fc3e4SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 580d53fc3e4SSøren Schmidt int error; 581d53fc3e4SSøren Schmidt 582a3ebeaa8SSøren Schmidt if (ctlr->dmainit) 5830068f98fSSøren Schmidt ctlr->dmainit(dev); 584d53fc3e4SSøren Schmidt if (ch->dma) 5850068f98fSSøren Schmidt ch->dma->alloc(dev); 586d53fc3e4SSøren Schmidt 587bbccd832SSøren Schmidt if ((error = ctlr->allocate(dev))) 588ca5d21e9SSøren Schmidt return error; 589ca5d21e9SSøren Schmidt 590d53fc3e4SSøren Schmidt return ata_attach(dev); 591331c488dSSøren Schmidt } 592331c488dSSøren Schmidt 593d53fc3e4SSøren Schmidt static int 5945a5b148dSSøren Schmidt ata_pcichannel_detach(device_t dev) 595d53fc3e4SSøren Schmidt { 596d53fc3e4SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 597d53fc3e4SSøren Schmidt int error; 598d53fc3e4SSøren Schmidt 599d53fc3e4SSøren Schmidt if ((error = ata_detach(dev))) 600d53fc3e4SSøren Schmidt return error; 601d53fc3e4SSøren Schmidt 602d53fc3e4SSøren Schmidt if (ch->dma) 6030068f98fSSøren Schmidt ch->dma->free(dev); 604d53fc3e4SSøren Schmidt 605265da99cSSøren Schmidt /* XXX SOS free resources for io and ctlio ?? */ 606bbccd832SSøren Schmidt 607d53fc3e4SSøren Schmidt return 0; 608d53fc3e4SSøren Schmidt } 609d53fc3e4SSøren Schmidt 6105a5b148dSSøren Schmidt static int 6115a5b148dSSøren Schmidt ata_pcichannel_locking(device_t dev, int mode) 6125a5b148dSSøren Schmidt { 6135a5b148dSSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); 6145a5b148dSSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 6155a5b148dSSøren Schmidt 6165a5b148dSSøren Schmidt if (ctlr->locking) 6170068f98fSSøren Schmidt return ctlr->locking(dev, mode); 6185a5b148dSSøren Schmidt else 6195a5b148dSSøren Schmidt return ch->unit; 6205a5b148dSSøren Schmidt } 6215a5b148dSSøren Schmidt 6225a5b148dSSøren Schmidt static void 6235a5b148dSSøren Schmidt ata_pcichannel_reset(device_t dev) 6245a5b148dSSøren Schmidt { 6255a5b148dSSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); 6265a5b148dSSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 6275a5b148dSSøren Schmidt 628eeda55ceSSøren Schmidt /* if DMA engine present reset it */ 629b0a7e6a5SSøren Schmidt if (ch->dma) { 630eeda55ceSSøren Schmidt if (ch->dma->reset) 631eeda55ceSSøren Schmidt ch->dma->reset(dev); 6320068f98fSSøren Schmidt ch->dma->unload(dev); 633b0a7e6a5SSøren Schmidt } 634b0a7e6a5SSøren Schmidt 635b0a7e6a5SSøren Schmidt /* reset the controller HW */ 6365a5b148dSSøren Schmidt if (ctlr->reset) 6370068f98fSSøren Schmidt ctlr->reset(dev); 6388dad6b7bSSøren Schmidt else 6390068f98fSSøren Schmidt ata_generic_reset(dev); 6405a5b148dSSøren Schmidt } 6415a5b148dSSøren Schmidt 6425a5b148dSSøren Schmidt static void 6435a5b148dSSøren Schmidt ata_pcichannel_setmode(device_t parent, device_t dev) 6445a5b148dSSøren Schmidt { 6455a5b148dSSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(GRANDPARENT(dev)); 6465a5b148dSSøren Schmidt struct ata_device *atadev = device_get_softc(dev); 6475a5b148dSSøren Schmidt int mode = atadev->mode; 6485a5b148dSSøren Schmidt 6490068f98fSSøren Schmidt ctlr->setmode(dev, ATA_PIO_MAX); 6505a5b148dSSøren Schmidt if (mode >= ATA_DMA) 6510068f98fSSøren Schmidt ctlr->setmode(dev, mode); 6525a5b148dSSøren Schmidt } 6535a5b148dSSøren Schmidt 6545a5b148dSSøren Schmidt static device_method_t ata_pcichannel_methods[] = { 655331c488dSSøren Schmidt /* device interface */ 6565a5b148dSSøren Schmidt DEVMETHOD(device_probe, ata_pcichannel_probe), 6575a5b148dSSøren Schmidt DEVMETHOD(device_attach, ata_pcichannel_attach), 6585a5b148dSSøren Schmidt DEVMETHOD(device_detach, ata_pcichannel_detach), 6598ca4df32SSøren Schmidt DEVMETHOD(device_shutdown, bus_generic_shutdown), 660186ba2b7SSøren Schmidt DEVMETHOD(device_suspend, ata_suspend), 661186ba2b7SSøren Schmidt DEVMETHOD(device_resume, ata_resume), 6625a5b148dSSøren Schmidt 6635a5b148dSSøren Schmidt /* ATA methods */ 6645a5b148dSSøren Schmidt DEVMETHOD(ata_setmode, ata_pcichannel_setmode), 6655a5b148dSSøren Schmidt DEVMETHOD(ata_locking, ata_pcichannel_locking), 6665a5b148dSSøren Schmidt DEVMETHOD(ata_reset, ata_pcichannel_reset), 6675a5b148dSSøren Schmidt 668331c488dSSøren Schmidt { 0, 0 } 669331c488dSSøren Schmidt }; 670331c488dSSøren Schmidt 6715a5b148dSSøren Schmidt driver_t ata_pcichannel_driver = { 672331c488dSSøren Schmidt "ata", 6735a5b148dSSøren Schmidt ata_pcichannel_methods, 6746ddce903SSøren Schmidt sizeof(struct ata_channel), 675331c488dSSøren Schmidt }; 676331c488dSSøren Schmidt 6775a5b148dSSøren Schmidt DRIVER_MODULE(ata, atapci, ata_pcichannel_driver, ata_devclass, 0, 0); 678