1 /* $NetBSD: asc_ioasic.c,v 1.20 2008/04/28 20:23:31 martin Exp $ */ 2 3 /*- 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Tohru Nishimura. 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 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 33 __KERNEL_RCSID(0, "$NetBSD: asc_ioasic.c,v 1.20 2008/04/28 20:23:31 martin Exp $"); 34 35 #include <sys/types.h> 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/device.h> 39 #include <sys/buf.h> 40 41 #include <uvm/uvm_extern.h> 42 43 #include <dev/scsipi/scsi_all.h> 44 #include <dev/scsipi/scsipi_all.h> 45 #include <dev/scsipi/scsiconf.h> 46 #include <dev/scsipi/scsi_message.h> 47 48 #include <machine/bus.h> 49 50 #include <dev/ic/ncr53c9xreg.h> 51 #include <dev/ic/ncr53c9xvar.h> 52 53 #include <dev/tc/tcvar.h> 54 #include <dev/tc/ioasicvar.h> 55 #include <dev/tc/ioasicreg.h> 56 57 struct asc_softc { 58 struct ncr53c9x_softc sc_ncr53c9x; /* glue to MI code */ 59 bus_space_tag_t sc_bst; /* bus space tag */ 60 bus_space_handle_t sc_bsh; /* bus space handle */ 61 bus_space_handle_t sc_scsi_bsh; /* ASC register handle */ 62 bus_dma_tag_t sc_dmat; /* bus dma tag */ 63 bus_dmamap_t sc_dmamap; /* bus dmamap */ 64 uint8_t **sc_dmaaddr; 65 size_t *sc_dmalen; 66 size_t sc_dmasize; 67 unsigned int sc_flags; 68 #define ASC_ISPULLUP 0x0001 69 #define ASC_DMAACTIVE 0x0002 70 #define ASC_MAPLOADED 0x0004 71 }; 72 73 static int asc_ioasic_match(device_t, cfdata_t, void *); 74 static void asc_ioasic_attach(device_t, device_t, void *); 75 76 CFATTACH_DECL_NEW(asc_ioasic, sizeof(struct asc_softc), 77 asc_ioasic_match, asc_ioasic_attach, NULL, NULL); 78 79 static uint8_t asc_read_reg(struct ncr53c9x_softc *, int); 80 static void asc_write_reg(struct ncr53c9x_softc *, int, u_char); 81 static int asc_dma_isintr(struct ncr53c9x_softc *sc); 82 static void asc_ioasic_reset(struct ncr53c9x_softc *); 83 static int asc_ioasic_intr(struct ncr53c9x_softc *); 84 static int asc_ioasic_setup(struct ncr53c9x_softc *, 85 uint8_t **, size_t *, int, size_t *); 86 static void asc_ioasic_go(struct ncr53c9x_softc *); 87 static void asc_ioasic_stop(struct ncr53c9x_softc *); 88 static int asc_dma_isactive(struct ncr53c9x_softc *); 89 90 static struct ncr53c9x_glue asc_ioasic_glue = { 91 asc_read_reg, 92 asc_write_reg, 93 asc_dma_isintr, 94 asc_ioasic_reset, 95 asc_ioasic_intr, 96 asc_ioasic_setup, 97 asc_ioasic_go, 98 asc_ioasic_stop, 99 asc_dma_isactive, 100 NULL, 101 }; 102 103 static int 104 asc_ioasic_match(device_t parent, cfdata_t cf, void *aux) 105 { 106 struct ioasicdev_attach_args *d = aux; 107 108 if (strncmp("asc", d->iada_modname, TC_ROM_LLEN)) 109 return 0; 110 111 return 1; 112 } 113 114 static void 115 asc_ioasic_attach(device_t parent, device_t self, void *aux) 116 { 117 struct asc_softc *asc = device_private(self); 118 struct ncr53c9x_softc *sc = &asc->sc_ncr53c9x; 119 struct ioasicdev_attach_args *d = aux; 120 struct ioasic_softc *isc = device_private(parent); 121 122 /* 123 * Set up glue for MI code early; we use some of it here. 124 */ 125 sc->sc_dev = self; 126 sc->sc_glue = &asc_ioasic_glue; 127 asc->sc_bst = isc->sc_bst; 128 asc->sc_bsh = isc->sc_bsh; 129 if (bus_space_subregion(asc->sc_bst, asc->sc_bsh, 130 IOASIC_SLOT_12_START, 0x100, &asc->sc_scsi_bsh)) { 131 aprint_error(": failed to map device registers\n"); 132 return; 133 } 134 asc->sc_dmat = isc->sc_dmat; 135 if (bus_dmamap_create(asc->sc_dmat, PAGE_SIZE * 2, 136 2, PAGE_SIZE, PAGE_SIZE, BUS_DMA_NOWAIT, 137 &asc->sc_dmamap)) { 138 aprint_error(": failed to create DMA map\n"); 139 return; 140 } 141 142 sc->sc_id = 7; 143 sc->sc_freq = 25000000; 144 145 /* gimme MHz */ 146 sc->sc_freq /= 1000000; 147 148 ioasic_intr_establish(parent, d->iada_cookie, TC_IPL_BIO, 149 ncr53c9x_intr, sc); 150 151 /* 152 * XXX More of this should be in ncr53c9x_attach(), but 153 * XXX should we really poke around the chip that much in 154 * XXX the MI code? Think about this more... 155 */ 156 157 /* 158 * Set up static configuration info. 159 */ 160 sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB; 161 sc->sc_cfg2 = NCRCFG2_SCSI2; 162 sc->sc_cfg3 = 0; 163 sc->sc_rev = NCR_VARIANT_NCR53C94; 164 165 /* 166 * XXX minsync and maxxfer _should_ be set up in MI code, 167 * XXX but it appears to have some dependency on what sort 168 * XXX of DMA we're hooked up to, etc. 169 */ 170 171 /* 172 * This is the value used to start sync negotiations 173 * Note that the NCR register "SYNCTP" is programmed 174 * in "clocks per byte", and has a minimum value of 4. 175 * The SCSI period used in negotiation is one-fourth 176 * of the time (in nanoseconds) needed to transfer one byte. 177 * Since the chip's clock is given in MHz, we have the following 178 * formula: 4 * period = (1000 / freq) * 4 179 */ 180 sc->sc_minsync = (1000 / sc->sc_freq) * 5 / 4 ; 181 sc->sc_maxxfer = 64 * 1024; 182 183 /* Do the common parts of attachment. */ 184 sc->sc_adapter.adapt_minphys = minphys; 185 sc->sc_adapter.adapt_request = ncr53c9x_scsipi_request; 186 ncr53c9x_attach(sc); 187 } 188 189 void 190 asc_ioasic_reset(struct ncr53c9x_softc *sc) 191 { 192 struct asc_softc *asc = (struct asc_softc *)sc; 193 uint32_t ssr; 194 195 ssr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR); 196 ssr &= ~IOASIC_CSR_DMAEN_SCSI; 197 bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR, ssr); 198 bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_SCSI_SCR, 0); 199 200 if (asc->sc_flags & ASC_MAPLOADED) 201 bus_dmamap_unload(asc->sc_dmat, asc->sc_dmamap); 202 asc->sc_flags &= ~(ASC_DMAACTIVE|ASC_MAPLOADED); 203 } 204 205 #define TWOPAGE(a) (PAGE_SIZE*2 - ((a) & (PAGE_SIZE-1))) 206 207 int 208 asc_ioasic_setup(struct ncr53c9x_softc *sc, uint8_t **addr, size_t *len, 209 int ispullup, size_t *dmasize) 210 { 211 struct asc_softc *asc = (struct asc_softc *)sc; 212 uint32_t ssr, scr, *p; 213 size_t size; 214 vaddr_t cp; 215 216 NCR_DMA(("%s: start %d@%p,%s\n", sc->sc_dev.dv_xname, 217 *asc->sc_dmalen, *asc->sc_dmaaddr, ispullup ? "IN" : "OUT")); 218 219 /* upto two 4KB pages */ 220 size = min(*dmasize, TWOPAGE((size_t)*addr)); 221 asc->sc_dmaaddr = addr; 222 asc->sc_dmalen = len; 223 asc->sc_dmasize = size; 224 asc->sc_flags = (ispullup) ? ASC_ISPULLUP : 0; 225 *dmasize = size; /* return trimmed transfer size */ 226 227 /* stop DMA engine first */ 228 ssr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR); 229 ssr &= ~IOASIC_CSR_DMAEN_SCSI; 230 bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR, ssr); 231 232 /* have dmamap for the transfering addresses */ 233 if (bus_dmamap_load(asc->sc_dmat, asc->sc_dmamap, 234 *addr, size, NULL /* kernel address */, BUS_DMA_NOWAIT)) 235 panic("%s: cannot allocate DMA address", 236 device_xname(sc->sc_dev)); 237 238 /* take care of 8B constraint on starting address */ 239 cp = (vaddr_t)*addr; 240 if ((cp & 7) == 0) { 241 /* comfortably aligned to 8B boundary */ 242 scr = 0; 243 } 244 else { 245 /* truncate to the boundary */ 246 p = (uint32_t *)(cp & ~7); 247 /* how many 16bit quantities in subject */ 248 scr = (cp & 7) >> 1; 249 /* trim down physical address too */ 250 asc->sc_dmamap->dm_segs[0].ds_addr &= ~7; 251 asc->sc_dmamap->dm_segs[0].ds_len += (cp & 6); 252 if ((asc->sc_flags & ASC_ISPULLUP) == 0) { 253 /* push down to SCSI device */ 254 scr |= 4; 255 /* round up physical address in this case */ 256 asc->sc_dmamap->dm_segs[0].ds_addr += 8; 257 /* don't care excess cache flush */ 258 } 259 /* pack fixup data in SDR0/SDR1 pair and instruct SCR */ 260 bus_space_write_4(asc->sc_bst, asc->sc_bsh, 261 IOASIC_SCSI_SDR0, p[0]); 262 bus_space_write_4(asc->sc_bst, asc->sc_bsh, 263 IOASIC_SCSI_SDR1, p[1]); 264 } 265 bus_space_write_4(asc->sc_bst, asc->sc_bsh, 266 IOASIC_SCSI_DMAPTR, 267 IOASIC_DMA_ADDR(asc->sc_dmamap->dm_segs[0].ds_addr)); 268 bus_space_write_4(asc->sc_bst, asc->sc_bsh, 269 IOASIC_SCSI_NEXTPTR, 270 (asc->sc_dmamap->dm_nsegs == 1) ? 271 ~0 : IOASIC_DMA_ADDR(asc->sc_dmamap->dm_segs[1].ds_addr)); 272 bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_SCSI_SCR, scr); 273 274 /* synchronize dmamap contents with memory image */ 275 bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap, 276 0, size, 277 (ispullup) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 278 279 asc->sc_flags |= ASC_MAPLOADED; 280 return 0; 281 } 282 283 void 284 asc_ioasic_go(struct ncr53c9x_softc *sc) 285 { 286 struct asc_softc *asc = (struct asc_softc *)sc; 287 uint32_t ssr; 288 289 ssr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR); 290 if (asc->sc_flags & ASC_ISPULLUP) 291 ssr |= IOASIC_CSR_SCSI_DIR; 292 else { 293 /* ULTRIX does in this way */ 294 ssr &= ~IOASIC_CSR_SCSI_DIR; 295 bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR, ssr); 296 ssr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR); 297 } 298 ssr |= IOASIC_CSR_DMAEN_SCSI; 299 bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR, ssr); 300 asc->sc_flags |= ASC_DMAACTIVE; 301 } 302 303 static int 304 asc_ioasic_intr(struct ncr53c9x_softc *sc) 305 { 306 struct asc_softc *asc = (struct asc_softc *)sc; 307 int trans, resid; 308 u_int tcl, tcm, ssr, scr, intr; 309 310 if ((asc->sc_flags & ASC_DMAACTIVE) == 0) 311 panic("%s: DMA wasn't active", __func__); 312 313 #define IOASIC_ASC_ERRORS \ 314 (IOASIC_INTR_SCSI_PTR_LOAD|IOASIC_INTR_SCSI_OVRUN|IOASIC_INTR_SCSI_READ_E) 315 /* 316 * When doing polled I/O, the SCSI bits in the interrupt register won't 317 * get cleared by the interrupt processing. This will cause the DMA 318 * address registers to not load on the next DMA transfer. 319 * Check for these bits here, and clear them if needed. 320 */ 321 intr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_INTR); 322 if ((intr & IOASIC_ASC_ERRORS) != 0) { 323 intr &= ~IOASIC_ASC_ERRORS; 324 bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_INTR, intr); 325 } 326 327 /* DMA has stopped */ 328 ssr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR); 329 ssr &= ~IOASIC_CSR_DMAEN_SCSI; 330 bus_space_write_4(asc->sc_bst, asc->sc_bsh, IOASIC_CSR, ssr); 331 332 asc->sc_flags &= ~ASC_DMAACTIVE; 333 334 if (asc->sc_dmasize == 0) { 335 /* A "Transfer Pad" operation completed */ 336 tcl = NCR_READ_REG(sc, NCR_TCL); 337 tcm = NCR_READ_REG(sc, NCR_TCM); 338 NCR_DMA(("ioasic_intr: discarded %d bytes (tcl=%d, tcm=%d)\n", 339 tcl | (tcm << 8), tcl, tcm)); 340 return 0; 341 } 342 343 resid = 0; 344 if ((asc->sc_flags & ASC_ISPULLUP) == 0 && 345 (resid = (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF)) != 0) { 346 NCR_DMA(("ioasic_intr: empty FIFO of %d ", resid)); 347 DELAY(1); 348 } 349 350 resid += (tcl = NCR_READ_REG(sc, NCR_TCL)); 351 resid += (tcm = NCR_READ_REG(sc, NCR_TCM)) << 8; 352 353 trans = asc->sc_dmasize - resid; 354 if (trans < 0) { /* transferred < 0 ? */ 355 printf("ioasic_intr: xfer (%d) > req (%d)\n", 356 trans, asc->sc_dmasize); 357 trans = asc->sc_dmasize; 358 } 359 NCR_DMA(("ioasic_intr: tcl=%d, tcm=%d; trans=%d, resid=%d\n", 360 tcl, tcm, trans, resid)); 361 362 bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap, 363 0, asc->sc_dmasize, 364 (asc->sc_flags & ASC_ISPULLUP) ? 365 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 366 367 scr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, IOASIC_SCSI_SCR); 368 if ((asc->sc_flags & ASC_ISPULLUP) && scr != 0) { 369 uint32_t sdr[2], ptr; 370 371 sdr[0] = bus_space_read_4(asc->sc_bst, asc->sc_bsh, 372 IOASIC_SCSI_SDR0); 373 sdr[1] = bus_space_read_4(asc->sc_bst, asc->sc_bsh, 374 IOASIC_SCSI_SDR1); 375 ptr = bus_space_read_4(asc->sc_bst, asc->sc_bsh, 376 IOASIC_SCSI_DMAPTR); 377 ptr = (ptr >> 3) & 0x1ffffffc; 378 /* 379 * scr: 1 -> short[0] 380 * 2 -> short[0] + short[1] 381 * 3 -> short[0] + short[1] + short[2] 382 */ 383 scr &= IOASIC_SCR_WORD; 384 memcpy((void *)MIPS_PHYS_TO_KSEG0(ptr), sdr, scr << 1); 385 } 386 387 bus_dmamap_unload(asc->sc_dmat, asc->sc_dmamap); 388 asc->sc_flags &= ~ASC_MAPLOADED; 389 390 *asc->sc_dmalen -= trans; 391 *asc->sc_dmaaddr += trans; 392 393 return 0; 394 } 395 396 397 void 398 asc_ioasic_stop(struct ncr53c9x_softc *sc) 399 { 400 struct asc_softc *asc = (struct asc_softc *)sc; 401 402 if (asc->sc_flags & ASC_MAPLOADED) { 403 bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap, 404 0, asc->sc_dmasize, 405 (asc->sc_flags & ASC_ISPULLUP) ? 406 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 407 bus_dmamap_unload(asc->sc_dmat, asc->sc_dmamap); 408 } 409 410 asc->sc_flags &= ~(ASC_DMAACTIVE|ASC_MAPLOADED); 411 } 412 413 static uint8_t 414 asc_read_reg(struct ncr53c9x_softc *sc, int reg) 415 { 416 struct asc_softc *asc = (struct asc_softc *)sc; 417 uint32_t v; 418 419 v = bus_space_read_4(asc->sc_bst, asc->sc_scsi_bsh, 420 reg * sizeof(uint32_t)); 421 422 return v & 0xff; 423 } 424 425 static void 426 asc_write_reg(struct ncr53c9x_softc *sc, int reg, uint8_t val) 427 { 428 struct asc_softc *asc = (struct asc_softc *)sc; 429 430 bus_space_write_4(asc->sc_bst, asc->sc_scsi_bsh, 431 reg * sizeof(uint32_t), val); 432 } 433 434 static int 435 asc_dma_isintr(struct ncr53c9x_softc *sc) 436 { 437 438 return (NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT) != 0; 439 } 440 441 static int 442 asc_dma_isactive(struct ncr53c9x_softc *sc) 443 { 444 struct asc_softc *asc = (struct asc_softc *)sc; 445 446 return (asc->sc_flags & ASC_DMAACTIVE) != 0; 447 } 448