1 /* $NetBSD: nca_isa.c,v 1.9 2002/01/07 21:47:11 thorpej 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/cdefs.h> 67 __KERNEL_RCSID(0, "$NetBSD: nca_isa.c,v 1.9 2002/01/07 21:47:11 thorpej Exp $"); 68 69 #include <sys/param.h> 70 #include <sys/systm.h> 71 #include <sys/device.h> 72 #include <sys/buf.h> 73 74 #include <machine/bus.h> 75 #include <machine/intr.h> 76 77 #include <dev/scsipi/scsi_all.h> 78 #include <dev/scsipi/scsipi_all.h> 79 #include <dev/scsipi/scsiconf.h> 80 81 #include <dev/isa/isavar.h> 82 #include <dev/isa/isadmavar.h> 83 84 #include <dev/ic/ncr5380reg.h> 85 #include <dev/ic/ncr5380var.h> 86 #include <dev/ic/ncr53c400reg.h> 87 88 struct nca_isa_softc { 89 struct ncr5380_softc sc_ncr5380; /* glue to MI code */ 90 91 void *sc_ih; 92 int sc_irq; 93 int sc_options; 94 }; 95 96 struct nca_isa_probe_data { 97 struct device sc_dev; 98 int sc_reg_offset; 99 int sc_host_type; 100 }; 101 102 int nca_isa_find __P((bus_space_tag_t, bus_space_handle_t, bus_size_t, 103 struct nca_isa_probe_data *)); 104 int nca_isa_match __P((struct device *, struct cfdata *, void *)); 105 void nca_isa_attach __P((struct device *, struct device *, void *)); 106 int nca_isa_test __P((bus_space_tag_t, bus_space_handle_t, bus_size_t)); 107 108 struct cfattach nca_isa_ca = { 109 sizeof(struct nca_isa_softc), nca_isa_match, nca_isa_attach 110 }; 111 112 113 /* Supported controller types */ 114 #define MAX_NCA_CONTROLLER 3 115 #define CTLR_NCR_5380 1 116 #define CTLR_NCR_53C400 2 117 #define CTLR_PAS16 3 118 119 #define NCA_ISA_IOSIZE 16 120 #define MIN_DMA_LEN 128 121 122 /* Options for disconnect/reselect, DMA, and interrupts. */ 123 #define NCA_NO_DISCONNECT 0xff 124 #define NCA_NO_PARITY_CHK 0xff00 125 #define NCA_FORCE_POLLING 0x10000 126 127 128 /* 129 * Initialization and test function used by nca_isa_find() 130 */ 131 int 132 nca_isa_test(iot, ioh, reg_offset) 133 bus_space_tag_t iot; 134 bus_space_handle_t ioh; 135 bus_size_t reg_offset; 136 { 137 /* Reset the SCSI bus. */ 138 bus_space_write_1(iot, ioh, reg_offset + C80_ICR, SCI_ICMD_RST); 139 bus_space_write_1(iot, ioh, reg_offset + C80_ODR, 0); 140 /* Hold reset for at least 25 microseconds. */ 141 delay(500); 142 /* Check that status cleared. */ 143 if (bus_space_read_1(iot, ioh, reg_offset + C80_CSBR) != SCI_BUS_RST) { 144 #ifdef DEBUG 145 printf("nca_isa_find: reset status not cleared [0x%x]\n", 146 bus_space_read_1(iot, ioh, reg_offset+C80_CSBR)); 147 #endif 148 bus_space_write_1(iot, ioh, reg_offset+C80_ICR, 0); 149 return 0; 150 } 151 /* Clear reset. */ 152 bus_space_write_1(iot, ioh, reg_offset + C80_ICR, 0); 153 /* Wait a Bus Clear Delay (800 ns + bus free delay 800 ns). */ 154 delay(16000); 155 156 /* Read RPI port, resetting parity/interrupt state. */ 157 bus_space_read_1(iot, ioh, reg_offset + C80_RPIR); 158 159 /* Test BSR: parity error, interrupt request and busy loss state 160 * should be cleared. */ 161 if (bus_space_read_1(iot, ioh, reg_offset + C80_BSR) & (SCI_CSR_PERR | 162 SCI_CSR_INT | SCI_CSR_DISC)) { 163 #ifdef DEBUG 164 printf("nca_isa_find: Parity/Interrupt/Busy not cleared [0x%x]\n", 165 bus_space_read_1(iot, ioh, reg_offset+C80_BSR)); 166 #endif 167 return 0; 168 } 169 170 /* We must have found one */ 171 return 1; 172 } 173 174 175 /* 176 * Look for the board 177 */ 178 int 179 nca_isa_find(iot, ioh, max_offset, epd) 180 bus_space_tag_t iot; 181 bus_space_handle_t ioh; 182 bus_size_t max_offset; 183 struct nca_isa_probe_data *epd; 184 { 185 /* 186 * We check for the existence of a board by trying to initialize it, 187 * Then sending the commands to reset the SCSI bus. 188 * (Unfortunately, this duplicates code which is already in the MI 189 * driver. Unavoidable as that code is not suited to this task.) 190 * This is largely stolen from FreeBSD. 191 */ 192 193 int cont_type; 194 bus_size_t base_offset, reg_offset = 0; 195 196 /* 197 * Some notes: 198 * In the case of a port-mapped board, we should be pointing 199 * right at the chip registers (if they are there at all). 200 * For a memory-mapped card, we loop through the 16K paragraph, 201 * 8 bytes at a time, until we either find it or run out 202 * of region. This means we will probably be doing things like 203 * trying to write to ROMS, etc. Hopefully, this is not a problem. 204 */ 205 206 for (base_offset = 0; base_offset < max_offset; base_offset += 0x08) { 207 #ifdef DEBUG 208 printf("nca_isa_find: testing offset 0x%x\n", (int)base_offset); 209 #endif 210 211 /* See if anything is there */ 212 if (bus_space_read_1(iot, ioh, base_offset) == 0xff) 213 continue; 214 215 /* Loop around for each board type */ 216 for (cont_type = 1; cont_type <= MAX_NCA_CONTROLLER; cont_type++) { 217 /* Per-controller initialization */ 218 switch (cont_type) { 219 case CTLR_NCR_5380: 220 /* No special inits */ 221 reg_offset = 0; 222 break; 223 case CTLR_NCR_53C400: 224 /* Reset into 5380-compat. mode */ 225 bus_space_write_1(iot, ioh, 226 base_offset + C400_CSR, 227 C400_CSR_5380_ENABLE); 228 reg_offset = C400_5380_REG_OFFSET; 229 break; 230 case CTLR_PAS16: 231 /* Not currently supported */ 232 reg_offset = 0; 233 cont_type = 0; 234 continue; 235 } 236 237 /* Initialize controller and bus */ 238 if (nca_isa_test(iot, ioh, base_offset+reg_offset)) { 239 epd->sc_reg_offset = base_offset; 240 epd->sc_host_type = cont_type; 241 return cont_type; /* This must be it */ 242 } 243 } 244 } 245 246 /* If we got here, we didn't find one */ 247 return 0; 248 } 249 250 251 /* 252 * See if there is anything at the config'd address. 253 * If so, call the real probe to see what it is. 254 */ 255 int 256 nca_isa_match(parent, match, aux) 257 struct device *parent; 258 struct cfdata *match; 259 void *aux; 260 { 261 struct isa_attach_args *ia = aux; 262 bus_space_tag_t iot = ia->ia_iot; 263 bus_space_tag_t memt = ia->ia_memt; 264 bus_space_handle_t ioh; 265 struct nca_isa_probe_data epd; 266 int rv = 0; 267 268 if (ISA_DIRECT_CONFIG(ia)) 269 return (0); 270 271 /* See if we are looking for a port- or memory-mapped adapter */ 272 if (ia->ia_nio > 0 || ia->ia_io[0].ir_addr != ISACF_PORT_DEFAULT) { 273 /* Port-mapped card */ 274 if (bus_space_map(iot, ia->ia_io[0].ir_addr, NCA_ISA_IOSIZE, 275 0, &ioh)) 276 return 0; 277 278 /* See if a 53C80/53C400 is there */ 279 rv = nca_isa_find(iot, ioh, 0x07, &epd); 280 281 bus_space_unmap(iot, ioh, NCA_ISA_IOSIZE); 282 283 if (rv) { 284 ia->ia_nio = 1; 285 ia->ia_io[0].ir_size = NCA_ISA_IOSIZE; 286 287 ia->ia_niomem = 0; 288 ia->ia_ndrq = 0; 289 } 290 } else if (ia->ia_niomem > 0) { 291 /* Memory-mapped card */ 292 if (bus_space_map(memt, ia->ia_iomem[0].ir_addr, 0x4000, 293 0, &ioh)) 294 return 0; 295 296 /* See if a 53C80/53C400 is somewhere in this para. */ 297 rv = nca_isa_find(memt, ioh, 0x03ff0, &epd); 298 299 bus_space_unmap(memt, ioh, 0x04000); 300 301 if (rv) { 302 ia->ia_niomem = 1; 303 ia->ia_iomem[0].ir_addr += epd.sc_reg_offset; 304 ia->ia_iomem[0].ir_size = NCA_ISA_IOSIZE; 305 306 ia->ia_nio = 0; 307 ia->ia_ndrq = 0; 308 } 309 } 310 311 return rv; 312 } 313 314 /* 315 * Attach this instance, and then all the sub-devices 316 */ 317 void 318 nca_isa_attach(parent, self, aux) 319 struct device *parent, *self; 320 void *aux; 321 { 322 struct isa_attach_args *ia = aux; 323 struct nca_isa_softc *esc = (void *)self; 324 struct ncr5380_softc *sc = &esc->sc_ncr5380; 325 bus_space_tag_t iot = ia->ia_iot; 326 bus_space_handle_t ioh; 327 struct nca_isa_probe_data epd; 328 isa_chipset_tag_t ic = ia->ia_ic; 329 330 printf("\n"); 331 332 if (ia->ia_nio > 0) { 333 iot = ia->ia_iot; 334 if (bus_space_map(iot, ia->ia_io[0].ir_addr, NCA_ISA_IOSIZE, 335 0, &ioh)) { 336 printf("%s: can't map i/o space\n", 337 sc->sc_dev.dv_xname); 338 return; 339 } 340 } else { 341 KASSERT(ia->ia_niomem > 0); 342 iot = ia->ia_memt; 343 if (bus_space_map(iot, ia->ia_iomem[0].ir_addr, NCA_ISA_IOSIZE, 344 0, &ioh)) { 345 printf("%s: can't map mem space\n", 346 sc->sc_dev.dv_xname); 347 return; 348 } 349 } 350 351 switch (nca_isa_find(iot, ioh, NCA_ISA_IOSIZE, &epd)) { 352 case 0: 353 /* Not found- must have gone away */ 354 printf("%s: nca_isa_find failed\n", sc->sc_dev.dv_xname); 355 return; 356 case CTLR_NCR_5380: 357 printf("%s: NCR 53C80 detected\n", sc->sc_dev.dv_xname); 358 sc->sci_r0 = 0; 359 sc->sci_r1 = 1; 360 sc->sci_r2 = 2; 361 sc->sci_r3 = 3; 362 sc->sci_r4 = 4; 363 sc->sci_r5 = 5; 364 sc->sci_r6 = 6; 365 sc->sci_r7 = 7; 366 sc->sc_rev = NCR_VARIANT_NCR5380; 367 break; 368 case CTLR_NCR_53C400: 369 printf("%s: NCR 53C400 detected\n", sc->sc_dev.dv_xname); 370 sc->sci_r0 = C400_5380_REG_OFFSET + 0; 371 sc->sci_r1 = C400_5380_REG_OFFSET + 1; 372 sc->sci_r2 = C400_5380_REG_OFFSET + 2; 373 sc->sci_r3 = C400_5380_REG_OFFSET + 3; 374 sc->sci_r4 = C400_5380_REG_OFFSET + 4; 375 sc->sci_r5 = C400_5380_REG_OFFSET + 5; 376 sc->sci_r6 = C400_5380_REG_OFFSET + 6; 377 sc->sci_r7 = C400_5380_REG_OFFSET + 7; 378 sc->sc_rev = NCR_VARIANT_NCR53C400; 379 break; 380 case CTLR_PAS16: 381 printf("%s: ProAudio Spectrum 16 detected\n", 382 sc->sc_dev.dv_xname); 383 sc->sc_rev = NCR_VARIANT_PAS16; 384 break; 385 } 386 387 /* 388 * MD function pointers used by the MI code. 389 */ 390 sc->sc_pio_out = ncr5380_pio_out; 391 sc->sc_pio_in = ncr5380_pio_in; 392 sc->sc_dma_alloc = NULL; 393 sc->sc_dma_free = NULL; 394 sc->sc_dma_setup = NULL; 395 sc->sc_dma_start = NULL; 396 sc->sc_dma_poll = NULL; 397 sc->sc_dma_eop = NULL; 398 sc->sc_dma_stop = NULL; 399 sc->sc_intr_on = NULL; 400 sc->sc_intr_off = NULL; 401 402 if (ia->ia_nirq > 0 && ia->ia_irq[0].ir_irq != ISACF_IRQ_DEFAULT) { 403 esc->sc_ih = isa_intr_establish(ic, ia->ia_irq[0].ir_irq, 404 IST_EDGE, IPL_BIO, ncr5380_intr, esc); 405 if (esc->sc_ih == NULL) { 406 printf("%s: couldn't establish interrupt\n", 407 sc->sc_dev.dv_xname); 408 return; 409 } 410 } else 411 sc->sc_flags |= NCR5380_FORCE_POLLING; 412 413 414 /* 415 * Support the "options" (config file flags). 416 * Disconnect/reselect is a per-target mask. 417 * Interrupts and DMA are per-controller. 418 */ 419 #if 0 420 esc->sc_options = 0x00000; /* no options */ 421 #else 422 esc->sc_options = 0x0ffff; /* all options except force poll */ 423 #endif 424 425 sc->sc_no_disconnect = 426 (esc->sc_options & NCA_NO_DISCONNECT); 427 sc->sc_parity_disable = 428 (esc->sc_options & NCA_NO_PARITY_CHK) >> 8; 429 if (esc->sc_options & NCA_FORCE_POLLING) 430 sc->sc_flags |= NCR5380_FORCE_POLLING; 431 sc->sc_min_dma_len = MIN_DMA_LEN; 432 433 434 /* 435 * Initialize fields used by the MI code 436 */ 437 sc->sc_regt = iot; 438 sc->sc_regh = ioh; 439 440 /* 441 * Fill in our portion of the scsipi_adapter. 442 */ 443 sc->sc_adapter.adapt_request = ncr5380_scsipi_request; 444 sc->sc_adapter.adapt_minphys = minphys; 445 446 /* 447 * Fill in our portion of the scsipi_channel. 448 */ 449 450 sc->sc_channel.chan_id = 7; 451 452 /* 453 * Initialize nca board itself. 454 */ 455 ncr5380_attach(sc); 456 } 457