1 /* $NetBSD: mba.c,v 1.37 2008/10/16 12:47:22 hans Exp $ */
3 * Copyright (c) 1994, 1996 Ludd, University of Lule}, Sweden.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed at Ludd, University of
17 * Lule}, Sweden and its contributors.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * Simple massbus drive routine.
36 * Autoconfig new devices 'on the fly'.
37 * More intelligent way to handle different interrupts.
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: mba.c,v 1.37 2008/10/16 12:47:22 hans Exp $");
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/device.h>
46 #include <sys/queue.h>
51 #include <uvm/uvm_extern.h>
53 #include <machine/bus.h>
54 #include <machine/scb.h>
55 #include <machine/nexus.h>
56 #include <machine/pte.h>
57 #include <machine/pcb.h>
58 #include <machine/sid.h>
59 #include <machine/cpu.h>
61 #include <vax/mba/mbareg.h>
62 #include <vax/mba/mbavar.h>
66 const struct mbaunit mbaunit
[] = {
67 {MBADT_RP04
, "rp04", MB_RP
},
68 {MBADT_RP05
, "rp05", MB_RP
},
69 {MBADT_RP06
, "rp06", MB_RP
},
70 {MBADT_RP07
, "rp07", MB_RP
},
71 {MBADT_RM02
, "rm02", MB_RP
},
72 {MBADT_RM03
, "rm03", MB_RP
},
73 {MBADT_RM05
, "rm05", MB_RP
},
74 {MBADT_RM80
, "rm80", MB_RP
},
78 void mbaqueue(struct mba_device
*);
80 static int mbamatch(device_t
, cfdata_t
, void *);
81 static void mbaattach(device_t
, device_t
, void *);
82 static void mbaintr(void *);
83 static int mbaprint(void *, const char *);
84 static void mbastart(struct mba_softc
*);
86 CFATTACH_DECL_NEW(mba_cmi
, sizeof(struct mba_softc
),
87 mbamatch
, mbaattach
, NULL
, NULL
);
89 CFATTACH_DECL_NEW(mba_sbi
, sizeof(struct mba_softc
),
90 mbamatch
, mbaattach
, NULL
, NULL
);
92 #define MBA_WCSR(reg, val) \
93 bus_space_write_4(sc->sc_iot, sc->sc_ioh, (reg), (val))
94 #define MBA_RCSR(reg) \
95 bus_space_read_4(sc->sc_iot, sc->sc_ioh, (reg))
98 * Look if this is a massbuss adapter.
101 mbamatch(device_t parent
, cfdata_t cf
, void *aux
)
103 struct sbi_attach_args
* const sa
= aux
;
105 if (vax_cputype
== VAX_750
) {
106 if (cf
->cf_loc
[CMICF_TR
] != CMICF_TR_DEFAULT
&&
107 cf
->cf_loc
[CMICF_TR
] != sa
->sa_nexnum
)
110 if (cf
->cf_loc
[SBICF_TR
] != SBICF_TR_DEFAULT
&&
111 cf
->cf_loc
[SBICF_TR
] != sa
->sa_nexnum
)
115 if (sa
->sa_type
== NEX_MBA
)
122 * Attach the found massbuss adapter. Setup its interrupt vectors,
123 * reset it and go searching for drives on it.
126 mbaattach(device_t parent
, device_t self
, void *aux
)
128 struct mba_softc
* const sc
= device_private(self
);
129 struct sbi_attach_args
* const sa
= aux
;
130 struct mba_attach_args ma
;
136 sc
->sc_iot
= sa
->sa_iot
;
137 sc
->sc_ioh
= sa
->sa_ioh
;
139 * Set up interrupt vectors for this MBA.
141 for (i
= 0x14; i
< 0x18; i
++)
142 scb_vecalloc(vecnum(0, i
, sa
->sa_nexnum
),
143 mbaintr
, sc
, SCB_ISTACK
, &sc
->sc_intrcnt
);
144 evcnt_attach_dynamic(&sc
->sc_intrcnt
, EVCNT_TYPE_INTR
, NULL
,
145 device_xname(self
), "intr");
147 STAILQ_INIT(&sc
->sc_xfers
);
148 MBA_WCSR(MBA_CR
, MBACR_INIT
); /* Reset adapter */
149 MBA_WCSR(MBA_CR
, MBACR_IE
); /* Enable interrupts */
151 for (i
= 0; i
< MAXMBADEV
; i
++) {
152 sc
->sc_state
= SC_AUTOCONF
;
153 if ((MBA_RCSR(MUREG(i
, MU_DS
)) & MBADS_DPR
) == 0)
155 /* We have a drive, ok. */
157 ma
.ma_type
= MBA_RCSR(MUREG(i
, MU_DT
)) & 0xf1ff;
158 for (j
= 0; mbaunit
[j
].nr
; j
++)
159 if (mbaunit
[j
].nr
== ma
.ma_type
)
161 ma
.ma_devtyp
= mbaunit
[j
].devtyp
;
162 ma
.ma_name
= mbaunit
[j
].name
;
163 ma
.ma_iot
= sc
->sc_iot
;
164 ma
.ma_ioh
= sc
->sc_ioh
+ MUREG(i
, 0);
165 config_found(sc
->sc_dev
, &ma
, mbaprint
);
170 * We got an interrupt. Check type of interrupt and call the specific
171 * device interrupt handling routine.
176 struct mba_softc
* const sc
= mba
;
177 struct mba_device
*md
;
179 int itype
, attn
, anr
;
181 itype
= MBA_RCSR(MBA_SR
);
182 MBA_WCSR(MBA_SR
, itype
);
184 attn
= MBA_RCSR(MUREG(0, MU_AS
)) & 0xff;
185 MBA_WCSR(MUREG(0, MU_AS
), attn
);
187 if (sc
->sc_state
== SC_AUTOCONF
)
188 return; /* During autoconfig */
190 md
= STAILQ_FIRST(&sc
->sc_xfers
);
191 bp
= bufq_peek(md
->md_q
);
193 * A data-transfer interrupt. Current operation is finished,
194 * call that device's finish routine to see what to do next.
196 if (sc
->sc_state
== SC_ACTIVE
) {
197 sc
->sc_state
= SC_IDLE
;
198 switch ((*md
->md_finish
)(md
, itype
, &attn
)) {
202 * Transfer is finished. Take buffer of drive
203 * queue, and take drive of adapter queue.
204 * If more to transfer, start the adapter again
205 * by calling mbastart().
207 (void)bufq_get(md
->md_q
);
208 STAILQ_REMOVE_HEAD(&sc
->sc_xfers
, md_link
);
209 if (bufq_peek(md
->md_q
) != NULL
) {
210 STAILQ_INSERT_TAIL(&sc
->sc_xfers
, md
, md_link
);
215 if (!STAILQ_EMPTY(&sc
->sc_xfers
))
221 * Something went wrong with the transfer. Try again.
231 if (sc
->sc_md
[anr
]->md_attn
== 0)
232 panic("Should check for new MBA device %d", anr
);
233 (*sc
->sc_md
[anr
]->md_attn
)(sc
->sc_md
[anr
]);
238 mbaprint(void *aux
, const char *mbaname
)
240 struct mba_attach_args
* const ma
= aux
;
244 aprint_normal("%s", ma
->ma_name
);
246 aprint_normal("device type %o", ma
->ma_type
);
247 aprint_normal(" at %s", mbaname
);
249 aprint_normal(" drive %d", ma
->ma_unit
);
250 return (ma
->ma_name
? UNCONF
: UNSUPP
);
254 * A device calls mbaqueue() when it wants to get on the adapter queue.
255 * Called at splbio(). If the adapter is inactive, start it.
258 mbaqueue(struct mba_device
*md
)
260 struct mba_softc
* const sc
= md
->md_mba
;
261 bool was_empty
= STAILQ_EMPTY(&sc
->sc_xfers
);
263 STAILQ_INSERT_TAIL(&sc
->sc_xfers
, md
, md_link
);
270 * Start activity on (idling) adapter. Calls disk_reallymapin() to setup
271 * for DMA transfer, then the unit-specific start routine.
274 mbastart(struct mba_softc
*sc
)
276 struct mba_device
* const md
= STAILQ_FIRST(&sc
->sc_xfers
);
277 struct buf
*bp
= bufq_peek(md
->md_q
);
279 disk_reallymapin(bp
, (void *)(sc
->sc_ioh
+ MAPREG(0)), 0, PG_V
);
281 sc
->sc_state
= SC_ACTIVE
;
282 MBA_WCSR(MBA_VAR
, ((u_int
)bp
->b_data
& VAX_PGOFSET
));
283 MBA_WCSR(MBA_BC
, (~bp
->b_bcount
) + 1);
284 (*md
->md_start
)(md
); /* machine-dependent start */