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