1 /* $NetBSD: nca_isa.c,v 1.6 2000/03/25 15:27:58 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by John M. Ruschmeyer. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * FreeBSD generic NCR-5380/NCR-53C400 SCSI driver 41 * 42 * Copyright (C) 1994 Serge Vakulenko (vak@cronyx.ru) 43 * 44 * Redistribution and use in source and binary forms, with or without 45 * modification, are permitted provided that the following conditions 46 * are met: 47 * 1. Redistributions of source code must retain the above copyright 48 * notice, this list of conditions and the following disclaimer. 49 * 2. Redistributions in binary form must reproduce the above copyright 50 * notice, this list of conditions and the following disclaimer in the 51 * documentation and/or other materials provided with the distribution. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPERS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 */ 65 66 #include <sys/param.h> 67 #include <sys/systm.h> 68 #include <sys/device.h> 69 #include <sys/buf.h> 70 71 #include <machine/bus.h> 72 #include <machine/intr.h> 73 74 #include <dev/scsipi/scsi_all.h> 75 #include <dev/scsipi/scsipi_all.h> 76 #include <dev/scsipi/scsiconf.h> 77 78 #include <dev/isa/isavar.h> 79 #include <dev/isa/isadmavar.h> 80 81 #include <dev/ic/ncr5380reg.h> 82 #include <dev/ic/ncr5380var.h> 83 #include <dev/ic/ncr53c400reg.h> 84 85 struct nca_isa_softc { 86 struct ncr5380_softc sc_ncr5380; /* glue to MI code */ 87 88 void *sc_ih; 89 int sc_irq; 90 int sc_options; 91 }; 92 93 struct nca_isa_probe_data { 94 struct device sc_dev; 95 int sc_reg_offset; 96 int sc_host_type; 97 }; 98 99 int nca_isa_find __P((bus_space_tag_t, bus_space_handle_t, bus_size_t, 100 struct nca_isa_probe_data *)); 101 int nca_isa_match __P((struct device *, struct cfdata *, void *)); 102 void nca_isa_attach __P((struct device *, struct device *, void *)); 103 int nca_isa_test __P((bus_space_tag_t, bus_space_handle_t, bus_size_t)); 104 105 struct cfattach nca_isa_ca = { 106 sizeof(struct nca_isa_softc), nca_isa_match, nca_isa_attach 107 }; 108 109 110 /* Supported controller types */ 111 #define MAX_NCA_CONTROLLER 3 112 #define CTLR_NCR_5380 1 113 #define CTLR_NCR_53C400 2 114 #define CTLR_PAS16 3 115 116 #define NCA_ISA_IOSIZE 16 117 #define MIN_DMA_LEN 128 118 119 /* Options for disconnect/reselect, DMA, and interrupts. */ 120 #define NCA_NO_DISCONNECT 0xff 121 #define NCA_NO_PARITY_CHK 0xff00 122 #define NCA_FORCE_POLLING 0x10000 123 124 125 /* 126 * Initialization and test function used by nca_isa_find() 127 */ 128 int 129 nca_isa_test(iot, ioh, reg_offset) 130 bus_space_tag_t iot; 131 bus_space_handle_t ioh; 132 bus_size_t reg_offset; 133 { 134 /* Reset the SCSI bus. */ 135 bus_space_write_1(iot, ioh, reg_offset + C80_ICR, SCI_ICMD_RST); 136 bus_space_write_1(iot, ioh, reg_offset + C80_ODR, 0); 137 /* Hold reset for at least 25 microseconds. */ 138 delay(500); 139 /* Check that status cleared. */ 140 if (bus_space_read_1(iot, ioh, reg_offset + C80_CSBR) != SCI_BUS_RST) { 141 #ifdef DEBUG 142 printf("nca_isa_find: reset status not cleared [0x%x]\n", 143 bus_space_read_1(iot, ioh, reg_offset+C80_CSBR)); 144 #endif 145 bus_space_write_1(iot, ioh, reg_offset+C80_ICR, 0); 146 return 0; 147 } 148 /* Clear reset. */ 149 bus_space_write_1(iot, ioh, reg_offset + C80_ICR, 0); 150 /* Wait a Bus Clear Delay (800 ns + bus free delay 800 ns). */ 151 delay(16000); 152 153 /* Read RPI port, resetting parity/interrupt state. */ 154 bus_space_read_1(iot, ioh, reg_offset + C80_RPIR); 155 156 /* Test BSR: parity error, interrupt request and busy loss state 157 * should be cleared. */ 158 if (bus_space_read_1(iot, ioh, reg_offset + C80_BSR) & (SCI_CSR_PERR | 159 SCI_CSR_INT | SCI_CSR_DISC)) { 160 #ifdef DEBUG 161 printf("nca_isa_find: Parity/Interrupt/Busy not cleared [0x%x]\n", 162 bus_space_read_1(iot, ioh, reg_offset+C80_BSR)); 163 #endif 164 return 0; 165 } 166 167 /* We must have found one */ 168 return 1; 169 } 170 171 172 /* 173 * Look for the board 174 */ 175 int 176 nca_isa_find(iot, ioh, max_offset, epd) 177 bus_space_tag_t iot; 178 bus_space_handle_t ioh; 179 bus_size_t max_offset; 180 struct nca_isa_probe_data *epd; 181 { 182 /* 183 * We check for the existence of a board by trying to initialize it, 184 * Then sending the commands to reset the SCSI bus. 185 * (Unfortunately, this duplicates code which is already in the MI 186 * driver. Unavoidable as that code is not suited to this task.) 187 * This is largely stolen from FreeBSD. 188 */ 189 190 int cont_type; 191 bus_size_t base_offset, reg_offset = 0; 192 193 /* 194 * Some notes: 195 * In the case of a port-mapped board, we should be pointing 196 * right at the chip registers (if they are there at all). 197 * For a memory-mapped card, we loop through the 16K paragraph, 198 * 8 bytes at a time, until we either find it or run out 199 * of region. This means we will probably be doing things like 200 * trying to write to ROMS, etc. Hopefully, this is not a problem. 201 */ 202 203 for (base_offset = 0; base_offset < max_offset; base_offset += 0x08) { 204 #ifdef DEBUG 205 printf("nca_isa_find: testing offset 0x%x\n", (int)base_offset); 206 #endif 207 208 /* See if anything is there */ 209 if (bus_space_read_1(iot, ioh, base_offset) == 0xff) 210 continue; 211 212 /* Loop around for each board type */ 213 for (cont_type = 1; cont_type <= MAX_NCA_CONTROLLER; cont_type++) { 214 /* Per-controller initialization */ 215 switch (cont_type) { 216 case CTLR_NCR_5380: 217 /* No special inits */ 218 reg_offset = 0; 219 break; 220 case CTLR_NCR_53C400: 221 /* Reset into 5380-compat. mode */ 222 bus_space_write_1(iot, ioh, 223 base_offset + C400_CSR, 224 C400_CSR_5380_ENABLE); 225 reg_offset = C400_5380_REG_OFFSET; 226 break; 227 case CTLR_PAS16: 228 /* Not currently supported */ 229 reg_offset = 0; 230 cont_type = 0; 231 continue; 232 } 233 234 /* Initialize controller and bus */ 235 if (nca_isa_test(iot, ioh, base_offset+reg_offset)) { 236 epd->sc_reg_offset = base_offset; 237 epd->sc_host_type = cont_type; 238 return cont_type; /* This must be it */ 239 } 240 } 241 } 242 243 /* If we got here, we didn't find one */ 244 return 0; 245 } 246 247 248 /* 249 * See if there is anything at the config'd address. 250 * If so, call the real probe to see what it is. 251 */ 252 int 253 nca_isa_match(parent, match, aux) 254 struct device *parent; 255 struct cfdata *match; 256 void *aux; 257 { 258 struct isa_attach_args *ia = aux; 259 bus_space_tag_t iot = ia->ia_iot; 260 bus_space_tag_t memt = ia->ia_memt; 261 bus_space_handle_t ioh; 262 struct nca_isa_probe_data epd; 263 int rv = 0; 264 265 /* See if we are looking for a port- or memory-mapped adapter */ 266 if (ia->ia_iobase != -1) { 267 /* Port-mapped card */ 268 if (bus_space_map(iot, ia->ia_iobase, NCA_ISA_IOSIZE, 0, &ioh)) 269 return 0; 270 271 /* See if a 53C80/53C400 is there */ 272 rv = nca_isa_find(iot, ioh, 0x07, &epd); 273 274 bus_space_unmap(iot, ioh, NCA_ISA_IOSIZE); 275 } else { 276 /* Memory-mapped card */ 277 if (bus_space_map(memt, ia->ia_maddr, 0x4000, 0, &ioh)) 278 return 0; 279 280 /* See if a 53C80/53C400 is somewhere in this para. */ 281 rv = nca_isa_find(memt, ioh, 0x03ff0, &epd); 282 283 bus_space_unmap(memt, ioh, 0x04000); 284 } 285 286 /* Adjust the attachment args if we found one */ 287 if (rv) { 288 if (ia->ia_iobase != -1) { 289 /* Port-mapped */ 290 ia->ia_iosize = NCA_ISA_IOSIZE; 291 } else { 292 /* Memory-mapped */ 293 ia->ia_maddr += epd.sc_reg_offset; 294 ia->ia_msize = NCA_ISA_IOSIZE; 295 ia->ia_iosize = 0; 296 } 297 } 298 299 return rv; 300 } 301 302 /* 303 * Attach this instance, and then all the sub-devices 304 */ 305 void 306 nca_isa_attach(parent, self, aux) 307 struct device *parent, *self; 308 void *aux; 309 { 310 struct isa_attach_args *ia = aux; 311 struct nca_isa_softc *esc = (void *)self; 312 struct ncr5380_softc *sc = &esc->sc_ncr5380; 313 bus_space_tag_t iot = ia->ia_iot; 314 bus_space_handle_t ioh; 315 struct nca_isa_probe_data epd; 316 isa_chipset_tag_t ic = ia->ia_ic; 317 318 printf("\n"); 319 320 if (ia->ia_iobase != -1) { 321 iot = ia->ia_iot; 322 if (bus_space_map(iot, ia->ia_iobase, NCA_ISA_IOSIZE, 0, &ioh)) { 323 printf("%s: can't map i/o space\n", 324 sc->sc_dev.dv_xname); 325 return; 326 } 327 } else { 328 iot = ia->ia_memt; 329 if (bus_space_map(iot, ia->ia_maddr, NCA_ISA_IOSIZE, 0, &ioh)) { 330 printf("%s: can't map mem space\n", 331 sc->sc_dev.dv_xname); 332 return; 333 } 334 } 335 336 switch (nca_isa_find(iot, ioh, NCA_ISA_IOSIZE, &epd)) { 337 case 0: 338 /* Not found- must have gone away */ 339 printf("%s: nca_isa_find failed\n", sc->sc_dev.dv_xname); 340 return; 341 case CTLR_NCR_5380: 342 printf("%s: NCR 53C80 detected\n", sc->sc_dev.dv_xname); 343 sc->sci_r0 = 0; 344 sc->sci_r1 = 1; 345 sc->sci_r2 = 2; 346 sc->sci_r3 = 3; 347 sc->sci_r4 = 4; 348 sc->sci_r5 = 5; 349 sc->sci_r6 = 6; 350 sc->sci_r7 = 7; 351 sc->sc_rev = NCR_VARIANT_NCR5380; 352 break; 353 case CTLR_NCR_53C400: 354 printf("%s: NCR 53C400 detected\n", sc->sc_dev.dv_xname); 355 sc->sci_r0 = C400_5380_REG_OFFSET + 0; 356 sc->sci_r1 = C400_5380_REG_OFFSET + 1; 357 sc->sci_r2 = C400_5380_REG_OFFSET + 2; 358 sc->sci_r3 = C400_5380_REG_OFFSET + 3; 359 sc->sci_r4 = C400_5380_REG_OFFSET + 4; 360 sc->sci_r5 = C400_5380_REG_OFFSET + 5; 361 sc->sci_r6 = C400_5380_REG_OFFSET + 6; 362 sc->sci_r7 = C400_5380_REG_OFFSET + 7; 363 sc->sc_rev = NCR_VARIANT_NCR53C400; 364 break; 365 case CTLR_PAS16: 366 printf("%s: ProAudio Spectrum 16 detected\n", sc->sc_dev.dv_xname); 367 sc->sc_rev = NCR_VARIANT_PAS16; 368 break; 369 } 370 371 372 /* 373 * MD function pointers used by the MI code. 374 */ 375 sc->sc_pio_out = ncr5380_pio_out; 376 sc->sc_pio_in = ncr5380_pio_in; 377 sc->sc_dma_alloc = NULL; 378 sc->sc_dma_free = NULL; 379 sc->sc_dma_setup = NULL; 380 sc->sc_dma_start = NULL; 381 sc->sc_dma_poll = NULL; 382 sc->sc_dma_eop = NULL; 383 sc->sc_dma_stop = NULL; 384 sc->sc_intr_on = NULL; 385 sc->sc_intr_off = NULL; 386 387 if (ia->ia_irq != IRQUNK) { 388 esc->sc_ih = isa_intr_establish(ic, ia->ia_irq, IST_EDGE, 389 IPL_BIO, ncr5380_intr, esc); 390 if (esc->sc_ih == NULL) { 391 printf("nca: couldn't establish interrupt\n"); 392 return; 393 } 394 } else 395 sc->sc_flags |= NCR5380_FORCE_POLLING; 396 397 398 /* 399 * Support the "options" (config file flags). 400 * Disconnect/reselect is a per-target mask. 401 * Interrupts and DMA are per-controller. 402 */ 403 #if 0 404 esc->sc_options = 0x00000; /* no options */ 405 #else 406 esc->sc_options = 0x0ffff; /* all options except force poll */ 407 #endif 408 409 sc->sc_no_disconnect = 410 (esc->sc_options & NCA_NO_DISCONNECT); 411 sc->sc_parity_disable = 412 (esc->sc_options & NCA_NO_PARITY_CHK) >> 8; 413 if (esc->sc_options & NCA_FORCE_POLLING) 414 sc->sc_flags |= NCR5380_FORCE_POLLING; 415 sc->sc_min_dma_len = MIN_DMA_LEN; 416 417 418 /* 419 * Initialize fields used by the MI code 420 */ 421 sc->sc_regt = iot; 422 sc->sc_regh = ioh; 423 424 sc->sc_link.scsipi_scsi.adapter_target = 7; 425 sc->sc_adapter.scsipi_minphys = minphys; 426 427 /* 428 * Initialize nca board itself. 429 */ 430 ncr5380_attach(sc); 431 } 432