1 /* $NetBSD: uha_isa.c,v 1.26 2002/10/02 03:10:50 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_isa.c,v 1.26 2002/10/02 03:10:50 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/isa/isavar.h> 59 #include <dev/isa/isadmavar.h> 60 61 #include <dev/ic/uhareg.h> 62 #include <dev/ic/uhavar.h> 63 64 #define UHA_ISA_IOSIZE 16 65 66 int uha_isa_probe __P((struct device *, struct cfdata *, void *)); 67 void uha_isa_attach __P((struct device *, struct device *, void *)); 68 69 CFATTACH_DECL(uha_isa, sizeof(struct uha_softc), 70 uha_isa_probe, uha_isa_attach, NULL, NULL); 71 72 #ifndef DDB 73 #define Debugger() panic("should call debugger here (uha_isa.c)") 74 #endif /* ! DDB */ 75 76 int u14_find __P((bus_space_tag_t, bus_space_handle_t, 77 struct uha_probe_data *)); 78 void u14_start_mbox __P((struct uha_softc *, struct uha_mscp *)); 79 int u14_poll __P((struct uha_softc *, struct scsipi_xfer *, int)); 80 int u14_intr __P((void *)); 81 void u14_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_isa_probe(parent, match, aux) 90 struct device *parent; 91 struct cfdata *match; 92 void *aux; 93 { 94 struct isa_attach_args *ia = aux; 95 bus_space_tag_t iot = ia->ia_iot; 96 bus_space_handle_t ioh; 97 struct uha_probe_data upd; 98 int rv; 99 100 if (ia->ia_nio < 1) 101 return (0); 102 if (ia->ia_nirq < 1) 103 return (0); 104 if (ia->ia_ndrq < 1) 105 return (0); 106 107 if (ISA_DIRECT_CONFIG(ia)) 108 return (0); 109 110 /* Disallow wildcarded i/o address. */ 111 if (ia->ia_io[0].ir_addr == ISACF_PORT_DEFAULT) 112 return (0); 113 114 if (bus_space_map(iot, ia->ia_io[0].ir_addr, UHA_ISA_IOSIZE, 0, &ioh)) 115 return (0); 116 117 rv = u14_find(iot, ioh, &upd); 118 119 bus_space_unmap(iot, ioh, UHA_ISA_IOSIZE); 120 121 if (rv) { 122 if (ia->ia_irq[0].ir_irq != ISACF_IRQ_DEFAULT && 123 ia->ia_irq[0].ir_irq != upd.sc_irq) 124 return (0); 125 if (ia->ia_drq[0].ir_drq != ISACF_DRQ_DEFAULT && 126 ia->ia_drq[0].ir_drq != upd.sc_drq) 127 return (0); 128 129 ia->ia_nio = 1; 130 ia->ia_io[0].ir_size = UHA_ISA_IOSIZE; 131 132 ia->ia_nirq = 1; 133 ia->ia_irq[0].ir_irq = upd.sc_irq; 134 135 ia->ia_ndrq = 1; 136 ia->ia_drq[0].ir_drq = upd.sc_drq; 137 138 ia->ia_niomem = 0; 139 } 140 return (rv); 141 } 142 143 /* 144 * Attach all the sub-devices we can find 145 */ 146 void 147 uha_isa_attach(parent, self, aux) 148 struct device *parent, *self; 149 void *aux; 150 { 151 struct isa_attach_args *ia = aux; 152 struct uha_softc *sc = (void *)self; 153 bus_space_tag_t iot = ia->ia_iot; 154 bus_dma_tag_t dmat = ia->ia_dmat; 155 bus_space_handle_t ioh; 156 struct uha_probe_data upd; 157 isa_chipset_tag_t ic = ia->ia_ic; 158 int error; 159 160 printf("\n"); 161 162 if (bus_space_map(iot, ia->ia_io[0].ir_addr, UHA_ISA_IOSIZE, 0, &ioh)) { 163 printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname); 164 return; 165 } 166 167 sc->sc_iot = iot; 168 sc->sc_ioh = ioh; 169 sc->sc_dmat = dmat; 170 if (!u14_find(iot, ioh, &upd)) { 171 printf("%s: u14_find failed\n", sc->sc_dev.dv_xname); 172 return; 173 } 174 175 if (upd.sc_drq != -1) { 176 sc->sc_dmaflags = 0; 177 if ((error = isa_dmacascade(ic, upd.sc_drq)) != 0) { 178 printf("%s: unable to cascade DRQ, error = %d\n", 179 sc->sc_dev.dv_xname, error); 180 return; 181 } 182 } else { 183 /* 184 * We have a VLB controller, and can do 32-bit DMA. 185 */ 186 sc->sc_dmaflags = ISABUS_DMA_32BIT; 187 } 188 189 sc->sc_ih = isa_intr_establish(ic, upd.sc_irq, IST_EDGE, IPL_BIO, 190 u14_intr, sc); 191 if (sc->sc_ih == NULL) { 192 printf("%s: couldn't establish interrupt\n", 193 sc->sc_dev.dv_xname); 194 return; 195 } 196 197 /* Save function pointers for later use. */ 198 sc->start_mbox = u14_start_mbox; 199 sc->poll = u14_poll; 200 sc->init = u14_init; 201 202 uha_attach(sc, &upd); 203 } 204 205 /* 206 * Start the board, ready for normal operation 207 */ 208 int 209 u14_find(iot, ioh, sc) 210 bus_space_tag_t iot; 211 bus_space_handle_t ioh; 212 struct uha_probe_data *sc; 213 { 214 u_int16_t model, config; 215 int irq, drq; 216 int resetcount = 4000; /* 4 secs? */ 217 218 model = (bus_space_read_1(iot, ioh, U14_ID + 0) << 8) | 219 (bus_space_read_1(iot, ioh, U14_ID + 1) << 0); 220 if ((model & 0xfff0) != 0x5640) 221 return (0); 222 223 config = (bus_space_read_1(iot, ioh, U14_CONFIG + 0) << 8) | 224 (bus_space_read_1(iot, ioh, U14_CONFIG + 1) << 0); 225 226 switch (model & 0x000f) { 227 case 0x0000: 228 switch (config & U14_DMA_MASK) { 229 case U14_DMA_CH5: 230 drq = 5; 231 break; 232 case U14_DMA_CH6: 233 drq = 6; 234 break; 235 case U14_DMA_CH7: 236 drq = 7; 237 break; 238 default: 239 printf("u14_find: illegal drq setting %x\n", 240 config & U14_DMA_MASK); 241 return (0); 242 } 243 break; 244 case 0x0001: 245 /* This is a 34f, and doesn't need an ISA DMA channel. */ 246 drq = -1; 247 break; 248 default: 249 printf("u14_find: unknown model %x\n", model); 250 return (0); 251 } 252 253 switch (config & U14_IRQ_MASK) { 254 case U14_IRQ10: 255 irq = 10; 256 break; 257 case U14_IRQ11: 258 irq = 11; 259 break; 260 case U14_IRQ14: 261 irq = 14; 262 break; 263 case U14_IRQ15: 264 irq = 15; 265 break; 266 default: 267 printf("u14_find: illegal irq setting %x\n", 268 config & U14_IRQ_MASK); 269 return (0); 270 } 271 272 bus_space_write_1(iot, ioh, U14_LINT, UHA_ASRST); 273 274 while (--resetcount) { 275 if (bus_space_read_1(iot, ioh, U14_LINT)) 276 break; 277 delay(1000); /* 1 mSec per loop */ 278 } 279 if (!resetcount) { 280 printf("u14_find: board timed out during reset\n"); 281 return (0); 282 } 283 284 /* if we want to fill in softc, do so now */ 285 if (sc) { 286 sc->sc_irq = irq; 287 sc->sc_drq = drq; 288 sc->sc_scsi_dev = config & U14_HOSTID_MASK; 289 } 290 291 return (1); 292 } 293 294 /* 295 * Function to send a command out through a mailbox 296 */ 297 void 298 u14_start_mbox(sc, mscp) 299 struct uha_softc *sc; 300 struct uha_mscp *mscp; 301 { 302 bus_space_tag_t iot = sc->sc_iot; 303 bus_space_handle_t ioh = sc->sc_ioh; 304 int spincount = 100000; /* 1s should be enough */ 305 306 while (--spincount) { 307 if ((bus_space_read_1(iot, ioh, U14_LINT) & U14_LDIP) == 0) 308 break; 309 delay(100); 310 } 311 if (!spincount) { 312 printf("%s: uha_start_mbox, board not responding\n", 313 sc->sc_dev.dv_xname); 314 Debugger(); 315 } 316 317 bus_space_write_4(iot, ioh, U14_OGMPTR, 318 sc->sc_dmamap_mscp->dm_segs[0].ds_addr + UHA_MSCP_OFF(mscp)); 319 if (mscp->flags & MSCP_ABORT) 320 bus_space_write_1(iot, ioh, U14_LINT, U14_ABORT); 321 else 322 bus_space_write_1(iot, ioh, U14_LINT, U14_OGMFULL); 323 324 if ((mscp->xs->xs_control & XS_CTL_POLL) == 0) 325 callout_reset(&mscp->xs->xs_callout, 326 mstohz(mscp->timeout), uha_timeout, mscp); 327 } 328 329 /* 330 * Function to poll for command completion when in poll mode. 331 * 332 * wait = timeout in msec 333 */ 334 int 335 u14_poll(sc, xs, count) 336 struct uha_softc *sc; 337 struct scsipi_xfer *xs; 338 int count; 339 { 340 bus_space_tag_t iot = sc->sc_iot; 341 bus_space_handle_t ioh = sc->sc_ioh; 342 343 while (count) { 344 /* 345 * If we had interrupts enabled, would we 346 * have got an interrupt? 347 */ 348 if (bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP) 349 u14_intr(sc); 350 if (xs->xs_status & XS_STS_DONE) 351 return (0); 352 delay(1000); 353 count--; 354 } 355 return (1); 356 } 357 358 /* 359 * Catch an interrupt from the adaptor 360 */ 361 int 362 u14_intr(arg) 363 void *arg; 364 { 365 struct uha_softc *sc = arg; 366 bus_space_tag_t iot = sc->sc_iot; 367 bus_space_handle_t ioh = sc->sc_ioh; 368 struct uha_mscp *mscp; 369 u_char uhastat; 370 u_long mboxval; 371 372 #ifdef UHADEBUG 373 printf("%s: uhaintr ", sc->sc_dev.dv_xname); 374 #endif /*UHADEBUG */ 375 376 if ((bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP) == 0) 377 return (0); 378 379 for (;;) { 380 /* 381 * First get all the information and then 382 * acknowledge the interrupt 383 */ 384 uhastat = bus_space_read_1(iot, ioh, U14_SINT); 385 mboxval = bus_space_read_4(iot, ioh, U14_ICMPTR); 386 /* XXX Send an ABORT_ACK instead? */ 387 bus_space_write_1(iot, ioh, U14_SINT, U14_ICM_ACK); 388 389 #ifdef UHADEBUG 390 printf("status = 0x%x ", uhastat); 391 #endif /*UHADEBUG*/ 392 393 /* 394 * Process the completed operation 395 */ 396 mscp = uha_mscp_phys_kv(sc, mboxval); 397 if (!mscp) { 398 printf("%s: BAD MSCP RETURNED!\n", 399 sc->sc_dev.dv_xname); 400 continue; /* whatever it was, it'll timeout */ 401 } 402 403 callout_stop(&mscp->xs->xs_callout); 404 uha_done(sc, mscp); 405 406 if ((bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP) == 0) 407 return (1); 408 } 409 } 410 411 void 412 u14_init(sc) 413 struct uha_softc *sc; 414 { 415 bus_space_tag_t iot = sc->sc_iot; 416 bus_space_handle_t ioh = sc->sc_ioh; 417 418 /* make sure interrupts are enabled */ 419 #ifdef UHADEBUG 420 printf("u14_init: lmask=%02x, smask=%02x\n", 421 bus_space_read_1(iot, ioh, U14_LMASK), 422 bus_space_read_1(iot, ioh, U14_SMASK)); 423 #endif 424 bus_space_write_1(iot, ioh, U14_LMASK, 0xd1); /* XXX */ 425 bus_space_write_1(iot, ioh, U14_SMASK, 0x91); /* XXX */ 426 } 427