1 /* $NetBSD: ciss_pci.c,v 1.22 2020/07/14 17:23:58 jdolecek 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.22 2020/07/14 17:23:58 jdolecek 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 51 static const struct { 52 int vendor; 53 int product; 54 const char *name; 55 } ciss_pci_devices[] = { 56 #define CISS_PCI_DEVICE(v, p, d) { PCI_VENDOR_##v, PCI_PRODUCT_##v##_##p, d } 57 CISS_PCI_DEVICE(COMPAQ, CSA532, "Compaq Smart Array 532"), 58 CISS_PCI_DEVICE(COMPAQ, CSA5300, "Compaq Smart Array 5300 V1"), 59 CISS_PCI_DEVICE(COMPAQ, CSA5300_2, "Compaq Smart Array 5300 V2"), 60 CISS_PCI_DEVICE(COMPAQ, CSA5312, "Compaq Smart Array 5312"), 61 CISS_PCI_DEVICE(COMPAQ, CSA5i, "Compaq Smart Array 5i"), 62 CISS_PCI_DEVICE(COMPAQ, CSA5i_2, "Compaq Smart Array 5i V2"), 63 CISS_PCI_DEVICE(COMPAQ, CSA6i, "Compaq Smart Array 6i"), 64 CISS_PCI_DEVICE(COMPAQ, CSA641, "Compaq Smart Array 641"), 65 CISS_PCI_DEVICE(COMPAQ, CSA642, "Compaq Smart Array 642"), 66 CISS_PCI_DEVICE(COMPAQ, CSA6400, "Compaq Smart Array 6400"), 67 CISS_PCI_DEVICE(COMPAQ, CSA6400EM, "Compaq Smart Array 6400EM"), 68 CISS_PCI_DEVICE(COMPAQ, CSA6422, "Compaq Smart Array 6422"), 69 CISS_PCI_DEVICE(COMPAQ, CSA64XX, "Compaq Smart Array 64XX"), 70 CISS_PCI_DEVICE(HP, HPSAE200, "Smart Array E200"), 71 CISS_PCI_DEVICE(HP, HPSAE200I_1, "HP Smart Array E200I-1"), 72 CISS_PCI_DEVICE(HP, HPSAE200I_2, "HP Smart Array E200I-2"), 73 CISS_PCI_DEVICE(HP, HPSAE200I_3, "HP Smart Array E200I-3"), 74 CISS_PCI_DEVICE(HP, HPSAP600, "HP Smart Array P600"), 75 CISS_PCI_DEVICE(HP, HPSAP800, "HP Smart Array P800"), 76 CISS_PCI_DEVICE(HP, HPSAV100, "HP Smart Array V100"), 77 CISS_PCI_DEVICE(HP, HPSA_1, "HP Smart Array 1"), 78 CISS_PCI_DEVICE(HP, HPSA_2, "HP Smart Array 2"), 79 CISS_PCI_DEVICE(HP, HPSA_3, "HP Smart Array 3"), 80 CISS_PCI_DEVICE(HP, HPSA_4, "HP Smart Array 4"), 81 CISS_PCI_DEVICE(HP, HPSA_5, "HP Smart Array 5"), 82 CISS_PCI_DEVICE(HP, HPSA_6, "HP Smart Array 6"), 83 CISS_PCI_DEVICE(HP, HPSA_7, "HP Smart Array 7"), 84 CISS_PCI_DEVICE(HP, HPSA_8, "HP Smart Array 8"), 85 CISS_PCI_DEVICE(HP, HPSA_9, "HP Smart Array 9"), 86 CISS_PCI_DEVICE(HP, HPSA_10, "HP Smart Array 10"), 87 CISS_PCI_DEVICE(HP, HPSA_11, "HP Smart Array 11"), 88 CISS_PCI_DEVICE(HP, HPSA_12, "HP Smart Array 12"), 89 CISS_PCI_DEVICE(HP, HPSA_13, "HP Smart Array 13"), 90 CISS_PCI_DEVICE(HP, HPSA_P700M, "Smart Array P700m"), 91 CISS_PCI_DEVICE(HP, HPSA_P212, "Smart Array P212"), 92 CISS_PCI_DEVICE(HP, HPSA_P410, "Smart Array P410"), 93 CISS_PCI_DEVICE(HP, HPSA_P410I, "Smart Array P410i"), 94 CISS_PCI_DEVICE(HP, HPSA_P411, "Smart Array P411"), 95 CISS_PCI_DEVICE(HP, HPSA_P812, "Smart Array P822"), 96 CISS_PCI_DEVICE(HP, HPSA_P712M, "Smart Array P712m"), 97 CISS_PCI_DEVICE(HP, HPSA_14, "Smart Array 14"), 98 CISS_PCI_DEVICE(HP, HPSA_P222, "Smart Array P222"), 99 CISS_PCI_DEVICE(HP, HPSA_P420, "Smart Array P420"), 100 CISS_PCI_DEVICE(HP, HPSA_P421, "Smart Array P421"), 101 CISS_PCI_DEVICE(HP, HPSA_P822, "Smart Array P822"), 102 CISS_PCI_DEVICE(HP, HPSA_P420I, "Smart Array P420i"), 103 CISS_PCI_DEVICE(HP, HPSA_P220I, "Smart Array P220i"), 104 CISS_PCI_DEVICE(HP, HPSA_P721I, "Smart Array P721i"), 105 CISS_PCI_DEVICE(HP, HPSA_P430I, "Smart Array P430i"), 106 CISS_PCI_DEVICE(HP, HPSA_P830I, "Smart Array P830i"), 107 CISS_PCI_DEVICE(HP, HPSA_P430, "Smart Array P430"), 108 CISS_PCI_DEVICE(HP, HPSA_P431, "Smart Array P431"), 109 CISS_PCI_DEVICE(HP, HPSA_P830, "Smart Array P830"), 110 CISS_PCI_DEVICE(HP, HPSA_P731M, "Smart Array P731m"), 111 CISS_PCI_DEVICE(HP, HPSA_P230I, "Smart Array P230i"), 112 CISS_PCI_DEVICE(HP, HPSA_P530, "Smart Array P530"), 113 CISS_PCI_DEVICE(HP, HPSA_P531, "Smart Array P531"), 114 CISS_PCI_DEVICE(HP, HPSA_P244BR, "Smart Array P244br"), 115 CISS_PCI_DEVICE(HP, HPSA_P741M, "Smart Array P741m"), 116 CISS_PCI_DEVICE(HP, HPSA_H240AR, "Smart Array H240ar"), 117 CISS_PCI_DEVICE(HP, HPSA_P440AR, "Smart Array H440ar"), 118 CISS_PCI_DEVICE(HP, HPSA_P840AR, "Smart Array P840ar"), 119 CISS_PCI_DEVICE(HP, HPSA_P440, "Smart Array P440"), 120 CISS_PCI_DEVICE(HP, HPSA_P441, "Smart Array P441"), 121 CISS_PCI_DEVICE(HP, HPSA_P841, "Smart Array P841"), 122 CISS_PCI_DEVICE(HP, HPSA_H244BR, "Smart Array H244br"), 123 CISS_PCI_DEVICE(HP, HPSA_H240, "Smart Array H240"), 124 CISS_PCI_DEVICE(HP, HPSA_H241, "Smart Array H241"), 125 CISS_PCI_DEVICE(HP, HPSA_P246BR, "Smart Array P246br"), 126 CISS_PCI_DEVICE(HP, HPSA_P840, "Smart Array P840"), 127 CISS_PCI_DEVICE(HP, HPSA_P542D, "Smart Array P542d"), 128 CISS_PCI_DEVICE(HP, HPSA_P240NR, "Smart Array P240nr"), 129 CISS_PCI_DEVICE(HP, HPSA_H240NR, "Smart Array H240nr"), 130 }; 131 132 int 133 ciss_pci_match(device_t parent, cfdata_t match, void *aux) 134 { 135 struct pci_attach_args *pa = aux; 136 pcireg_t reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); 137 int i; 138 139 for (i = 0; i < __arraycount(ciss_pci_devices); i++) 140 { 141 if ((PCI_VENDOR(pa->pa_id) == ciss_pci_devices[i].vendor && 142 PCI_PRODUCT(pa->pa_id) == ciss_pci_devices[i].product) || 143 (PCI_VENDOR(reg) == ciss_pci_devices[i].vendor && 144 PCI_PRODUCT(reg) == ciss_pci_devices[i].product)) 145 return 1; 146 } 147 148 return 0; 149 } 150 151 void 152 ciss_pci_attach(device_t parent, device_t self, void *aux) 153 { 154 struct ciss_softc *sc = device_private(self); 155 struct pci_attach_args *pa = aux; 156 bus_size_t size, cfgsz; 157 pci_intr_handle_t *ih; 158 const char *intrstr; 159 int cfg_bar, memtype; 160 pcireg_t reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); 161 int i; 162 char intrbuf[PCI_INTRSTR_LEN]; 163 int (*intr_handler)(void *); 164 165 sc->sc_dev = self; 166 167 aprint_naive("\n"); 168 for (i = 0; i < __arraycount(ciss_pci_devices); i++) 169 { 170 if ((PCI_VENDOR(pa->pa_id) == ciss_pci_devices[i].vendor && 171 PCI_PRODUCT(pa->pa_id) == ciss_pci_devices[i].product) || 172 (PCI_VENDOR(reg) == ciss_pci_devices[i].vendor && 173 PCI_PRODUCT(reg) == ciss_pci_devices[i].product)) 174 { 175 aprint_normal(": %s\n", ciss_pci_devices[i].name); 176 break; 177 } 178 } 179 180 memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, CISS_BAR); 181 if (memtype != (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT) && 182 memtype != (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT)) { 183 aprint_error_dev(self, "wrong BAR type\n"); 184 return; 185 } 186 if (pci_mapreg_map(pa, CISS_BAR, memtype, 0, 187 &sc->sc_iot, &sc->sc_ioh, NULL, &size)) { 188 aprint_error_dev(self, "can't map controller i/o space\n"); 189 return; 190 } 191 sc->sc_dmat = pa->pa_dmat; 192 193 sc->iem = CISS_INTR_OPQ_SA5; 194 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); 195 if (PCI_VENDOR(reg) == PCI_VENDOR_COMPAQ && 196 (PCI_PRODUCT(reg) == PCI_PRODUCT_COMPAQ_CSA5i || 197 PCI_PRODUCT(reg) == PCI_PRODUCT_COMPAQ_CSA532 || 198 PCI_PRODUCT(reg) == PCI_PRODUCT_COMPAQ_CSA5312)) 199 sc->iem = CISS_INTR_OPQ_SA5B; 200 201 cfg_bar = bus_space_read_2(sc->sc_iot, sc->sc_ioh, CISS_CFG_BAR); 202 sc->cfgoff = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_CFG_OFF); 203 if (cfg_bar != CISS_BAR) { 204 if (pci_mapreg_map(pa, cfg_bar, PCI_MAPREG_TYPE_MEM, 0, 205 NULL, &sc->cfg_ioh, NULL, &cfgsz)) { 206 aprint_error_dev(self, 207 "can't map controller config space\n"); 208 bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); 209 return; 210 } 211 } else { 212 sc->cfg_ioh = sc->sc_ioh; 213 cfgsz = size; 214 } 215 216 if (sc->cfgoff + sizeof(struct ciss_config) > cfgsz) { 217 aprint_error_dev(self, "unfit config space\n"); 218 bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); 219 if (cfg_bar != CISS_BAR) 220 bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz); 221 return; 222 } 223 224 /* Read the configuration */ 225 bus_space_read_region_4(sc->sc_iot, sc->cfg_ioh, sc->cfgoff, 226 (u_int32_t *)&sc->cfg, sizeof(sc->cfg) / 4); 227 228 /* disable interrupts until ready */ 229 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CISS_IMR, 230 bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_IMR) | 231 sc->iem | CISS_INTR_OPQ | CISS_INTR_MSI); 232 233 int counts[PCI_INTR_TYPE_SIZE] = { 234 [PCI_INTR_TYPE_INTX] = 1, 235 [PCI_INTR_TYPE_MSI] = 0, 236 [PCI_INTR_TYPE_MSIX] = 0, 237 }; 238 int max_type = PCI_INTR_TYPE_INTX; 239 240 /* 241 * Allow MSI/MSI-X only if PERFORMANT method is supported, SIMPLE 242 * doesn't seem to work with MSI. 243 */ 244 if (CISS_PERF_SUPPORTED(sc)) { 245 #if 1 246 counts[PCI_INTR_TYPE_MSI] = counts[PCI_INTR_TYPE_MSIX] = 1; 247 max_type = PCI_INTR_TYPE_MSIX; 248 #endif 249 sc->iem |= CISS_INTR_OPQ | CISS_INTR_MSI; 250 } 251 252 if (pci_intr_alloc(pa, &ih, counts, max_type)) { 253 aprint_error_dev(self, "can't map interrupt\n"); 254 bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); 255 if (cfg_bar != CISS_BAR) 256 bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz); 257 return; 258 } 259 intrstr = pci_intr_string(pa->pa_pc, ih[0], intrbuf, sizeof(intrbuf)); 260 261 switch (pci_intr_type(pa->pa_pc, ih[0])) { 262 case PCI_INTR_TYPE_INTX: 263 intr_handler = CISS_PERF_SUPPORTED(sc) 264 ? ciss_intr_perf_intx : ciss_intr_simple_intx; 265 break; 266 default: 267 KASSERT(CISS_PERF_SUPPORTED(sc)); 268 intr_handler = ciss_intr_perf_msi; 269 break; 270 } 271 272 sc->sc_ih = pci_intr_establish_xname(pa->pa_pc, ih[0], IPL_BIO, 273 intr_handler, sc, device_xname(self)); 274 if (!sc->sc_ih) { 275 aprint_error_dev(sc->sc_dev, "can't establish interrupt"); 276 if (intrstr) 277 aprint_error(" at %s", intrstr); 278 aprint_error("\n"); 279 pci_intr_release(pa->pa_pc, ih, 1); 280 bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); 281 if (cfg_bar != CISS_BAR) 282 bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz); 283 return; 284 } 285 aprint_normal_dev(self, "interrupting at %s\n", intrstr); 286 287 aprint_normal("%s", device_xname(sc->sc_dev)); 288 if (ciss_attach(sc)) { 289 pci_intr_disestablish(pa->pa_pc, sc->sc_ih); 290 sc->sc_ih = NULL; 291 bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); 292 if (cfg_bar != CISS_BAR) 293 bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz); 294 return; 295 } 296 297 /* enable interrupts now */ 298 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CISS_IMR, 299 bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_IMR) & ~sc->iem); 300 } 301