1 /* $OpenBSD: uha_eisa.c,v 1.15 2021/03/07 06:18:48 jsg Exp $ */ 2 /* $NetBSD: uha_eisa.c,v 1.5 1996/10/21 22:31:07 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Charles M. Hannum. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/device.h> 36 #include <sys/kernel.h> 37 #include <uvm/uvm_extern.h> 38 39 #include <machine/bus.h> 40 #include <machine/intr.h> 41 42 #include <scsi/scsi_all.h> 43 #include <scsi/scsiconf.h> 44 45 #include <dev/eisa/eisavar.h> 46 #include <dev/eisa/eisadevs.h> 47 48 #include <dev/ic/uhareg.h> 49 #include <dev/ic/uhavar.h> 50 51 #define UHA_EISA_SLOT_OFFSET 0xc80 52 #define UHA_EISA_IOSIZE 0x020 53 54 int uha_eisa_match(struct device *, void *, void *); 55 void uha_eisa_attach(struct device *, struct device *, void *); 56 57 struct cfattach uha_eisa_ca = { 58 sizeof(struct uha_softc), uha_eisa_match, uha_eisa_attach 59 }; 60 61 #define KVTOPHYS(x) vtophys((vaddr_t)(x)) 62 63 int u24_find(bus_space_tag_t, bus_space_handle_t, struct uha_softc *); 64 void u24_start_mbox(struct uha_softc *, struct uha_mscp *); 65 int u24_poll(struct uha_softc *, struct scsi_xfer *, int); 66 int u24_intr(void *); 67 void u24_init(struct uha_softc *); 68 69 /* 70 * Check the slots looking for a board we recognise 71 * If we find one, note its address (slot) and call 72 * the actual probe routine to check it out. 73 */ 74 int 75 uha_eisa_match(struct device *parent, void *match, void *aux) 76 { 77 struct eisa_attach_args *ea = aux; 78 bus_space_tag_t iot = ea->ea_iot; 79 bus_space_handle_t ioh; 80 int rv; 81 82 /* must match one of our known ID strings */ 83 if (strncmp(ea->ea_idstring, "USC024", 6)) 84 return (0); 85 86 if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) + 87 UHA_EISA_SLOT_OFFSET, UHA_EISA_IOSIZE, 0, &ioh)) 88 return (0); 89 90 rv = u24_find(iot, ioh, NULL); 91 92 bus_space_unmap(iot, ioh, UHA_EISA_IOSIZE); 93 94 return (rv); 95 } 96 97 /* 98 * Attach all the sub-devices we can find 99 */ 100 void 101 uha_eisa_attach(struct device *parent, struct device *self, void *aux) 102 { 103 struct eisa_attach_args *ea = aux; 104 struct uha_softc *sc = (void *)self; 105 bus_space_tag_t iot = ea->ea_iot; 106 bus_space_handle_t ioh; 107 eisa_chipset_tag_t ec = ea->ea_ec; 108 eisa_intr_handle_t ih; 109 const char *model, *intrstr; 110 111 if (!strncmp(ea->ea_idstring, "USC024", 6)) 112 model = EISA_PRODUCT_USC0240; 113 else 114 model = "unknown model!"; 115 printf(": %s\n", model); 116 117 if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) + 118 UHA_EISA_SLOT_OFFSET, UHA_EISA_IOSIZE, 0, &ioh)) 119 panic("uha_attach: can't map I/O addresses"); 120 121 sc->sc_iot = iot; 122 sc->sc_ioh = ioh; 123 if (!u24_find(iot, ioh, sc)) 124 panic("uha_attach: u24_find failed!"); 125 126 if (eisa_intr_map(ec, sc->sc_irq, &ih)) { 127 printf("%s: couldn't map interrupt (%d)\n", 128 sc->sc_dev.dv_xname, sc->sc_irq); 129 return; 130 } 131 intrstr = eisa_intr_string(ec, ih); 132 sc->sc_ih = eisa_intr_establish(ec, ih, IST_LEVEL, IPL_BIO, 133 u24_intr, sc, sc->sc_dev.dv_xname); 134 if (sc->sc_ih == NULL) { 135 printf("%s: couldn't establish interrupt", 136 sc->sc_dev.dv_xname); 137 if (intrstr != NULL) 138 printf(" at %s", intrstr); 139 printf("\n"); 140 return; 141 } 142 printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); 143 144 /* Save function pointers for later use. */ 145 sc->start_mbox = u24_start_mbox; 146 sc->poll = u24_poll; 147 sc->init = u24_init; 148 149 uha_attach(sc); 150 } 151 152 int 153 u24_find(bus_space_tag_t iot, bus_space_handle_t ioh, struct uha_softc *sc) 154 { 155 u_int8_t config0, config1, config2; 156 int irq, drq; 157 int resetcount = 4000; /* 4 secs? */ 158 159 config0 = bus_space_read_1(iot, ioh, U24_CONFIG + 0); 160 config1 = bus_space_read_1(iot, ioh, U24_CONFIG + 1); 161 config2 = bus_space_read_1(iot, ioh, U24_CONFIG + 2); 162 if ((config0 & U24_MAGIC1) == 0 || 163 (config1 & U24_MAGIC2) == 0) 164 return (0); 165 166 drq = -1; 167 168 switch (config0 & U24_IRQ_MASK) { 169 case U24_IRQ10: 170 irq = 10; 171 break; 172 case U24_IRQ11: 173 irq = 11; 174 break; 175 case U24_IRQ14: 176 irq = 14; 177 break; 178 case U24_IRQ15: 179 irq = 15; 180 break; 181 default: 182 printf("u24_find: illegal irq setting %x\n", 183 config0 & U24_IRQ_MASK); 184 return (0); 185 } 186 187 bus_space_write_1(iot, ioh, U24_LINT, UHA_ASRST); 188 189 while (--resetcount) { 190 if (bus_space_read_1(iot, ioh, U24_LINT)) 191 break; 192 delay(1000); /* 1 mSec per loop */ 193 } 194 if (!resetcount) { 195 printf("u24_find: board timed out during reset\n"); 196 return (0); 197 } 198 199 /* if we want to fill in softc, do so now */ 200 if (sc != NULL) { 201 sc->sc_irq = irq; 202 sc->sc_drq = drq; 203 sc->sc_scsi_dev = config2 & U24_HOSTID_MASK; 204 } 205 206 return (1); 207 } 208 209 void 210 u24_start_mbox(struct uha_softc *sc, struct uha_mscp *mscp) 211 { 212 bus_space_tag_t iot = sc->sc_iot; 213 bus_space_handle_t ioh = sc->sc_ioh; 214 int spincount = 100000; /* 1s should be enough */ 215 216 while (--spincount) { 217 if ((bus_space_read_1(iot, ioh, U24_LINT) & U24_LDIP) == 0) 218 break; 219 delay(100); 220 } 221 if (!spincount) 222 panic("%s: uha_start_mbox, board not responding", 223 sc->sc_dev.dv_xname); 224 225 bus_space_write_4(iot, ioh, U24_OGMPTR, KVTOPHYS(mscp)); 226 if (mscp->flags & MSCP_ABORT) 227 bus_space_write_1(iot, ioh, U24_OGMCMD, 0x80); 228 else 229 bus_space_write_1(iot, ioh, U24_OGMCMD, 0x01); 230 bus_space_write_1(iot, ioh, U24_LINT, U24_OGMFULL); 231 232 if ((mscp->xs->flags & SCSI_POLL) == 0) 233 timeout_add_msec(&mscp->xs->stimeout, mscp->timeout); 234 } 235 236 int 237 u24_poll(struct uha_softc *sc, struct scsi_xfer *xs, int count) 238 { 239 bus_space_tag_t iot = sc->sc_iot; 240 bus_space_handle_t ioh = sc->sc_ioh; 241 int s; 242 243 while (count) { 244 /* 245 * If we had interrupts enabled, would we 246 * have got an interrupt? 247 */ 248 if (bus_space_read_1(iot, ioh, U24_SINT) & U24_SDIP) { 249 s = splbio(); 250 u24_intr(sc); 251 splx(s); 252 } 253 if (xs->flags & ITSDONE) 254 return (0); 255 delay(1000); 256 count--; 257 } 258 return (1); 259 } 260 261 int 262 u24_intr(void *arg) 263 { 264 struct uha_softc *sc = arg; 265 bus_space_tag_t iot = sc->sc_iot; 266 bus_space_handle_t ioh = sc->sc_ioh; 267 struct uha_mscp *mscp; 268 u_char uhastat; 269 u_long mboxval; 270 271 #ifdef UHADEBUG 272 printf("%s: uhaintr ", sc->sc_dev.dv_xname); 273 #endif /*UHADEBUG */ 274 275 if ((bus_space_read_1(iot, ioh, U24_SINT) & U24_SDIP) == 0) 276 return (0); 277 278 for (;;) { 279 /* 280 * First get all the information and then 281 * acknowledge the interrupt 282 */ 283 uhastat = bus_space_read_1(iot, ioh, U24_SINT); 284 mboxval = bus_space_read_4(iot, ioh, U24_ICMPTR); 285 bus_space_write_1(iot, ioh, U24_SINT, U24_ICM_ACK); 286 bus_space_write_1(iot, ioh, U24_ICMCMD, 0); 287 288 #ifdef UHADEBUG 289 printf("status = 0x%x ", uhastat); 290 #endif /*UHADEBUG*/ 291 292 /* 293 * Process the completed operation 294 */ 295 mscp = uha_mscp_phys_kv(sc, mboxval); 296 if (!mscp) { 297 printf("%s: BAD MSCP RETURNED!\n", 298 sc->sc_dev.dv_xname); 299 continue; /* whatever it was, it'll timeout */ 300 } 301 timeout_del(&mscp->xs->stimeout); 302 uha_done(sc, mscp); 303 304 if ((bus_space_read_1(iot, ioh, U24_SINT) & U24_SDIP) == 0) 305 return (1); 306 } 307 } 308 309 void 310 u24_init(struct uha_softc *sc) 311 { 312 bus_space_tag_t iot = sc->sc_iot; 313 bus_space_handle_t ioh = sc->sc_ioh; 314 315 /* free OGM and ICM */ 316 bus_space_write_1(iot, ioh, U24_OGMCMD, 0); 317 bus_space_write_1(iot, ioh, U24_ICMCMD, 0); 318 /* make sure interrupts are enabled */ 319 #ifdef UHADEBUG 320 printf("u24_init: lmask=%02x, smask=%02x\n", 321 bus_space_read_1(iot, ioh, U24_LMASK), 322 bus_space_read_1(iot, ioh, U24_SMASK)); 323 #endif 324 bus_space_write_1(iot, ioh, U24_LMASK, 0xd2); /* XXX */ 325 bus_space_write_1(iot, ioh, U24_SMASK, 0x92); /* XXX */ 326 } 327