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