1331c488dSSøren Schmidt /*- 28ca4df32SSøren Schmidt * Copyright (c) 1998 - 2005 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 29aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 30aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 31aad970f1SDavid E. O'Brien 327800211bSSøren Schmidt #include "opt_ata.h" 33331c488dSSøren Schmidt #include <sys/param.h> 34331c488dSSøren Schmidt #include <sys/systm.h> 35331c488dSSøren Schmidt #include <sys/kernel.h> 36331c488dSSøren Schmidt #include <sys/module.h> 378ca4df32SSøren Schmidt #include <sys/ata.h> 38331c488dSSøren Schmidt #include <sys/bus.h> 39331c488dSSøren Schmidt #include <sys/malloc.h> 40a7a120f6SSøren Schmidt #include <sys/sema.h> 415fdbb0d2SSøren Schmidt #include <sys/taskqueue.h> 425df3ca78SSøren Schmidt #include <vm/uma.h> 43331c488dSSøren Schmidt #include <machine/stdarg.h> 44331c488dSSøren Schmidt #include <machine/resource.h> 45331c488dSSøren Schmidt #include <machine/bus.h> 46331c488dSSøren Schmidt #ifdef __alpha__ 47331c488dSSøren Schmidt #include <machine/md_var.h> 48331c488dSSøren Schmidt #endif 49331c488dSSøren Schmidt #include <sys/rman.h> 504fbd232cSWarner Losh #include <dev/pci/pcivar.h> 514fbd232cSWarner Losh #include <dev/pci/pcireg.h> 52331c488dSSøren Schmidt #include <dev/ata/ata-all.h> 53bb5bdd38SSøren Schmidt #include <dev/ata/ata-pci.h> 548ca4df32SSøren Schmidt #include <ata_if.h> 55331c488dSSøren Schmidt 56bb5bdd38SSøren Schmidt /* local vars */ 57bb5bdd38SSøren Schmidt static MALLOC_DEFINE(M_ATAPCI, "ATA PCI", "ATA driver PCI"); 58331c488dSSøren Schmidt 5972c2f499SSøren Schmidt /* misc defines */ 6072c2f499SSøren Schmidt #define IOMASK 0xfffffffc 6172c2f499SSøren Schmidt 62bb5bdd38SSøren Schmidt /* prototypes */ 638ca4df32SSøren Schmidt static int ata_pci_allocate(device_t dev, struct ata_channel *ch); 646419d0b0SSøren Schmidt static void ata_pci_dmainit(struct ata_channel *); 65331c488dSSøren Schmidt 664ee3fbe8SSøren Schmidt int 674ee3fbe8SSøren Schmidt ata_legacy(device_t dev) 684ee3fbe8SSøren Schmidt { 694ee3fbe8SSøren Schmidt return ((pci_read_config(dev, PCIR_PROGIF, 1)&PCIP_STORAGE_IDE_MASTERDEV) && 704ee3fbe8SSøren Schmidt ((pci_read_config(dev, PCIR_PROGIF, 1) & 714ee3fbe8SSøren Schmidt (PCIP_STORAGE_IDE_MODEPRIM | PCIP_STORAGE_IDE_MODESEC)) != 724ee3fbe8SSøren Schmidt (PCIP_STORAGE_IDE_MODEPRIM | PCIP_STORAGE_IDE_MODESEC))); 734ee3fbe8SSøren Schmidt } 744ee3fbe8SSøren Schmidt 758ca4df32SSøren Schmidt int 76331c488dSSøren Schmidt ata_pci_probe(device_t dev) 77331c488dSSøren Schmidt { 78bb5bdd38SSøren Schmidt if (pci_get_class(dev) != PCIC_STORAGE) 79331c488dSSøren Schmidt return ENXIO; 80331c488dSSøren Schmidt 81bb5bdd38SSøren Schmidt switch (pci_get_vendor(dev)) { 82bb5bdd38SSøren Schmidt case ATA_ACARD_ID: 8345f13b84SSøren Schmidt if (!ata_acard_ident(dev)) 8445f13b84SSøren Schmidt return 0; 8545f13b84SSøren Schmidt break; 86bb5bdd38SSøren Schmidt case ATA_ACER_LABS_ID: 8745f13b84SSøren Schmidt if (!ata_ali_ident(dev)) 8845f13b84SSøren Schmidt return 0; 8945f13b84SSøren Schmidt break; 90bb5bdd38SSøren Schmidt case ATA_AMD_ID: 9145f13b84SSøren Schmidt if (!ata_amd_ident(dev)) 9245f13b84SSøren Schmidt return 0; 9345f13b84SSøren Schmidt break; 94bb5bdd38SSøren Schmidt case ATA_CYRIX_ID: 9545f13b84SSøren Schmidt if (!ata_cyrix_ident(dev)) 9645f13b84SSøren Schmidt return 0; 9745f13b84SSøren Schmidt break; 98bb5bdd38SSøren Schmidt case ATA_CYPRESS_ID: 9945f13b84SSøren Schmidt if (!ata_cypress_ident(dev)) 10045f13b84SSøren Schmidt return 0; 10145f13b84SSøren Schmidt break; 102bb5bdd38SSøren Schmidt case ATA_HIGHPOINT_ID: 10345f13b84SSøren Schmidt if (!ata_highpoint_ident(dev)) 10445f13b84SSøren Schmidt return 0; 10545f13b84SSøren Schmidt break; 106bb5bdd38SSøren Schmidt case ATA_INTEL_ID: 10745f13b84SSøren Schmidt if (!ata_intel_ident(dev)) 10845f13b84SSøren Schmidt return 0; 10945f13b84SSøren Schmidt break; 11088bdf804SSøren Schmidt case ATA_ITE_ID: 11188bdf804SSøren Schmidt if (!ata_ite_ident(dev)) 11288bdf804SSøren Schmidt return 0; 11388bdf804SSøren Schmidt break; 114a5cd71eeSSøren Schmidt case ATA_NATIONAL_ID: 115a5cd71eeSSøren Schmidt if (!ata_national_ident(dev)) 116a5cd71eeSSøren Schmidt return 0; 117a5cd71eeSSøren Schmidt break; 118bb5bdd38SSøren Schmidt case ATA_NVIDIA_ID: 11945f13b84SSøren Schmidt if (!ata_nvidia_ident(dev)) 12045f13b84SSøren Schmidt return 0; 12145f13b84SSøren Schmidt break; 122bb5bdd38SSøren Schmidt case ATA_PROMISE_ID: 12345f13b84SSøren Schmidt if (!ata_promise_ident(dev)) 12445f13b84SSøren Schmidt return 0; 12545f13b84SSøren Schmidt break; 126bb5bdd38SSøren Schmidt case ATA_SERVERWORKS_ID: 12745f13b84SSøren Schmidt if (!ata_serverworks_ident(dev)) 12845f13b84SSøren Schmidt return 0; 12945f13b84SSøren Schmidt break; 130bb5bdd38SSøren Schmidt case ATA_SILICON_IMAGE_ID: 13145f13b84SSøren Schmidt if (!ata_sii_ident(dev)) 13245f13b84SSøren Schmidt return 0; 13345f13b84SSøren Schmidt break; 134bb5bdd38SSøren Schmidt case ATA_SIS_ID: 13545f13b84SSøren Schmidt if (!ata_sis_ident(dev)) 13645f13b84SSøren Schmidt return 0; 13745f13b84SSøren Schmidt break; 138bb5bdd38SSøren Schmidt case ATA_VIA_ID: 13945f13b84SSøren Schmidt if (!ata_via_ident(dev)) 14045f13b84SSøren Schmidt return 0; 14145f13b84SSøren Schmidt break; 14288bdf804SSøren Schmidt case ATA_CENATEK_ID: 14388bdf804SSøren Schmidt if (pci_get_devid(dev) == ATA_CENATEK_ROCKET) { 144566cf07aSSøren Schmidt ata_generic_ident(dev); 145bb5bdd38SSøren Schmidt device_set_desc(dev, "Cenatek Rocket Drive controller"); 146331c488dSSøren Schmidt return 0; 147331c488dSSøren Schmidt } 14845f13b84SSøren Schmidt break; 14988bdf804SSøren Schmidt case ATA_MICRON_ID: 15088bdf804SSøren Schmidt if (pci_get_devid(dev) == ATA_MICRON_RZ1000 || 15188bdf804SSøren Schmidt pci_get_devid(dev) == ATA_MICRON_RZ1001) { 152566cf07aSSøren Schmidt ata_generic_ident(dev); 153bb5bdd38SSøren Schmidt device_set_desc(dev, 15488bdf804SSøren Schmidt "RZ 100? ATA controller !WARNING! data loss/corruption risk"); 155bb5bdd38SSøren Schmidt return 0; 156bb5bdd38SSøren Schmidt } 15745f13b84SSøren Schmidt break; 15845f13b84SSøren Schmidt } 159bb5bdd38SSøren Schmidt 160bb5bdd38SSøren Schmidt /* unknown chipset, try generic DMA if it seems possible */ 16145f13b84SSøren Schmidt if ((pci_get_class(dev) == PCIC_STORAGE) && 162bb5bdd38SSøren Schmidt (pci_get_subclass(dev) == PCIS_STORAGE_IDE)) 163bb5bdd38SSøren Schmidt return ata_generic_ident(dev); 16445f13b84SSøren Schmidt 165bb5bdd38SSøren Schmidt return ENXIO; 166bb5bdd38SSøren Schmidt } 167331c488dSSøren Schmidt 1688ca4df32SSøren Schmidt int 169331c488dSSøren Schmidt ata_pci_attach(device_t dev) 170331c488dSSøren Schmidt { 171566cf07aSSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(dev); 172498e5543SSøren Schmidt u_int32_t cmd; 1731b7cfe44SSøren Schmidt int unit; 174331c488dSSøren Schmidt 175566cf07aSSøren Schmidt /* do chipset specific setups only needed once */ 1766230b63cSSøren Schmidt if (ata_legacy(dev) || pci_read_config(dev, PCIR_BAR(2), 4) & IOMASK) 177566cf07aSSøren Schmidt ctlr->channels = 2; 178566cf07aSSøren Schmidt else 179566cf07aSSøren Schmidt ctlr->channels = 1; 180566cf07aSSøren Schmidt ctlr->allocate = ata_pci_allocate; 181566cf07aSSøren Schmidt ctlr->dmainit = ata_pci_dmainit; 1828ca4df32SSøren Schmidt ctlr->dev = dev; 183566cf07aSSøren Schmidt 184498e5543SSøren Schmidt /* if needed try to enable busmastering */ 185498e5543SSøren Schmidt cmd = pci_read_config(dev, PCIR_COMMAND, 2); 1867800211bSSøren Schmidt if (!(cmd & PCIM_CMD_BUSMASTEREN)) { 1877800211bSSøren Schmidt pci_write_config(dev, PCIR_COMMAND, cmd | PCIM_CMD_BUSMASTEREN, 2); 1887800211bSSøren Schmidt cmd = pci_read_config(dev, PCIR_COMMAND, 2); 1897800211bSSøren Schmidt } 190331c488dSSøren Schmidt 191498e5543SSøren Schmidt /* if busmastering mode "stuck" use it */ 192498e5543SSøren Schmidt if ((cmd & PCIM_CMD_BUSMASTEREN) == PCIM_CMD_BUSMASTEREN) { 193498e5543SSøren Schmidt ctlr->r_type1 = SYS_RES_IOPORT; 194498e5543SSøren Schmidt ctlr->r_rid1 = ATA_BMADDR_RID; 1955f96beb9SNate Lawson ctlr->r_res1 = bus_alloc_resource_any(dev, ctlr->r_type1, &ctlr->r_rid1, 1965f96beb9SNate Lawson RF_ACTIVE); 197331c488dSSøren Schmidt } 198331c488dSSøren Schmidt 199c2833977SSøren Schmidt ctlr->chipinit(dev); 200c2833977SSøren Schmidt 201566cf07aSSøren Schmidt /* attach all channels on this controller */ 2026230b63cSSøren Schmidt for (unit = 0; unit < ctlr->channels; unit++) { 2036230b63cSSøren Schmidt if (unit == 0 && (pci_get_progif(dev) & 0x81) == 0x80) { 2046230b63cSSøren Schmidt device_add_child(dev, "ata", unit); 2056230b63cSSøren Schmidt continue; 2066230b63cSSøren Schmidt } 2076230b63cSSøren Schmidt if (unit == 1 && (pci_get_progif(dev) & 0x84) == 0x80) { 2086230b63cSSøren Schmidt device_add_child(dev, "ata", unit); 2096230b63cSSøren Schmidt continue; 2106230b63cSSøren Schmidt } 2116230b63cSSøren Schmidt device_add_child(dev, "ata", devclass_find_free_unit(ata_devclass, 2)); 2126230b63cSSøren Schmidt } 2138ca4df32SSøren Schmidt bus_generic_attach(dev); 2148ca4df32SSøren Schmidt return 0; 215f2972d7eSSøren Schmidt } 216498e5543SSøren Schmidt 2178ca4df32SSøren Schmidt int 218498e5543SSøren Schmidt ata_pci_detach(device_t dev) 219498e5543SSøren Schmidt { 220498e5543SSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(dev); 2218ca4df32SSøren Schmidt device_t *children; 2228ca4df32SSøren Schmidt int nchildren, i; 223498e5543SSøren Schmidt 2248ca4df32SSøren Schmidt /* detach & delete all children */ 2258ca4df32SSøren Schmidt if (!device_get_children(dev, &children, &nchildren)) { 2268ca4df32SSøren Schmidt for (i = 0; i < nchildren; i++) 2278ca4df32SSøren Schmidt device_delete_child(dev, children[i]); 2288ca4df32SSøren Schmidt free(children, M_TEMP); 229331c488dSSøren Schmidt } 230331c488dSSøren Schmidt 231498e5543SSøren Schmidt if (ctlr->r_irq) { 232498e5543SSøren Schmidt bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle); 233498e5543SSøren Schmidt bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ctlr->r_irq); 234498e5543SSøren Schmidt } 235498e5543SSøren Schmidt if (ctlr->r_res2) 236498e5543SSøren Schmidt bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2); 237498e5543SSøren Schmidt if (ctlr->r_res1) 238498e5543SSøren Schmidt bus_release_resource(dev, ctlr->r_type1, ctlr->r_rid1, ctlr->r_res1); 239498e5543SSøren Schmidt 240498e5543SSøren Schmidt return 0; 241498e5543SSøren Schmidt } 242331c488dSSøren Schmidt 2438ca4df32SSøren Schmidt struct resource * 244331c488dSSøren Schmidt ata_pci_alloc_resource(device_t dev, device_t child, int type, int *rid, 245331c488dSSøren Schmidt u_long start, u_long end, u_long count, u_int flags) 246331c488dSSøren Schmidt { 2476ddce903SSøren Schmidt struct ata_pci_controller *controller = device_get_softc(dev); 2486ddce903SSøren Schmidt int unit = ((struct ata_channel *)device_get_softc(child))->unit; 249bb5bdd38SSøren Schmidt struct resource *res = NULL; 250331c488dSSøren Schmidt int myrid; 251331c488dSSøren Schmidt 252331c488dSSøren Schmidt if (type == SYS_RES_IOPORT) { 253331c488dSSøren Schmidt switch (*rid) { 254331c488dSSøren Schmidt case ATA_IOADDR_RID: 2554ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 2566ddce903SSøren Schmidt start = (unit ? ATA_SECONDARY : ATA_PRIMARY); 257331c488dSSøren Schmidt count = ATA_IOSIZE; 258f2972d7eSSøren Schmidt end = start + count - 1; 259331c488dSSøren Schmidt } 2606230b63cSSøren Schmidt myrid = PCIR_BAR(0) + (unit << 3); 261331c488dSSøren Schmidt res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, 262331c488dSSøren Schmidt SYS_RES_IOPORT, &myrid, 263331c488dSSøren Schmidt start, end, count, flags); 264331c488dSSøren Schmidt break; 265331c488dSSøren Schmidt 266331c488dSSøren Schmidt case ATA_ALTADDR_RID: 2674ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 268470fcc93SSøren Schmidt start = (unit ? ATA_SECONDARY : ATA_PRIMARY) + ATA_ALTOFFSET; 269470fcc93SSøren Schmidt count = ATA_ALTIOSIZE; 270f2972d7eSSøren Schmidt end = start + count - 1; 271331c488dSSøren Schmidt } 2726230b63cSSøren Schmidt myrid = PCIR_BAR(1) + (unit << 3); 273331c488dSSøren Schmidt res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, 274331c488dSSøren Schmidt SYS_RES_IOPORT, &myrid, 275331c488dSSøren Schmidt start, end, count, flags); 276331c488dSSøren Schmidt break; 277331c488dSSøren Schmidt } 278331c488dSSøren Schmidt return res; 279331c488dSSøren Schmidt } 280331c488dSSøren Schmidt 281331c488dSSøren Schmidt if (type == SYS_RES_IRQ && *rid == ATA_IRQ_RID) { 2824ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 283331c488dSSøren Schmidt #ifdef __alpha__ 2846ddce903SSøren Schmidt return alpha_platform_alloc_ide_intr(unit); 285331c488dSSøren Schmidt #else 2866ddce903SSøren Schmidt int irq = (unit == 0 ? 14 : 15); 287331c488dSSøren Schmidt 288331c488dSSøren Schmidt return BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 289468fe0fdSSøren Schmidt SYS_RES_IRQ, rid, irq, irq, 1, flags); 290331c488dSSøren Schmidt #endif 291331c488dSSøren Schmidt } 292331c488dSSøren Schmidt else { 293bb5bdd38SSøren Schmidt return controller->r_irq; 294331c488dSSøren Schmidt } 295331c488dSSøren Schmidt } 296331c488dSSøren Schmidt return 0; 297331c488dSSøren Schmidt } 298331c488dSSøren Schmidt 2998ca4df32SSøren Schmidt int 300331c488dSSøren Schmidt ata_pci_release_resource(device_t dev, device_t child, int type, int rid, 301331c488dSSøren Schmidt struct resource *r) 302331c488dSSøren Schmidt { 3036ddce903SSøren Schmidt int unit = ((struct ata_channel *)device_get_softc(child))->unit; 304331c488dSSøren Schmidt 305331c488dSSøren Schmidt if (type == SYS_RES_IOPORT) { 306331c488dSSøren Schmidt switch (rid) { 307331c488dSSøren Schmidt case ATA_IOADDR_RID: 308b5a5e99dSSøren Schmidt return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, 3096230b63cSSøren Schmidt SYS_RES_IOPORT, 3106230b63cSSøren Schmidt PCIR_BAR(0) + (unit << 3), r); 311331c488dSSøren Schmidt break; 312331c488dSSøren Schmidt 313331c488dSSøren Schmidt case ATA_ALTADDR_RID: 314b5a5e99dSSøren Schmidt return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, 3156230b63cSSøren Schmidt SYS_RES_IOPORT, 3166230b63cSSøren Schmidt PCIR_BAR(1) + (unit << 3), r); 317331c488dSSøren Schmidt break; 318331c488dSSøren Schmidt default: 319331c488dSSøren Schmidt return ENOENT; 320331c488dSSøren Schmidt } 321331c488dSSøren Schmidt } 322331c488dSSøren Schmidt if (type == SYS_RES_IRQ) { 323331c488dSSøren Schmidt if (rid != ATA_IRQ_RID) 324331c488dSSøren Schmidt return ENOENT; 325331c488dSSøren Schmidt 3264ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 327331c488dSSøren Schmidt #ifdef __alpha__ 3286ddce903SSøren Schmidt return alpha_platform_release_ide_intr(unit, r); 329331c488dSSøren Schmidt #else 330b5a5e99dSSøren Schmidt return BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 331b5a5e99dSSøren Schmidt SYS_RES_IRQ, rid, r); 332331c488dSSøren Schmidt #endif 333331c488dSSøren Schmidt } 334bb5bdd38SSøren Schmidt else 335331c488dSSøren Schmidt return 0; 336331c488dSSøren Schmidt } 337331c488dSSøren Schmidt return EINVAL; 338331c488dSSøren Schmidt } 339331c488dSSøren Schmidt 3408ca4df32SSøren Schmidt int 341331c488dSSøren Schmidt ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq, 342bb5bdd38SSøren Schmidt int flags, driver_intr_t *function, void *argument, 343331c488dSSøren Schmidt void **cookiep) 344331c488dSSøren Schmidt { 3454ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 346331c488dSSøren Schmidt #ifdef __alpha__ 347bb5bdd38SSøren Schmidt return alpha_platform_setup_ide_intr(child, irq, function, argument, 348bb5bdd38SSøren Schmidt cookiep); 349331c488dSSøren Schmidt #else 350331c488dSSøren Schmidt return BUS_SETUP_INTR(device_get_parent(dev), child, irq, 351bb5bdd38SSøren Schmidt flags, function, argument, cookiep); 352331c488dSSøren Schmidt #endif 353331c488dSSøren Schmidt } 354bb5bdd38SSøren Schmidt else { 355bb5bdd38SSøren Schmidt struct ata_pci_controller *controller = device_get_softc(dev); 356bb5bdd38SSøren Schmidt int unit = ((struct ata_channel *)device_get_softc(child))->unit; 357bb5bdd38SSøren Schmidt 358bb5bdd38SSøren Schmidt controller->interrupt[unit].function = function; 359bb5bdd38SSøren Schmidt controller->interrupt[unit].argument = argument; 360bb5bdd38SSøren Schmidt *cookiep = controller; 361bb5bdd38SSøren Schmidt return 0; 362bb5bdd38SSøren Schmidt } 363331c488dSSøren Schmidt } 364331c488dSSøren Schmidt 3658ca4df32SSøren Schmidt int 366331c488dSSøren Schmidt ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, 367331c488dSSøren Schmidt void *cookie) 368331c488dSSøren Schmidt { 3694ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 370331c488dSSøren Schmidt #ifdef __alpha__ 371331c488dSSøren Schmidt return alpha_platform_teardown_ide_intr(child, irq, cookie); 372331c488dSSøren Schmidt #else 373331c488dSSøren Schmidt return BUS_TEARDOWN_INTR(device_get_parent(dev), child, irq, cookie); 374331c488dSSøren Schmidt #endif 375331c488dSSøren Schmidt } 3762e6c2a10SSøren Schmidt else { 3772e6c2a10SSøren Schmidt struct ata_pci_controller *controller = device_get_softc(dev); 3782e6c2a10SSøren Schmidt int unit = ((struct ata_channel *)device_get_softc(child))->unit; 3792e6c2a10SSøren Schmidt 3802e6c2a10SSøren Schmidt controller->interrupt[unit].function = NULL; 3812e6c2a10SSøren Schmidt controller->interrupt[unit].argument = NULL; 382bb5bdd38SSøren Schmidt return 0; 383331c488dSSøren Schmidt } 3842e6c2a10SSøren Schmidt } 385331c488dSSøren Schmidt 386566cf07aSSøren Schmidt static int 387566cf07aSSøren Schmidt ata_pci_allocate(device_t dev, struct ata_channel *ch) 388566cf07aSSøren Schmidt { 389566cf07aSSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); 390566cf07aSSøren Schmidt struct resource *io = NULL, *altio = NULL; 391566cf07aSSøren Schmidt int i, rid; 392566cf07aSSøren Schmidt 393566cf07aSSøren Schmidt rid = ATA_IOADDR_RID; 394566cf07aSSøren Schmidt io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 395566cf07aSSøren Schmidt 0, ~0, ATA_IOSIZE, RF_ACTIVE); 396566cf07aSSøren Schmidt if (!io) 397566cf07aSSøren Schmidt return ENXIO; 398566cf07aSSøren Schmidt 399566cf07aSSøren Schmidt rid = ATA_ALTADDR_RID; 400566cf07aSSøren Schmidt altio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 401566cf07aSSøren Schmidt 0, ~0, ATA_ALTIOSIZE, RF_ACTIVE); 402566cf07aSSøren Schmidt if (!altio) { 403566cf07aSSøren Schmidt bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, io); 404566cf07aSSøren Schmidt return ENXIO; 405566cf07aSSøren Schmidt } 406566cf07aSSøren Schmidt 407566cf07aSSøren Schmidt for (i = ATA_DATA; i <= ATA_STATUS; i ++) { 408566cf07aSSøren Schmidt ch->r_io[i].res = io; 409566cf07aSSøren Schmidt ch->r_io[i].offset = i; 410566cf07aSSøren Schmidt } 411566cf07aSSøren Schmidt ch->r_io[ATA_ALTSTAT].res = altio; 4124ee3fbe8SSøren Schmidt ch->r_io[ATA_ALTSTAT].offset = ata_legacy(device_get_parent(dev)) ? 0 : 2; 4131b39bd24SSøren Schmidt ch->r_io[ATA_IDX_ADDR].res = io; 414566cf07aSSøren Schmidt 415498e5543SSøren Schmidt if (ctlr->r_res1) { 416566cf07aSSøren Schmidt for (i = ATA_BMCMD_PORT; i <= ATA_BMDTP_PORT; i++) { 417498e5543SSøren Schmidt ch->r_io[i].res = ctlr->r_res1; 418566cf07aSSøren Schmidt ch->r_io[i].offset = (i - ATA_BMCMD_PORT)+(ch->unit * ATA_BMIOSIZE); 419566cf07aSSøren Schmidt } 420566cf07aSSøren Schmidt } 421f2972d7eSSøren Schmidt 422f2972d7eSSøren Schmidt ata_generic_hw(ch); 423f2972d7eSSøren Schmidt 424566cf07aSSøren Schmidt return 0; 425566cf07aSSøren Schmidt } 426566cf07aSSøren Schmidt 4278ca4df32SSøren Schmidt static void 4288ca4df32SSøren Schmidt ata_pci_setmode(device_t parent, device_t dev) 4298ca4df32SSøren Schmidt { 4308ca4df32SSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(parent); 4318ca4df32SSøren Schmidt struct ata_device *atadev = device_get_softc(dev); 4328ca4df32SSøren Schmidt int mode = atadev->mode; 4338ca4df32SSøren Schmidt 4348ca4df32SSøren Schmidt ctlr->setmode(atadev, ATA_PIO_MAX); 4358ca4df32SSøren Schmidt if (mode >= ATA_DMA) 4368ca4df32SSøren Schmidt ctlr->setmode(atadev, mode); 4378ca4df32SSøren Schmidt } 4388ca4df32SSøren Schmidt 4398ca4df32SSøren Schmidt static int 4408ca4df32SSøren Schmidt ata_pci_locking(device_t parent, device_t dev, int mode) 4418ca4df32SSøren Schmidt { 4428ca4df32SSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(parent); 4438ca4df32SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 4448ca4df32SSøren Schmidt 4458ca4df32SSøren Schmidt if (ctlr->locking) 4468ca4df32SSøren Schmidt return ctlr->locking(ch, mode); 4478ca4df32SSøren Schmidt else 4488ca4df32SSøren Schmidt return ch->unit; 4498ca4df32SSøren Schmidt } 4508ca4df32SSøren Schmidt 4518ca4df32SSøren Schmidt static void 4528ca4df32SSøren Schmidt ata_pci_reset(device_t parent, device_t dev) 4538ca4df32SSøren Schmidt { 4548ca4df32SSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(parent); 4558ca4df32SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 4568ca4df32SSøren Schmidt 4578ca4df32SSøren Schmidt if (ctlr->reset) 4588ca4df32SSøren Schmidt ctlr->reset(ch); 4598ca4df32SSøren Schmidt } 4608ca4df32SSøren Schmidt 461566cf07aSSøren Schmidt static int 46280344be5SSøren Schmidt ata_pci_dmastart(struct ata_channel *ch) 463566cf07aSSøren Schmidt { 464566cf07aSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) | 465566cf07aSSøren Schmidt (ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR))); 4668ca4df32SSøren Schmidt ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->sg_bus); 467c5b2c44cSSøren Schmidt ch->dma->flags |= ATA_DMA_ACTIVE; 468566cf07aSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, 46945bf968aSSøren Schmidt (ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_WRITE_READ) | 47080344be5SSøren Schmidt ((ch->dma->flags & ATA_DMA_READ) ? ATA_BMCMD_WRITE_READ : 0) | 47180344be5SSøren Schmidt ATA_BMCMD_START_STOP); 472566cf07aSSøren Schmidt return 0; 473566cf07aSSøren Schmidt } 474566cf07aSSøren Schmidt 475566cf07aSSøren Schmidt static int 476566cf07aSSøren Schmidt ata_pci_dmastop(struct ata_channel *ch) 477566cf07aSSøren Schmidt { 478566cf07aSSøren Schmidt int error; 479566cf07aSSøren Schmidt 480566cf07aSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, 481566cf07aSSøren Schmidt ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP); 4827e6d7588SSøren Schmidt ch->dma->flags &= ~ATA_DMA_ACTIVE; 483c5b2c44cSSøren Schmidt error = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; 484566cf07aSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR); 4855fdbb0d2SSøren Schmidt return error; 486566cf07aSSøren Schmidt } 487566cf07aSSøren Schmidt 4886419d0b0SSøren Schmidt static void 489566cf07aSSøren Schmidt ata_pci_dmainit(struct ata_channel *ch) 490566cf07aSSøren Schmidt { 4916419d0b0SSøren Schmidt ata_dmainit(ch); 4926419d0b0SSøren Schmidt if (ch->dma) { 493566cf07aSSøren Schmidt ch->dma->start = ata_pci_dmastart; 494566cf07aSSøren Schmidt ch->dma->stop = ata_pci_dmastop; 4956419d0b0SSøren Schmidt } 496566cf07aSSøren Schmidt } 497566cf07aSSøren Schmidt 498331c488dSSøren Schmidt static device_method_t ata_pci_methods[] = { 499331c488dSSøren Schmidt /* device interface */ 500331c488dSSøren Schmidt DEVMETHOD(device_probe, ata_pci_probe), 501331c488dSSøren Schmidt DEVMETHOD(device_attach, ata_pci_attach), 502498e5543SSøren Schmidt DEVMETHOD(device_detach, ata_pci_detach), 503331c488dSSøren Schmidt DEVMETHOD(device_shutdown, bus_generic_shutdown), 504331c488dSSøren Schmidt DEVMETHOD(device_suspend, bus_generic_suspend), 505331c488dSSøren Schmidt DEVMETHOD(device_resume, bus_generic_resume), 506331c488dSSøren Schmidt 507331c488dSSøren Schmidt /* bus methods */ 508331c488dSSøren Schmidt DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource), 509331c488dSSøren Schmidt DEVMETHOD(bus_release_resource, ata_pci_release_resource), 510331c488dSSøren Schmidt DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 511331c488dSSøren Schmidt DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 512331c488dSSøren Schmidt DEVMETHOD(bus_setup_intr, ata_pci_setup_intr), 513331c488dSSøren Schmidt DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr), 5148ca4df32SSøren Schmidt 5158ca4df32SSøren Schmidt /* ATA methods */ 5168ca4df32SSøren Schmidt DEVMETHOD(ata_setmode, ata_pci_setmode), 5178ca4df32SSøren Schmidt DEVMETHOD(ata_locking, ata_pci_locking), 5188ca4df32SSøren Schmidt DEVMETHOD(ata_reset, ata_pci_reset), 519331c488dSSøren Schmidt { 0, 0 } 520331c488dSSøren Schmidt }; 521331c488dSSøren Schmidt 5228ca4df32SSøren Schmidt devclass_t atapci_devclass; 5238ca4df32SSøren Schmidt 524331c488dSSøren Schmidt static driver_t ata_pci_driver = { 525331c488dSSøren Schmidt "atapci", 526331c488dSSøren Schmidt ata_pci_methods, 5276ddce903SSøren Schmidt sizeof(struct ata_pci_controller), 528331c488dSSøren Schmidt }; 529331c488dSSøren Schmidt 5308ca4df32SSøren Schmidt DRIVER_MODULE(atapci, pci, ata_pci_driver, atapci_devclass, 0, 0); 5318ca4df32SSøren Schmidt MODULE_VERSION(atapci, 1); 5328ca4df32SSøren Schmidt MODULE_DEPEND(atapci, ata, 1, 1, 1); 533331c488dSSøren Schmidt 534331c488dSSøren Schmidt static int 535d53fc3e4SSøren Schmidt ata_channel_probe(device_t dev) 536331c488dSSøren Schmidt { 5376ddce903SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 538331c488dSSøren Schmidt device_t *children; 539d53fc3e4SSøren Schmidt int count, i; 5408ca4df32SSøren Schmidt char buffer[32]; 541331c488dSSøren Schmidt 542498e5543SSøren Schmidt /* take care of green memory */ 543498e5543SSøren Schmidt bzero(ch, sizeof(struct ata_channel)); 544498e5543SSøren Schmidt 545331c488dSSøren Schmidt /* find channel number on this controller */ 546331c488dSSøren Schmidt device_get_children(device_get_parent(dev), &children, &count); 547331c488dSSøren Schmidt for (i = 0; i < count; i++) { 548331c488dSSøren Schmidt if (children[i] == dev) 5496ddce903SSøren Schmidt ch->unit = i; 550331c488dSSøren Schmidt } 551331c488dSSøren Schmidt free(children, M_TEMP); 5528ba4488cSSøren Schmidt 5538ca4df32SSøren Schmidt sprintf(buffer, "ATA channel %d", ch->unit); 5548ca4df32SSøren Schmidt device_set_desc_copy(dev, buffer); 5558ca4df32SSøren Schmidt 556d53fc3e4SSøren Schmidt return ata_probe(dev); 557d53fc3e4SSøren Schmidt } 558d53fc3e4SSøren Schmidt 559d53fc3e4SSøren Schmidt static int 560d53fc3e4SSøren Schmidt ata_channel_attach(device_t dev) 561d53fc3e4SSøren Schmidt { 562d53fc3e4SSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); 563d53fc3e4SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 564d53fc3e4SSøren Schmidt int error; 565d53fc3e4SSøren Schmidt 566d04d7894SSøren Schmidt if (ctlr->r_res1) 567d53fc3e4SSøren Schmidt ctlr->dmainit(ch); 568d53fc3e4SSøren Schmidt if (ch->dma) 569d53fc3e4SSøren Schmidt ch->dma->alloc(ch); 570d53fc3e4SSøren Schmidt 571ca5d21e9SSøren Schmidt if ((error = ctlr->allocate(dev, ch))) 572ca5d21e9SSøren Schmidt return error; 573ca5d21e9SSøren Schmidt 574d53fc3e4SSøren Schmidt return ata_attach(dev); 575331c488dSSøren Schmidt } 576331c488dSSøren Schmidt 577d53fc3e4SSøren Schmidt static int 578d53fc3e4SSøren Schmidt ata_channel_detach(device_t dev) 579d53fc3e4SSøren Schmidt { 580d53fc3e4SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 581d53fc3e4SSøren Schmidt int error; 582d53fc3e4SSøren Schmidt 583d53fc3e4SSøren Schmidt if ((error = ata_detach(dev))) 584d53fc3e4SSøren Schmidt return error; 585d53fc3e4SSøren Schmidt 586d53fc3e4SSøren Schmidt if (ch->dma) 587d53fc3e4SSøren Schmidt ch->dma->free(ch); 588d53fc3e4SSøren Schmidt 589d53fc3e4SSøren Schmidt return 0; 590d53fc3e4SSøren Schmidt } 591d53fc3e4SSøren Schmidt 592d53fc3e4SSøren Schmidt static device_method_t ata_channel_methods[] = { 593331c488dSSøren Schmidt /* device interface */ 594d53fc3e4SSøren Schmidt DEVMETHOD(device_probe, ata_channel_probe), 595d53fc3e4SSøren Schmidt DEVMETHOD(device_attach, ata_channel_attach), 596d53fc3e4SSøren Schmidt DEVMETHOD(device_detach, ata_channel_detach), 5978ca4df32SSøren Schmidt DEVMETHOD(device_shutdown, bus_generic_shutdown), 5988ca4df32SSøren Schmidt DEVMETHOD(device_suspend, bus_generic_suspend), 5998ca4df32SSøren Schmidt DEVMETHOD(device_resume, bus_generic_resume), 600331c488dSSøren Schmidt { 0, 0 } 601331c488dSSøren Schmidt }; 602331c488dSSøren Schmidt 6038ca4df32SSøren Schmidt driver_t ata_channel_driver = { 604331c488dSSøren Schmidt "ata", 605d53fc3e4SSøren Schmidt ata_channel_methods, 6066ddce903SSøren Schmidt sizeof(struct ata_channel), 607331c488dSSøren Schmidt }; 608331c488dSSøren Schmidt 609d53fc3e4SSøren Schmidt DRIVER_MODULE(ata, atapci, ata_channel_driver, ata_devclass, 0, 0); 610