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