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