1 /* $NetBSD: uha_isa.c,v 1.9 1997/08/27 11:25:11 bouyer Exp $ */ 2 3 /* 4 * Copyright (c) 1994, 1996, 1997 Charles M. Hannum. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Charles M. Hannum. 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/device.h> 36 #include <sys/kernel.h> 37 #include <sys/proc.h> 38 #include <sys/user.h> 39 40 #include <machine/bus.h> 41 #include <machine/intr.h> 42 43 #include <dev/scsipi/scsi_all.h> 44 #include <dev/scsipi/scsipi_all.h> 45 #include <dev/scsipi/scsiconf.h> 46 47 #include <dev/isa/isavar.h> 48 #include <dev/isa/isadmavar.h> 49 50 #include <dev/ic/uhareg.h> 51 #include <dev/ic/uhavar.h> 52 53 #define UHA_ISA_IOSIZE 16 54 55 #ifdef __BROKEN_INDIRECT_CONFIG 56 int uha_isa_probe __P((struct device *, void *, void *)); 57 #else 58 int uha_isa_probe __P((struct device *, struct cfdata *, void *)); 59 #endif 60 void uha_isa_attach __P((struct device *, struct device *, void *)); 61 62 struct cfattach uha_isa_ca = { 63 sizeof(struct uha_softc), uha_isa_probe, uha_isa_attach 64 }; 65 66 #ifndef DDB 67 #define Debugger() panic("should call debugger here (uha_isa.c)") 68 #endif /* ! DDB */ 69 70 int u14_find __P((bus_space_tag_t, bus_space_handle_t, 71 struct uha_probe_data *)); 72 void u14_start_mbox __P((struct uha_softc *, struct uha_mscp *)); 73 int u14_poll __P((struct uha_softc *, struct scsipi_xfer *, int)); 74 int u14_intr __P((void *)); 75 void u14_init __P((struct uha_softc *)); 76 77 /* 78 * Check the slots looking for a board we recognise 79 * If we find one, note it's address (slot) and call 80 * the actual probe routine to check it out. 81 */ 82 int 83 uha_isa_probe(parent, match, aux) 84 struct device *parent; 85 #ifdef __BROKEN_INDIRECT_CONFIG 86 void *match; 87 #else 88 struct cfdata *match; 89 #endif 90 void *aux; 91 { 92 struct isa_attach_args *ia = aux; 93 bus_space_tag_t iot = ia->ia_iot; 94 bus_space_handle_t ioh; 95 struct uha_probe_data upd; 96 int rv; 97 98 if (bus_space_map(iot, ia->ia_iobase, UHA_ISA_IOSIZE, 0, &ioh)) 99 return (0); 100 101 rv = u14_find(iot, ioh, &upd); 102 103 bus_space_unmap(iot, ioh, UHA_ISA_IOSIZE); 104 105 if (rv) { 106 if (ia->ia_irq != -1 && ia->ia_irq != upd.sc_irq) 107 return (0); 108 if (ia->ia_drq != -1 && ia->ia_drq != upd.sc_drq) 109 return (0); 110 ia->ia_irq = upd.sc_irq; 111 ia->ia_drq = upd.sc_drq; 112 ia->ia_msize = 0; 113 ia->ia_iosize = UHA_ISA_IOSIZE; 114 } 115 return (rv); 116 } 117 118 /* 119 * Attach all the sub-devices we can find 120 */ 121 void 122 uha_isa_attach(parent, self, aux) 123 struct device *parent, *self; 124 void *aux; 125 { 126 struct isa_attach_args *ia = aux; 127 struct uha_softc *sc = (void *)self; 128 bus_space_tag_t iot = ia->ia_iot; 129 bus_dma_tag_t dmat = ia->ia_dmat; 130 bus_space_handle_t ioh; 131 struct uha_probe_data upd; 132 isa_chipset_tag_t ic = ia->ia_ic; 133 134 printf("\n"); 135 136 if (bus_space_map(iot, ia->ia_iobase, UHA_ISA_IOSIZE, 0, &ioh)) 137 panic("uha_isa_attach: bus_space_map failed!"); 138 139 sc->sc_iot = iot; 140 sc->sc_ioh = ioh; 141 sc->sc_dmat = dmat; 142 if (!u14_find(iot, ioh, &upd)) 143 panic("uha_isa_attach: u14_find failed!"); 144 145 if (upd.sc_drq != -1) { 146 sc->sc_dmaflags = 0; 147 isa_dmacascade(parent, upd.sc_drq); 148 } else { 149 /* 150 * We have a VLB controller, and can do 32-bit DMA. 151 */ 152 sc->sc_dmaflags = ISABUS_DMA_32BIT; 153 } 154 155 sc->sc_ih = isa_intr_establish(ic, upd.sc_irq, IST_EDGE, IPL_BIO, 156 u14_intr, sc); 157 if (sc->sc_ih == NULL) { 158 printf("%s: couldn't establish interrupt\n", 159 sc->sc_dev.dv_xname); 160 return; 161 } 162 163 /* Save function pointers for later use. */ 164 sc->start_mbox = u14_start_mbox; 165 sc->poll = u14_poll; 166 sc->init = u14_init; 167 168 uha_attach(sc, &upd); 169 } 170 171 /* 172 * Start the board, ready for normal operation 173 */ 174 int 175 u14_find(iot, ioh, sc) 176 bus_space_tag_t iot; 177 bus_space_handle_t ioh; 178 struct uha_probe_data *sc; 179 { 180 u_int16_t model, config; 181 int irq, drq; 182 int resetcount = 4000; /* 4 secs? */ 183 184 model = (bus_space_read_1(iot, ioh, U14_ID + 0) << 8) | 185 (bus_space_read_1(iot, ioh, U14_ID + 1) << 0); 186 if ((model & 0xfff0) != 0x5640) 187 return (0); 188 189 config = (bus_space_read_1(iot, ioh, U14_CONFIG + 0) << 8) | 190 (bus_space_read_1(iot, ioh, U14_CONFIG + 1) << 0); 191 192 switch (model & 0x000f) { 193 case 0x0000: 194 switch (config & U14_DMA_MASK) { 195 case U14_DMA_CH5: 196 drq = 5; 197 break; 198 case U14_DMA_CH6: 199 drq = 6; 200 break; 201 case U14_DMA_CH7: 202 drq = 7; 203 break; 204 default: 205 printf("u14_find: illegal drq setting %x\n", 206 config & U14_DMA_MASK); 207 return (0); 208 } 209 break; 210 case 0x0001: 211 /* This is a 34f, and doesn't need an ISA DMA channel. */ 212 drq = -1; 213 break; 214 default: 215 printf("u14_find: unknown model %x\n", model); 216 return (0); 217 } 218 219 switch (config & U14_IRQ_MASK) { 220 case U14_IRQ10: 221 irq = 10; 222 break; 223 case U14_IRQ11: 224 irq = 11; 225 break; 226 case U14_IRQ14: 227 irq = 14; 228 break; 229 case U14_IRQ15: 230 irq = 15; 231 break; 232 default: 233 printf("u14_find: illegal irq setting %x\n", 234 config & U14_IRQ_MASK); 235 return (0); 236 } 237 238 bus_space_write_1(iot, ioh, U14_LINT, UHA_ASRST); 239 240 while (--resetcount) { 241 if (bus_space_read_1(iot, ioh, U14_LINT)) 242 break; 243 delay(1000); /* 1 mSec per loop */ 244 } 245 if (!resetcount) { 246 printf("u14_find: board timed out during reset\n"); 247 return (0); 248 } 249 250 /* if we want to fill in softc, do so now */ 251 if (sc) { 252 sc->sc_irq = irq; 253 sc->sc_drq = drq; 254 sc->sc_scsi_dev = config & U14_HOSTID_MASK; 255 } 256 257 return (1); 258 } 259 260 /* 261 * Function to send a command out through a mailbox 262 */ 263 void 264 u14_start_mbox(sc, mscp) 265 struct uha_softc *sc; 266 struct uha_mscp *mscp; 267 { 268 bus_space_tag_t iot = sc->sc_iot; 269 bus_space_handle_t ioh = sc->sc_ioh; 270 int spincount = 100000; /* 1s should be enough */ 271 272 while (--spincount) { 273 if ((bus_space_read_1(iot, ioh, U14_LINT) & U14_LDIP) == 0) 274 break; 275 delay(100); 276 } 277 if (!spincount) { 278 printf("%s: uha_start_mbox, board not responding\n", 279 sc->sc_dev.dv_xname); 280 Debugger(); 281 } 282 283 bus_space_write_4(iot, ioh, U14_OGMPTR, 284 mscp->dmamap_self->dm_segs[0].ds_addr); 285 if (mscp->flags & MSCP_ABORT) 286 bus_space_write_1(iot, ioh, U14_LINT, U14_ABORT); 287 else 288 bus_space_write_1(iot, ioh, U14_LINT, U14_OGMFULL); 289 290 if ((mscp->xs->flags & SCSI_POLL) == 0) 291 timeout(uha_timeout, mscp, (mscp->timeout * hz) / 1000); 292 } 293 294 /* 295 * Function to poll for command completion when in poll mode. 296 * 297 * wait = timeout in msec 298 */ 299 int 300 u14_poll(sc, xs, count) 301 struct uha_softc *sc; 302 struct scsipi_xfer *xs; 303 int count; 304 { 305 bus_space_tag_t iot = sc->sc_iot; 306 bus_space_handle_t ioh = sc->sc_ioh; 307 308 while (count) { 309 /* 310 * If we had interrupts enabled, would we 311 * have got an interrupt? 312 */ 313 if (bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP) 314 u14_intr(sc); 315 if (xs->flags & ITSDONE) 316 return (0); 317 delay(1000); 318 count--; 319 } 320 return (1); 321 } 322 323 /* 324 * Catch an interrupt from the adaptor 325 */ 326 int 327 u14_intr(arg) 328 void *arg; 329 { 330 struct uha_softc *sc = arg; 331 bus_space_tag_t iot = sc->sc_iot; 332 bus_space_handle_t ioh = sc->sc_ioh; 333 struct uha_mscp *mscp; 334 u_char uhastat; 335 u_long mboxval; 336 337 #ifdef UHADEBUG 338 printf("%s: uhaintr ", sc->sc_dev.dv_xname); 339 #endif /*UHADEBUG */ 340 341 if ((bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP) == 0) 342 return (0); 343 344 for (;;) { 345 /* 346 * First get all the information and then 347 * acknowledge the interrupt 348 */ 349 uhastat = bus_space_read_1(iot, ioh, U14_SINT); 350 mboxval = bus_space_read_4(iot, ioh, U14_ICMPTR); 351 /* XXX Send an ABORT_ACK instead? */ 352 bus_space_write_1(iot, ioh, U14_SINT, U14_ICM_ACK); 353 354 #ifdef UHADEBUG 355 printf("status = 0x%x ", uhastat); 356 #endif /*UHADEBUG*/ 357 358 /* 359 * Process the completed operation 360 */ 361 mscp = uha_mscp_phys_kv(sc, mboxval); 362 if (!mscp) { 363 printf("%s: BAD MSCP RETURNED!\n", 364 sc->sc_dev.dv_xname); 365 continue; /* whatever it was, it'll timeout */ 366 } 367 368 untimeout(uha_timeout, mscp); 369 uha_done(sc, mscp); 370 371 if ((bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP) == 0) 372 return (1); 373 } 374 } 375 376 void 377 u14_init(sc) 378 struct uha_softc *sc; 379 { 380 bus_space_tag_t iot = sc->sc_iot; 381 bus_space_handle_t ioh = sc->sc_ioh; 382 383 /* make sure interrupts are enabled */ 384 #ifdef UHADEBUG 385 printf("u14_init: lmask=%02x, smask=%02x\n", 386 bus_space_read_1(iot, ioh, U14_LMASK), 387 bus_space_read_1(iot, ioh, U14_SMASK)); 388 #endif 389 bus_space_write_1(iot, ioh, U14_LMASK, 0xd1); /* XXX */ 390 bus_space_write_1(iot, ioh, U14_SMASK, 0x91); /* XXX */ 391 } 392