1 /* $OpenBSD: qla_sbus.c,v 1.2 2014/07/12 18:48:52 tedu Exp $ */ 2 /* 3 * Copyright (c) 2014 Mark Kettenis 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/device.h> 20 #include <sys/malloc.h> 21 #include <sys/systm.h> 22 23 #include <machine/bus.h> 24 #include <machine/intr.h> 25 #include <machine/autoconf.h> 26 27 #include <dev/sbus/sbusvar.h> 28 #include <dev/pci/pcireg.h> 29 #include <dev/pci/pcivar.h> 30 #include <dev/pci/pcidevs.h> 31 32 #include <scsi/scsi_all.h> 33 #include <scsi/scsiconf.h> 34 35 #include <dev/ic/qlareg.h> 36 #include <dev/ic/qlavar.h> 37 38 #define QLA_SBUS_REG_OFFSET 0x100 39 #define QLA_SBUS_REG_SIZE 0x300 40 41 int qla_sbus_match(struct device *, void *, void *); 42 void qla_sbus_attach(struct device *, struct device *, void *); 43 44 struct cfattach qla_sbus_ca = { 45 sizeof(struct qla_softc), 46 qla_sbus_match, 47 qla_sbus_attach 48 }; 49 50 int 51 qla_sbus_match(struct device *parent, void *cf, void *aux) 52 { 53 struct sbus_attach_args *sa = aux; 54 55 if (strcmp("SUNW,qlc", sa->sa_name) == 0 || 56 strcmp("QLGC,qla", sa->sa_name) == 0) 57 return 2; 58 59 return 0; 60 } 61 62 void 63 qla_sbus_attach(struct device *parent, struct device *self, void *aux) 64 { 65 struct qla_softc *sc = (void *)self; 66 struct sbus_attach_args *sa = aux; 67 struct sparc_bus_space_tag *iot; 68 bus_space_handle_t ioh; 69 pcireg_t id, class; 70 char devinfo[256]; 71 72 if (sa->sa_nintr < 1) { 73 printf(": no interrupt\n"); 74 return; 75 } 76 77 if (sa->sa_nreg < 1) { 78 printf(": no registers\n"); 79 return; 80 } 81 82 /* 83 * These cards have a standard PCI chips that sit behind an 84 * FPGA with some bridging logic. Since the PCI bus is 85 * little-endian, we need a little-endian bus tag. So we 86 * build one here. 87 */ 88 iot = malloc(sizeof(*iot), M_DEVBUF, M_NOWAIT); 89 if (iot == NULL) { 90 printf(": can't allocate bus tag\n"); 91 return; 92 } 93 *iot = *sa->sa_bustag; 94 iot->asi = ASI_PRIMARY_LITTLE; 95 96 if (sbus_bus_map(iot, sa->sa_slot, sa->sa_offset, 97 sa->sa_size, 0, 0, &ioh) != 0) { 98 printf(": can't map registers\n"); 99 goto free; 100 } 101 102 /* 103 * PCI config space is mapped at the start of the SBus 104 * register space. We use it to identify the ISP chip. 105 */ 106 id = bus_space_read_4(iot, ioh, PCI_ID_REG); 107 class = bus_space_read_4(iot, ioh, PCI_CLASS_REG); 108 109 pci_devinfo(id, class, 0, devinfo, sizeof(devinfo)); 110 printf(": %s\n", devinfo); 111 112 switch (PCI_PRODUCT(id)) { 113 case PCI_PRODUCT_QLOGIC_ISP2200: 114 sc->sc_isp_gen = QLA_GEN_ISP2200; 115 sc->sc_isp_type = QLA_ISP2200; 116 break; 117 118 case PCI_PRODUCT_QLOGIC_ISP2300: 119 sc->sc_isp_gen = QLA_GEN_ISP23XX; 120 sc->sc_isp_type = QLA_ISP2300; 121 break; 122 123 case PCI_PRODUCT_QLOGIC_ISP2312: 124 sc->sc_isp_gen = QLA_GEN_ISP23XX; 125 sc->sc_isp_type = QLA_ISP2312; 126 break; 127 128 default: 129 printf("%s: unsupported ISP chip\n", DEVNAME(sc)); 130 goto unmap; 131 } 132 133 if (bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_BIO, 0, 134 qla_intr, sc, sc->sc_dev.dv_xname) == NULL) { 135 printf("%s: can't establish interrupt\n", DEVNAME(sc)); 136 goto unmap; 137 } 138 139 if (bus_space_subregion(iot, ioh, QLA_SBUS_REG_OFFSET, 140 QLA_SBUS_REG_SIZE, &sc->sc_ioh) != 0) { 141 printf("%s: can't submap registers\n", DEVNAME(sc)); 142 goto unmap; 143 } 144 145 sc->sc_iot = iot; 146 sc->sc_ios = QLA_SBUS_REG_SIZE; 147 sc->sc_dmat = sa->sa_dmatag; 148 149 qla_attach(sc); 150 return; 151 152 unmap: 153 bus_space_unmap(iot, ioh, sa->sa_size); 154 free: 155 free(iot, M_DEVBUF, 0); 156 } 157