1 /* $NetBSD: mba.c,v 1.42 2021/08/07 16:19:07 thorpej Exp $ */
2 /*
3 * Copyright (c) 1994, 1996 Ludd, University of Lule}, Sweden.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 /*
28 * Simple massbus drive routine.
29 * TODO:
30 * Autoconfig new devices 'on the fly'.
31 * More intelligent way to handle different interrupts.
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: mba.c,v 1.42 2021/08/07 16:19:07 thorpej Exp $");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/bus.h>
40 #include <sys/cpu.h>
41 #include <sys/device.h>
42 #include <sys/queue.h>
43 #include <sys/buf.h>
44 #include <sys/bufq.h>
45 #include <sys/proc.h>
46
47 #include <machine/scb.h>
48 #include <machine/nexus.h>
49 #include <machine/pte.h>
50 #include <machine/sid.h>
51 #include <machine/sid.h>
52
53 #include <vax/mba/mbareg.h>
54 #include <vax/mba/mbavar.h>
55
56 #include "locators.h"
57
58 const struct mbaunit mbaunit[] = {
59 {MBADT_RP04, "rp04", MB_RP},
60 {MBADT_RP05, "rp05", MB_RP},
61 {MBADT_RP06, "rp06", MB_RP},
62 {MBADT_RP07, "rp07", MB_RP},
63 {MBADT_RM02, "rm02", MB_RP},
64 {MBADT_RM03, "rm03", MB_RP},
65 {MBADT_RM05, "rm05", MB_RP},
66 {MBADT_RM80, "rm80", MB_RP},
67 {0, 0, 0}
68 };
69
70 void mbaqueue(struct mba_device *);
71
72 static int mbamatch(device_t, cfdata_t, void *);
73 static void mbaattach(device_t, device_t, void *);
74 static void mbaintr(void *);
75 static int mbaprint(void *, const char *);
76 static void mbastart(struct mba_softc *);
77
78 CFATTACH_DECL_NEW(mba_cmi, sizeof(struct mba_softc),
79 mbamatch, mbaattach, NULL, NULL);
80
81 CFATTACH_DECL_NEW(mba_sbi, sizeof(struct mba_softc),
82 mbamatch, mbaattach, NULL, NULL);
83
84 #define MBA_WCSR(reg, val) \
85 bus_space_write_4(sc->sc_iot, sc->sc_ioh, (reg), (val))
86 #define MBA_RCSR(reg) \
87 bus_space_read_4(sc->sc_iot, sc->sc_ioh, (reg))
88
89 /*
90 * Look if this is a massbuss adapter.
91 */
92 int
mbamatch(device_t parent,cfdata_t cf,void * aux)93 mbamatch(device_t parent, cfdata_t cf, void *aux)
94 {
95 struct sbi_attach_args * const sa = aux;
96
97 if (vax_cputype == VAX_750) {
98 if (cf->cf_loc[CMICF_TR] != CMICF_TR_DEFAULT &&
99 cf->cf_loc[CMICF_TR] != sa->sa_nexnum)
100 return 0;
101 } else {
102 if (cf->cf_loc[SBICF_TR] != SBICF_TR_DEFAULT &&
103 cf->cf_loc[SBICF_TR] != sa->sa_nexnum)
104 return 0;
105 }
106
107 if (sa->sa_type == NEX_MBA)
108 return 1;
109
110 return 0;
111 }
112
113 /*
114 * Attach the found massbuss adapter. Setup its interrupt vectors,
115 * reset it and go searching for drives on it.
116 */
117 void
mbaattach(device_t parent,device_t self,void * aux)118 mbaattach(device_t parent, device_t self, void *aux)
119 {
120 struct mba_softc * const sc = device_private(self);
121 struct sbi_attach_args * const sa = aux;
122 struct mba_attach_args ma;
123 int i, j;
124
125 aprint_normal("\n");
126
127 sc->sc_dev = self;
128 sc->sc_iot = sa->sa_iot;
129 sc->sc_ioh = sa->sa_ioh;
130 /*
131 * Set up interrupt vectors for this MBA.
132 */
133 for (i = 0x14; i < 0x18; i++)
134 scb_vecalloc(vecnum(0, i, sa->sa_nexnum),
135 mbaintr, sc, SCB_ISTACK, &sc->sc_intrcnt);
136 evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
137 device_xname(self), "intr");
138
139 STAILQ_INIT(&sc->sc_xfers);
140 MBA_WCSR(MBA_CR, MBACR_INIT); /* Reset adapter */
141 MBA_WCSR(MBA_CR, MBACR_IE); /* Enable interrupts */
142
143 for (i = 0; i < MAXMBADEV; i++) {
144 sc->sc_state = SC_AUTOCONF;
145 if ((MBA_RCSR(MUREG(i, MU_DS)) & MBADS_DPR) == 0)
146 continue;
147 /* We have a drive, ok. */
148 ma.ma_unit = i;
149 ma.ma_type = MBA_RCSR(MUREG(i, MU_DT)) & 0xf1ff;
150 for (j = 0; mbaunit[j].nr; j++)
151 if (mbaunit[j].nr == ma.ma_type)
152 break;
153 ma.ma_devtyp = mbaunit[j].devtyp;
154 ma.ma_name = mbaunit[j].name;
155 ma.ma_iot = sc->sc_iot;
156 ma.ma_ioh = sc->sc_ioh + MUREG(i, 0);
157 config_found(sc->sc_dev, &ma, mbaprint, CFARGS_NONE);
158 }
159 }
160
161 /*
162 * We got an interrupt. Check type of interrupt and call the specific
163 * device interrupt handling routine.
164 */
165 void
mbaintr(void * mba)166 mbaintr(void *mba)
167 {
168 struct mba_softc * const sc = mba;
169 struct mba_device *md;
170 struct buf *bp;
171 int itype, attn, anr;
172
173 itype = MBA_RCSR(MBA_SR);
174 MBA_WCSR(MBA_SR, itype);
175
176 attn = MBA_RCSR(MUREG(0, MU_AS)) & 0xff;
177 MBA_WCSR(MUREG(0, MU_AS), attn);
178
179 if (sc->sc_state == SC_AUTOCONF)
180 return; /* During autoconfig */
181
182 md = STAILQ_FIRST(&sc->sc_xfers);
183 bp = bufq_peek(md->md_q);
184 /*
185 * A data-transfer interrupt. Current operation is finished,
186 * call that device's finish routine to see what to do next.
187 */
188 if (sc->sc_state == SC_ACTIVE) {
189 sc->sc_state = SC_IDLE;
190 switch ((*md->md_finish)(md, itype, &attn)) {
191
192 case XFER_FINISH:
193 /*
194 * Transfer is finished. Take buffer of drive
195 * queue, and take drive of adapter queue.
196 * If more to transfer, start the adapter again
197 * by calling mbastart().
198 */
199 (void)bufq_get(md->md_q);
200 STAILQ_REMOVE_HEAD(&sc->sc_xfers, md_link);
201 if (bufq_peek(md->md_q) != NULL) {
202 STAILQ_INSERT_TAIL(&sc->sc_xfers, md, md_link);
203 }
204
205 bp->b_resid = 0;
206 biodone(bp);
207 if (!STAILQ_EMPTY(&sc->sc_xfers))
208 mbastart(sc);
209 break;
210
211 case XFER_RESTART:
212 /*
213 * Something went wrong with the transfer. Try again.
214 */
215 mbastart(sc);
216 break;
217 }
218 }
219
220 while (attn) {
221 anr = ffs(attn) - 1;
222 attn &= ~(1 << anr);
223 if (sc->sc_md[anr]->md_attn == 0)
224 panic("Should check for new MBA device %d", anr);
225 (*sc->sc_md[anr]->md_attn)(sc->sc_md[anr]);
226 }
227 }
228
229 int
mbaprint(void * aux,const char * mbaname)230 mbaprint(void *aux, const char *mbaname)
231 {
232 struct mba_attach_args * const ma = aux;
233
234 if (mbaname) {
235 if (ma->ma_name)
236 aprint_normal("%s", ma->ma_name);
237 else
238 aprint_normal("device type %o", ma->ma_type);
239 aprint_normal(" at %s", mbaname);
240 }
241 aprint_normal(" drive %d", ma->ma_unit);
242 return (ma->ma_name ? UNCONF : UNSUPP);
243 }
244
245 /*
246 * A device calls mbaqueue() when it wants to get on the adapter queue.
247 * Called at splbio(). If the adapter is inactive, start it.
248 */
249 void
mbaqueue(struct mba_device * md)250 mbaqueue(struct mba_device *md)
251 {
252 struct mba_softc * const sc = md->md_mba;
253 bool was_empty = STAILQ_EMPTY(&sc->sc_xfers);
254
255 STAILQ_INSERT_TAIL(&sc->sc_xfers, md, md_link);
256
257 if (was_empty)
258 mbastart(sc);
259 }
260
261 /*
262 * Start activity on (idling) adapter. Calls disk_reallymapin() to setup
263 * for DMA transfer, then the unit-specific start routine.
264 */
265 void
mbastart(struct mba_softc * sc)266 mbastart(struct mba_softc *sc)
267 {
268 struct mba_device * const md = STAILQ_FIRST(&sc->sc_xfers);
269 struct buf *bp = bufq_peek(md->md_q);
270
271 disk_reallymapin(bp, (void *)(sc->sc_ioh + MAPREG(0)), 0, PG_V);
272
273 sc->sc_state = SC_ACTIVE;
274 MBA_WCSR(MBA_VAR, ((u_int)bp->b_data & VAX_PGOFSET));
275 MBA_WCSR(MBA_BC, (~bp->b_bcount) + 1);
276 (*md->md_start)(md); /* machine-dependent start */
277 }
278