1 /* $NetBSD: cosc.c,v 1.19 2014/01/21 19:46:45 christos 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/cdefs.h> 45 __KERNEL_RCSID(0, "$NetBSD: cosc.c,v 1.19 2014/01/21 19:46:45 christos Exp $"); 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/kernel.h> 50 #include <sys/device.h> 51 52 #include <uvm/uvm_extern.h> 53 54 #include <dev/scsipi/scsi_all.h> 55 #include <dev/scsipi/scsipi_all.h> 56 #include <dev/scsipi/scsiconf.h> 57 #include <machine/bootconfig.h> 58 #include <machine/io.h> 59 #include <machine/intr.h> 60 #include <arm/arm32/katelib.h> 61 #include <acorn32/podulebus/podulebus.h> 62 #include <acorn32/podulebus/escreg.h> 63 #include <acorn32/podulebus/escvar.h> 64 #include <acorn32/podulebus/coscreg.h> 65 #include <acorn32/podulebus/coscvar.h> 66 #include <dev/podulebus/podules.h> 67 68 void coscattach(device_t, device_t, void *); 69 int coscmatch(device_t, cfdata_t, void *); 70 71 CFATTACH_DECL_NEW(cosc, sizeof(struct cosc_softc), 72 coscmatch, coscattach, NULL, NULL); 73 74 int cosc_intr(void *); 75 int cosc_setup_dma(struct esc_softc *, void *, int, int); 76 int cosc_build_dma_chain(struct esc_softc *, struct esc_dma_chain *, void *, 77 int); 78 int cosc_need_bump(struct esc_softc *, void *, int); 79 void cosc_led(struct esc_softc *, int); 80 void cosc_set_dma_adr(struct esc_softc *, void *); 81 void cosc_set_dma_tc(struct esc_softc *, unsigned int); 82 void cosc_set_dma_mode(struct esc_softc *, int); 83 84 #if COSC_POLL > 0 85 int cosc_poll = 1; 86 #endif 87 88 int 89 coscmatch(device_t parent, cfdata_t cf, void *aux) 90 { 91 struct podule_attach_args *pa = aux; 92 93 /* Look for the card */ 94 95 if (pa->pa_product == PODULE_CONNECT32) 96 return(1); 97 98 /* Old versions of the ROM on this card could have the wrong ID */ 99 100 if (pa ->pa_product == PODULE_ACORN_SCSI && 101 strncmp(pa->pa_podule->description, "MCS", 3) == 0) 102 return(1); 103 return(0); 104 } 105 106 static int dummy[6]; 107 108 void 109 coscattach(device_t parent, device_t self, void *aux) 110 { 111 struct cosc_softc *sc = device_private(self); 112 struct podule_attach_args *pa = aux; 113 cosc_regmap_p rp = &sc->sc_regmap; 114 vu_char *esc; 115 116 if (pa->pa_podule_number == -1) 117 panic("Podule has disappeared !"); 118 119 sc->sc_podule_number = pa->pa_podule_number; 120 sc->sc_podule = pa->pa_podule; 121 podules[sc->sc_podule_number].attached = 1; 122 123 printf(":"); 124 125 if (pa->pa_podule->manufacturer == MANUFACTURER_ACORN 126 && pa->pa_podule->product == PODULE_ACORN_SCSI) 127 printf(" Faulty expansion card identity\n"); 128 129 sc->sc_iobase = (vu_char *)sc->sc_podule->fast_base; 130 131 /* Select page zero (so we can see the config info) */ 132 133 sc->sc_iobase[COSC_PAGE_REGISTER] = 0; 134 135 rp->chipreset = (vu_char *)&dummy[0]; 136 rp->inten = (vu_char *)&dummy[1]; 137 rp->status = (vu_char *)&dummy[2]; 138 rp->term = &sc->sc_iobase[COSC_TERMINATION_CONTROL]; 139 rp->led = (vu_char *)&dummy[4]; 140 esc = &sc->sc_iobase[COSC_ESCOFFSET_BASE]; 141 142 rp->esc.esc_tc_low = &esc[COSC_ESCOFFSET_TCL]; 143 rp->esc.esc_tc_mid = &esc[COSC_ESCOFFSET_TCM]; 144 rp->esc.esc_fifo = &esc[COSC_ESCOFFSET_FIFO]; 145 rp->esc.esc_command = &esc[COSC_ESCOFFSET_COMMAND]; 146 rp->esc.esc_dest_id = &esc[COSC_ESCOFFSET_DESTID]; 147 rp->esc.esc_timeout = &esc[COSC_ESCOFFSET_TIMEOUT]; 148 rp->esc.esc_syncper = &esc[COSC_ESCOFFSET_PERIOD]; 149 rp->esc.esc_syncoff = &esc[COSC_ESCOFFSET_OFFSET]; 150 rp->esc.esc_config1 = &esc[COSC_ESCOFFSET_CONFIG1]; 151 rp->esc.esc_clkconv = &esc[COSC_ESCOFFSET_CLOCKCONV]; 152 rp->esc.esc_test = &esc[COSC_ESCOFFSET_TEST]; 153 rp->esc.esc_config2 = &esc[COSC_ESCOFFSET_CONFIG2]; 154 rp->esc.esc_config3 = &esc[COSC_ESCOFFSET_CONFIG3]; 155 rp->esc.esc_config4 = &esc[COSC_ESCOFFSET_CONFIG4]; 156 rp->esc.esc_tc_high = &esc[COSC_ESCOFFSET_TCH]; 157 rp->esc.esc_fifo_bot = &esc[COSC_ESCOFFSET_FIFOBOTTOM]; 158 159 *rp->esc.esc_command = ESC_CMD_RESET_CHIP; 160 delay(1000); 161 *rp->esc.esc_command = ESC_CMD_NOP; 162 163 /* See if we recognise the controller */ 164 165 switch (*rp->esc.esc_tc_high) { 166 case 0x12: 167 printf(" AM53CF94"); 168 break; 169 default: 170 printf(" Unknown controller (%02x)", *rp->esc.esc_tc_high); 171 break; 172 } 173 174 /* Set termination power */ 175 176 if (sc->sc_iobase[COSC_CONFIG_TERMINATION] & COSC_CONFIG_TERMINATION_ON) { 177 printf(" termpwr on"); 178 sc->sc_iobase[COSC_TERMINATION_CONTROL] = COSC_TERMINATION_ON; 179 } else { 180 printf(" termpwr off"); 181 sc->sc_iobase[COSC_TERMINATION_CONTROL] = COSC_TERMINATION_OFF; 182 } 183 184 /* Don't know what this is for */ 185 186 { 187 int byte; 188 int loop; 189 190 byte = sc->sc_iobase[COSC_REGISTER_01]; 191 byte = 0; 192 for (loop = 0; loop < 8; ++loop) { 193 if (sc->sc_iobase[COSC_REGISTER_00] & 0x01) 194 byte |= (1 << loop); 195 } 196 printf(" byte=%02x", byte); 197 } 198 199 /* 200 * Control register 4 is an AMD special (not on FAS216) 201 * 202 * The powerdown and glitch eater facilities could be useful 203 * Use the podule configuration for this register 204 */ 205 206 sc->sc_softc.sc_config4 = sc->sc_iobase[COSC_CONFIG_CONTROL_REG4]; 207 208 sc->sc_softc.sc_esc = (esc_regmap_p)rp; 209 /* sc->sc_softc.sc_spec = &sc->sc_specific;*/ 210 211 sc->sc_softc.sc_led = cosc_led; 212 sc->sc_softc.sc_setup_dma = cosc_setup_dma; 213 sc->sc_softc.sc_build_dma_chain = cosc_build_dma_chain; 214 sc->sc_softc.sc_need_bump = cosc_need_bump; 215 216 sc->sc_softc.sc_clock_freq = 40; /* Connect32 runs at 40MHz */ 217 sc->sc_softc.sc_timeout = 250; /* Set default timeout to 250ms */ 218 sc->sc_softc.sc_config_flags = ESC_NO_DMA; 219 sc->sc_softc.sc_host_id = sc->sc_iobase[COSC_CONFIG_CONTROL_REG1] & ESC_DEST_ID_MASK; 220 221 printf(" hostid=%d", sc->sc_softc.sc_host_id); 222 223 #if COSC_POLL > 0 224 if (boot_args) 225 get_bootconf_option(boot_args, "coscpoll", 226 BOOTOPT_TYPE_BOOLEAN, &cosc_poll); 227 228 if (cosc_poll) { 229 printf(" polling"); 230 sc->sc_softc.sc_adapter.adapt_flags |= SCSIPI_ADAPT_POLL_ONLY; 231 } 232 #endif 233 234 sc->sc_softc.sc_bump_sz = PAGE_SIZE; 235 sc->sc_softc.sc_bump_pa = 0x0; 236 237 escinitialize(&sc->sc_softc); 238 239 sc->sc_softc.sc_dev = self; 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 device_xname(self), "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 device_xname(self)); 279 } 280 281 printf("\n"); 282 283 /* attach all scsi units on us */ 284 config_found(self, &sc->sc_softc.sc_channel, scsiprint); 285 } 286 287 288 /* Turn on/off led */ 289 290 void 291 cosc_led(struct esc_softc *sc, int mode) 292 { 293 if (mode) { 294 sc->sc_led_status++; 295 } else { 296 if (sc->sc_led_status) 297 sc->sc_led_status--; 298 } 299 #if 0 300 cosc_regmap_p rp = (cosc_regmap_p)sc->sc_esc; 301 *rp->led = c->sc_led_status ? 1 : 0; 302 #endif 303 } 304 305 306 int 307 cosc_intr(void *arg) 308 { 309 struct esc_softc *dev = arg; 310 cosc_regmap_p rp; 311 int quickints; 312 313 rp = (cosc_regmap_p)dev->sc_esc; 314 315 printf("cosc_intr:%08x %02x\n", (u_int)rp->esc.esc_status, *rp->esc.esc_status); 316 317 if (*rp->esc.esc_status & ESC_STAT_INTERRUPT_PENDING) { 318 quickints = 16; 319 do { 320 dev->sc_status = *rp->esc.esc_status; 321 dev->sc_interrupt = *rp->esc.esc_interrupt; 322 323 if (dev->sc_interrupt & ESC_INT_RESELECTED) { 324 dev->sc_resel[0] = *rp->esc.esc_fifo; 325 dev->sc_resel[1] = *rp->esc.esc_fifo; 326 } 327 328 escintr(dev); 329 330 } while((*rp->esc.esc_status & ESC_STAT_INTERRUPT_PENDING) 331 && --quickints); 332 } 333 334 return(0); /* Pass interrupt on down the chain */ 335 } 336 337 338 /* Load transfer address into dma register */ 339 340 void 341 cosc_set_dma_adr(struct esc_softc *sc, void *ptr) 342 { 343 printf("cosc_set_dma_adr(sc = 0x%08x, ptr = 0x%08x)\n", (u_int)sc, (u_int)ptr); 344 return; 345 } 346 347 348 /* Set DMA transfer counter */ 349 350 void 351 cosc_set_dma_tc(struct esc_softc *sc, unsigned int len) 352 { 353 printf("cosc_set_dma_tc(sc, len = 0x%08x)", len); 354 355 /* Set the transfer size on the SCSI controller */ 356 357 *sc->sc_esc->esc_tc_low = len; len >>= 8; 358 *sc->sc_esc->esc_tc_mid = len; len >>= 8; 359 *sc->sc_esc->esc_tc_high = len; 360 } 361 362 363 /* Set DMA mode */ 364 365 void 366 cosc_set_dma_mode(struct esc_softc *sc, int mode) 367 { 368 printf("cosc_set_dma_mode(sc, mode = %d)", mode); 369 } 370 371 372 /* Initialize DMA for transfer */ 373 374 int 375 cosc_setup_dma(struct esc_softc *sc, void *ptr, int len, int mode) 376 { 377 /* printf("cosc_setup_dma(sc, ptr = 0x%08x, len = 0x%08x, mode = 0x%08x)\n", (u_int)ptr, len, mode);*/ 378 return(0); 379 380 } 381 382 383 /* Check if address and len is ok for DMA transfer */ 384 385 int 386 cosc_need_bump(struct esc_softc *sc, void *ptr, int len) 387 { 388 int p; 389 390 p = (int)ptr & 0x03; 391 392 if (p) { 393 p = 4-p; 394 395 if (len < 256) 396 p = len; 397 } 398 399 return(p); 400 } 401 402 403 /* Interrupt driven routines */ 404 405 int 406 cosc_build_dma_chain(struct esc_softc *sc, struct esc_dma_chain *chain, void *p, int l) 407 { 408 printf("cosc_build_dma_chain()\n"); 409 return(0); 410 } 411