1 /*- 2 * Copyright (c) 2002 Adaptec Inc. 3 * All rights reserved. 4 * 5 * Written by: David Jeffery 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD: src/sys/dev/ips/ips_pci.c,v 1.10 2004/03/19 17:36:47 scottl Exp $ 29 * $DragonFly: src/sys/dev/raid/ips/ips_pci.c,v 1.12 2005/05/24 20:59:04 dillon Exp $ 30 */ 31 32 #include <dev/raid/ips/ips.h> 33 34 static int ips_pci_free(ips_softc_t *sc); 35 static void ips_intrhook(void *arg); 36 37 static struct ips_pci_product { 38 uint16_t vendor, device; 39 const char *desc; 40 int (*ips_adapter_reinit)(struct ips_softc *, int); 41 void (*ips_adapter_intr)(void *); 42 void (*ips_issue_cmd)(ips_command_t *); 43 } ips_pci_products[] = { 44 { IPS_VENDOR_ID, IPS_MORPHEUS_DEVICE_ID, "IBM ServeRAID Adapter", 45 ips_morpheus_reinit, ips_morpheus_intr, ips_issue_morpheus_cmd }, 46 { IPS_VENDOR_ID, IPS_COPPERHEAD_DEVICE_ID, "IBM ServeRAID Adapter", 47 ips_copperhead_reinit, ips_copperhead_intr, 48 ips_issue_copperhead_cmd }, 49 { IPS_VENDOR_ID_ADAPTEC, IPS_MARCO_DEVICE_ID, 50 "Adaptec ServeRAID Adapter", ips_morpheus_reinit, ips_morpheus_intr, 51 ips_issue_morpheus_cmd }, 52 { 0, 0, NULL } 53 }; 54 55 static int 56 ips_pci_probe(device_t dev) 57 { 58 uint16_t vendor = pci_get_vendor(dev); 59 uint16_t device = pci_get_device(dev); 60 struct ips_pci_product *pp; 61 ips_softc_t *sc; 62 63 for (pp = ips_pci_products; pp->vendor; pp++) { 64 if (vendor == pp->vendor && device == pp->device) { 65 sc = (ips_softc_t *)device_get_softc(dev); 66 sc->ips_adapter_reinit = pp->ips_adapter_reinit; 67 sc->ips_adapter_intr = pp->ips_adapter_intr; 68 sc->ips_issue_cmd = pp->ips_issue_cmd; 69 device_set_desc(dev, pp->desc); 70 return (0); 71 } 72 } 73 return (ENXIO); 74 } 75 76 static int 77 ips_pci_attach(device_t dev) 78 { 79 u_int32_t command; 80 ips_softc_t *sc; 81 int error; 82 83 if (resource_disabled(device_get_name(dev), device_get_unit(dev))) { 84 device_printf(dev, "device is disabled\n"); 85 /* but return 0 so the !$)$)*!$*) unit isn't reused */ 86 return (0); 87 } 88 DEVICE_PRINTF(1, dev, "in attach.\n"); 89 sc = (ips_softc_t *)device_get_softc(dev); 90 sc->dev = dev; 91 /* make sure busmastering is on */ 92 pci_enable_busmaster(dev); 93 command = pci_read_config(dev, PCIR_COMMAND, 1); 94 /* seting up io space */ 95 sc->iores = NULL; 96 if (command & PCIM_CMD_MEMEN) { 97 PRINTF(10, "trying MEMIO\n"); 98 if (pci_get_device(dev) == IPS_COPPERHEAD_DEVICE_ID) 99 sc->rid = PCIR_BAR(1); 100 else 101 sc->rid = PCIR_BAR(0); 102 sc->iotype = SYS_RES_MEMORY; 103 sc->iores = bus_alloc_resource_any(dev, sc->iotype, 104 &sc->rid, RF_ACTIVE); 105 } 106 if (sc->iores == NULL && command & PCIM_CMD_PORTEN) { 107 PRINTF(10, "trying PORTIO\n"); 108 sc->rid = PCIR_BAR(0); 109 sc->iotype = SYS_RES_IOPORT; 110 sc->iores = bus_alloc_resource_any(dev, sc->iotype, 111 &sc->rid, RF_ACTIVE); 112 } 113 if (sc->iores == NULL) { 114 device_printf(dev, "resource allocation failed\n"); 115 return (ENXIO); 116 } 117 sc->bustag = rman_get_bustag(sc->iores); 118 sc->bushandle = rman_get_bushandle(sc->iores); 119 /* 120 * allocate an interrupt. when does the irq become active? 121 * after leaving attach? 122 */ 123 sc->irqrid = 0; 124 if ((sc->irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, 125 &sc->irqrid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 126 device_printf(dev, "irq allocation failed\n"); 127 goto error; 128 } 129 error = bus_setup_intr(dev, sc->irqres, INTR_TYPE_BIO, 130 sc->ips_adapter_intr, sc, 131 &sc->irqcookie, NULL); 132 if (error) { 133 device_printf(dev, "irq setup failed\n"); 134 goto error; 135 } 136 if (bus_dma_tag_create( /* parent */ NULL, 137 /* alignemnt */ 1, 138 /* boundary */ 0, 139 /* lowaddr */ BUS_SPACE_MAXADDR_32BIT, 140 /* highaddr */ BUS_SPACE_MAXADDR, 141 /* filter */ NULL, 142 /* filterarg */ NULL, 143 /* maxsize */ BUS_SPACE_MAXSIZE_32BIT, 144 /* numsegs */ IPS_MAX_SG_ELEMENTS, 145 /* maxsegsize*/ BUS_SPACE_MAXSIZE_32BIT, 146 /* flags */ 0, 147 &sc->adapter_dmatag) != 0) { 148 printf("IPS can't alloc dma tag\n"); 149 goto error; 150 } 151 sc->ips_ich.ich_func = ips_intrhook; 152 sc->ips_ich.ich_arg = sc; 153 sc->ips_ich.ich_desc = "ips"; 154 if (config_intrhook_establish(&sc->ips_ich) != 0) { 155 printf("IPS can't establish configuration hook\n"); 156 goto error; 157 } 158 return 0; 159 error: 160 ips_pci_free(sc); 161 return (ENXIO); 162 } 163 164 static void 165 ips_intrhook(void *arg) 166 { 167 struct ips_softc *sc = arg; 168 169 config_intrhook_disestablish(&sc->ips_ich); 170 if (ips_adapter_init(sc)) 171 ips_pci_free(sc); 172 else 173 sc->configured = 1; 174 } 175 176 static int 177 ips_pci_free(ips_softc_t *sc) 178 { 179 180 if (sc->adapter_dmatag) 181 bus_dma_tag_destroy(sc->adapter_dmatag); 182 if (sc->irqcookie) 183 bus_teardown_intr(sc->dev, sc->irqres, sc->irqcookie); 184 if (sc->irqres) 185 bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irqrid, 186 sc->irqres); 187 if (sc->iores) 188 bus_release_resource(sc->dev, sc->iotype, sc->rid, sc->iores); 189 sc->configured = 0; 190 return 0; 191 } 192 193 static int 194 ips_pci_detach(device_t dev) 195 { 196 ips_softc_t *sc; 197 198 DEVICE_PRINTF(1, dev, "detaching ServeRaid\n"); 199 sc = (ips_softc_t *)device_get_softc(dev); 200 if (sc->configured) { 201 sc->configured = 0; 202 ips_flush_cache(sc); 203 if (ips_adapter_free(sc)) 204 return EBUSY; 205 ips_pci_free(sc); 206 } 207 return 0; 208 } 209 210 static int 211 ips_pci_shutdown(device_t dev) 212 { 213 ips_softc_t *sc; 214 215 sc = (ips_softc_t *)device_get_softc(dev); 216 if (sc->configured) 217 ips_flush_cache(sc); 218 return 0; 219 } 220 221 static device_method_t ips_driver_methods[] = { 222 DEVMETHOD(device_probe, ips_pci_probe), 223 DEVMETHOD(device_attach, ips_pci_attach), 224 DEVMETHOD(device_detach, ips_pci_detach), 225 DEVMETHOD(device_shutdown, ips_pci_shutdown), 226 { 0, 0 } 227 }; 228 229 static driver_t ips_pci_driver = { 230 "ips", 231 ips_driver_methods, 232 sizeof(ips_softc_t), 233 }; 234 235 static devclass_t ips_devclass; 236 DRIVER_MODULE(ips, pci, ips_pci_driver, ips_devclass, 0, 0); 237