1/* $OpenBSD: uha_eisa.c,v 1.16 2022/04/06 18:59:28 naddy 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 54int uha_eisa_match(struct device *, void *, void *); 55void uha_eisa_attach(struct device *, struct device *, void *); 56 57const 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 63int u24_find(bus_space_tag_t, bus_space_handle_t, struct uha_softc *); 64void u24_start_mbox(struct uha_softc *, struct uha_mscp *); 65int u24_poll(struct uha_softc *, struct scsi_xfer *, int); 66int u24_intr(void *); 67void 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 */ 74int 75uha_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 */ 100void 101uha_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 152int 153u24_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 209void 210u24_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 236int 237u24_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 261int 262u24_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 309void 310u24_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