1 /* $NetBSD: si.c,v 1.6 2001/04/25 17:53:18 bouyer Exp $ */ 2 3 /* 4 * Copyright (c) 1996 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Adam Glass, David Jones, Gordon W. Ross, and Jens A. Nilsson. 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 * This file contains the machine-dependent parts of the Sony CXD1180 41 * controller. The machine-independent parts are in ncr5380sbc.c. 42 * Written by Izumi Tsutsui. 43 * 44 * This code is based on arch/vax/vsa/ncr.c and sun3/dev/si.c 45 */ 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/device.h> 50 #include <sys/buf.h> 51 52 #include <machine/cpu.h> 53 54 #include <dev/scsipi/scsipi_all.h> 55 #include <dev/scsipi/scsiconf.h> 56 57 #include <dev/ic/ncr5380reg.h> 58 #include <dev/ic/ncr5380var.h> 59 60 #include <news68k/dev/hbvar.h> 61 #include <news68k/dev/dmac_0266.h> 62 63 #define MIN_DMA_LEN 128 64 #define DMAC_BASE 0xe0e80000 /* XXX */ 65 66 struct si_dma_handle { 67 int dh_flags; 68 #define SIDH_BUSY 0x01 69 #define SIDH_OUT 0x02 70 caddr_t dh_addr; 71 int dh_len; 72 }; 73 74 struct si_softc { 75 struct ncr5380_softc ncr_sc; 76 int sc_options; 77 volatile struct dma_regs *sc_regs; 78 struct si_dma_handle ncr_dma[SCI_OPENINGS]; 79 }; 80 81 void si_attach __P((struct device *, struct device *, void *)); 82 int si_match __P((struct device *, struct cfdata *, void *)); 83 int si_intr __P((int)); 84 85 void si_dma_alloc __P((struct ncr5380_softc *)); 86 void si_dma_free __P((struct ncr5380_softc *)); 87 void si_dma_setup __P((struct ncr5380_softc *)); 88 void si_dma_start __P((struct ncr5380_softc *)); 89 void si_dma_poll __P((struct ncr5380_softc *)); 90 void si_dma_eop __P((struct ncr5380_softc *)); 91 void si_dma_stop __P((struct ncr5380_softc *)); 92 93 struct cfattach si_ca = { 94 sizeof(struct si_softc), si_match, si_attach 95 }; 96 97 /* 98 * Options for disconnect/reselect, DMA, and interrupts. 99 * By default, allow disconnect/reselect on targets 4-6. 100 * Those are normally tapes that really need it enabled. 101 * The options are taken from the config file. 102 */ 103 #define SI_NO_DISCONNECT 0x000ff 104 #define SI_NO_PARITY_CHK 0x0ff00 105 #define SI_FORCE_POLLING 0x10000 106 #define SI_DISABLE_DMA 0x20000 107 108 int si_options = 0x0f; 109 110 111 int 112 si_match(parent, cf, aux) 113 struct device *parent; 114 struct cfdata *cf; 115 void *aux; 116 { 117 struct hb_attach_args *ha = aux; 118 int addr; 119 120 if (strcmp(ha->ha_name, "si")) 121 return 0; 122 123 addr = IIOV(ha->ha_address); 124 125 if (badaddr((void *)addr, 1)) 126 return 0; 127 128 return 1; 129 } 130 131 /* 132 * Card attach function 133 */ 134 135 void 136 si_attach(parent, self, aux) 137 struct device *parent, *self; 138 void *aux; 139 { 140 struct si_softc *sc = (struct si_softc *)self; 141 struct ncr5380_softc *ncr_sc = &sc->ncr_sc; 142 struct cfdata *cf = self->dv_cfdata; 143 struct hb_attach_args *ha = aux; 144 u_char *addr; 145 146 /* Get options from config flags if specified. */ 147 if (cf->cf_flags) 148 sc->sc_options = cf->cf_flags; 149 else 150 sc->sc_options = si_options; 151 152 printf(": options=0x%x\n", sc->sc_options); 153 154 ncr_sc->sc_no_disconnect = (sc->sc_options & SI_NO_DISCONNECT); 155 ncr_sc->sc_parity_disable = (sc->sc_options & SI_NO_PARITY_CHK) >> 8; 156 if (sc->sc_options & SI_FORCE_POLLING) 157 ncr_sc->sc_flags |= NCR5380_FORCE_POLLING; 158 159 ncr_sc->sc_min_dma_len = MIN_DMA_LEN; 160 ncr_sc->sc_dma_alloc = si_dma_alloc; 161 ncr_sc->sc_dma_free = si_dma_free; 162 ncr_sc->sc_dma_poll = si_dma_poll; 163 ncr_sc->sc_dma_setup = si_dma_setup; 164 ncr_sc->sc_dma_start = si_dma_start; 165 ncr_sc->sc_dma_eop = si_dma_eop; 166 ncr_sc->sc_dma_stop = si_dma_stop; 167 168 if (sc->sc_options & SI_DISABLE_DMA) 169 /* Override this function pointer. */ 170 ncr_sc->sc_dma_alloc = NULL; 171 172 addr = (u_char *)IIOV(ha->ha_address); 173 ncr_sc->sci_r0 = addr + 0; 174 ncr_sc->sci_r1 = addr + 1; 175 ncr_sc->sci_r2 = addr + 2; 176 ncr_sc->sci_r3 = addr + 3; 177 ncr_sc->sci_r4 = addr + 4; 178 ncr_sc->sci_r5 = addr + 5; 179 ncr_sc->sci_r6 = addr + 6; 180 ncr_sc->sci_r7 = addr + 7; 181 182 ncr_sc->sc_rev = NCR_VARIANT_CXD1180; 183 184 ncr_sc->sc_pio_in = ncr5380_pio_in; 185 ncr_sc->sc_pio_out = ncr5380_pio_out; 186 187 ncr_sc->sc_adapter.adapt_minphys = minphys; 188 ncr_sc->sc_channel.chan_id = 7; 189 190 /* soft reset DMAC */ 191 sc->sc_regs = (void *)IIOV(DMAC_BASE); 192 sc->sc_regs->ctl = DC_CTL_RST; 193 194 ncr5380_attach(ncr_sc); 195 } 196 197 int 198 si_intr(unit) 199 int unit; 200 { 201 struct si_softc *sc; 202 extern struct cfdriver si_cd; 203 204 if (unit >= si_cd.cd_ndevs) 205 return 0; 206 207 sc = si_cd.cd_devs[unit]; 208 (void)ncr5380_intr(&sc->ncr_sc); 209 210 return 0; 211 } 212 213 /* 214 * DMA routines for news1700 machines 215 */ 216 217 void 218 si_dma_alloc(ncr_sc) 219 struct ncr5380_softc *ncr_sc; 220 { 221 struct si_softc *sc = (struct si_softc *)ncr_sc; 222 struct sci_req *sr = ncr_sc->sc_current; 223 struct scsipi_xfer *xs = sr->sr_xs; 224 struct si_dma_handle *dh; 225 int xlen, i; 226 227 #ifdef DIAGNOSTIC 228 if (sr->sr_dma_hand != NULL) 229 panic("si_dma_alloc: already have DMA handle"); 230 #endif 231 232 /* Polled transfers shouldn't allocate a DMA handle. */ 233 if (sr->sr_flags & SR_IMMED) 234 return; 235 236 xlen = ncr_sc->sc_datalen; 237 238 /* Make sure our caller checked sc_min_dma_len. */ 239 if (xlen < MIN_DMA_LEN) 240 panic("si_dma_alloc: len=0x%x\n", xlen); 241 242 /* 243 * Find free DMA handle. Guaranteed to find one since we 244 * have as many DMA handles as the driver has processes. 245 * (instances?) 246 */ 247 for (i = 0; i < SCI_OPENINGS; i++) { 248 if ((sc->ncr_dma[i].dh_flags & SIDH_BUSY) == 0) 249 goto found; 250 } 251 panic("si_dma_alloc(): no free DMA handles"); 252 found: 253 dh = &sc->ncr_dma[i]; 254 dh->dh_flags = SIDH_BUSY; 255 dh->dh_addr = ncr_sc->sc_dataptr; 256 dh->dh_len = xlen; 257 258 /* Remember dest buffer parameters */ 259 if (xs->xs_control & XS_CTL_DATA_OUT) 260 dh->dh_flags |= SIDH_OUT; 261 262 sr->sr_dma_hand = dh; 263 } 264 265 void 266 si_dma_free(ncr_sc) 267 struct ncr5380_softc *ncr_sc; 268 { 269 struct sci_req *sr = ncr_sc->sc_current; 270 struct si_dma_handle *dh = sr->sr_dma_hand; 271 272 if (dh->dh_flags & SIDH_BUSY) 273 dh->dh_flags = 0; 274 else 275 printf("si_dma_free: free'ing unused buffer\n"); 276 277 sr->sr_dma_hand = NULL; 278 } 279 280 void 281 si_dma_setup(ncr_sc) 282 struct ncr5380_softc *ncr_sc; 283 { 284 /* Do nothing here */ 285 } 286 287 void 288 si_dma_start(ncr_sc) 289 struct ncr5380_softc *ncr_sc; 290 { 291 struct si_softc *sc = (struct si_softc *)ncr_sc; 292 volatile struct dma_regs *dmac = sc->sc_regs; 293 struct sci_req *sr = ncr_sc->sc_current; 294 struct si_dma_handle *dh = sr->sr_dma_hand; 295 u_int addr, offset, rest; 296 long len; 297 int i; 298 299 /* 300 * Set the news68k-specific registers. 301 */ 302 303 /* reset DMAC */ 304 dmac->ctl = DC_CTL_RST; 305 dmac->ctl = 0; 306 307 addr = (u_int)dh->dh_addr; 308 offset = addr & DMAC_SEG_OFFSET; 309 len = (u_int)dh->dh_len; 310 311 /* set DMA transfer length and offset of first segment */ 312 dmac->tcnt = len; 313 dmac->offset = offset; 314 315 /* set first DMA segment address */ 316 dmac->tag = 0; 317 dmac->mapent = kvtop((caddr_t)addr) >> DMAC_SEG_SHIFT; 318 rest = DMAC_SEG_SIZE - offset; 319 addr += rest; 320 len -= rest; 321 322 /* set all the rest segments */ 323 for (i = 1; len > 0; i++) { 324 dmac->tag = i; 325 dmac->mapent = kvtop((caddr_t)addr) >> DMAC_SEG_SHIFT; 326 len -= DMAC_SEG_SIZE; 327 addr += DMAC_SEG_SIZE; 328 } 329 /* terminate TAG */ 330 dmac->tag = 0; 331 332 /* 333 * Now from the 5380-internal DMA registers. 334 */ 335 if (dh->dh_flags & SIDH_OUT) { 336 NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_DATA_OUT); 337 NCR5380_WRITE(ncr_sc, sci_icmd, SCI_ICMD_DATA); 338 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) 339 | SCI_MODE_DMA); 340 341 /* set Dir */ 342 dmac->ctl = 0; 343 344 /* start DMA */ 345 NCR5380_WRITE(ncr_sc, sci_dma_send, 0); 346 dmac->ctl = DC_CTL_ENB; 347 } else { 348 NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_DATA_IN); 349 NCR5380_WRITE(ncr_sc, sci_icmd, 0); 350 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) 351 | SCI_MODE_DMA); 352 353 /* set Dir */ 354 dmac->ctl = DC_CTL_MOD; 355 356 /* start DMA */ 357 NCR5380_WRITE(ncr_sc, sci_irecv, 0); 358 dmac->ctl = DC_CTL_MOD | DC_CTL_ENB; 359 } 360 ncr_sc->sc_state |= NCR_DOINGDMA; 361 } 362 363 /* 364 * When? 365 */ 366 void 367 si_dma_poll(ncr_sc) 368 struct ncr5380_softc *ncr_sc; 369 { 370 printf("si_dma_poll\n"); 371 } 372 373 /* 374 * news68k (probabry) does not use the EOP signal. 375 */ 376 void 377 si_dma_eop(ncr_sc) 378 struct ncr5380_softc *ncr_sc; 379 { 380 printf("si_dma_eop\n"); 381 } 382 383 void 384 si_dma_stop(ncr_sc) 385 struct ncr5380_softc *ncr_sc; 386 { 387 struct si_softc *sc = (struct si_softc *)ncr_sc; 388 volatile struct dma_regs *dmac = sc->sc_regs; 389 struct sci_req *sr = ncr_sc->sc_current; 390 struct si_dma_handle *dh = sr->sr_dma_hand; 391 int resid, ntrans, i; 392 393 /* check DMAC interrupt status */ 394 if ((dmac->stat & DC_ST_INT) == 0) { 395 #ifdef DEBUG 396 printf("si_dma_stop: no DMA interrupt"); 397 #endif 398 return; /* XXX */ 399 } 400 401 if ((ncr_sc->sc_state & NCR_DOINGDMA) == 0) { 402 #ifdef DEBUG 403 printf("si_dma_stop: dma not running\n"); 404 #endif 405 return; 406 } 407 ncr_sc->sc_state &= ~NCR_DOINGDMA; 408 409 /* OK, have either phase mis-match or end of DMA. */ 410 /* Set an impossible phase to prevent data movement? */ 411 NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_INVALID); 412 413 /* Note that timeout may have set the error flag. */ 414 if (ncr_sc->sc_state & NCR_ABORTING) 415 goto out; 416 417 /* 418 * Sometimes the FIFO buffer isn't drained when the 419 * interrupt is posted. Just loop here and hope that 420 * it will drain soon. 421 */ 422 for (i = 0; i < 200000; i++) { /* 2 sec */ 423 resid = dmac->tcnt; 424 if (resid == 0) 425 break; 426 DELAY(10); 427 } 428 429 if (resid) 430 printf("si_dma_stop: resid=0x%x\n", resid); 431 432 ntrans = dh->dh_len - resid; 433 434 ncr_sc->sc_dataptr += ntrans; 435 ncr_sc->sc_datalen -= ntrans; 436 437 if ((dh->dh_flags & SIDH_OUT) == 0) { 438 PCIA(); 439 } 440 441 out: 442 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) & 443 ~(SCI_MODE_DMA)); 444 NCR5380_WRITE(ncr_sc, sci_icmd, 0); 445 } 446