Home | History | Annotate | Line # | Download | only in pci
ciss_pci.c revision 1.19
      1 /*	$NetBSD: ciss_pci.c,v 1.19 2020/07/14 12:04:46 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.19 2020/07/14 12:04:46 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 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 void
    247 ciss_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 	char intrbuf[PCI_INTRSTR_LEN];
    258 	int (*intr_handler)(void *);
    259 
    260 	sc->sc_dev = self;
    261 
    262 	aprint_naive("\n");
    263 	for (i = 0; ciss_pci_devices[i].vendor; i++)
    264 	{
    265 		if ((PCI_VENDOR(pa->pa_id) == ciss_pci_devices[i].vendor &&
    266 		     PCI_PRODUCT(pa->pa_id) == ciss_pci_devices[i].product) ||
    267 		    (PCI_VENDOR(reg) == ciss_pci_devices[i].vendor &&
    268 		     PCI_PRODUCT(reg) == ciss_pci_devices[i].product))
    269 		{
    270 			aprint_normal(": %s\n", ciss_pci_devices[i].name);
    271 			break;
    272 		}
    273 	}
    274 
    275 	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, CISS_BAR);
    276 	if (memtype != (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT) &&
    277 	    memtype != (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT)) {
    278 		aprint_error_dev(self, "wrong BAR type\n");
    279 		return;
    280 	}
    281 	if (pci_mapreg_map(pa, CISS_BAR, memtype, 0,
    282 	    &sc->sc_iot, &sc->sc_ioh, NULL, &size)) {
    283 		aprint_error_dev(self, "can't map controller i/o space\n");
    284 		return;
    285 	}
    286 	sc->sc_dmat = pa->pa_dmat;
    287 
    288 	sc->iem = CISS_INTR_OPQ_SA5;
    289 	reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
    290 	if (PCI_VENDOR(reg) == PCI_VENDOR_COMPAQ &&
    291 	    (PCI_PRODUCT(reg) == PCI_PRODUCT_COMPAQ_CSA5i ||
    292 	     PCI_PRODUCT(reg) == PCI_PRODUCT_COMPAQ_CSA532 ||
    293 	     PCI_PRODUCT(reg) == PCI_PRODUCT_COMPAQ_CSA5312))
    294 		sc->iem = CISS_INTR_OPQ_SA5B;
    295 
    296 	cfg_bar = bus_space_read_2(sc->sc_iot, sc->sc_ioh, CISS_CFG_BAR);
    297 	sc->cfgoff = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_CFG_OFF);
    298 	if (cfg_bar != CISS_BAR) {
    299 		if (pci_mapreg_map(pa, cfg_bar, PCI_MAPREG_TYPE_MEM, 0,
    300 		    NULL, &sc->cfg_ioh, NULL, &cfgsz)) {
    301 			aprint_error_dev(self,
    302 			    "can't map controller config space\n");
    303 			bus_space_unmap(sc->sc_iot, sc->sc_ioh, size);
    304 			return;
    305 		}
    306 	} else {
    307 		sc->cfg_ioh = sc->sc_ioh;
    308 		cfgsz = size;
    309 	}
    310 
    311 	if (sc->cfgoff + sizeof(struct ciss_config) > cfgsz) {
    312 		aprint_error_dev(self, "unfit config space\n");
    313 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, size);
    314 		if (cfg_bar != CISS_BAR)
    315 			bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz);
    316 		return;
    317 	}
    318 
    319 	/* Read the configuration */
    320 	bus_space_read_region_4(sc->sc_iot, sc->cfg_ioh, sc->cfgoff,
    321 	    (u_int32_t *)&sc->cfg, sizeof(sc->cfg) / 4);
    322 
    323 	/* disable interrupts until ready */
    324 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, CISS_IMR,
    325 	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_IMR) |
    326 		sc->iem | CISS_INTR_OPQ | CISS_INTR_MSI);
    327 
    328 	int counts[PCI_INTR_TYPE_SIZE] = {
    329 		[PCI_INTR_TYPE_INTX] = 1,
    330 		[PCI_INTR_TYPE_MSI] = 0,
    331 		[PCI_INTR_TYPE_MSIX] = 0,
    332 	};
    333 	int max_type = PCI_INTR_TYPE_INTX;
    334 
    335 	/*
    336 	 * Allow MSI/MSI-X only if PERFORMANT method is supported, SIMPLE
    337 	 * doesn't seem to work with MSI.
    338 	 */
    339 	if (CISS_PERF_SUPPORTED(sc)) {
    340 #if 1
    341 		counts[PCI_INTR_TYPE_MSI] = counts[PCI_INTR_TYPE_MSIX] = 1;
    342 		max_type = PCI_INTR_TYPE_MSIX;
    343 #endif
    344 		sc->iem |= CISS_INTR_OPQ | CISS_INTR_MSI;
    345 	}
    346 
    347 	if (pci_intr_alloc(pa, &ih, counts, max_type)) {
    348 		aprint_error_dev(self, "can't map interrupt\n");
    349 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, size);
    350 		if (cfg_bar != CISS_BAR)
    351 			bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz);
    352 		return;
    353 	}
    354 	intrstr = pci_intr_string(pa->pa_pc, ih[0], intrbuf, sizeof(intrbuf));
    355 
    356 	switch (pci_intr_type(pa->pa_pc, ih[0])) {
    357 	case PCI_INTR_TYPE_INTX:
    358 		intr_handler = CISS_PERF_SUPPORTED(sc)
    359 		    ? ciss_intr_perf_intx : ciss_intr_simple_intx;
    360 		break;
    361 	default:
    362 		KASSERT(CISS_PERF_SUPPORTED(sc));
    363 		intr_handler = ciss_intr_perf_msi;
    364 		break;
    365 	}
    366 
    367 	sc->sc_ih = pci_intr_establish_xname(pa->pa_pc, ih[0], IPL_BIO,
    368 	    intr_handler, sc, device_xname(self));
    369 	if (!sc->sc_ih) {
    370 		aprint_error_dev(sc->sc_dev, "can't establish interrupt");
    371 		if (intrstr)
    372 			aprint_error(" at %s", intrstr);
    373 		aprint_error("\n");
    374 		pci_intr_release(pa->pa_pc, ih, 1);
    375 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, size);
    376 		if (cfg_bar != CISS_BAR)
    377 			bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz);
    378 		return;
    379 	}
    380 	aprint_normal_dev(self, "interrupting at %s\n", intrstr);
    381 
    382 	aprint_normal("%s", device_xname(sc->sc_dev));
    383 	if (ciss_attach(sc)) {
    384 		pci_intr_disestablish(pa->pa_pc, sc->sc_ih);
    385 		sc->sc_ih = NULL;
    386 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, size);
    387 		if (cfg_bar != CISS_BAR)
    388 			bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz);
    389 		return;
    390 	}
    391 
    392 	/* enable interrupts now */
    393 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, CISS_IMR,
    394 	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_IMR) & ~sc->iem);
    395 }
    396