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