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 */ 63bbccd832SSøren Schmidt static int ata_pci_allocate(device_t dev); 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 } 279331c488dSSøren Schmidt 280331c488dSSøren Schmidt if (type == SYS_RES_IRQ && *rid == ATA_IRQ_RID) { 2814ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 282331c488dSSøren Schmidt #ifdef __alpha__ 283bbccd832SSøren Schmidt res = alpha_platform_alloc_ide_intr(unit); 284331c488dSSøren Schmidt #else 2856ddce903SSøren Schmidt int irq = (unit == 0 ? 14 : 15); 286331c488dSSøren Schmidt 287bbccd832SSøren Schmidt res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 288468fe0fdSSøren Schmidt SYS_RES_IRQ, rid, irq, irq, 1, flags); 289331c488dSSøren Schmidt #endif 290331c488dSSøren Schmidt } 291bbccd832SSøren Schmidt else 292bbccd832SSøren Schmidt res = controller->r_irq; 293331c488dSSøren Schmidt } 294bbccd832SSøren Schmidt 295bbccd832SSøren Schmidt return res; 296331c488dSSøren Schmidt } 297331c488dSSøren Schmidt 2988ca4df32SSøren Schmidt int 299331c488dSSøren Schmidt ata_pci_release_resource(device_t dev, device_t child, int type, int rid, 300331c488dSSøren Schmidt struct resource *r) 301331c488dSSøren Schmidt { 3026ddce903SSøren Schmidt int unit = ((struct ata_channel *)device_get_softc(child))->unit; 303331c488dSSøren Schmidt 304331c488dSSøren Schmidt if (type == SYS_RES_IOPORT) { 305331c488dSSøren Schmidt switch (rid) { 306331c488dSSøren Schmidt case ATA_IOADDR_RID: 307b5a5e99dSSøren Schmidt return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, 3086230b63cSSøren Schmidt SYS_RES_IOPORT, 3096230b63cSSøren Schmidt PCIR_BAR(0) + (unit << 3), r); 310331c488dSSøren Schmidt break; 311331c488dSSøren Schmidt 312331c488dSSøren Schmidt case ATA_ALTADDR_RID: 313b5a5e99dSSøren Schmidt return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, 3146230b63cSSøren Schmidt SYS_RES_IOPORT, 3156230b63cSSøren Schmidt PCIR_BAR(1) + (unit << 3), r); 316331c488dSSøren Schmidt break; 317331c488dSSøren Schmidt default: 318331c488dSSøren Schmidt return ENOENT; 319331c488dSSøren Schmidt } 320331c488dSSøren Schmidt } 321331c488dSSøren Schmidt if (type == SYS_RES_IRQ) { 322331c488dSSøren Schmidt if (rid != ATA_IRQ_RID) 323331c488dSSøren Schmidt return ENOENT; 324331c488dSSøren Schmidt 3254ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 326331c488dSSøren Schmidt #ifdef __alpha__ 3276ddce903SSøren Schmidt return alpha_platform_release_ide_intr(unit, r); 328331c488dSSøren Schmidt #else 329b5a5e99dSSøren Schmidt return BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 330b5a5e99dSSøren Schmidt SYS_RES_IRQ, rid, r); 331331c488dSSøren Schmidt #endif 332331c488dSSøren Schmidt } 333bb5bdd38SSøren Schmidt else 334331c488dSSøren Schmidt return 0; 335331c488dSSøren Schmidt } 336331c488dSSøren Schmidt return EINVAL; 337331c488dSSøren Schmidt } 338331c488dSSøren Schmidt 3398ca4df32SSøren Schmidt int 340331c488dSSøren Schmidt ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq, 341bb5bdd38SSøren Schmidt int flags, driver_intr_t *function, void *argument, 342331c488dSSøren Schmidt void **cookiep) 343331c488dSSøren Schmidt { 3444ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 345331c488dSSøren Schmidt #ifdef __alpha__ 346bb5bdd38SSøren Schmidt return alpha_platform_setup_ide_intr(child, irq, function, argument, 347bb5bdd38SSøren Schmidt cookiep); 348331c488dSSøren Schmidt #else 349331c488dSSøren Schmidt return BUS_SETUP_INTR(device_get_parent(dev), child, irq, 350bb5bdd38SSøren Schmidt flags, function, argument, cookiep); 351331c488dSSøren Schmidt #endif 352331c488dSSøren Schmidt } 353bb5bdd38SSøren Schmidt else { 354bb5bdd38SSøren Schmidt struct ata_pci_controller *controller = device_get_softc(dev); 355bb5bdd38SSøren Schmidt int unit = ((struct ata_channel *)device_get_softc(child))->unit; 356bb5bdd38SSøren Schmidt 357bb5bdd38SSøren Schmidt controller->interrupt[unit].function = function; 358bb5bdd38SSøren Schmidt controller->interrupt[unit].argument = argument; 359bb5bdd38SSøren Schmidt *cookiep = controller; 360bb5bdd38SSøren Schmidt return 0; 361bb5bdd38SSøren Schmidt } 362331c488dSSøren Schmidt } 363331c488dSSøren Schmidt 3648ca4df32SSøren Schmidt int 365331c488dSSøren Schmidt ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, 366331c488dSSøren Schmidt void *cookie) 367331c488dSSøren Schmidt { 3684ee3fbe8SSøren Schmidt if (ata_legacy(dev)) { 369331c488dSSøren Schmidt #ifdef __alpha__ 370331c488dSSøren Schmidt return alpha_platform_teardown_ide_intr(child, irq, cookie); 371331c488dSSøren Schmidt #else 372331c488dSSøren Schmidt return BUS_TEARDOWN_INTR(device_get_parent(dev), child, irq, cookie); 373331c488dSSøren Schmidt #endif 374331c488dSSøren Schmidt } 3752e6c2a10SSøren Schmidt else { 3762e6c2a10SSøren Schmidt struct ata_pci_controller *controller = device_get_softc(dev); 3772e6c2a10SSøren Schmidt int unit = ((struct ata_channel *)device_get_softc(child))->unit; 3782e6c2a10SSøren Schmidt 3792e6c2a10SSøren Schmidt controller->interrupt[unit].function = NULL; 3802e6c2a10SSøren Schmidt controller->interrupt[unit].argument = NULL; 381bb5bdd38SSøren Schmidt return 0; 382331c488dSSøren Schmidt } 3832e6c2a10SSøren Schmidt } 384331c488dSSøren Schmidt 385566cf07aSSøren Schmidt static int 386bbccd832SSøren Schmidt ata_pci_allocate(device_t dev) 387566cf07aSSøren Schmidt { 388566cf07aSSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); 389bbccd832SSøren Schmidt struct ata_channel *ch = device_get_softc(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; 3945a5b148dSSøren Schmidt io = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 395566cf07aSSøren Schmidt if (!io) 396566cf07aSSøren Schmidt return ENXIO; 397566cf07aSSøren Schmidt 398566cf07aSSøren Schmidt rid = ATA_ALTADDR_RID; 3995a5b148dSSøren Schmidt altio = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 400566cf07aSSøren Schmidt if (!altio) { 401566cf07aSSøren Schmidt bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, io); 402566cf07aSSøren Schmidt return ENXIO; 403566cf07aSSøren Schmidt } 404566cf07aSSøren Schmidt 405566cf07aSSøren Schmidt for (i = ATA_DATA; i <= ATA_STATUS; i ++) { 406566cf07aSSøren Schmidt ch->r_io[i].res = io; 407566cf07aSSøren Schmidt ch->r_io[i].offset = i; 408566cf07aSSøren Schmidt } 409566cf07aSSøren Schmidt ch->r_io[ATA_ALTSTAT].res = altio; 4104ee3fbe8SSøren Schmidt ch->r_io[ATA_ALTSTAT].offset = ata_legacy(device_get_parent(dev)) ? 0 : 2; 4111b39bd24SSøren Schmidt ch->r_io[ATA_IDX_ADDR].res = io; 412566cf07aSSøren Schmidt 413498e5543SSøren Schmidt if (ctlr->r_res1) { 414566cf07aSSøren Schmidt for (i = ATA_BMCMD_PORT; i <= ATA_BMDTP_PORT; i++) { 415498e5543SSøren Schmidt ch->r_io[i].res = ctlr->r_res1; 416566cf07aSSøren Schmidt ch->r_io[i].offset = (i - ATA_BMCMD_PORT)+(ch->unit * ATA_BMIOSIZE); 417566cf07aSSøren Schmidt } 418566cf07aSSøren Schmidt } 419f2972d7eSSøren Schmidt 420f2972d7eSSøren Schmidt ata_generic_hw(ch); 421f2972d7eSSøren Schmidt 422566cf07aSSøren Schmidt return 0; 423566cf07aSSøren Schmidt } 424566cf07aSSøren Schmidt 425566cf07aSSøren Schmidt static int 42680344be5SSøren Schmidt ata_pci_dmastart(struct ata_channel *ch) 427566cf07aSSøren Schmidt { 428566cf07aSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) | 429566cf07aSSøren Schmidt (ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR))); 4308ca4df32SSøren Schmidt ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->sg_bus); 431c5b2c44cSSøren Schmidt ch->dma->flags |= ATA_DMA_ACTIVE; 432566cf07aSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, 43345bf968aSSøren Schmidt (ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_WRITE_READ) | 43480344be5SSøren Schmidt ((ch->dma->flags & ATA_DMA_READ) ? ATA_BMCMD_WRITE_READ : 0) | 43580344be5SSøren Schmidt ATA_BMCMD_START_STOP); 436566cf07aSSøren Schmidt return 0; 437566cf07aSSøren Schmidt } 438566cf07aSSøren Schmidt 439566cf07aSSøren Schmidt static int 440566cf07aSSøren Schmidt ata_pci_dmastop(struct ata_channel *ch) 441566cf07aSSøren Schmidt { 442566cf07aSSøren Schmidt int error; 443566cf07aSSøren Schmidt 444566cf07aSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, 445566cf07aSSøren Schmidt ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP); 4467e6d7588SSøren Schmidt ch->dma->flags &= ~ATA_DMA_ACTIVE; 447c5b2c44cSSøren Schmidt error = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; 448566cf07aSSøren Schmidt ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR); 4495fdbb0d2SSøren Schmidt return error; 450566cf07aSSøren Schmidt } 451566cf07aSSøren Schmidt 4526419d0b0SSøren Schmidt static void 453566cf07aSSøren Schmidt ata_pci_dmainit(struct ata_channel *ch) 454566cf07aSSøren Schmidt { 4556419d0b0SSøren Schmidt ata_dmainit(ch); 4566419d0b0SSøren Schmidt if (ch->dma) { 457566cf07aSSøren Schmidt ch->dma->start = ata_pci_dmastart; 458566cf07aSSøren Schmidt ch->dma->stop = ata_pci_dmastop; 4596419d0b0SSøren Schmidt } 460566cf07aSSøren Schmidt } 461566cf07aSSøren Schmidt 462331c488dSSøren Schmidt static device_method_t ata_pci_methods[] = { 463331c488dSSøren Schmidt /* device interface */ 464331c488dSSøren Schmidt DEVMETHOD(device_probe, ata_pci_probe), 465331c488dSSøren Schmidt DEVMETHOD(device_attach, ata_pci_attach), 466498e5543SSøren Schmidt DEVMETHOD(device_detach, ata_pci_detach), 467331c488dSSøren Schmidt DEVMETHOD(device_shutdown, bus_generic_shutdown), 468331c488dSSøren Schmidt DEVMETHOD(device_suspend, bus_generic_suspend), 469331c488dSSøren Schmidt DEVMETHOD(device_resume, bus_generic_resume), 470331c488dSSøren Schmidt 471331c488dSSøren Schmidt /* bus methods */ 472331c488dSSøren Schmidt DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource), 473331c488dSSøren Schmidt DEVMETHOD(bus_release_resource, ata_pci_release_resource), 474331c488dSSøren Schmidt DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 475331c488dSSøren Schmidt DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 476331c488dSSøren Schmidt DEVMETHOD(bus_setup_intr, ata_pci_setup_intr), 477331c488dSSøren Schmidt DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr), 4788ca4df32SSøren Schmidt 479331c488dSSøren Schmidt { 0, 0 } 480331c488dSSøren Schmidt }; 481331c488dSSøren Schmidt 4828ca4df32SSøren Schmidt devclass_t atapci_devclass; 4838ca4df32SSøren Schmidt 484331c488dSSøren Schmidt static driver_t ata_pci_driver = { 485331c488dSSøren Schmidt "atapci", 486331c488dSSøren Schmidt ata_pci_methods, 4876ddce903SSøren Schmidt sizeof(struct ata_pci_controller), 488331c488dSSøren Schmidt }; 489331c488dSSøren Schmidt 4908ca4df32SSøren Schmidt DRIVER_MODULE(atapci, pci, ata_pci_driver, atapci_devclass, 0, 0); 4918ca4df32SSøren Schmidt MODULE_VERSION(atapci, 1); 4928ca4df32SSøren Schmidt MODULE_DEPEND(atapci, ata, 1, 1, 1); 493331c488dSSøren Schmidt 494331c488dSSøren Schmidt static int 4955a5b148dSSøren Schmidt ata_pcichannel_probe(device_t dev) 496331c488dSSøren Schmidt { 4976ddce903SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 498331c488dSSøren Schmidt device_t *children; 499d53fc3e4SSøren Schmidt int count, i; 5008ca4df32SSøren Schmidt char buffer[32]; 501331c488dSSøren Schmidt 502498e5543SSøren Schmidt /* take care of green memory */ 503498e5543SSøren Schmidt bzero(ch, sizeof(struct ata_channel)); 504498e5543SSøren Schmidt 505331c488dSSøren Schmidt /* find channel number on this controller */ 506331c488dSSøren Schmidt device_get_children(device_get_parent(dev), &children, &count); 507331c488dSSøren Schmidt for (i = 0; i < count; i++) { 508331c488dSSøren Schmidt if (children[i] == dev) 5096ddce903SSøren Schmidt ch->unit = i; 510331c488dSSøren Schmidt } 511331c488dSSøren Schmidt free(children, M_TEMP); 5128ba4488cSSøren Schmidt 5138ca4df32SSøren Schmidt sprintf(buffer, "ATA channel %d", ch->unit); 5148ca4df32SSøren Schmidt device_set_desc_copy(dev, buffer); 5158ca4df32SSøren Schmidt 516d53fc3e4SSøren Schmidt return ata_probe(dev); 517d53fc3e4SSøren Schmidt } 518d53fc3e4SSøren Schmidt 519d53fc3e4SSøren Schmidt static int 5205a5b148dSSøren Schmidt ata_pcichannel_attach(device_t dev) 521d53fc3e4SSøren Schmidt { 522d53fc3e4SSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); 523d53fc3e4SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 524d53fc3e4SSøren Schmidt int error; 525d53fc3e4SSøren Schmidt 526d04d7894SSøren Schmidt if (ctlr->r_res1) 527d53fc3e4SSøren Schmidt ctlr->dmainit(ch); 528d53fc3e4SSøren Schmidt if (ch->dma) 529d53fc3e4SSøren Schmidt ch->dma->alloc(ch); 530d53fc3e4SSøren Schmidt 531bbccd832SSøren Schmidt if ((error = ctlr->allocate(dev))) 532ca5d21e9SSøren Schmidt return error; 533ca5d21e9SSøren Schmidt 534d53fc3e4SSøren Schmidt return ata_attach(dev); 535331c488dSSøren Schmidt } 536331c488dSSøren Schmidt 537d53fc3e4SSøren Schmidt static int 5385a5b148dSSøren Schmidt ata_pcichannel_detach(device_t dev) 539d53fc3e4SSøren Schmidt { 540d53fc3e4SSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 541d53fc3e4SSøren Schmidt int error; 542d53fc3e4SSøren Schmidt 543d53fc3e4SSøren Schmidt if ((error = ata_detach(dev))) 544d53fc3e4SSøren Schmidt return error; 545d53fc3e4SSøren Schmidt 546d53fc3e4SSøren Schmidt if (ch->dma) 547d53fc3e4SSøren Schmidt ch->dma->free(ch); 548d53fc3e4SSøren Schmidt 549bbccd832SSøren Schmidt /* free resources for io and altio XXX SOS */ 550bbccd832SSøren Schmidt 551d53fc3e4SSøren Schmidt return 0; 552d53fc3e4SSøren Schmidt } 553d53fc3e4SSøren Schmidt 5545a5b148dSSøren Schmidt static int 5555a5b148dSSøren Schmidt ata_pcichannel_locking(device_t dev, int mode) 5565a5b148dSSøren Schmidt { 5575a5b148dSSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); 5585a5b148dSSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 5595a5b148dSSøren Schmidt 5605a5b148dSSøren Schmidt if (ctlr->locking) 5615a5b148dSSøren Schmidt return ctlr->locking(ch, mode); 5625a5b148dSSøren Schmidt else 5635a5b148dSSøren Schmidt return ch->unit; 5645a5b148dSSøren Schmidt } 5655a5b148dSSøren Schmidt 5665a5b148dSSøren Schmidt static void 5675a5b148dSSøren Schmidt ata_pcichannel_reset(device_t dev) 5685a5b148dSSøren Schmidt { 5695a5b148dSSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); 5705a5b148dSSøren Schmidt struct ata_channel *ch = device_get_softc(dev); 5715a5b148dSSøren Schmidt 5725a5b148dSSøren Schmidt if (ctlr->reset) 5735a5b148dSSøren Schmidt ctlr->reset(ch); 5745a5b148dSSøren Schmidt } 5755a5b148dSSøren Schmidt 5765a5b148dSSøren Schmidt static void 5775a5b148dSSøren Schmidt ata_pcichannel_setmode(device_t parent, device_t dev) 5785a5b148dSSøren Schmidt { 5795a5b148dSSøren Schmidt struct ata_pci_controller *ctlr = device_get_softc(GRANDPARENT(dev)); 5805a5b148dSSøren Schmidt struct ata_device *atadev = device_get_softc(dev); 5815a5b148dSSøren Schmidt int mode = atadev->mode; 5825a5b148dSSøren Schmidt 5835a5b148dSSøren Schmidt ctlr->setmode(atadev, ATA_PIO_MAX); 5845a5b148dSSøren Schmidt if (mode >= ATA_DMA) 5855a5b148dSSøren Schmidt ctlr->setmode(atadev, mode); 5865a5b148dSSøren Schmidt } 5875a5b148dSSøren Schmidt 5885a5b148dSSøren Schmidt static device_method_t ata_pcichannel_methods[] = { 589331c488dSSøren Schmidt /* device interface */ 5905a5b148dSSøren Schmidt DEVMETHOD(device_probe, ata_pcichannel_probe), 5915a5b148dSSøren Schmidt DEVMETHOD(device_attach, ata_pcichannel_attach), 5925a5b148dSSøren Schmidt DEVMETHOD(device_detach, ata_pcichannel_detach), 5938ca4df32SSøren Schmidt DEVMETHOD(device_shutdown, bus_generic_shutdown), 5948ca4df32SSøren Schmidt DEVMETHOD(device_suspend, bus_generic_suspend), 5958ca4df32SSøren Schmidt DEVMETHOD(device_resume, bus_generic_resume), 5965a5b148dSSøren Schmidt 5975a5b148dSSøren Schmidt /* ATA methods */ 5985a5b148dSSøren Schmidt DEVMETHOD(ata_setmode, ata_pcichannel_setmode), 5995a5b148dSSøren Schmidt DEVMETHOD(ata_locking, ata_pcichannel_locking), 6005a5b148dSSøren Schmidt DEVMETHOD(ata_reset, ata_pcichannel_reset), 6015a5b148dSSøren Schmidt 602331c488dSSøren Schmidt { 0, 0 } 603331c488dSSøren Schmidt }; 604331c488dSSøren Schmidt 6055a5b148dSSøren Schmidt driver_t ata_pcichannel_driver = { 606331c488dSSøren Schmidt "ata", 6075a5b148dSSøren Schmidt ata_pcichannel_methods, 6086ddce903SSøren Schmidt sizeof(struct ata_channel), 609331c488dSSøren Schmidt }; 610331c488dSSøren Schmidt 6115a5b148dSSøren Schmidt DRIVER_MODULE(ata, atapci, ata_pcichannel_driver, ata_devclass, 0, 0); 612