1 /* $NetBSD: oak.c,v 1.7 2001/12/02 14:49:32 bjh21 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.7 2001/12/02 14:49:32 bjh21 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 struct cfattach oak_ca = { 113 sizeof(struct oak_softc), oak_match, oak_attach 114 }; 115 116 /* 117 * Card probe function 118 * 119 * Just match the manufacturer and podule ID's 120 */ 121 122 int 123 oak_match(struct device *parent, struct cfdata *cf, void *aux) 124 { 125 struct podulebus_attach_args *pa = aux; 126 127 if (matchpodule(pa, MANUFACTURER_OAK, PODULE_OAK_SCSI, -1)) 128 return 1; 129 130 /* PowerROM */ 131 if (pa->pa_product == PODULE_ALSYSTEMS_SCSI && 132 podulebus_initloader(pa) == 0 && 133 podloader_callloader(pa, 0, 0) == PRID_OAK_SCSI1) 134 return 1; 135 136 return 0; 137 } 138 139 /* 140 * Card attach function 141 * 142 */ 143 144 void 145 oak_attach(struct device *parent, struct device *self, void *aux) 146 { 147 struct oak_softc *sc = (struct oak_softc *)self; 148 struct podulebus_attach_args *pa = aux; 149 u_char *iobase; 150 char hi_option[sizeof(sc->sc_ncr5380.sc_dev.dv_xname) + 8]; 151 152 sc->sc_ncr5380.sc_flags |= NCR5380_FORCE_POLLING; 153 sc->sc_ncr5380.sc_min_dma_len = 0; 154 sc->sc_ncr5380.sc_no_disconnect = 0xff; 155 sc->sc_ncr5380.sc_parity_disable = 0; 156 157 sc->sc_ncr5380.sc_dma_alloc = NULL; 158 sc->sc_ncr5380.sc_dma_free = NULL; 159 sc->sc_ncr5380.sc_dma_poll = NULL; 160 sc->sc_ncr5380.sc_dma_setup = NULL; 161 sc->sc_ncr5380.sc_dma_start = NULL; 162 sc->sc_ncr5380.sc_dma_eop = NULL; 163 sc->sc_ncr5380.sc_dma_stop = NULL; 164 sc->sc_ncr5380.sc_intr_on = NULL; 165 sc->sc_ncr5380.sc_intr_off = NULL; 166 167 #ifdef NCR5380_USE_BUS_SPACE 168 sc->sc_ncr5380.sc_regt = pa->pa_mod_t; 169 bus_space_map(sc->sc_ncr5380.sc_regt, pa->pa_mod_base, 8, 0, 170 &sc->sc_ncr5380.sc_regh); 171 sc->sc_ncr5380.sci_r0 = 0; 172 sc->sc_ncr5380.sci_r1 = 1; 173 sc->sc_ncr5380.sci_r2 = 2; 174 sc->sc_ncr5380.sci_r3 = 3; 175 sc->sc_ncr5380.sci_r4 = 4; 176 sc->sc_ncr5380.sci_r5 = 5; 177 sc->sc_ncr5380.sci_r6 = 6; 178 sc->sc_ncr5380.sci_r7 = 7; 179 #else 180 iobase = (u_char *)pa->pa_mod_base; 181 sc->sc_ncr5380.sci_r0 = iobase + 0; 182 sc->sc_ncr5380.sci_r1 = iobase + 4; 183 sc->sc_ncr5380.sci_r2 = iobase + 8; 184 sc->sc_ncr5380.sci_r3 = iobase + 12; 185 sc->sc_ncr5380.sci_r4 = iobase + 16; 186 sc->sc_ncr5380.sci_r5 = iobase + 20; 187 sc->sc_ncr5380.sci_r6 = iobase + 24; 188 sc->sc_ncr5380.sci_r7 = iobase + 28; 189 #endif 190 sc->sc_pdmat = pa->pa_mod_t; 191 bus_space_map(sc->sc_pdmat, pa->pa_mod_base + OAK_PDMA_OFFSET, 0x20, 0, 192 &sc->sc_pdmah); 193 194 sc->sc_ncr5380.sc_rev = NCR_VARIANT_NCR5380; 195 196 sc->sc_ncr5380.sc_pio_in = ncr5380_pio_in; 197 sc->sc_ncr5380.sc_pio_out = ncr5380_pio_out; 198 199 /* Provide an override for the host id */ 200 sc->sc_ncr5380.sc_channel.chan_id = 7; 201 sprintf(hi_option, "%s.hostid", sc->sc_ncr5380.sc_dev.dv_xname); 202 (void)get_bootconf_option(boot_args, hi_option, 203 BOOTOPT_TYPE_INT, &sc->sc_ncr5380.sc_channel.chan_id); 204 sc->sc_ncr5380.sc_adapter.adapt_minphys = minphys; 205 206 printf(": host=%d, using 8 bit PIO\n", 207 sc->sc_ncr5380.sc_channel.chan_id); 208 209 ncr5380_attach(&sc->sc_ncr5380); 210 } 211 212 /* 213 * XXX The code below doesn't work correctly. I probably need more 214 * details on how the card works. [bjh21 20011202] 215 */ 216 #if 0 217 218 #ifndef OAK_TSIZE_OUT 219 #define OAK_TSIZE_OUT 128 220 #endif 221 222 #ifndef OAK_TSIZE_IN 223 #define OAK_TSIZE_IN 128 224 #endif 225 226 #define TIMEOUT 1000000 227 228 static __inline int 229 oak_ready(struct ncr5380_softc *sc) 230 { 231 int i; 232 int status; 233 234 for (i = TIMEOUT; i > 0; i--) { 235 status = NCR5380_READ(sc, sci_csr); 236 if ((status & (SCI_CSR_DREQ | SCI_CSR_PHASE_MATCH)) == 237 (SCI_CSR_DREQ | SCI_CSR_PHASE_MATCH)) 238 return(1); 239 240 if ((status & SCI_CSR_PHASE_MATCH) == 0 || 241 SCI_BUSY(sc) == 0) 242 return(0); 243 } 244 printf("%s: ready timeout\n", sc->sc_dev.dv_xname); 245 return(0); 246 247 #if 0 /* The Linux driver does this: */ 248 struct oak_softc *sc = (void *)ncr_sc; 249 bus_space_tag_t pdmat = sc->sc_pdmat; 250 bus_space_handle_t pdmah = sc->sc_pdmah; 251 int i, status; 252 253 for (i = TIMEOUT; i > 0; i--) { 254 status = bus_space_read_2(pdmat, pdmah, OAK_PDMA_STATUS); 255 if (status & 0x200) 256 return(0); 257 if (status & 0x100) 258 return(1); 259 } 260 printf("%s: ready timeout, status = 0x%x\n", ncr_sc->sc_dev.dv_xname, 261 status); 262 return(0); 263 #endif 264 } 265 266 267 268 /* Return zero on success. */ 269 static __inline void oak_wait_not_req(struct ncr5380_softc *sc) 270 { 271 int timo; 272 for (timo = TIMEOUT; timo; timo--) { 273 if ((NCR5380_READ(sc, sci_bus_csr) & SCI_BUS_REQ) == 0 || 274 (NCR5380_READ(sc, sci_csr) & SCI_CSR_PHASE_MATCH) == 0 || 275 SCI_BUSY(sc) == 0) { 276 return; 277 } 278 } 279 printf("%s: pdma not_req timeout\n", sc->sc_dev.dv_xname); 280 } 281 282 static int 283 oak_pdma_in(struct ncr5380_softc *ncr_sc, int phase, int datalen, 284 u_char *data) 285 { 286 struct oak_softc *sc = (void *)ncr_sc; 287 bus_space_tag_t pdmat = sc->sc_pdmat; 288 bus_space_handle_t pdmah = sc->sc_pdmah; 289 int s, resid, len; 290 291 s = splbio(); 292 293 NCR5380_WRITE(ncr_sc, sci_mode, 294 NCR5380_READ(ncr_sc, sci_mode) | SCI_MODE_DMA); 295 NCR5380_WRITE(ncr_sc, sci_irecv, 0); 296 297 resid = datalen; 298 while (resid > 0) { 299 len = min(resid, OAK_TSIZE_IN); 300 if (oak_ready(ncr_sc) == 0) 301 goto interrupt; 302 KASSERT(BUS_SPACE_ALIGNED_POINTER(data, u_int16_t)); 303 bus_space_read_multi_2(pdmat, pdmah, OAK_PDMA_READ, 304 (u_int16_t *)data, len/2); 305 data += len; 306 resid -= len; 307 } 308 309 oak_wait_not_req(ncr_sc); 310 311 interrupt: 312 SCI_CLR_INTR(ncr_sc); 313 NCR5380_WRITE(ncr_sc, sci_mode, 314 NCR5380_READ(ncr_sc, sci_mode) & ~SCI_MODE_DMA); 315 splx(s); 316 return datalen - resid; 317 } 318 319 static int 320 oak_pdma_out(struct ncr5380_softc *ncr_sc, int phase, int datalen, 321 u_char *data) 322 { 323 struct oak_softc *sc = (void *)ncr_sc; 324 bus_space_tag_t pdmat = sc->sc_pdmat; 325 bus_space_handle_t pdmah = sc->sc_pdmah; 326 int i, s, icmd, resid; 327 328 s = splbio(); 329 icmd = NCR5380_READ(ncr_sc, sci_icmd) & SCI_ICMD_RMASK; 330 NCR5380_WRITE(ncr_sc, sci_icmd, icmd | SCI_ICMD_DATA); 331 NCR5380_WRITE(ncr_sc, sci_mode, 332 NCR5380_READ(ncr_sc, sci_mode) | SCI_MODE_DMA); 333 NCR5380_WRITE(ncr_sc, sci_dma_send, 0); 334 335 resid = datalen; 336 if (oak_ready(ncr_sc) == 0) 337 goto interrupt; 338 339 if (resid > OAK_TSIZE_OUT) { 340 /* 341 * Because of the chips DMA prefetch, phase changes 342 * etc, won't be detected until we have written at 343 * least one byte more. We pre-write 4 bytes so 344 * subsequent transfers will be aligned to a 4 byte 345 * boundary. Assuming disconects will only occur on 346 * block boundaries, we then correct for the pre-write 347 * when and if we get a phase change. If the chip had 348 * DMA byte counting hardware, the assumption would not 349 * be necessary. 350 */ 351 KASSERT(BUS_SPACE_ALIGNED_POINTER(data, u_int16_t)); 352 bus_space_write_multi_2(pdmat, pdmah, OAK_PDMA_WRITE, 353 (u_int16_t *)data, 4/2); 354 data += 4; 355 resid -= 4; 356 357 for (; resid >= OAK_TSIZE_OUT; resid -= OAK_TSIZE_OUT) { 358 if (oak_ready(ncr_sc) == 0) { 359 resid += 4; /* Overshot */ 360 goto interrupt; 361 } 362 bus_space_write_multi_2(pdmat, pdmah, OAK_PDMA_WRITE, 363 (u_int16_t *)data, OAK_TSIZE_OUT/2); 364 data += OAK_TSIZE_OUT; 365 } 366 if (oak_ready(ncr_sc) == 0) { 367 resid += 4; /* Overshot */ 368 goto interrupt; 369 } 370 } 371 372 if (resid) { 373 bus_space_write_multi_2(pdmat, pdmah, OAK_PDMA_WRITE, 374 (u_int16_t *)data, resid/2); 375 resid = 0; 376 } 377 for (i = TIMEOUT; i > 0; i--) { 378 if ((NCR5380_READ(ncr_sc, sci_csr) 379 & (SCI_CSR_DREQ|SCI_CSR_PHASE_MATCH)) 380 != SCI_CSR_DREQ) 381 break; 382 } 383 if (i != 0) 384 bus_space_write_2(pdmat, pdmah, OAK_PDMA_WRITE, 0); 385 else 386 printf("%s: timeout waiting for final SCI_DSR_DREQ.\n", 387 ncr_sc->sc_dev.dv_xname); 388 389 oak_wait_not_req(ncr_sc); 390 interrupt: 391 SCI_CLR_INTR(ncr_sc); 392 NCR5380_WRITE(ncr_sc, sci_mode, 393 NCR5380_READ(ncr_sc, sci_mode) & ~SCI_MODE_DMA); 394 NCR5380_WRITE(ncr_sc, sci_icmd, icmd); 395 splx(s); 396 return(datalen - resid); 397 } 398 #endif 399