1/* $NetBSD: ciss_pci.c,v 1.8 2009/05/12 08:23:00 cegger Exp $ */ 2/* $OpenBSD: ciss_pci.c,v 1.9 2005/12/13 15:56:01 brad Exp $ */ 3 4/* 5 * Copyright (c) 2005 Michael Shalayeff 6 * All rights reserved. 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN 17 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 18 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21#include <sys/cdefs.h> 22__KERNEL_RCSID(0, "$NetBSD: ciss_pci.c,v 1.8 2009/05/12 08:23:00 cegger Exp $"); 23 24#include <sys/param.h> 25#include <sys/systm.h> 26#include <sys/kernel.h> 27#include <sys/malloc.h> 28#include <sys/device.h> 29 30#include <dev/pci/pcidevs.h> 31#include <dev/pci/pcivar.h> 32 33#include <sys/bus.h> 34 35#include <dev/scsipi/scsipi_all.h> 36#include <dev/scsipi/scsipi_disk.h> 37#include <dev/scsipi/scsipiconf.h> 38 39#include <dev/ic/cissreg.h> 40#include <dev/ic/cissvar.h> 41 42#define CISS_BAR 0x10 43 44int ciss_pci_match(device_t, cfdata_t, void *); 45void ciss_pci_attach(device_t, device_t, void *); 46 47CFATTACH_DECL(ciss_pci, sizeof(struct ciss_softc), 48 ciss_pci_match, ciss_pci_attach, NULL, NULL); 49 50const struct { 51 int vendor; 52 int product; 53 const char *name; 54} ciss_pci_devices[] = { 55 { 56 PCI_VENDOR_COMPAQ, 57 PCI_PRODUCT_COMPAQ_CSA532, 58 "Compaq Smart Array 532" 59 }, 60 { 61 PCI_VENDOR_COMPAQ, 62 PCI_PRODUCT_COMPAQ_CSA5300, 63 "Compaq Smart Array 5300 V1" 64 }, 65 { 66 PCI_VENDOR_COMPAQ, 67 PCI_PRODUCT_COMPAQ_CSA5300_2, 68 "Compaq Smart Array 5300 V2" 69 }, 70 { 71 PCI_VENDOR_COMPAQ, 72 PCI_PRODUCT_COMPAQ_CSA5312, 73 "Compaq Smart Array 5312" 74 }, 75 { 76 PCI_VENDOR_COMPAQ, 77 PCI_PRODUCT_COMPAQ_CSA5i, 78 "Compaq Smart Array 5i" 79 }, 80 { 81 PCI_VENDOR_COMPAQ, 82 PCI_PRODUCT_COMPAQ_CSA5i_2, 83 "Compaq Smart Array 5i V2" 84 }, 85 { 86 PCI_VENDOR_COMPAQ, 87 PCI_PRODUCT_COMPAQ_CSA6i, 88 "Compaq Smart Array 6i" 89 }, 90 { 91 PCI_VENDOR_COMPAQ, 92 PCI_PRODUCT_COMPAQ_CSA641, 93 "Compaq Smart Array 641" 94 }, 95 { 96 PCI_VENDOR_COMPAQ, 97 PCI_PRODUCT_COMPAQ_CSA642, 98 "Compaq Smart Array 642" 99 }, 100 { 101 PCI_VENDOR_COMPAQ, 102 PCI_PRODUCT_COMPAQ_CSA6400, 103 "Compaq Smart Array 6400" 104 }, 105 { 106 PCI_VENDOR_COMPAQ, 107 PCI_PRODUCT_COMPAQ_CSA6400EM, 108 "Compaq Smart Array 6400EM" 109 }, 110 { 111 PCI_VENDOR_COMPAQ, 112 PCI_PRODUCT_COMPAQ_CSA6422, 113 "Compaq Smart Array 6422" 114 }, 115 { 116 PCI_VENDOR_COMPAQ, 117 PCI_PRODUCT_COMPAQ_CSA64XX, 118 "Compaq Smart Array 64XX" 119 }, 120 { 121 PCI_VENDOR_HP, 122 PCI_PRODUCT_HP_HPSAE200, 123 "Smart Array E200" 124 }, 125 { 126 PCI_VENDOR_HP, 127 PCI_PRODUCT_HP_HPSAE200I_1, 128 "HP Smart Array E200I-1" 129 }, 130 { 131 PCI_VENDOR_HP, 132 PCI_PRODUCT_HP_HPSAE200I_2, 133 "HP Smart Array E200I-2" 134 }, 135 { 136 PCI_VENDOR_HP, 137 PCI_PRODUCT_HP_HPSAE200I_3, 138 "HP Smart Array E200I-3" 139 }, 140 { 141 PCI_VENDOR_HP, 142 PCI_PRODUCT_HP_HPSAP600, 143 "HP Smart Array P600" 144 }, 145 { 146 PCI_VENDOR_HP, 147 PCI_PRODUCT_HP_HPSAP800, 148 "HP Smart Array P800" 149 }, 150 { 151 PCI_VENDOR_HP, 152 PCI_PRODUCT_HP_HPSAV100, 153 "HP Smart Array V100" 154 }, 155 { 156 PCI_VENDOR_HP, 157 PCI_PRODUCT_HP_HPSA_1, 158 "HP Smart Array 1" 159 }, 160 { 161 PCI_VENDOR_HP, 162 PCI_PRODUCT_HP_HPSA_2, 163 "HP Smart Array 2" 164 }, 165 { 166 PCI_VENDOR_HP, 167 PCI_PRODUCT_HP_HPSA_3, 168 "HP Smart Array 3" 169 }, 170 { 171 PCI_VENDOR_HP, 172 PCI_PRODUCT_HP_HPSA_4, 173 "HP Smart Array 4" 174 }, 175 { 176 PCI_VENDOR_HP, 177 PCI_PRODUCT_HP_HPSA_5, 178 "HP Smart Array 5" 179 }, 180 { 181 PCI_VENDOR_HP, 182 PCI_PRODUCT_HP_HPSA_6, 183 "HP Smart Array 6" 184 }, 185 { 186 PCI_VENDOR_HP, 187 PCI_PRODUCT_HP_HPSA_7, 188 "HP Smart Array 7" 189 }, 190 { 191 PCI_VENDOR_HP, 192 PCI_PRODUCT_HP_HPSA_8, 193 "HP Smart Array 8" 194 }, 195 { 196 PCI_VENDOR_HP, 197 PCI_PRODUCT_HP_HPSA_9, 198 "HP Smart Array 9" 199 }, 200 { 201 PCI_VENDOR_HP, 202 PCI_PRODUCT_HP_HPSA_10, 203 "HP Smart Array 10" 204 }, 205 { 206 PCI_VENDOR_HP, 207 PCI_PRODUCT_HP_HPSA_11, 208 "HP Smart Array 11" 209 }, 210 { 211 PCI_VENDOR_HP, 212 PCI_PRODUCT_HP_HPSA_12, 213 "HP Smart Array 12" 214 }, 215 { 216 PCI_VENDOR_HP, 217 PCI_PRODUCT_HP_HPSA_13, 218 "HP Smart Array 13" 219 }, 220 { 221 0, 222 0, 223 NULL 224 } 225}; 226 227int 228ciss_pci_match(device_t parent, cfdata_t match, void *aux) 229{ 230 struct pci_attach_args *pa = aux; 231 pcireg_t reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); 232 int i; 233 234 for (i = 0; ciss_pci_devices[i].vendor; i++) 235 { 236 if ((PCI_VENDOR(pa->pa_id) == ciss_pci_devices[i].vendor && 237 PCI_PRODUCT(pa->pa_id) == ciss_pci_devices[i].product) || 238 (PCI_VENDOR(reg) == ciss_pci_devices[i].vendor && 239 PCI_PRODUCT(reg) == ciss_pci_devices[i].product)) 240 return 1; 241 } 242 243 return 0; 244} 245 246void 247ciss_pci_attach(device_t parent, device_t self, void *aux) 248{ 249 struct ciss_softc *sc = device_private(self); 250 struct pci_attach_args *pa = aux; 251 bus_size_t size, cfgsz; 252 pci_intr_handle_t ih; 253 const char *intrstr; 254 int cfg_bar, memtype; 255 pcireg_t reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); 256 int i; 257 258 for (i = 0; ciss_pci_devices[i].vendor; i++) 259 { 260 if ((PCI_VENDOR(pa->pa_id) == ciss_pci_devices[i].vendor && 261 PCI_PRODUCT(pa->pa_id) == ciss_pci_devices[i].product) || 262 (PCI_VENDOR(reg) == ciss_pci_devices[i].vendor && 263 PCI_PRODUCT(reg) == ciss_pci_devices[i].product)) 264 { 265 printf(": %s\n", ciss_pci_devices[i].name); 266 break; 267 } 268 } 269 270 memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, CISS_BAR); 271 if (memtype != (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT) && 272 memtype != (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT)) { 273 printf(": wrong BAR type\n"); 274 return; 275 } 276 if (pci_mapreg_map(pa, CISS_BAR, memtype, 0, 277 &sc->sc_iot, &sc->sc_ioh, NULL, &size)) { 278 printf(": can't map controller i/o space\n"); 279 return; 280 } 281 sc->sc_dmat = pa->pa_dmat; 282 283 sc->iem = CISS_READYENA; 284 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); 285 if (PCI_VENDOR(reg) == PCI_VENDOR_COMPAQ && 286 (PCI_PRODUCT(reg) == PCI_PRODUCT_COMPAQ_CSA5i || 287 PCI_PRODUCT(reg) == PCI_PRODUCT_COMPAQ_CSA532 || 288 PCI_PRODUCT(reg) == PCI_PRODUCT_COMPAQ_CSA5312)) 289 sc->iem = CISS_READYENAB; 290 291 cfg_bar = bus_space_read_2(sc->sc_iot, sc->sc_ioh, CISS_CFG_BAR); 292 sc->cfgoff = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_CFG_OFF); 293 if (cfg_bar != CISS_BAR) { 294 if (pci_mapreg_map(pa, cfg_bar, PCI_MAPREG_TYPE_MEM, 0, 295 NULL, &sc->cfg_ioh, NULL, &cfgsz)) { 296 printf(": can't map controller config space\n"); 297 bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); 298 return; 299 } 300 } else { 301 sc->cfg_ioh = sc->sc_ioh; 302 cfgsz = size; 303 } 304 305 if (sc->cfgoff + sizeof(struct ciss_config) > cfgsz) { 306 printf(": unfit config space\n"); 307 bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); 308 if (cfg_bar != CISS_BAR) 309 bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz); 310 return; 311 } 312 313 /* disable interrupts until ready */ 314 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CISS_IMR, 315 bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_IMR) | sc->iem); 316 317 if (pci_intr_map(pa, &ih)) { 318 printf(": can't map interrupt\n"); 319 bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); 320 if (cfg_bar != CISS_BAR) 321 bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz); 322 return; 323 } 324 intrstr = pci_intr_string(pa->pa_pc, ih); 325 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ciss_intr, sc); 326 if (!sc->sc_ih) { 327 aprint_error_dev(&sc->sc_dev, "can't establish interrupt"); 328 if (intrstr) 329 aprint_error(" at %s", intrstr); 330 aprint_error("\n"); 331 bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); 332 if (cfg_bar != CISS_BAR) 333 bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz); 334 } 335 336 printf("%s: interrupting at %s\n%s", device_xname(&sc->sc_dev), intrstr, 337 device_xname(&sc->sc_dev)); 338 339 if (ciss_attach(sc)) { 340 pci_intr_disestablish(pa->pa_pc, sc->sc_ih); 341 sc->sc_ih = NULL; 342 bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); 343 if (cfg_bar != CISS_BAR) 344 bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz); 345 return; 346 } 347 348 /* enable interrupts now */ 349 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CISS_IMR, 350 bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_IMR) & ~sc->iem); 351} 352