1 /* $NetBSD: sec.c,v 1.14 2009/02/12 06:24:45 rumble Exp $ */
4 * Copyright (c) 2000, 2001, 2006 Ben Harris
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * sec.c -- driver for Acorn SCSI expansion cards (AKA30, AKA31, AKA32)
32 * These cards are documented in:
33 * Acorn Archimedes 500 series / Acorn R200 series Technical Reference Manual
34 * Published by Acorn Computers Limited
36 * Part number 0486,052
37 * Issue 1, November 1990
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: sec.c,v 1.14 2009/02/12 06:24:45 rumble Exp $");
43 #include <sys/param.h>
46 #include <sys/device.h>
47 #include <sys/malloc.h>
48 #include <sys/reboot.h> /* For bootverbose */
49 #include <sys/syslog.h>
50 #include <sys/systm.h>
52 #include <dev/scsipi/scsi_all.h>
53 #include <dev/scsipi/scsipi_all.h>
54 #include <dev/scsipi/scsiconf.h>
58 #include <dev/ic/wd33c93reg.h>
59 #include <dev/ic/wd33c93var.h>
60 #include <dev/ic/nec71071reg.h>
62 #include <dev/podulebus/podulebus.h>
63 #include <dev/podulebus/podules.h>
64 #include <dev/podulebus/powerromreg.h>
65 #include <dev/podulebus/secreg.h>
70 struct wd33c93_softc sc_sbic
;
71 bus_space_tag_t sc_pod_t
;
72 bus_space_handle_t sc_pod_h
;
73 bus_space_tag_t sc_mod_t
;
74 bus_space_handle_t sc_mod_h
;
76 struct evcnt sc_intrcnt
;
79 /* Details of the current DMA transfer */
85 /* Details of the current block within the above transfer */
89 #define SEC_DMABLK 16384
91 #define SEC_DMAMODE MODE_TMODE_DMD
93 /* autoconfiguration glue */
94 static int sec_match(device_t
, cfdata_t
, void *);
95 static void sec_attach(device_t
, device_t
, void *);
98 static bool sec_shutdown(device_t
, int);
100 /* callbacks from MI WD33C93 driver */
101 static int sec_dmasetup(struct wd33c93_softc
*, void **, size_t *, int,
103 static int sec_dmago(struct wd33c93_softc
*);
104 static void sec_dmastop(struct wd33c93_softc
*);
105 static void sec_reset(struct wd33c93_softc
*);
107 static int sec_intr(void *);
108 static int sec_dmatc(struct sec_softc
*sc
);
110 void sec_dumpdma(void *arg
);
112 CFATTACH_DECL_NEW(sec
, sizeof(struct sec_softc
),
113 sec_match
, sec_attach
, NULL
, NULL
);
116 sec_setpage(struct sec_softc
*sc
, int page
)
119 sc
->sc_mpr
= (sc
->sc_mpr
& ~SEC_MPR_PAGE
) | page
;
120 bus_space_write_1(sc
->sc_pod_t
, sc
->sc_pod_h
, SEC_MPR
, sc
->sc_mpr
);
124 sec_cli(struct sec_softc
*sc
)
127 bus_space_write_1(sc
->sc_pod_t
, sc
->sc_pod_h
, SEC_CLRINT
, 0);
131 dmac_write(struct sec_softc
*sc
, int reg
, uint8_t val
)
134 bus_space_write_1(sc
->sc_mod_t
, sc
->sc_mod_h
,
135 SEC_DMAC
+ DMAC(reg
), val
);
138 static inline uint8_t
139 dmac_read(struct sec_softc
*sc
, int reg
)
142 return bus_space_read_1(sc
->sc_mod_t
, sc
->sc_mod_h
,
143 SEC_DMAC
+ DMAC(reg
));
147 sec_match(device_t parent
, cfdata_t cf
, void *aux
)
149 struct podulebus_attach_args
*pa
= aux
;
151 /* Standard ROM, skipping the MCS card that used the same ID. */
152 if (pa
->pa_product
== PODULE_ACORN_SCSI
&&
153 strncmp(pa
->pa_descr
, "MCS", 3) != 0)
157 if (pa
->pa_product
== PODULE_ALSYSTEMS_SCSI
&&
158 podulebus_initloader(pa
) == 0 &&
159 podloader_callloader(pa
, 0, 0) == PRID_ACORN_SCSI1
)
166 sec_attach(device_t parent
, device_t self
, void *aux
)
168 struct podulebus_attach_args
*pa
= aux
;
169 struct sec_softc
*sc
= device_private(self
);
172 sc
->sc_sbic
.sc_dev
= self
;
173 /* Set up bus spaces */
174 sc
->sc_pod_t
= pa
->pa_fast_t
;
175 bus_space_map(pa
->pa_fast_t
, pa
->pa_fast_base
, 0x1000, 0,
177 sc
->sc_mod_t
= pa
->pa_mod_t
;
178 bus_space_map(pa
->pa_mod_t
, pa
->pa_mod_base
, 0x1000, 0,
181 sc
->sc_sbic
.sc_regt
= sc
->sc_mod_t
;
182 bus_space_subregion(sc
->sc_mod_t
, sc
->sc_mod_h
, SEC_SBIC
+ 0, 1,
183 &sc
->sc_sbic
.sc_asr_regh
);
184 bus_space_subregion(sc
->sc_mod_t
, sc
->sc_mod_h
, SEC_SBIC
+ 1, 1,
185 &sc
->sc_sbic
.sc_data_regh
);
187 sc
->sc_sbic
.sc_id
= 7;
188 sc
->sc_sbic
.sc_clkfreq
= SEC_CLKFREQ
;
189 sc
->sc_sbic
.sc_dmamode
= SBIC_CTL_BURST_DMA
;
191 sc
->sc_sbic
.sc_adapter
.adapt_request
= wd33c93_scsi_request
;
192 sc
->sc_sbic
.sc_adapter
.adapt_minphys
= minphys
;
194 sc
->sc_sbic
.sc_dmasetup
= sec_dmasetup
;
195 sc
->sc_sbic
.sc_dmago
= sec_dmago
;
196 sc
->sc_sbic
.sc_dmastop
= sec_dmastop
;
197 sc
->sc_sbic
.sc_reset
= sec_reset
;
200 bus_space_write_1(sc
->sc_pod_t
, sc
->sc_pod_h
, SEC_MPR
, sc
->sc_mpr
);
202 for (i
= 0; i
< SEC_NPAGES
; i
++) {
204 bus_space_set_region_2(sc
->sc_mod_t
, sc
->sc_mod_h
,
205 SEC_SRAM
, 0, SEC_PAGESIZE
/ 2);
208 wd33c93_attach(&sc
->sc_sbic
);
210 evcnt_attach_dynamic(&sc
->sc_intrcnt
, EVCNT_TYPE_INTR
, NULL
,
211 device_xname(self
), "intr");
212 sc
->sc_ih
= podulebus_irq_establish(pa
->pa_ih
, IPL_BIO
, sec_intr
,
213 sc
, &sc
->sc_intrcnt
);
215 sc
->sc_mpr
|= SEC_MPR_IE
;
216 bus_space_write_1(sc
->sc_pod_t
, sc
->sc_pod_h
, SEC_MPR
, sc
->sc_mpr
);
217 pmf_device_register1(sc
->sc_sbic
.sc_dev
, NULL
, NULL
, sec_shutdown
);
221 * Before reboot, reset the page register to 0 so that RISC OS can see
225 sec_shutdown(device_t dev
, int howto
)
227 struct sec_softc
*sc
= device_private(dev
);
234 sec_copyin(struct sec_softc
*sc
, void *dest
, int src
, size_t size
)
240 KASSERT(src
+ size
<= SEC_MEMSIZE
);
243 * There's a stray byte at the start. Read the word
246 sec_setpage(sc
, src
/ SEC_PAGESIZE
);
247 tmp
= bus_space_read_2(sc
->sc_mod_t
, sc
->sc_mod_h
,
248 SEC_SRAM
+ (src
% SEC_PAGESIZE
/ 2));
249 *(uint8_t *)dest
= tmp
>> 8;
250 dest
= ((uint8_t *)dest
) + 1;
253 KASSERT(src
% 2 == 0);
254 KASSERT(ALIGNED_POINTER(dest
, uint16_t));
256 extra_byte
= size
% 2;
259 cnt
= SEC_PAGESIZE
- src
% SEC_PAGESIZE
;
262 sec_setpage(sc
, src
/ SEC_PAGESIZE
);
263 /* bus ops are in words */
264 bus_space_read_region_2(sc
->sc_mod_t
, sc
->sc_mod_h
,
265 SEC_SRAM
+ src
% SEC_PAGESIZE
/ 2, wptr
, cnt
/ 2);
271 sec_setpage(sc
, src
/ SEC_PAGESIZE
);
273 bus_space_read_2(sc
->sc_mod_t
, sc
->sc_mod_h
,
274 SEC_SRAM
+ src
% SEC_PAGESIZE
/ 2) & 0xff;
279 sec_copyout(struct sec_softc
*sc
, const void *src
, int dest
, size_t size
)
282 const uint16_t *wptr
;
286 KASSERT(dest
+ size
<= SEC_MEMSIZE
);
289 * There's a stray byte at the start. Read the word
292 sec_setpage(sc
, dest
/ SEC_PAGESIZE
);
293 tmp
= bus_space_read_2(sc
->sc_mod_t
, sc
->sc_mod_h
,
294 SEC_SRAM
+ (dest
% SEC_PAGESIZE
/ 2));
296 tmp
|= *(uint8_t const *)src
<< 8;
297 bus_space_write_2(sc
->sc_mod_t
, sc
->sc_mod_h
,
298 SEC_SRAM
+ (dest
% SEC_PAGESIZE
/ 2), tmp
);
299 src
= ((uint8_t const *)src
) + 1;
302 KASSERT(dest
% 2 == 0);
303 KASSERT(ALIGNED_POINTER(src
, uint16_t));
305 extra_byte
= size
% 2;
308 cnt
= SEC_PAGESIZE
- dest
% SEC_PAGESIZE
;
311 sec_setpage(sc
, dest
/ SEC_PAGESIZE
);
312 /* bus ops are in words */
313 bus_space_write_region_2(sc
->sc_mod_t
, sc
->sc_mod_h
,
314 dest
% SEC_PAGESIZE
/ 2, wptr
, cnt
/ 2);
321 * There's a stray byte at the end. Read the word
324 sec_setpage(sc
, dest
/ SEC_PAGESIZE
);
325 tmp
= bus_space_read_2(sc
->sc_mod_t
, sc
->sc_mod_h
,
326 SEC_SRAM
+ (dest
% SEC_PAGESIZE
/ 2));
328 tmp
|= *(uint8_t const *)wptr
;
329 bus_space_write_2(sc
->sc_mod_t
, sc
->sc_mod_h
,
330 SEC_SRAM
+ (dest
% SEC_PAGESIZE
/ 2), tmp
);
335 sec_dmablk(struct sec_softc
*sc
, int blk
)
341 KASSERT(blk
* SEC_DMABLK
< sc
->sc_dmalen
);
342 off
= (blk
% SEC_NBLKS
) * SEC_DMABLK
+ sc
->sc_dmaoff
;
343 len
= MIN(SEC_DMABLK
, sc
->sc_dmalen
- (blk
* SEC_DMABLK
));
344 dmac_write(sc
, NEC71071_ADDRLO
, off
& 0xff);
345 dmac_write(sc
, NEC71071_ADDRMID
, off
>> 8);
346 dmac_write(sc
, NEC71071_ADDRHI
, 0);
348 * "Note: The number of DMA transfer cycles is actually the
349 * value of the current count register + 1. Therefore, when
350 * programming the count register, specify the number of DMA
351 * transfers minus one." -- uPD71071 datasheet
353 dmac_write(sc
, NEC71071_COUNTLO
, (len
- 1) & 0xff);
354 dmac_write(sc
, NEC71071_COUNTHI
, (len
- 1) >> 8);
358 sec_copyoutblk(struct sec_softc
*sc
, int blk
)
364 KASSERT(blk
* SEC_DMABLK
< sc
->sc_dmalen
);
365 KASSERT(!sc
->sc_dmain
);
366 off
= (blk
% SEC_NBLKS
) * SEC_DMABLK
+ sc
->sc_dmaoff
;
367 len
= MIN(SEC_DMABLK
, sc
->sc_dmalen
- (blk
* SEC_DMABLK
));
368 sec_copyout(sc
, (char*)sc
->sc_dmaaddr
+ (blk
* SEC_DMABLK
), off
, len
);
372 sec_copyinblk(struct sec_softc
*sc
, int blk
)
378 KASSERT(blk
* SEC_DMABLK
< sc
->sc_dmalen
);
379 KASSERT(sc
->sc_dmain
);
380 off
= (blk
% SEC_NBLKS
) * SEC_DMABLK
+ sc
->sc_dmaoff
;
381 len
= MIN(SEC_DMABLK
, sc
->sc_dmalen
- (blk
* SEC_DMABLK
));
382 sec_copyin(sc
, (char*)sc
->sc_dmaaddr
+ (blk
* SEC_DMABLK
), off
, len
);
386 sec_dmasetup(struct wd33c93_softc
*sc_sbic
, void **addr
, size_t *len
,
387 int datain
, size_t *dmasize
)
389 struct sec_softc
*sc
= (struct sec_softc
*)sc_sbic
;
392 sc
->sc_dmaaddr
= *addr
;
393 sc
->sc_dmaoff
= ALIGNED_POINTER(*addr
, uint16_t) ? 0 : 1;
394 sc
->sc_dmalen
= *len
;
395 sc
->sc_dmain
= datain
;
397 mode
= SEC_DMAMODE
| (datain
? MODE_TDIR_IOTM
: MODE_TDIR_MTIO
);
398 /* Program first block into DMAC and queue up second. */
399 dmac_write(sc
, NEC71071_CHANNEL
, 0);
401 sec_copyoutblk(sc
, 0);
403 /* Mode control register */
404 dmac_write(sc
, NEC71071_MODE
, mode
);
405 return sc
->sc_dmalen
;
409 sec_dmago(struct wd33c93_softc
*sc_sbic
)
411 struct sec_softc
*sc
= (struct sec_softc
*)sc_sbic
;
413 dmac_write(sc
, NEC71071_MASK
, 0xe);
414 sc
->sc_dmaactive
= true;
415 if (!sc
->sc_dmain
&& sc
->sc_dmalen
> SEC_DMABLK
)
416 sec_copyoutblk(sc
, 1);
417 return sc
->sc_dmalen
;
421 sec_dmastop(struct wd33c93_softc
*sc_sbic
)
423 struct sec_softc
*sc
= (struct sec_softc
*)sc_sbic
;
425 dmac_write(sc
, NEC71071_MASK
, 0xf);
426 if (sc
->sc_dmaactive
&& sc
->sc_dmain
)
427 sec_copyinblk(sc
, sc
->sc_dmablk
);
428 sc
->sc_dmaactive
= false;
432 * Reset the SCSI bus, and incidentally the SBIC and DMAC.
435 sec_reset(struct wd33c93_softc
*sc_sbic
)
437 struct sec_softc
*sc
= (struct sec_softc
*)sc_sbic
;
440 bus_space_write_1(sc
->sc_pod_t
, sc
->sc_pod_h
, SEC_MPR
,
441 sc
->sc_mpr
| SEC_MPR_UR
);
443 bus_space_write_1(sc
->sc_pod_t
, sc
->sc_pod_h
, SEC_MPR
, sc
->sc_mpr
);
444 /* Wait for and clear the reset-complete interrupt */
446 GET_SBIC_asr(sc_sbic
, asr
);
447 while (!(asr
& SBIC_ASR_INT
));
448 GET_SBIC_csr(sc_sbic
, csr
);
449 dmac_write(sc
, NEC71071_DCTRL1
, DCTRL1_CMP
| DCTRL1_RQL
);
450 dmac_write(sc
, NEC71071_DCTRL2
, 0);
457 struct sec_softc
*sc
= arg
;
460 isr
= bus_space_read_1(sc
->sc_pod_t
, sc
->sc_pod_h
, SEC_ISR
);
461 if (!(isr
& SEC_ISR_IRQ
))
463 if (isr
& SEC_ISR_DMAC
)
465 if (isr
& SEC_ISR_SBIC
)
466 wd33c93_intr(&sc
->sc_sbic
);
471 sec_dmatc(struct sec_softc
*sc
)
475 /* DMAC finished block n-1 and is now working on block n */
477 if (sc
->sc_dmalen
> sc
->sc_dmablk
* SEC_DMABLK
) {
478 dmac_write(sc
, NEC71071_CHANNEL
, 0);
479 sec_dmablk(sc
, sc
->sc_dmablk
);
480 dmac_write(sc
, NEC71071_MASK
, 0xe);
482 sc
->sc_dmalen
> (sc
->sc_dmablk
+ 1) * SEC_DMABLK
)
483 sec_copyoutblk(sc
, sc
->sc_dmablk
+ 1);
485 /* All blocks fully processed. */
486 sc
->sc_dmaactive
= false;
489 sec_copyinblk(sc
, sc
->sc_dmablk
- 1);
495 sec_dumpdma(void *arg
)
497 struct sec_softc
*sc
= arg
;
499 dmac_write(sc
, NEC71071_CHANNEL
, 0);
500 printf("%s: DMA state: cur count %02x%02x cur addr %02x%02x%02x ",
501 device_xname(sc
->sc_sbic
.sc_dev
),
502 dmac_read(sc
, NEC71071_COUNTHI
), dmac_read(sc
, NEC71071_COUNTLO
),
503 dmac_read(sc
, NEC71071_ADDRHI
), dmac_read(sc
, NEC71071_ADDRMID
),
504 dmac_read(sc
, NEC71071_ADDRLO
));
505 dmac_write(sc
, NEC71071_CHANNEL
, 0 | CHANNEL_WBASE
);
506 printf("base count %02x%02x base addr %02x%02x%02x\n",
507 dmac_read(sc
, NEC71071_COUNTHI
), dmac_read(sc
, NEC71071_COUNTLO
),
508 dmac_read(sc
, NEC71071_ADDRHI
), dmac_read(sc
, NEC71071_ADDRMID
),
509 dmac_read(sc
, NEC71071_ADDRLO
));
510 printf("%s: DMA state: dctrl %1x%02x mode %02x status %02x req %02x "
512 device_xname(sc
->sc_sbic
.sc_dev
), dmac_read(sc
, NEC71071_DCTRL2
),
513 dmac_read(sc
, NEC71071_DCTRL1
), dmac_read(sc
, NEC71071_MODE
),
514 dmac_read(sc
, NEC71071_STATUS
), dmac_read(sc
, NEC71071_REQUEST
),
515 dmac_read(sc
, NEC71071_MASK
));
516 printf("%s: soft DMA state: %zd@%p%s%d\n",
517 device_xname(sc
->sc_sbic
.sc_dev
),
518 sc
->sc_dmalen
, sc
->sc_dmaaddr
, sc
->sc_dmain
? "<-" : "->",
522 void sec_dumpall(void); /* Call from DDB */
524 extern struct cfdriver sec_cd
;
526 void sec_dumpall(void)
529 struct sec_softc
*sc
;
531 for (i
= 0; i
< sec_cd
.cd_ndevs
; ++i
) {
532 sc
= device_lookup_private(&sec_cd
, i
);