1 /* $OpenBSD: uha_isa.c,v 1.10 2009/08/26 22:29:09 jasper 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 <sys/proc.h> 39 #include <sys/user.h> 40 41 #include <machine/bus.h> 42 #include <machine/intr.h> 43 44 #include <scsi/scsi_all.h> 45 #include <scsi/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 int uha_isa_probe(struct device *, void *, void *); 56 void uha_isa_attach(struct device *, struct device *, void *); 57 58 struct cfattach uha_isa_ca = { 59 sizeof(struct uha_softc), uha_isa_probe, uha_isa_attach 60 }; 61 62 #define KVTOPHYS(x) vtophys((vaddr_t)(x)) 63 64 int u14_find(bus_space_tag_t, bus_space_handle_t, struct uha_softc *); 65 void u14_start_mbox(struct uha_softc *, struct uha_mscp *); 66 int u14_poll(struct uha_softc *, struct scsi_xfer *, int); 67 int u14_intr(void *); 68 void u14_init(struct uha_softc *); 69 70 /* 71 * Check the slots looking for a board we recognise 72 * If we find one, note its address (slot) and call 73 * the actual probe routine to check it out. 74 */ 75 int 76 uha_isa_probe(parent, match, aux) 77 struct device *parent; 78 void *match, *aux; 79 { 80 struct isa_attach_args *ia = aux; 81 struct uha_softc sc; 82 bus_space_tag_t iot = ia->ia_iot; 83 bus_space_handle_t ioh; 84 int rv; 85 86 if (bus_space_map(iot, ia->ia_iobase, UHA_ISA_IOSIZE, 0, &ioh)) 87 return (0); 88 89 rv = u14_find(iot, ioh, &sc); 90 91 bus_space_unmap(iot, ioh, UHA_ISA_IOSIZE); 92 93 if (rv) { 94 if (ia->ia_irq != -1 && ia->ia_irq != sc.sc_irq) 95 return (0); 96 if (ia->ia_drq != -1 && ia->ia_drq != sc.sc_drq) 97 return (0); 98 ia->ia_irq = sc.sc_irq; 99 ia->ia_drq = sc.sc_drq; 100 ia->ia_msize = 0; 101 ia->ia_iosize = UHA_ISA_IOSIZE; 102 } 103 return (rv); 104 } 105 106 /* 107 * Attach all the sub-devices we can find 108 */ 109 void 110 uha_isa_attach(parent, self, aux) 111 struct device *parent, *self; 112 void *aux; 113 { 114 struct isa_attach_args *ia = aux; 115 struct uha_softc *sc = (void *)self; 116 bus_space_tag_t iot = ia->ia_iot; 117 bus_space_handle_t ioh; 118 isa_chipset_tag_t ic = ia->ia_ic; 119 120 printf("\n"); 121 122 if (bus_space_map(iot, ia->ia_iobase, UHA_ISA_IOSIZE, 0, &ioh)) 123 panic("uha_attach: bus_space_map failed!"); 124 125 sc->sc_iot = iot; 126 sc->sc_ioh = ioh; 127 if (!u14_find(iot, ioh, sc)) 128 panic("uha_attach: u14_find failed!"); 129 130 if (sc->sc_drq != -1) 131 isadma_cascade(sc->sc_drq); 132 133 sc->sc_ih = isa_intr_establish(ic, sc->sc_irq, IST_EDGE, IPL_BIO, 134 u14_intr, sc, sc->sc_dev.dv_xname); 135 if (sc->sc_ih == NULL) { 136 printf("%s: couldn't establish interrupt\n", 137 sc->sc_dev.dv_xname); 138 return; 139 } 140 141 /* Save function pointers for later use. */ 142 sc->start_mbox = u14_start_mbox; 143 sc->poll = u14_poll; 144 sc->init = u14_init; 145 146 uha_attach(sc); 147 } 148 149 /* 150 * Start the board, ready for normal operation 151 */ 152 int 153 u14_find(iot, ioh, sc) 154 bus_space_tag_t iot; 155 bus_space_handle_t ioh; 156 struct uha_softc *sc; 157 { 158 u_int16_t model, config; 159 int irq, drq; 160 int resetcount = 4000; /* 4 secs? */ 161 162 model = (bus_space_read_1(iot, ioh, U14_ID + 0) << 8) | 163 (bus_space_read_1(iot, ioh, U14_ID + 1) << 0); 164 if ((model & 0xfff0) != 0x5640) 165 return (0); 166 167 config = (bus_space_read_1(iot, ioh, U14_CONFIG + 0) << 8) | 168 (bus_space_read_1(iot, ioh, U14_CONFIG + 1) << 0); 169 170 switch (model & 0x000f) { 171 case 0x0000: 172 switch (config & U14_DMA_MASK) { 173 case U14_DMA_CH5: 174 drq = 5; 175 break; 176 case U14_DMA_CH6: 177 drq = 6; 178 break; 179 case U14_DMA_CH7: 180 drq = 7; 181 break; 182 default: 183 printf("u14_find: illegal drq setting %x\n", 184 config & U14_DMA_MASK); 185 return (0); 186 } 187 break; 188 case 0x0001: 189 /* This is a 34f, and doesn't need an ISA DMA channel. */ 190 drq = -1; 191 break; 192 default: 193 printf("u14_find: unknown model %x\n", model); 194 return (0); 195 } 196 197 switch (config & U14_IRQ_MASK) { 198 case U14_IRQ10: 199 irq = 10; 200 break; 201 case U14_IRQ11: 202 irq = 11; 203 break; 204 case U14_IRQ14: 205 irq = 14; 206 break; 207 case U14_IRQ15: 208 irq = 15; 209 break; 210 default: 211 printf("u14_find: illegal irq setting %x\n", 212 config & U14_IRQ_MASK); 213 return (0); 214 } 215 216 bus_space_write_1(iot, ioh, U14_LINT, UHA_ASRST); 217 218 while (--resetcount) { 219 if (bus_space_read_1(iot, ioh, U14_LINT)) 220 break; 221 delay(1000); /* 1 mSec per loop */ 222 } 223 if (!resetcount) { 224 printf("u14_find: board timed out during reset\n"); 225 return (0); 226 } 227 228 /* if we want to fill in softc, do so now */ 229 if (sc != NULL) { 230 sc->sc_irq = irq; 231 sc->sc_drq = drq; 232 sc->sc_scsi_dev = config & U14_HOSTID_MASK; 233 } 234 235 return (1); 236 } 237 238 /* 239 * Function to send a command out through a mailbox 240 */ 241 void 242 u14_start_mbox(sc, mscp) 243 struct uha_softc *sc; 244 struct uha_mscp *mscp; 245 { 246 bus_space_tag_t iot = sc->sc_iot; 247 bus_space_handle_t ioh = sc->sc_ioh; 248 int spincount = 100000; /* 1s should be enough */ 249 250 while (--spincount) { 251 if ((bus_space_read_1(iot, ioh, U14_LINT) & U14_LDIP) == 0) 252 break; 253 delay(100); 254 } 255 if (!spincount) 256 panic("%s: uha_start_mbox, board not responding", 257 sc->sc_dev.dv_xname); 258 259 bus_space_write_4(iot, ioh, U14_OGMPTR, KVTOPHYS(mscp)); 260 if (mscp->flags & MSCP_ABORT) 261 bus_space_write_1(iot, ioh, U14_LINT, U14_ABORT); 262 else 263 bus_space_write_1(iot, ioh, U14_LINT, U14_OGMFULL); 264 265 if ((mscp->xs->flags & SCSI_POLL) == 0) 266 timeout_add_msec(&mscp->xs->stimeout, mscp->timeout); 267 } 268 269 /* 270 * Function to poll for command completion when in poll mode. 271 * 272 * wait = timeout in msec 273 */ 274 int 275 u14_poll(sc, xs, count) 276 struct uha_softc *sc; 277 struct scsi_xfer *xs; 278 int count; 279 { 280 bus_space_tag_t iot = sc->sc_iot; 281 bus_space_handle_t ioh = sc->sc_ioh; 282 283 while (count) { 284 /* 285 * If we had interrupts enabled, would we 286 * have got an interrupt? 287 */ 288 if (bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP) 289 u14_intr(sc); 290 if (xs->flags & ITSDONE) 291 return (0); 292 delay(1000); 293 count--; 294 } 295 return (1); 296 } 297 298 /* 299 * Catch an interrupt from the adaptor 300 */ 301 int 302 u14_intr(arg) 303 void *arg; 304 { 305 struct uha_softc *sc = arg; 306 bus_space_tag_t iot = sc->sc_iot; 307 bus_space_handle_t ioh = sc->sc_ioh; 308 struct uha_mscp *mscp; 309 u_char uhastat; 310 u_long mboxval; 311 312 #ifdef UHADEBUG 313 printf("%s: uhaintr ", sc->sc_dev.dv_xname); 314 #endif /*UHADEBUG */ 315 316 if ((bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP) == 0) 317 return (0); 318 319 for (;;) { 320 /* 321 * First get all the information and then 322 * acknowledge the interrupt 323 */ 324 uhastat = bus_space_read_1(iot, ioh, U14_SINT); 325 mboxval = bus_space_read_4(iot, ioh, U14_ICMPTR); 326 /* XXX Send an ABORT_ACK instead? */ 327 bus_space_write_1(iot, ioh, U14_SINT, U14_ICM_ACK); 328 329 #ifdef UHADEBUG 330 printf("status = 0x%x ", uhastat); 331 #endif /*UHADEBUG*/ 332 333 /* 334 * Process the completed operation 335 */ 336 mscp = uha_mscp_phys_kv(sc, mboxval); 337 if (!mscp) { 338 printf("%s: BAD MSCP RETURNED!\n", 339 sc->sc_dev.dv_xname); 340 continue; /* whatever it was, it'll timeout */ 341 } 342 343 timeout_del(&mscp->xs->stimeout); 344 uha_done(sc, mscp); 345 346 if ((bus_space_read_1(iot, ioh, U14_SINT) & U14_SDIP) == 0) 347 return (1); 348 } 349 } 350 351 void 352 u14_init(sc) 353 struct uha_softc *sc; 354 { 355 bus_space_tag_t iot = sc->sc_iot; 356 bus_space_handle_t ioh = sc->sc_ioh; 357 358 /* make sure interrupts are enabled */ 359 #ifdef UHADEBUG 360 printf("u14_init: lmask=%02x, smask=%02x\n", 361 bus_space_read_1(iot, ioh, U14_LMASK), 362 bus_space_read_1(iot, ioh, U14_SMASK)); 363 #endif 364 bus_space_write_1(iot, ioh, U14_LMASK, 0xd1); /* XXX */ 365 bus_space_write_1(iot, ioh, U14_SMASK, 0x91); /* XXX */ 366 } 367