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