1 /* $NetBSD: uha_isa.c,v 1.38 2009/11/23 02:13:47 rmind 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.38 2009/11/23 02:13:47 rmind 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(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 it's 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 = (void *)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 printf("\n"); 147 148 if (bus_space_map(iot, ia->ia_io[0].ir_addr, UHA_ISA_IOSIZE, 0, &ioh)) { 149 aprint_error_dev(&sc->sc_dev, "can't map i/o space\n"); 150 return; 151 } 152 153 sc->sc_iot = iot; 154 sc->sc_ioh = ioh; 155 sc->sc_dmat = dmat; 156 if (!u14_find(iot, ioh, &upd)) { 157 aprint_error_dev(&sc->sc_dev, "u14_find failed\n"); 158 return; 159 } 160 161 if (upd.sc_drq != -1) { 162 sc->sc_dmaflags = 0; 163 if ((error = isa_dmacascade(ic, upd.sc_drq)) != 0) { 164 aprint_error_dev(&sc->sc_dev, "unable to cascade DRQ, error = %d\n", error); 165 return; 166 } 167 } else { 168 /* 169 * We have a VLB controller, and can do 32-bit DMA. 170 */ 171 sc->sc_dmaflags = ISABUS_DMA_32BIT; 172 } 173 174 sc->sc_ih = isa_intr_establish(ic, upd.sc_irq, IST_EDGE, IPL_BIO, 175 u14_intr, sc); 176 if (sc->sc_ih == NULL) { 177 aprint_error_dev(&sc->sc_dev, "couldn't establish interrupt\n"); 178 return; 179 } 180 181 /* Save function pointers for later use. */ 182 sc->start_mbox = u14_start_mbox; 183 sc->poll = u14_poll; 184 sc->init = u14_init; 185 186 uha_attach(sc, &upd); 187 } 188 189 /* 190 * Start the board, ready for normal operation 191 */ 192 int 193 u14_find(bus_space_tag_t iot, bus_space_handle_t ioh, struct uha_probe_data *sc) 194 { 195 u_int16_t model, config; 196 int irq, drq; 197 int resetcount = 4000; /* 4 secs? */ 198 199 model = (bus_space_read_1(iot, ioh, U14_ID + 0) << 8) | 200 (bus_space_read_1(iot, ioh, U14_ID + 1) << 0); 201 if ((model & 0xfff0) != 0x5640) 202 return (0); 203 204 config = (bus_space_read_1(iot, ioh, U14_CONFIG + 0) << 8) | 205 (bus_space_read_1(iot, ioh, U14_CONFIG + 1) << 0); 206 207 switch (model & 0x000f) { 208 case 0x0000: 209 switch (config & U14_DMA_MASK) { 210 case U14_DMA_CH5: 211 drq = 5; 212 break; 213 case U14_DMA_CH6: 214 drq = 6; 215 break; 216 case U14_DMA_CH7: 217 drq = 7; 218 break; 219 default: 220 printf("u14_find: illegal drq setting %x\n", 221 config & U14_DMA_MASK); 222 return (0); 223 } 224 break; 225 case 0x0001: 226 /* This is a 34f, and doesn't need an ISA DMA channel. */ 227 drq = -1; 228 break; 229 default: 230 printf("u14_find: unknown model %x\n", model); 231 return (0); 232 } 233 234 switch (config & U14_IRQ_MASK) { 235 case U14_IRQ10: 236 irq = 10; 237 break; 238 case U14_IRQ11: 239 irq = 11; 240 break; 241 case U14_IRQ14: 242 irq = 14; 243 break; 244 case U14_IRQ15: 245 irq = 15; 246 break; 247 default: 248 printf("u14_find: illegal irq setting %x\n", 249 config & U14_IRQ_MASK); 250 return (0); 251 } 252 253 bus_space_write_1(iot, ioh, U14_LINT, UHA_ASRST); 254 255 while (--resetcount) { 256 if (bus_space_read_1(iot, ioh, U14_LINT)) 257 break; 258 delay(1000); /* 1 mSec per loop */ 259 } 260 if (!resetcount) { 261 printf("u14_find: board timed out during reset\n"); 262 return (0); 263 } 264 265 /* if we want to fill in softc, do so now */ 266 if (sc) { 267 sc->sc_irq = irq; 268 sc->sc_drq = drq; 269 sc->sc_scsi_dev = config & U14_HOSTID_MASK; 270 } 271 272 return (1); 273 } 274 275 /* 276 * Function to send a command out through a mailbox 277 */ 278 void 279 u14_start_mbox(struct uha_softc *sc, struct uha_mscp *mscp) 280 { 281 bus_space_tag_t iot = sc->sc_iot; 282 bus_space_handle_t ioh = sc->sc_ioh; 283 int spincount = 100000; /* 1s should be enough */ 284 285 while (--spincount) { 286 if ((bus_space_read_1(iot, ioh, U14_LINT) & U14_LDIP) == 0) 287 break; 288 delay(100); 289 } 290 if (!spincount) { 291 aprint_error_dev(&sc->sc_dev, "uha_start_mbox, board not responding\n"); 292 Debugger(); 293 } 294 295 bus_space_write_4(iot, ioh, U14_OGMPTR, 296 sc->sc_dmamap_mscp->dm_segs[0].ds_addr + UHA_MSCP_OFF(mscp)); 297 if (mscp->flags & MSCP_ABORT) 298 bus_space_write_1(iot, ioh, U14_LINT, U14_ABORT); 299 else 300 bus_space_write_1(iot, ioh, U14_LINT, U14_OGMFULL); 301 302 if ((mscp->xs->xs_control & XS_CTL_POLL) == 0) 303 callout_reset(&mscp->xs->xs_callout, 304 mstohz(mscp->timeout), uha_timeout, mscp); 305 } 306 307 /* 308 * Function to poll for command completion when in poll mode. 309 * 310 * wait = timeout in msec 311 */ 312 int 313 u14_poll(struct uha_softc *sc, struct scsipi_xfer *xs, int count) 314 { 315 bus_space_tag_t iot = sc->sc_iot; 316 bus_space_handle_t ioh = sc->sc_ioh; 317 318 while (count) { 319 /* 320 * If we had interrupts enabled, would we 321 * have got an interrupt? 322 */ 323 if (bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP) 324 u14_intr(sc); 325 if (xs->xs_status & XS_STS_DONE) 326 return (0); 327 delay(1000); 328 count--; 329 } 330 return (1); 331 } 332 333 /* 334 * Catch an interrupt from the adaptor 335 */ 336 int 337 u14_intr(void *arg) 338 { 339 struct uha_softc *sc = arg; 340 bus_space_tag_t iot = sc->sc_iot; 341 bus_space_handle_t ioh = sc->sc_ioh; 342 struct uha_mscp *mscp; 343 u_char uhastat; 344 u_long mboxval; 345 346 #ifdef UHADEBUG 347 printf("%s: uhaintr ", device_xname(&sc->sc_dev)); 348 #endif /*UHADEBUG */ 349 350 if ((bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP) == 0) 351 return (0); 352 353 for (;;) { 354 /* 355 * First get all the information and then 356 * acknowledge the interrupt 357 */ 358 uhastat = bus_space_read_1(iot, ioh, U14_SINT); 359 mboxval = bus_space_read_4(iot, ioh, U14_ICMPTR); 360 /* XXX Send an ABORT_ACK instead? */ 361 bus_space_write_1(iot, ioh, U14_SINT, U14_ICM_ACK); 362 363 #ifdef UHADEBUG 364 printf("status = 0x%x ", uhastat); 365 #endif /*UHADEBUG*/ 366 367 /* 368 * Process the completed operation 369 */ 370 mscp = uha_mscp_phys_kv(sc, mboxval); 371 if (!mscp) { 372 printf("%s: BAD MSCP RETURNED!\n", 373 device_xname(&sc->sc_dev)); 374 continue; /* whatever it was, it'll timeout */ 375 } 376 377 callout_stop(&mscp->xs->xs_callout); 378 uha_done(sc, mscp); 379 380 if ((bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP) == 0) 381 return (1); 382 } 383 } 384 385 void 386 u14_init(struct uha_softc *sc) 387 { 388 bus_space_tag_t iot = sc->sc_iot; 389 bus_space_handle_t ioh = sc->sc_ioh; 390 391 /* make sure interrupts are enabled */ 392 #ifdef UHADEBUG 393 printf("u14_init: lmask=%02x, smask=%02x\n", 394 bus_space_read_1(iot, ioh, U14_LMASK), 395 bus_space_read_1(iot, ioh, U14_SMASK)); 396 #endif 397 bus_space_write_1(iot, ioh, U14_LMASK, 0xd1); /* XXX */ 398 bus_space_write_1(iot, ioh, U14_SMASK, 0x91); /* XXX */ 399 } 400