Home | History | Annotate | Line # | Download | only in pci
ciss_pci.c revision 1.1.6.2
      1 /*	$NetBSD: ciss_pci.c,v 1.1.6.2 2006/04/11 01:15:22 riz 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.1.6.2 2006/04/11 01:15:22 riz 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 <machine/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(struct device *, struct cfdata *, void *);
     45 void	ciss_pci_attach(struct device *, struct device *, void *);
     46 
     47 CFATTACH_DECL(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(struct device *parent, struct cfdata *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(struct device *parent, struct device *self, void *aux)
    248 {
    249 	struct ciss_softc *sc = (struct ciss_softc *)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 		printf("%s: can't establish interrupt", sc->sc_dev.dv_xname);
    328 		if (intrstr)
    329 			printf(" at %s", intrstr);
    330 		printf("\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", sc->sc_dev.dv_xname, intrstr,
    337 	       sc->sc_dev.dv_xname);
    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