1 /* $NetBSD: ciss_pci.c,v 1.14 2018/02/12 23:11:00 joerg 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.14 2018/02/12 23:11:00 joerg 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 44 int ciss_pci_match(device_t, cfdata_t, void *); 45 void ciss_pci_attach(device_t, device_t, void *); 46 47 CFATTACH_DECL_NEW(ciss_pci, sizeof(struct ciss_softc), 48 ciss_pci_match, ciss_pci_attach, NULL, NULL); 49 50 const 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 227 int 228 ciss_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 246 #ifdef CISS_NO_INTERRUPT_HACK 247 static void 248 ciss_intr_wrapper(void *sc_) 249 { 250 struct ciss_softc *sc = sc_; 251 int s; 252 253 s = splbio(); 254 ciss_intr(sc); 255 splx(s); 256 callout_schedule(&sc->sc_interrupt_hack, 1); 257 } 258 #endif 259 260 void 261 ciss_pci_attach(device_t parent, device_t self, void *aux) 262 { 263 struct ciss_softc *sc = device_private(self); 264 struct pci_attach_args *pa = aux; 265 bus_size_t size, cfgsz; 266 pci_intr_handle_t ih; 267 const char *intrstr; 268 int cfg_bar, memtype; 269 pcireg_t reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); 270 int i; 271 char intrbuf[PCI_INTRSTR_LEN]; 272 273 #ifdef CISS_NO_INTERRUPT_HACK 274 callout_init(&sc->sc_interrupt_hack, 0); 275 callout_setfunc(&sc->sc_interrupt_hack, ciss_intr_wrapper, sc); 276 #endif 277 sc->sc_dev = self; 278 279 aprint_naive("\n"); 280 for (i = 0; ciss_pci_devices[i].vendor; i++) 281 { 282 if ((PCI_VENDOR(pa->pa_id) == ciss_pci_devices[i].vendor && 283 PCI_PRODUCT(pa->pa_id) == ciss_pci_devices[i].product) || 284 (PCI_VENDOR(reg) == ciss_pci_devices[i].vendor && 285 PCI_PRODUCT(reg) == ciss_pci_devices[i].product)) 286 { 287 aprint_normal(": %s\n", ciss_pci_devices[i].name); 288 break; 289 } 290 } 291 292 memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, CISS_BAR); 293 if (memtype != (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT) && 294 memtype != (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT)) { 295 aprint_error_dev(self, "wrong BAR type\n"); 296 return; 297 } 298 if (pci_mapreg_map(pa, CISS_BAR, memtype, 0, 299 &sc->sc_iot, &sc->sc_ioh, NULL, &size)) { 300 aprint_error_dev(self, "can't map controller i/o space\n"); 301 return; 302 } 303 sc->sc_dmat = pa->pa_dmat; 304 305 sc->iem = CISS_INTR_OPQ_SA5; 306 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); 307 if (PCI_VENDOR(reg) == PCI_VENDOR_COMPAQ && 308 (PCI_PRODUCT(reg) == PCI_PRODUCT_COMPAQ_CSA5i || 309 PCI_PRODUCT(reg) == PCI_PRODUCT_COMPAQ_CSA532 || 310 PCI_PRODUCT(reg) == PCI_PRODUCT_COMPAQ_CSA5312)) 311 sc->iem = CISS_INTR_OPQ_SA5B; 312 313 cfg_bar = bus_space_read_2(sc->sc_iot, sc->sc_ioh, CISS_CFG_BAR); 314 sc->cfgoff = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_CFG_OFF); 315 if (cfg_bar != CISS_BAR) { 316 if (pci_mapreg_map(pa, cfg_bar, PCI_MAPREG_TYPE_MEM, 0, 317 NULL, &sc->cfg_ioh, NULL, &cfgsz)) { 318 aprint_error_dev(self, 319 "can't map controller config space\n"); 320 bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); 321 return; 322 } 323 } else { 324 sc->cfg_ioh = sc->sc_ioh; 325 cfgsz = size; 326 } 327 328 if (sc->cfgoff + sizeof(struct ciss_config) > cfgsz) { 329 aprint_error_dev(self, "unfit config space\n"); 330 bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); 331 if (cfg_bar != CISS_BAR) 332 bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz); 333 return; 334 } 335 336 /* disable interrupts until ready */ 337 #ifndef CISS_NO_INTERRUPT_HACK 338 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CISS_IMR, 339 bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_IMR) | sc->iem); 340 #endif 341 342 if (pci_intr_map(pa, &ih)) { 343 aprint_error_dev(self, "can't map interrupt\n"); 344 bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); 345 if (cfg_bar != CISS_BAR) 346 bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz); 347 return; 348 } 349 intrstr = pci_intr_string(pa->pa_pc, ih, intrbuf, sizeof(intrbuf)); 350 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ciss_intr, sc); 351 if (!sc->sc_ih) { 352 aprint_error_dev(sc->sc_dev, "can't establish interrupt"); 353 if (intrstr) 354 aprint_error(" at %s", intrstr); 355 aprint_error("\n"); 356 bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); 357 if (cfg_bar != CISS_BAR) 358 bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz); 359 } 360 361 aprint_normal_dev(self, "interrupting at %s\n%s", intrstr, 362 device_xname(sc->sc_dev)); 363 364 if (ciss_attach(sc)) { 365 pci_intr_disestablish(pa->pa_pc, sc->sc_ih); 366 sc->sc_ih = NULL; 367 bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); 368 if (cfg_bar != CISS_BAR) 369 bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz); 370 return; 371 } 372 373 #ifndef CISS_NO_INTERRUPT_HACK 374 /* enable interrupts now */ 375 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CISS_IMR, 376 bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_IMR) & ~sc->iem); 377 #else 378 callout_schedule(&sc->sc_interrupt_hack, 1); 379 #endif 380 } 381