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