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