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