1 /* $OpenBSD: ami_pci.c,v 1.18 2003/06/02 19:24:22 mickey Exp $ */ 2 3 /* 4 * Copyright (c) 2001 Michael Shalayeff 5 * All rights reserved. 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 ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/kernel.h> 32 #include <sys/malloc.h> 33 #include <sys/device.h> 34 35 #include <dev/pci/pcidevs.h> 36 #include <dev/pci/pcivar.h> 37 38 #include <machine/bus.h> 39 40 #include <scsi/scsi_all.h> 41 #include <scsi/scsi_disk.h> 42 #include <scsi/scsiconf.h> 43 44 #include <dev/ic/amireg.h> 45 #include <dev/ic/amivar.h> 46 47 #define AMI_BAR 0x10 48 #define AMI_PCI_MEMSIZE 0x1000 49 #define AMI_SUBSYSID 0x2c 50 #define PCI_EBCR 0x40 51 #define AMI_WAKEUP 0x64 52 53 /* "Quartz" i960 Config space */ 54 #define AMI_PCI_INIT 0x9c 55 #define AMI_INITSTAT(i) (((i) >> 8) & 0xff) 56 #define AMI_INITTARG(i) (((i) >> 16) & 0xff) 57 #define AMI_INITCHAN(i) (((i) >> 24) & 0xff) 58 #define AMI_PCI_SIG 0xa0 59 #define AMI_SIGNATURE_1 0xcccc /* older adapters */ 60 #define AMI_SIGNATURE_2 0x3344 /* newer adapters */ 61 #define AMI_PCI_SGL 0xa4 62 #define AMI_SGL_LHC 0x00000299 63 #define AMI_SGL_HLC 0x00000199 64 65 int ami_pci_match(struct device *, void *, void *); 66 void ami_pci_attach(struct device *, struct device *, void *); 67 68 struct cfattach ami_pci_ca = { 69 sizeof(struct ami_softc), ami_pci_match, ami_pci_attach 70 }; 71 72 static const 73 struct ami_pci_device { 74 int vendor; 75 int product; 76 int flags; 77 #define AMI_CHECK_SIGN 0x001 78 } ami_pci_devices[] = { 79 { PCI_VENDOR_AMI, PCI_PRODUCT_AMI_MEGARAID, 0 }, 80 { PCI_VENDOR_AMI, PCI_PRODUCT_AMI_MEGARAID428, 0 }, 81 { PCI_VENDOR_AMI, PCI_PRODUCT_AMI_MEGARAID434, 0 }, 82 { PCI_VENDOR_DELL, PCI_PRODUCT_DELL_PERC_4DI, 0 }, 83 { PCI_VENDOR_DELL, PCI_PRODUCT_DELL_PERC_4DI_2, 0 }, 84 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_80960RP_ATU, AMI_CHECK_SIGN }, 85 { 0 } 86 }; 87 88 static const 89 struct ami_pci_subsys { 90 pcireg_t id; 91 char name[12]; 92 } ami_pci_subsys[] = { 93 /* only those of a special name are listed here */ 94 { 0x09A0101E, "Dell 466v1" }, 95 { 0x11111111, "Dell 466v2" }, 96 { 0x11121111, "Dell 438" }, 97 { 0x11111028, "Dell 466v3" }, 98 { 0x10c6103c, "HP 438" }, 99 { 0x10c7103c, "HP T5/T6" }, 100 { 0x10cc103c, "HP T7" }, 101 { 0x10cd103c, "HP 466" }, 102 { 0 } 103 }; 104 105 static const 106 struct ami_pci_vendor { 107 u_int16_t id; 108 char name[8]; 109 } ami_pci_vendors[] = { 110 { 0x101e, "AMI" }, 111 { 0x1028, "Dell" }, 112 { 0x103c, "HP" }, 113 { 0 } 114 }; 115 116 int 117 ami_pci_match(parent, match, aux) 118 struct device *parent; 119 void *match; 120 void *aux; 121 { 122 struct pci_attach_args *pa = aux; 123 const struct ami_pci_device *pami; 124 pcireg_t sig; 125 126 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_I2O) 127 return (0); 128 129 for (pami = ami_pci_devices; pami->vendor; pami++) { 130 if (pami->vendor == PCI_VENDOR(pa->pa_id) && 131 pami->product == PCI_PRODUCT(pa->pa_id)) { 132 if (!(pami->flags & AMI_CHECK_SIGN)) 133 return (1); 134 /* some cards have 0x11223344, but some only 16bit */ 135 sig = pci_conf_read(pa->pa_pc, pa->pa_tag, 136 AMI_PCI_SIG) & 0xffff; 137 if (sig == AMI_SIGNATURE_1 || 138 sig == AMI_SIGNATURE_2) 139 return (1); 140 } 141 } 142 return (0); 143 } 144 145 void 146 ami_pci_attach(parent, self, aux) 147 struct device *parent, *self; 148 void *aux; 149 { 150 struct ami_softc *sc = (struct ami_softc *)self; 151 struct pci_attach_args *pa = aux; 152 pci_intr_handle_t ih; 153 const char *intrstr, *model = NULL, *lhc; 154 const struct ami_pci_subsys *ssp; 155 bus_size_t size; 156 pcireg_t csr; 157 #if 0 158 /* reset */ 159 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_EBCR, 160 pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_EBCR) | 0x20); 161 pci_conf_write(pa->pa_pc, pa->pa_tag, AMI_WAKEUP, 0); 162 #endif 163 csr = pci_mapreg_type(pa->pa_pc, pa->pa_tag, AMI_BAR); 164 csr |= PCI_MAPREG_MEM_TYPE_32BIT; 165 if (pci_mapreg_map(pa, AMI_BAR, csr, 0, 166 &sc->iot, &sc->ioh, NULL, &size, AMI_PCI_MEMSIZE)) { 167 printf(": can't map controller pci space\n"); 168 return; 169 } 170 171 if (csr == PCI_MAPREG_TYPE_IO) { 172 sc->sc_init = ami_schwartz_init; 173 sc->sc_exec = ami_schwartz_exec; 174 sc->sc_done = ami_schwartz_done; 175 } else { 176 sc->sc_init = ami_quartz_init; 177 sc->sc_exec = ami_quartz_exec; 178 sc->sc_done = ami_quartz_done; 179 } 180 sc->dmat = pa->pa_dmat; 181 182 /* enable bus mastering (should not it be mi?) */ 183 csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 184 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 185 csr | PCI_COMMAND_MASTER_ENABLE); 186 187 if (pci_intr_map(pa, &ih)) { 188 printf(": can't map interrupt\n"); 189 bus_space_unmap(sc->iot, sc->ioh, size); 190 return; 191 } 192 intrstr = pci_intr_string(pa->pa_pc, ih); 193 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ami_intr, sc, 194 sc->sc_dev.dv_xname); 195 if (!sc->sc_ih) { 196 printf(": can't establish interrupt"); 197 if (intrstr) 198 printf(" at %s", intrstr); 199 printf("\n"); 200 bus_space_unmap(sc->iot, sc->ioh, size); 201 } 202 203 printf(": %s", intrstr); 204 205 csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); 206 for (ssp = ami_pci_subsys; ssp->id; ssp++) 207 if (ssp->id == csr) { 208 model = ssp->name; 209 break; 210 } 211 212 if (!model && PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMI) 213 switch (PCI_PRODUCT(pa->pa_id)) { 214 case PCI_PRODUCT_AMI_MEGARAID428: 215 model = "AMI 428"; 216 break; 217 case PCI_PRODUCT_AMI_MEGARAID434: 218 model = "AMI 434"; 219 break; 220 } 221 222 /* XXX 438 is netraid 3si for hp cards, but we get to know 223 they are hp too late in md code */ 224 225 if (!model) { 226 const struct ami_pci_vendor *vp; 227 static char modelbuf[12]; 228 229 for (vp = ami_pci_vendors; 230 vp->id && vp->id != (csr & 0xffff); vp++); 231 if (vp->id) 232 snprintf(modelbuf, sizeof modelbuf, "%s %x", vp->name, 233 (csr >> 16) & 0xffff); 234 else 235 snprintf(modelbuf, sizeof modelbuf, "unknown 0x%08x", 236 csr); 237 model = modelbuf; 238 } 239 240 switch (pci_conf_read(pa->pa_pc, pa->pa_tag, AMI_PCI_SGL)) { 241 case AMI_SGL_LHC: lhc = "64b/lhc"; break; 242 case AMI_SGL_HLC: lhc = "64b/hlc"; break; 243 default: lhc = "32b"; 244 } 245 246 printf(" %s/%s\n%s", model, lhc, sc->sc_dev.dv_xname); 247 248 if (ami_attach(sc)) { 249 pci_intr_disestablish(pa->pa_pc, sc->sc_ih); 250 sc->sc_ih = NULL; 251 bus_space_unmap(sc->iot, sc->ioh, size); 252 } 253 } 254