1 /* $NetBSD: uha_eisa.c,v 1.21 2002/10/02 16:33:48 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 <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: uha_eisa.c,v 1.21 2002/10/02 16:33:48 thorpej Exp $"); 41 42 #include "opt_ddb.h" 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/device.h> 47 #include <sys/kernel.h> 48 #include <sys/proc.h> 49 #include <sys/user.h> 50 51 #include <machine/bus.h> 52 #include <machine/intr.h> 53 54 #include <dev/scsipi/scsi_all.h> 55 #include <dev/scsipi/scsipi_all.h> 56 #include <dev/scsipi/scsiconf.h> 57 58 #include <dev/eisa/eisavar.h> 59 #include <dev/eisa/eisadevs.h> 60 61 #include <dev/ic/uhareg.h> 62 #include <dev/ic/uhavar.h> 63 64 #define UHA_EISA_SLOT_OFFSET 0xc80 65 #define UHA_EISA_IOSIZE 0x020 66 67 int uha_eisa_match __P((struct device *, struct cfdata *, void *)); 68 void uha_eisa_attach __P((struct device *, struct device *, void *)); 69 70 CFATTACH_DECL(uha_eisa, sizeof(struct uha_softc), 71 uha_eisa_match, uha_eisa_attach, NULL, NULL); 72 73 #ifndef DDB 74 #define Debugger() panic("should call debugger here (uha_eisa.c)") 75 #endif /* ! DDB */ 76 77 int u24_find __P((bus_space_tag_t, bus_space_handle_t, 78 struct uha_probe_data *)); 79 void u24_start_mbox __P((struct uha_softc *, struct uha_mscp *)); 80 int u24_poll __P((struct uha_softc *, struct scsipi_xfer *, int)); 81 int u24_intr __P((void *)); 82 void u24_init __P((struct uha_softc *)); 83 84 /* 85 * Check the slots looking for a board we recognise 86 * If we find one, note it's address (slot) and call 87 * the actual probe routine to check it out. 88 */ 89 int 90 uha_eisa_match(parent, match, aux) 91 struct device *parent; 92 struct cfdata *match; 93 void *aux; 94 { 95 struct eisa_attach_args *ea = aux; 96 bus_space_tag_t iot = ea->ea_iot; 97 bus_space_handle_t ioh; 98 int rv; 99 100 /* must match one of our known ID strings */ 101 if (strncmp(ea->ea_idstring, "USC024", 6)) 102 return (0); 103 104 if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) + 105 UHA_EISA_SLOT_OFFSET, UHA_EISA_IOSIZE, 0, &ioh)) 106 return (0); 107 108 rv = u24_find(iot, ioh, NULL); 109 110 bus_space_unmap(iot, ioh, UHA_EISA_IOSIZE); 111 112 return (rv); 113 } 114 115 /* 116 * Attach all the sub-devices we can find 117 */ 118 void 119 uha_eisa_attach(parent, self, aux) 120 struct device *parent, *self; 121 void *aux; 122 { 123 struct eisa_attach_args *ea = aux; 124 struct uha_softc *sc = (void *)self; 125 bus_space_tag_t iot = ea->ea_iot; 126 bus_dma_tag_t dmat = ea->ea_dmat; 127 bus_space_handle_t ioh; 128 struct uha_probe_data upd; 129 eisa_chipset_tag_t ec = ea->ea_ec; 130 eisa_intr_handle_t ih; 131 const char *model, *intrstr; 132 133 if (!strncmp(ea->ea_idstring, "USC024", 6)) 134 model = EISA_PRODUCT_USC0240; 135 else 136 model = "unknown model!"; 137 printf(": %s\n", model); 138 139 if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) + 140 UHA_EISA_SLOT_OFFSET, UHA_EISA_IOSIZE, 0, &ioh)) 141 panic("uha_eisa_attach: could not map I/O addresses"); 142 143 sc->sc_iot = iot; 144 sc->sc_ioh = ioh; 145 sc->sc_dmat = dmat; 146 if (!u24_find(iot, ioh, &upd)) 147 panic("uha_eisa_attach: u24_find failed!"); 148 149 sc->sc_dmaflags = 0; 150 151 if (eisa_intr_map(ec, upd.sc_irq, &ih)) { 152 printf("%s: couldn't map interrupt (%d)\n", 153 sc->sc_dev.dv_xname, upd.sc_irq); 154 return; 155 } 156 intrstr = eisa_intr_string(ec, ih); 157 sc->sc_ih = eisa_intr_establish(ec, ih, IST_LEVEL, IPL_BIO, 158 u24_intr, sc); 159 if (sc->sc_ih == NULL) { 160 printf("%s: couldn't establish interrupt", 161 sc->sc_dev.dv_xname); 162 if (intrstr != NULL) 163 printf(" at %s", intrstr); 164 printf("\n"); 165 return; 166 } 167 printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); 168 169 /* Save function pointers for later use. */ 170 sc->start_mbox = u24_start_mbox; 171 sc->poll = u24_poll; 172 sc->init = u24_init; 173 174 uha_attach(sc, &upd); 175 } 176 177 int 178 u24_find(iot, ioh, sc) 179 bus_space_tag_t iot; 180 bus_space_handle_t ioh; 181 struct uha_probe_data *sc; 182 { 183 u_int8_t config0, config1, config2; 184 int irq, drq; 185 int resetcount = 4000; /* 4 secs? */ 186 187 config0 = bus_space_read_1(iot, ioh, U24_CONFIG + 0); 188 config1 = bus_space_read_1(iot, ioh, U24_CONFIG + 1); 189 config2 = bus_space_read_1(iot, ioh, U24_CONFIG + 2); 190 if ((config0 & U24_MAGIC1) == 0 || 191 (config1 & U24_MAGIC2) == 0) 192 return (0); 193 194 drq = -1; 195 196 switch (config0 & U24_IRQ_MASK) { 197 case U24_IRQ10: 198 irq = 10; 199 break; 200 case U24_IRQ11: 201 irq = 11; 202 break; 203 case U24_IRQ14: 204 irq = 14; 205 break; 206 case U24_IRQ15: 207 irq = 15; 208 break; 209 default: 210 printf("u24_find: illegal irq setting %x\n", 211 config0 & U24_IRQ_MASK); 212 return (0); 213 } 214 215 bus_space_write_1(iot, ioh, U24_LINT, UHA_ASRST); 216 217 while (--resetcount) { 218 if (bus_space_read_1(iot, ioh, U24_LINT)) 219 break; 220 delay(1000); /* 1 mSec per loop */ 221 } 222 if (!resetcount) { 223 printf("u24_find: board timed out during reset\n"); 224 return (0); 225 } 226 227 /* if we want to fill in softc, do so now */ 228 if (sc) { 229 sc->sc_irq = irq; 230 sc->sc_drq = drq; 231 sc->sc_scsi_dev = config2 & U24_HOSTID_MASK; 232 } 233 234 return (1); 235 } 236 237 void 238 u24_start_mbox(sc, mscp) 239 struct uha_softc *sc; 240 struct uha_mscp *mscp; 241 { 242 bus_space_tag_t iot = sc->sc_iot; 243 bus_space_handle_t ioh = sc->sc_ioh; 244 int spincount = 100000; /* 1s should be enough */ 245 246 while (--spincount) { 247 if ((bus_space_read_1(iot, ioh, U24_LINT) & U24_LDIP) == 0) 248 break; 249 delay(100); 250 } 251 if (!spincount) { 252 printf("%s: uha_start_mbox, board not responding\n", 253 sc->sc_dev.dv_xname); 254 Debugger(); 255 } 256 257 bus_space_write_4(iot, ioh, U24_OGMPTR, 258 sc->sc_dmamap_mscp->dm_segs[0].ds_addr + UHA_MSCP_OFF(mscp)); 259 if (mscp->flags & MSCP_ABORT) 260 bus_space_write_1(iot, ioh, U24_OGMCMD, 0x80); 261 else 262 bus_space_write_1(iot, ioh, U24_OGMCMD, 0x01); 263 bus_space_write_1(iot, ioh, U24_LINT, U24_OGMFULL); 264 265 if ((mscp->xs->xs_control & XS_CTL_POLL) == 0) 266 callout_reset(&mscp->xs->xs_callout, 267 mstohz(mscp->timeout), uha_timeout, mscp); 268 } 269 270 int 271 u24_poll(sc, xs, count) 272 struct uha_softc *sc; 273 struct scsipi_xfer *xs; 274 int count; 275 { 276 bus_space_tag_t iot = sc->sc_iot; 277 bus_space_handle_t ioh = sc->sc_ioh; 278 279 while (count) { 280 /* 281 * If we had interrupts enabled, would we 282 * have got an interrupt? 283 */ 284 if (bus_space_read_1(iot, ioh, U24_SINT) & U24_SDIP) 285 u24_intr(sc); 286 if (xs->xs_status & XS_STS_DONE) 287 return (0); 288 delay(1000); 289 count--; 290 } 291 return (1); 292 } 293 294 int 295 u24_intr(arg) 296 void *arg; 297 { 298 struct uha_softc *sc = arg; 299 bus_space_tag_t iot = sc->sc_iot; 300 bus_space_handle_t ioh = sc->sc_ioh; 301 struct uha_mscp *mscp; 302 u_char uhastat; 303 u_long mboxval; 304 305 #ifdef UHADEBUG 306 printf("%s: uhaintr ", sc->sc_dev.dv_xname); 307 #endif /*UHADEBUG */ 308 309 if ((bus_space_read_1(iot, ioh, U24_SINT) & U24_SDIP) == 0) 310 return (0); 311 312 for (;;) { 313 /* 314 * First get all the information and then 315 * acknowledge the interrupt 316 */ 317 uhastat = bus_space_read_1(iot, ioh, U24_SINT); 318 mboxval = bus_space_read_4(iot, ioh, U24_ICMPTR); 319 bus_space_write_1(iot, ioh, U24_SINT, U24_ICM_ACK); 320 bus_space_write_1(iot, ioh, U24_ICMCMD, 0); 321 322 #ifdef UHADEBUG 323 printf("status = 0x%x ", uhastat); 324 #endif /*UHADEBUG*/ 325 326 /* 327 * Process the completed operation 328 */ 329 mscp = uha_mscp_phys_kv(sc, mboxval); 330 if (!mscp) { 331 printf("%s: BAD MSCP RETURNED!\n", 332 sc->sc_dev.dv_xname); 333 continue; /* whatever it was, it'll timeout */ 334 } 335 callout_stop(&mscp->xs->xs_callout); 336 uha_done(sc, mscp); 337 338 if ((bus_space_read_1(iot, ioh, U24_SINT) & U24_SDIP) == 0) 339 return (1); 340 } 341 } 342 343 void 344 u24_init(sc) 345 struct uha_softc *sc; 346 { 347 bus_space_tag_t iot = sc->sc_iot; 348 bus_space_handle_t ioh = sc->sc_ioh; 349 350 /* free OGM and ICM */ 351 bus_space_write_1(iot, ioh, U24_OGMCMD, 0); 352 bus_space_write_1(iot, ioh, U24_ICMCMD, 0); 353 /* make sure interrupts are enabled */ 354 #ifdef UHADEBUG 355 printf("u24_init: lmask=%02x, smask=%02x\n", 356 bus_space_read_1(iot, ioh, U24_LMASK), 357 bus_space_read_1(iot, ioh, U24_SMASK)); 358 #endif 359 bus_space_write_1(iot, ioh, U24_LMASK, 0xd2); /* XXX */ 360 bus_space_write_1(iot, ioh, U24_SMASK, 0x92); /* XXX */ 361 } 362