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