1 /* $NetBSD: oak.c,v 1.12 2002/10/02 16:52:24 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Mark Brinicombe of Causality Limited. 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 * Oak Solutions SCSI 1 driver using the generic NCR5380 driver. 41 * 42 * From <URL:http://foldoc.doc.ic.ac.uk/acorn/doc/scsi>: 43 * --------8<-------- 44 * From: Hugo Fiennes 45 * [...] 46 * The oak scsi plays some other tricks to get max around 2.2Mb/sec: 47 * it is a 16- bit interface (using their own hardware and an 8-bit 48 * scsi controller to 'double-up' the data). What it does is: every 49 * 128 bytes it uses a polling loop (see above) to check data is 50 * present and the drive has reported no errors, etc. Inside each 128 51 * byte block it just reads data as fast as it can: on a normal card 52 * this would result in disaster if the drive wasn't fast enough to 53 * feed the machine: on the oak card however, the hardware will not 54 * assert IOGT (IO grant), so hanging the machine in a wait state 55 * until data is ready. This can have problems: if the drive is to 56 * slow (unlikely) the machine will completely stiff as the ARM3 can't 57 * be kept in such a state for more than 10(?) us. 58 * -------->8-------- 59 * 60 * So far, my attempts at doing this have failed, though. 61 * 62 * This card has to be polled: it doesn't have anything connected to 63 * PIRQ*. This seems to be a common failing of Archimedes disc 64 * controllers. 65 */ 66 67 #include <sys/cdefs.h> 68 __KERNEL_RCSID(0, "$NetBSD: oak.c,v 1.12 2002/10/02 16:52:24 thorpej Exp $"); 69 70 #include <sys/param.h> 71 72 #include <sys/systm.h> 73 #include <sys/kernel.h> 74 #include <sys/device.h> 75 #include <sys/buf.h> 76 #include <dev/scsipi/scsi_all.h> 77 #include <dev/scsipi/scsipi_all.h> 78 #include <dev/scsipi/scsiconf.h> 79 80 #include <dev/ic/ncr5380reg.h> 81 #include <dev/ic/ncr5380var.h> 82 83 #include <machine/bootconfig.h> 84 85 #include <dev/podulebus/podulebus.h> 86 #include <dev/podulebus/podules.h> 87 #include <dev/podulebus/powerromreg.h> 88 89 #include <dev/podulebus/oakreg.h> 90 91 void oak_attach (struct device *, struct device *, void *); 92 int oak_match (struct device *, struct cfdata *, void *); 93 94 #if 0 95 static int oak_pdma_in(struct ncr5380_softc *, int, int, u_char *); 96 static int oak_pdma_out(struct ncr5380_softc *, int, int, u_char *); 97 #endif 98 99 /* 100 * Oak SCSI 1 softc structure. 101 * 102 * Contains the generic ncr5380 device node, podule information and 103 * global information required by the driver. 104 */ 105 106 struct oak_softc { 107 struct ncr5380_softc sc_ncr5380; 108 bus_space_tag_t sc_pdmat; 109 bus_space_handle_t sc_pdmah; 110 }; 111 112 CFATTACH_DECL(oak, sizeof(struct oak_softc), 113 oak_match, oak_attach, NULL, NULL); 114 115 /* 116 * Card probe function 117 * 118 * Just match the manufacturer and podule ID's 119 */ 120 121 int 122 oak_match(struct device *parent, struct cfdata *cf, void *aux) 123 { 124 struct podulebus_attach_args *pa = aux; 125 126 if (pa->pa_product == PODULE_OAK_SCSI) 127 return 1; 128 129 /* PowerROM */ 130 if (pa->pa_product == PODULE_ALSYSTEMS_SCSI && 131 podulebus_initloader(pa) == 0 && 132 podloader_callloader(pa, 0, 0) == PRID_OAK_SCSI1) 133 return 1; 134 135 return 0; 136 } 137 138 /* 139 * Card attach function 140 * 141 */ 142 143 void 144 oak_attach(struct device *parent, struct device *self, void *aux) 145 { 146 struct oak_softc *sc = (struct oak_softc *)self; 147 struct podulebus_attach_args *pa = aux; 148 #ifndef NCR5380_USE_BUS_SPACE 149 u_char *iobase; 150 #endif 151 char hi_option[sizeof(sc->sc_ncr5380.sc_dev.dv_xname) + 8]; 152 153 sc->sc_ncr5380.sc_flags |= NCR5380_FORCE_POLLING; 154 sc->sc_ncr5380.sc_min_dma_len = 0; 155 sc->sc_ncr5380.sc_no_disconnect = 0xff; 156 sc->sc_ncr5380.sc_parity_disable = 0; 157 158 sc->sc_ncr5380.sc_dma_alloc = NULL; 159 sc->sc_ncr5380.sc_dma_free = NULL; 160 sc->sc_ncr5380.sc_dma_poll = NULL; 161 sc->sc_ncr5380.sc_dma_setup = NULL; 162 sc->sc_ncr5380.sc_dma_start = NULL; 163 sc->sc_ncr5380.sc_dma_eop = NULL; 164 sc->sc_ncr5380.sc_dma_stop = NULL; 165 sc->sc_ncr5380.sc_intr_on = NULL; 166 sc->sc_ncr5380.sc_intr_off = NULL; 167 168 #ifdef NCR5380_USE_BUS_SPACE 169 sc->sc_ncr5380.sc_regt = pa->pa_mod_t; 170 bus_space_map(sc->sc_ncr5380.sc_regt, pa->pa_mod_base, 8, 0, 171 &sc->sc_ncr5380.sc_regh); 172 sc->sc_ncr5380.sci_r0 = 0; 173 sc->sc_ncr5380.sci_r1 = 1; 174 sc->sc_ncr5380.sci_r2 = 2; 175 sc->sc_ncr5380.sci_r3 = 3; 176 sc->sc_ncr5380.sci_r4 = 4; 177 sc->sc_ncr5380.sci_r5 = 5; 178 sc->sc_ncr5380.sci_r6 = 6; 179 sc->sc_ncr5380.sci_r7 = 7; 180 #else 181 iobase = (u_char *)pa->pa_mod_base; 182 sc->sc_ncr5380.sci_r0 = iobase + 0; 183 sc->sc_ncr5380.sci_r1 = iobase + 4; 184 sc->sc_ncr5380.sci_r2 = iobase + 8; 185 sc->sc_ncr5380.sci_r3 = iobase + 12; 186 sc->sc_ncr5380.sci_r4 = iobase + 16; 187 sc->sc_ncr5380.sci_r5 = iobase + 20; 188 sc->sc_ncr5380.sci_r6 = iobase + 24; 189 sc->sc_ncr5380.sci_r7 = iobase + 28; 190 #endif 191 sc->sc_pdmat = pa->pa_mod_t; 192 bus_space_map(sc->sc_pdmat, pa->pa_mod_base + OAK_PDMA_OFFSET, 0x20, 0, 193 &sc->sc_pdmah); 194 195 sc->sc_ncr5380.sc_rev = NCR_VARIANT_NCR5380; 196 197 sc->sc_ncr5380.sc_pio_in = ncr5380_pio_in; 198 sc->sc_ncr5380.sc_pio_out = ncr5380_pio_out; 199 200 /* Provide an override for the host id */ 201 sc->sc_ncr5380.sc_channel.chan_id = 7; 202 sprintf(hi_option, "%s.hostid", sc->sc_ncr5380.sc_dev.dv_xname); 203 (void)get_bootconf_option(boot_args, hi_option, 204 BOOTOPT_TYPE_INT, &sc->sc_ncr5380.sc_channel.chan_id); 205 sc->sc_ncr5380.sc_adapter.adapt_minphys = minphys; 206 207 printf(": host=%d, using 8 bit PIO\n", 208 sc->sc_ncr5380.sc_channel.chan_id); 209 210 ncr5380_attach(&sc->sc_ncr5380); 211 } 212 213 /* 214 * XXX The code below doesn't work correctly. I probably need more 215 * details on how the card works. [bjh21 20011202] 216 */ 217 #if 0 218 219 #ifndef OAK_TSIZE_OUT 220 #define OAK_TSIZE_OUT 128 221 #endif 222 223 #ifndef OAK_TSIZE_IN 224 #define OAK_TSIZE_IN 128 225 #endif 226 227 #define TIMEOUT 1000000 228 229 static __inline int 230 oak_ready(struct ncr5380_softc *sc) 231 { 232 int i; 233 int status; 234 235 for (i = TIMEOUT; i > 0; i--) { 236 status = NCR5380_READ(sc, sci_csr); 237 if ((status & (SCI_CSR_DREQ | SCI_CSR_PHASE_MATCH)) == 238 (SCI_CSR_DREQ | SCI_CSR_PHASE_MATCH)) 239 return(1); 240 241 if ((status & SCI_CSR_PHASE_MATCH) == 0 || 242 SCI_BUSY(sc) == 0) 243 return(0); 244 } 245 printf("%s: ready timeout\n", sc->sc_dev.dv_xname); 246 return(0); 247 248 #if 0 /* The Linux driver does this: */ 249 struct oak_softc *sc = (void *)ncr_sc; 250 bus_space_tag_t pdmat = sc->sc_pdmat; 251 bus_space_handle_t pdmah = sc->sc_pdmah; 252 int i, status; 253 254 for (i = TIMEOUT; i > 0; i--) { 255 status = bus_space_read_2(pdmat, pdmah, OAK_PDMA_STATUS); 256 if (status & 0x200) 257 return(0); 258 if (status & 0x100) 259 return(1); 260 } 261 printf("%s: ready timeout, status = 0x%x\n", ncr_sc->sc_dev.dv_xname, 262 status); 263 return(0); 264 #endif 265 } 266 267 268 269 /* Return zero on success. */ 270 static __inline void oak_wait_not_req(struct ncr5380_softc *sc) 271 { 272 int timo; 273 for (timo = TIMEOUT; timo; timo--) { 274 if ((NCR5380_READ(sc, sci_bus_csr) & SCI_BUS_REQ) == 0 || 275 (NCR5380_READ(sc, sci_csr) & SCI_CSR_PHASE_MATCH) == 0 || 276 SCI_BUSY(sc) == 0) { 277 return; 278 } 279 } 280 printf("%s: pdma not_req timeout\n", sc->sc_dev.dv_xname); 281 } 282 283 static int 284 oak_pdma_in(struct ncr5380_softc *ncr_sc, int phase, int datalen, 285 u_char *data) 286 { 287 struct oak_softc *sc = (void *)ncr_sc; 288 bus_space_tag_t pdmat = sc->sc_pdmat; 289 bus_space_handle_t pdmah = sc->sc_pdmah; 290 int s, resid, len; 291 292 s = splbio(); 293 294 NCR5380_WRITE(ncr_sc, sci_mode, 295 NCR5380_READ(ncr_sc, sci_mode) | SCI_MODE_DMA); 296 NCR5380_WRITE(ncr_sc, sci_irecv, 0); 297 298 resid = datalen; 299 while (resid > 0) { 300 len = min(resid, OAK_TSIZE_IN); 301 if (oak_ready(ncr_sc) == 0) 302 goto interrupt; 303 KASSERT(BUS_SPACE_ALIGNED_POINTER(data, u_int16_t)); 304 bus_space_read_multi_2(pdmat, pdmah, OAK_PDMA_READ, 305 (u_int16_t *)data, len/2); 306 data += len; 307 resid -= len; 308 } 309 310 oak_wait_not_req(ncr_sc); 311 312 interrupt: 313 SCI_CLR_INTR(ncr_sc); 314 NCR5380_WRITE(ncr_sc, sci_mode, 315 NCR5380_READ(ncr_sc, sci_mode) & ~SCI_MODE_DMA); 316 splx(s); 317 return datalen - resid; 318 } 319 320 static int 321 oak_pdma_out(struct ncr5380_softc *ncr_sc, int phase, int datalen, 322 u_char *data) 323 { 324 struct oak_softc *sc = (void *)ncr_sc; 325 bus_space_tag_t pdmat = sc->sc_pdmat; 326 bus_space_handle_t pdmah = sc->sc_pdmah; 327 int i, s, icmd, resid; 328 329 s = splbio(); 330 icmd = NCR5380_READ(ncr_sc, sci_icmd) & SCI_ICMD_RMASK; 331 NCR5380_WRITE(ncr_sc, sci_icmd, icmd | SCI_ICMD_DATA); 332 NCR5380_WRITE(ncr_sc, sci_mode, 333 NCR5380_READ(ncr_sc, sci_mode) | SCI_MODE_DMA); 334 NCR5380_WRITE(ncr_sc, sci_dma_send, 0); 335 336 resid = datalen; 337 if (oak_ready(ncr_sc) == 0) 338 goto interrupt; 339 340 if (resid > OAK_TSIZE_OUT) { 341 /* 342 * Because of the chips DMA prefetch, phase changes 343 * etc, won't be detected until we have written at 344 * least one byte more. We pre-write 4 bytes so 345 * subsequent transfers will be aligned to a 4 byte 346 * boundary. Assuming disconects will only occur on 347 * block boundaries, we then correct for the pre-write 348 * when and if we get a phase change. If the chip had 349 * DMA byte counting hardware, the assumption would not 350 * be necessary. 351 */ 352 KASSERT(BUS_SPACE_ALIGNED_POINTER(data, u_int16_t)); 353 bus_space_write_multi_2(pdmat, pdmah, OAK_PDMA_WRITE, 354 (u_int16_t *)data, 4/2); 355 data += 4; 356 resid -= 4; 357 358 for (; resid >= OAK_TSIZE_OUT; resid -= OAK_TSIZE_OUT) { 359 if (oak_ready(ncr_sc) == 0) { 360 resid += 4; /* Overshot */ 361 goto interrupt; 362 } 363 bus_space_write_multi_2(pdmat, pdmah, OAK_PDMA_WRITE, 364 (u_int16_t *)data, OAK_TSIZE_OUT/2); 365 data += OAK_TSIZE_OUT; 366 } 367 if (oak_ready(ncr_sc) == 0) { 368 resid += 4; /* Overshot */ 369 goto interrupt; 370 } 371 } 372 373 if (resid) { 374 bus_space_write_multi_2(pdmat, pdmah, OAK_PDMA_WRITE, 375 (u_int16_t *)data, resid/2); 376 resid = 0; 377 } 378 for (i = TIMEOUT; i > 0; i--) { 379 if ((NCR5380_READ(ncr_sc, sci_csr) 380 & (SCI_CSR_DREQ|SCI_CSR_PHASE_MATCH)) 381 != SCI_CSR_DREQ) 382 break; 383 } 384 if (i != 0) 385 bus_space_write_2(pdmat, pdmah, OAK_PDMA_WRITE, 0); 386 else 387 printf("%s: timeout waiting for final SCI_DSR_DREQ.\n", 388 ncr_sc->sc_dev.dv_xname); 389 390 oak_wait_not_req(ncr_sc); 391 interrupt: 392 SCI_CLR_INTR(ncr_sc); 393 NCR5380_WRITE(ncr_sc, sci_mode, 394 NCR5380_READ(ncr_sc, sci_mode) & ~SCI_MODE_DMA); 395 NCR5380_WRITE(ncr_sc, sci_icmd, icmd); 396 splx(s); 397 return(datalen - resid); 398 } 399 #endif 400