1 /* $NetBSD: cosc.c,v 1.10 2002/10/05 17:16:34 chs Exp $ */ 2 3 /* 4 * Copyright (c) 1996 Mark Brinicombe 5 * 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 Mark Brinicombe 18 * for the NetBSD Project. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 * 34 * from: asc.c,v 1.8 1996/06/12 20:46:58 mark Exp 35 */ 36 37 /* 38 * Driver for the MCS Connect 32 SCSI 2 card with AM53C94 SCSI controller. 39 * 40 * Thanks to Mike <mcsmike@knipp.de> at MCS for loaning a card. 41 * Thanks to Andreas Gandor <andi@knipp.de> for some technical information 42 */ 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/kernel.h> 47 #include <sys/device.h> 48 #include <dev/scsipi/scsi_all.h> 49 #include <dev/scsipi/scsipi_all.h> 50 #include <dev/scsipi/scsiconf.h> 51 #include <machine/bootconfig.h> 52 #include <machine/io.h> 53 #include <machine/intr.h> 54 #include <arm/arm32/katelib.h> 55 #include <acorn32/podulebus/podulebus.h> 56 #include <acorn32/podulebus/escreg.h> 57 #include <acorn32/podulebus/escvar.h> 58 #include <acorn32/podulebus/coscreg.h> 59 #include <acorn32/podulebus/coscvar.h> 60 #include <dev/podulebus/podules.h> 61 62 void coscattach(struct device *, struct device *, void *); 63 int coscmatch(struct device *, struct cfdata *, void *); 64 65 CFATTACH_DECL(cosc, sizeof(struct cosc_softc), 66 coscmatch, coscattach, NULL, NULL); 67 68 int cosc_intr(void *); 69 int cosc_setup_dma(struct esc_softc *, void *, int, int); 70 int cosc_build_dma_chain(struct esc_softc *, struct esc_dma_chain *, void *, 71 int); 72 int cosc_need_bump(struct esc_softc *, void *, int); 73 void cosc_led(struct esc_softc *, int); 74 void cosc_set_dma_adr(struct esc_softc *, void *); 75 void cosc_set_dma_tc(struct esc_softc *, unsigned int); 76 void cosc_set_dma_mode(struct esc_softc *, int); 77 78 #if COSC_POLL > 0 79 int cosc_poll = 1; 80 #endif 81 82 int 83 coscmatch(pdp, cf, auxp) 84 struct device *pdp; 85 struct cfdata *cf; 86 void *auxp; 87 { 88 struct podule_attach_args *pa = (struct podule_attach_args *)auxp; 89 90 /* Look for the card */ 91 92 if (pa->pa_product == PODULE_CONNECT32) 93 return(1); 94 95 /* Old versions of the ROM on this card could have the wrong ID */ 96 97 if (pa ->pa_product == PODULE_ACORN_SCSI && 98 strncmp(pa->pa_podule->description, "MCS", 3) == 0) 99 return(1); 100 return(0); 101 } 102 103 static int dummy[6]; 104 105 void 106 coscattach(pdp, dp, auxp) 107 struct device *pdp, *dp; 108 void *auxp; 109 { 110 struct cosc_softc *sc = (struct cosc_softc *)dp; 111 struct podule_attach_args *pa; 112 cosc_regmap_p rp = &sc->sc_regmap; 113 vu_char *esc; 114 115 pa = (struct podule_attach_args *)auxp; 116 117 if (pa->pa_podule_number == -1) 118 panic("Podule has disappeared !"); 119 120 sc->sc_podule_number = pa->pa_podule_number; 121 sc->sc_podule = pa->pa_podule; 122 podules[sc->sc_podule_number].attached = 1; 123 124 printf(":"); 125 126 if (pa->pa_podule->manufacturer == MANUFACTURER_ACORN 127 && pa->pa_podule->product == PODULE_ACORN_SCSI) 128 printf(" Faulty expansion card identity\n"); 129 130 sc->sc_iobase = (vu_char *)sc->sc_podule->fast_base; 131 132 /* Select page zero (so we can see the config info) */ 133 134 sc->sc_iobase[COSC_PAGE_REGISTER] = 0; 135 136 rp->chipreset = (vu_char *)&dummy[0]; 137 rp->inten = (vu_char *)&dummy[1]; 138 rp->status = (vu_char *)&dummy[2]; 139 rp->term = &sc->sc_iobase[COSC_TERMINATION_CONTROL]; 140 rp->led = (vu_char *)&dummy[4]; 141 esc = &sc->sc_iobase[COSC_ESCOFFSET_BASE]; 142 143 rp->esc.esc_tc_low = &esc[COSC_ESCOFFSET_TCL]; 144 rp->esc.esc_tc_mid = &esc[COSC_ESCOFFSET_TCM]; 145 rp->esc.esc_fifo = &esc[COSC_ESCOFFSET_FIFO]; 146 rp->esc.esc_command = &esc[COSC_ESCOFFSET_COMMAND]; 147 rp->esc.esc_dest_id = &esc[COSC_ESCOFFSET_DESTID]; 148 rp->esc.esc_timeout = &esc[COSC_ESCOFFSET_TIMEOUT]; 149 rp->esc.esc_syncper = &esc[COSC_ESCOFFSET_PERIOD]; 150 rp->esc.esc_syncoff = &esc[COSC_ESCOFFSET_OFFSET]; 151 rp->esc.esc_config1 = &esc[COSC_ESCOFFSET_CONFIG1]; 152 rp->esc.esc_clkconv = &esc[COSC_ESCOFFSET_CLOCKCONV]; 153 rp->esc.esc_test = &esc[COSC_ESCOFFSET_TEST]; 154 rp->esc.esc_config2 = &esc[COSC_ESCOFFSET_CONFIG2]; 155 rp->esc.esc_config3 = &esc[COSC_ESCOFFSET_CONFIG3]; 156 rp->esc.esc_config4 = &esc[COSC_ESCOFFSET_CONFIG4]; 157 rp->esc.esc_tc_high = &esc[COSC_ESCOFFSET_TCH]; 158 rp->esc.esc_fifo_bot = &esc[COSC_ESCOFFSET_FIFOBOTTOM]; 159 160 *rp->esc.esc_command = ESC_CMD_RESET_CHIP; 161 delay(1000); 162 *rp->esc.esc_command = ESC_CMD_NOP; 163 164 /* See if we recognise the controller */ 165 166 switch (*rp->esc.esc_tc_high) { 167 case 0x12: 168 printf(" AM53CF94"); 169 break; 170 default: 171 printf(" Unknown controller (%02x)", *rp->esc.esc_tc_high); 172 break; 173 } 174 175 /* Set termination power */ 176 177 if (sc->sc_iobase[COSC_CONFIG_TERMINATION] & COSC_CONFIG_TERMINATION_ON) { 178 printf(" termpwr on"); 179 sc->sc_iobase[COSC_TERMINATION_CONTROL] = COSC_TERMINATION_ON; 180 } else { 181 printf(" termpwr off"); 182 sc->sc_iobase[COSC_TERMINATION_CONTROL] = COSC_TERMINATION_OFF; 183 } 184 185 /* Don't know what this is for */ 186 187 { 188 int byte; 189 int loop; 190 191 byte = sc->sc_iobase[COSC_REGISTER_01]; 192 byte = 0; 193 for (loop = 0; loop < 8; ++loop) { 194 if (sc->sc_iobase[COSC_REGISTER_00] & 0x01) 195 byte |= (1 << loop); 196 } 197 printf(" byte=%02x", byte); 198 } 199 200 /* 201 * Control register 4 is an AMD special (not on FAS216) 202 * 203 * The powerdown and glitch eater facilities could be useful 204 * Use the podule configuration for this register 205 */ 206 207 sc->sc_softc.sc_config4 = sc->sc_iobase[COSC_CONFIG_CONTROL_REG4]; 208 209 sc->sc_softc.sc_esc = (esc_regmap_p)rp; 210 /* sc->sc_softc.sc_spec = &sc->sc_specific;*/ 211 212 sc->sc_softc.sc_led = cosc_led; 213 sc->sc_softc.sc_setup_dma = cosc_setup_dma; 214 sc->sc_softc.sc_build_dma_chain = cosc_build_dma_chain; 215 sc->sc_softc.sc_need_bump = cosc_need_bump; 216 217 sc->sc_softc.sc_clock_freq = 40; /* Connect32 runs at 40MHz */ 218 sc->sc_softc.sc_timeout = 250; /* Set default timeout to 250ms */ 219 sc->sc_softc.sc_config_flags = ESC_NO_DMA; 220 sc->sc_softc.sc_host_id = sc->sc_iobase[COSC_CONFIG_CONTROL_REG1] & ESC_DEST_ID_MASK; 221 222 printf(" hostid=%d", sc->sc_softc.sc_host_id); 223 224 #if COSC_POLL > 0 225 if (boot_args) 226 get_bootconf_option(boot_args, "coscpoll", 227 BOOTOPT_TYPE_BOOLEAN, &cosc_poll); 228 229 if (cosc_poll) { 230 printf(" polling"); 231 sc->sc_softc.sc_adapter.adapt_flags |= SCSIPI_ADAPT_POLL_ONLY; 232 } 233 #endif 234 235 sc->sc_softc.sc_bump_sz = NBPG; 236 sc->sc_softc.sc_bump_pa = 0x0; 237 238 escinitialize((struct esc_softc *)sc); 239 240 sc->sc_softc.sc_adapter.adapt_dev = &sc->sc_softc.sc_dev; 241 sc->sc_softc.sc_adapter.adapt_nchannels = 1; 242 sc->sc_softc.sc_adapter.adapt_openings = 7; 243 sc->sc_softc.sc_adapter.adapt_max_periph = 1; 244 sc->sc_softc.sc_adapter.adapt_ioctl = NULL; 245 sc->sc_softc.sc_adapter.adapt_minphys = esc_minphys; 246 sc->sc_softc.sc_adapter.adapt_request = esc_scsi_request; 247 248 sc->sc_softc.sc_channel.chan_adapter = &sc->sc_softc.sc_adapter; 249 sc->sc_softc.sc_channel.chan_bustype = &scsi_bustype; 250 sc->sc_softc.sc_channel.chan_channel = 0; 251 sc->sc_softc.sc_channel.chan_ntargets = 8; 252 sc->sc_softc.sc_channel.chan_nluns = 8; 253 sc->sc_softc.sc_channel.chan_id = sc->sc_softc.sc_host_id; 254 255 /* initialise the card */ 256 #if 0 257 *rp->inten = (COSC_POLL?0:1); 258 *rp->led = 0; 259 #endif 260 261 sc->sc_softc.sc_ih.ih_func = cosc_intr; 262 sc->sc_softc.sc_ih.ih_arg = &sc->sc_softc; 263 sc->sc_softc.sc_ih.ih_level = IPL_BIO; 264 sc->sc_softc.sc_ih.ih_name = "scsi: cosc"; 265 sc->sc_softc.sc_ih.ih_maskaddr = sc->sc_podule->irq_addr; 266 sc->sc_softc.sc_ih.ih_maskbits = sc->sc_podule->irq_mask; 267 268 #if COSC_POLL > 0 269 if (!cosc_poll) 270 #endif 271 { 272 evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, 273 dp->dv_xname, "intr"); 274 sc->sc_ih = podulebus_irq_establish(pa->pa_ih, IPL_BIO, 275 cosc_intr, sc, &sc->sc_intrcnt); 276 if (sc->sc_ih == NULL) 277 panic("%s: Cannot install IRQ handler", 278 dp->dv_xname); 279 } 280 281 printf("\n"); 282 283 /* attach all scsi units on us */ 284 config_found(dp, &sc->sc_softc.sc_channel, scsiprint); 285 } 286 287 288 /* Turn on/off led */ 289 290 void 291 cosc_led(sc, mode) 292 struct esc_softc *sc; 293 int mode; 294 { 295 cosc_regmap_p rp; 296 297 rp = (cosc_regmap_p)sc->sc_esc; 298 299 if (mode) { 300 sc->sc_led_status++; 301 } else { 302 if (sc->sc_led_status) 303 sc->sc_led_status--; 304 } 305 /* *rp->led = (sc->sc_led_status?1:0);*/ 306 } 307 308 309 int 310 cosc_intr(arg) 311 void *arg; 312 { 313 struct esc_softc *dev = arg; 314 cosc_regmap_p rp; 315 int quickints; 316 317 rp = (cosc_regmap_p)dev->sc_esc; 318 319 printf("cosc_intr:%08x %02x\n", (u_int)rp->esc.esc_status, *rp->esc.esc_status); 320 321 if (*rp->esc.esc_status & ESC_STAT_INTERRUPT_PENDING) { 322 quickints = 16; 323 do { 324 dev->sc_status = *rp->esc.esc_status; 325 dev->sc_interrupt = *rp->esc.esc_interrupt; 326 327 if (dev->sc_interrupt & ESC_INT_RESELECTED) { 328 dev->sc_resel[0] = *rp->esc.esc_fifo; 329 dev->sc_resel[1] = *rp->esc.esc_fifo; 330 } 331 332 escintr(dev); 333 334 } while((*rp->esc.esc_status & ESC_STAT_INTERRUPT_PENDING) 335 && --quickints); 336 } 337 338 return(0); /* Pass interrupt on down the chain */ 339 } 340 341 342 /* Load transfer address into dma register */ 343 344 void 345 cosc_set_dma_adr(sc, ptr) 346 struct esc_softc *sc; 347 void *ptr; 348 { 349 printf("cosc_set_dma_adr(sc = 0x%08x, ptr = 0x%08x)\n", (u_int)sc, (u_int)ptr); 350 return; 351 } 352 353 354 /* Set DMA transfer counter */ 355 356 void 357 cosc_set_dma_tc(sc, len) 358 struct esc_softc *sc; 359 unsigned int len; 360 { 361 printf("cosc_set_dma_tc(sc, len = 0x%08x)", len); 362 363 /* Set the transfer size on the SCSI controller */ 364 365 *sc->sc_esc->esc_tc_low = len; len >>= 8; 366 *sc->sc_esc->esc_tc_mid = len; len >>= 8; 367 *sc->sc_esc->esc_tc_high = len; 368 } 369 370 371 /* Set DMA mode */ 372 373 void 374 cosc_set_dma_mode(sc, mode) 375 struct esc_softc *sc; 376 int mode; 377 { 378 printf("cosc_set_dma_mode(sc, mode = %d)", mode); 379 } 380 381 382 /* Initialize DMA for transfer */ 383 384 int 385 cosc_setup_dma(sc, ptr, len, mode) 386 struct esc_softc *sc; 387 void *ptr; 388 int len; 389 int mode; 390 { 391 /* printf("cosc_setup_dma(sc, ptr = 0x%08x, len = 0x%08x, mode = 0x%08x)\n", (u_int)ptr, len, mode);*/ 392 return(0); 393 394 } 395 396 397 /* Check if address and len is ok for DMA transfer */ 398 399 int 400 cosc_need_bump(sc, ptr, len) 401 struct esc_softc *sc; 402 void *ptr; 403 int len; 404 { 405 int p; 406 407 p = (int)ptr & 0x03; 408 409 if (p) { 410 p = 4-p; 411 412 if (len < 256) 413 p = len; 414 } 415 416 return(p); 417 } 418 419 420 /* Interrupt driven routines */ 421 422 int 423 cosc_build_dma_chain(sc, chain, p, l) 424 struct esc_softc *sc; 425 struct esc_dma_chain *chain; 426 void *p; 427 int l; 428 { 429 printf("cosc_build_dma_chain()\n"); 430 return(0); 431 } 432