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