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