edc_mca.c revision 1.9.2.2 1 1.9.2.2 nathanw /* $NetBSD: edc_mca.c,v 1.9.2.2 2001/06/21 20:04:00 nathanw Exp $ */
2 1.9.2.2 nathanw
3 1.9.2.2 nathanw /*
4 1.9.2.2 nathanw * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 1.9.2.2 nathanw *
6 1.9.2.2 nathanw * This code is derived from software contributed to The NetBSD Foundation
7 1.9.2.2 nathanw * by Jaromir Dolecek.
8 1.9.2.2 nathanw *
9 1.9.2.2 nathanw * Redistribution and use in source and binary forms, with or without
10 1.9.2.2 nathanw * modification, are permitted provided that the following conditions
11 1.9.2.2 nathanw * are met:
12 1.9.2.2 nathanw * 1. Redistributions of source code must retain the above copyright
13 1.9.2.2 nathanw * notice, this list of conditions and the following disclaimer.
14 1.9.2.2 nathanw * 2. Redistributions in binary form must reproduce the above copyright
15 1.9.2.2 nathanw * notice, this list of conditions and the following disclaimer in the
16 1.9.2.2 nathanw * documentation and/or other materials provided with the distribution.
17 1.9.2.2 nathanw * 3. All advertising materials mentioning features or use of this software
18 1.9.2.2 nathanw * must display the following acknowledgement:
19 1.9.2.2 nathanw * This product includes software developed by the NetBSD
20 1.9.2.2 nathanw * Foundation, Inc. and its contributors.
21 1.9.2.2 nathanw * 4. The name of the author may not be used to endorse or promote products
22 1.9.2.2 nathanw * derived from this software without specific prior written permission.
23 1.9.2.2 nathanw *
24 1.9.2.2 nathanw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25 1.9.2.2 nathanw * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 1.9.2.2 nathanw * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 1.9.2.2 nathanw * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 1.9.2.2 nathanw * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 1.9.2.2 nathanw * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 1.9.2.2 nathanw * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 1.9.2.2 nathanw * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 1.9.2.2 nathanw * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 1.9.2.2 nathanw * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 1.9.2.2 nathanw */
35 1.9.2.2 nathanw
36 1.9.2.2 nathanw /*
37 1.9.2.2 nathanw * Driver for MCA ESDI controllers and disks conforming to IBM DASD
38 1.9.2.2 nathanw * spec.
39 1.9.2.2 nathanw *
40 1.9.2.2 nathanw * The driver was written with DASD Storage Interface Specification
41 1.9.2.2 nathanw * for MCA rev. 2.2 in hands, thanks to Scott Telford <st (at) epcc.ed.ac.uk>.
42 1.9.2.2 nathanw *
43 1.9.2.2 nathanw * TODO:
44 1.9.2.2 nathanw * - move the MCA DMA controller (edc_setup_dma()) goo to device driver
45 1.9.2.2 nathanw * independant location
46 1.9.2.2 nathanw * - improve error recovery
47 1.9.2.2 nathanw * add any soft resets when anything gets stuck?
48 1.9.2.2 nathanw * - test with > 1 disk (this is supported by some controllers), eliminate
49 1.9.2.2 nathanw * any remaining devno=0 assumptions if there are any still
50 1.9.2.2 nathanw * - test with > 1 ESDI controller in machine; shared interrupts
51 1.9.2.2 nathanw * necessary for this to work should be supported - edc_intr() specifically
52 1.9.2.2 nathanw * checks if the interrupt is for this controller
53 1.9.2.2 nathanw */
54 1.9.2.2 nathanw
55 1.9.2.2 nathanw #include "rnd.h"
56 1.9.2.2 nathanw
57 1.9.2.2 nathanw #include <sys/param.h>
58 1.9.2.2 nathanw #include <sys/systm.h>
59 1.9.2.2 nathanw #include <sys/errno.h>
60 1.9.2.2 nathanw #include <sys/device.h>
61 1.9.2.2 nathanw #include <sys/malloc.h>
62 1.9.2.2 nathanw #include <sys/endian.h>
63 1.9.2.2 nathanw #include <sys/disklabel.h>
64 1.9.2.2 nathanw #include <sys/disk.h>
65 1.9.2.2 nathanw #include <sys/syslog.h>
66 1.9.2.2 nathanw #include <sys/proc.h>
67 1.9.2.2 nathanw #include <sys/vnode.h>
68 1.9.2.2 nathanw #include <sys/kernel.h>
69 1.9.2.2 nathanw #if NRND > 0
70 1.9.2.2 nathanw #include <sys/rnd.h>
71 1.9.2.2 nathanw #endif
72 1.9.2.2 nathanw
73 1.9.2.2 nathanw #include <machine/bus.h>
74 1.9.2.2 nathanw #include <machine/intr.h>
75 1.9.2.2 nathanw
76 1.9.2.2 nathanw #include <dev/mca/mcareg.h>
77 1.9.2.2 nathanw #include <dev/mca/mcavar.h>
78 1.9.2.2 nathanw #include <dev/mca/mcadevs.h>
79 1.9.2.2 nathanw
80 1.9.2.2 nathanw #include <dev/mca/edcreg.h>
81 1.9.2.2 nathanw #include <dev/mca/edvar.h>
82 1.9.2.2 nathanw #include <dev/mca/edcvar.h>
83 1.9.2.2 nathanw
84 1.9.2.2 nathanw #define EDC_ATTN_MAXTRIES 10000 /* How many times check for unbusy */
85 1.9.2.2 nathanw
86 1.9.2.2 nathanw struct edc_mca_softc {
87 1.9.2.2 nathanw struct device sc_dev;
88 1.9.2.2 nathanw
89 1.9.2.2 nathanw bus_space_tag_t sc_iot;
90 1.9.2.2 nathanw bus_space_handle_t sc_ioh;
91 1.9.2.2 nathanw
92 1.9.2.2 nathanw bus_dma_tag_t sc_dmat; /* DMA tag as passed by parent */
93 1.9.2.2 nathanw bus_space_handle_t sc_dmaextcmdh;
94 1.9.2.2 nathanw bus_space_handle_t sc_dmaexech;
95 1.9.2.2 nathanw
96 1.9.2.2 nathanw void *sc_ih; /* interrupt handle */
97 1.9.2.2 nathanw int sc_drq; /* DRQ number */
98 1.9.2.2 nathanw int sc_cmd_async; /* asynchronous cmd pending */
99 1.9.2.2 nathanw
100 1.9.2.2 nathanw int sc_flags;
101 1.9.2.2 nathanw #define DASD_QUIET 0x01 /* don't dump cmd error info */
102 1.9.2.2 nathanw #define DASD_MAXDEVS 8
103 1.9.2.2 nathanw struct ed_softc *sc_ed[DASD_MAXDEVS];
104 1.9.2.2 nathanw struct ed_softc sc_controller;
105 1.9.2.2 nathanw };
106 1.9.2.2 nathanw
107 1.9.2.2 nathanw int edc_mca_probe __P((struct device *, struct cfdata *, void *));
108 1.9.2.2 nathanw void edc_mca_attach __P((struct device *, struct device *, void *));
109 1.9.2.2 nathanw
110 1.9.2.2 nathanw struct cfattach edc_mca_ca = {
111 1.9.2.2 nathanw sizeof(struct edc_mca_softc), edc_mca_probe, edc_mca_attach
112 1.9.2.2 nathanw };
113 1.9.2.2 nathanw
114 1.9.2.2 nathanw #define DMA_EXTCMD 0x18
115 1.9.2.2 nathanw #define DMA_EXEC 0x1A
116 1.9.2.2 nathanw
117 1.9.2.2 nathanw static int edc_intr __P((void *));
118 1.9.2.2 nathanw static void edc_dump_status_block __P((struct edc_mca_softc *, int, int));
119 1.9.2.2 nathanw static int edc_setup_dma __P((struct edc_mca_softc *, int,
120 1.9.2.2 nathanw bus_addr_t, bus_size_t));
121 1.9.2.2 nathanw static int edc_do_attn __P((struct edc_mca_softc *, int, int, int));
122 1.9.2.2 nathanw static int edc_cmd_wait __P((struct edc_mca_softc *, int, int, int));
123 1.9.2.2 nathanw
124 1.9.2.2 nathanw int
125 1.9.2.2 nathanw edc_mca_probe(parent, match, aux)
126 1.9.2.2 nathanw struct device *parent;
127 1.9.2.2 nathanw struct cfdata *match;
128 1.9.2.2 nathanw void *aux;
129 1.9.2.2 nathanw {
130 1.9.2.2 nathanw struct mca_attach_args *ma = aux;
131 1.9.2.2 nathanw
132 1.9.2.2 nathanw switch (ma->ma_id) {
133 1.9.2.2 nathanw case MCA_PRODUCT_IBM_ESDIC:
134 1.9.2.2 nathanw case MCA_PRODUCT_IBM_ESDIC_IG:
135 1.9.2.2 nathanw return (1);
136 1.9.2.2 nathanw default:
137 1.9.2.2 nathanw return (0);
138 1.9.2.2 nathanw }
139 1.9.2.2 nathanw }
140 1.9.2.2 nathanw
141 1.9.2.2 nathanw void
142 1.9.2.2 nathanw edc_mca_attach(parent, self, aux)
143 1.9.2.2 nathanw struct device *parent, *self;
144 1.9.2.2 nathanw void *aux;
145 1.9.2.2 nathanw {
146 1.9.2.2 nathanw struct edc_mca_softc *sc = (void *) self;
147 1.9.2.2 nathanw struct mca_attach_args *ma = aux;
148 1.9.2.2 nathanw int pos2, pos3, pos4;
149 1.9.2.2 nathanw int irq, drq, iobase;
150 1.9.2.2 nathanw const char *typestr;
151 1.9.2.2 nathanw struct ed_softc *ed;
152 1.9.2.2 nathanw struct ed_attach_args eda;
153 1.9.2.2 nathanw int devno, maxdevs;
154 1.9.2.2 nathanw
155 1.9.2.2 nathanw pos2 = mca_conf_read(ma->ma_mc, ma->ma_slot, 2);
156 1.9.2.2 nathanw pos3 = mca_conf_read(ma->ma_mc, ma->ma_slot, 3);
157 1.9.2.2 nathanw pos4 = mca_conf_read(ma->ma_mc, ma->ma_slot, 4);
158 1.9.2.2 nathanw
159 1.9.2.2 nathanw /*
160 1.9.2.2 nathanw * POS register 2: (adf pos0)
161 1.9.2.2 nathanw *
162 1.9.2.2 nathanw * 7 6 5 4 3 2 1 0
163 1.9.2.2 nathanw * \ \____/ \ \__ enable: 0=adapter disabled, 1=adapter enabled
164 1.9.2.2 nathanw * \ \ \___ Primary/Alternate Port Adresses:
165 1.9.2.2 nathanw * \ \ 0=0x3510-3517 1=0x3518-0x351f
166 1.9.2.2 nathanw * \ \_____ DMA Arbitration Level: 0101=5 0110=6 0111=7
167 1.9.2.2 nathanw * \ 0000=0 0001=1 0011=3 0100=4
168 1.9.2.2 nathanw * \_________ Fairness On/Off: 1=On 0=Off
169 1.9.2.2 nathanw *
170 1.9.2.2 nathanw * POS register 3: (adf pos1)
171 1.9.2.2 nathanw *
172 1.9.2.2 nathanw * 7 6 5 4 3 2 1 0
173 1.9.2.2 nathanw * 0 0 \_/
174 1.9.2.2 nathanw * \__________ DMA Burst Pacing Interval: 10=24ms 11=31ms
175 1.9.2.2 nathanw * 01=16ms 00=Burst Disabled
176 1.9.2.2 nathanw *
177 1.9.2.2 nathanw * POS register 4: (adf pos2)
178 1.9.2.2 nathanw *
179 1.9.2.2 nathanw * 7 6 5 4 3 2 1 0
180 1.9.2.2 nathanw * \_/ \__ DMA Pacing Control: 1=Disabled 0=Enabled
181 1.9.2.2 nathanw * \____ Time to Release: 1X=6ms 01=3ms 00=Immediate
182 1.9.2.2 nathanw *
183 1.9.2.2 nathanw * IRQ is fixed to 14 (0x0e).
184 1.9.2.2 nathanw */
185 1.9.2.2 nathanw
186 1.9.2.2 nathanw switch (ma->ma_id) {
187 1.9.2.2 nathanw case MCA_PRODUCT_IBM_ESDIC:
188 1.9.2.2 nathanw typestr = "IBM ESDI Fixed Disk Controller";
189 1.9.2.2 nathanw break;
190 1.9.2.2 nathanw case MCA_PRODUCT_IBM_ESDIC_IG:
191 1.9.2.2 nathanw typestr = "IBM Integ. ESDI Fixed Disk & Controller";
192 1.9.2.2 nathanw break;
193 1.9.2.2 nathanw default:
194 1.9.2.2 nathanw /* never reached */
195 1.9.2.2 nathanw }
196 1.9.2.2 nathanw
197 1.9.2.2 nathanw irq = ESDIC_IRQ;
198 1.9.2.2 nathanw iobase = (pos2 & IO_IS_ALT) ? ESDIC_IOALT : ESDIC_IOPRM;
199 1.9.2.2 nathanw drq = (pos2 & DRQ_MASK) >> 2;
200 1.9.2.2 nathanw
201 1.9.2.2 nathanw printf(" slot %d irq %d drq %d: %s\n", ma->ma_slot+1,
202 1.9.2.2 nathanw irq, drq, typestr);
203 1.9.2.2 nathanw
204 1.9.2.2 nathanw #ifdef DIAGNOSTIC
205 1.9.2.2 nathanw /*
206 1.9.2.2 nathanw * It's not strictly necessary to check this, machine configuration
207 1.9.2.2 nathanw * utility uses only valid adresses.
208 1.9.2.2 nathanw */
209 1.9.2.2 nathanw if (drq == 2 || drq >= 8) {
210 1.9.2.2 nathanw printf("%s: invalid DMA Arbitration Level %d\n",
211 1.9.2.2 nathanw sc->sc_dev.dv_xname, drq);
212 1.9.2.2 nathanw return;
213 1.9.2.2 nathanw }
214 1.9.2.2 nathanw #endif
215 1.9.2.2 nathanw
216 1.9.2.2 nathanw printf("%s: Fairness %s, Release %s, ",
217 1.9.2.2 nathanw sc->sc_dev.dv_xname,
218 1.9.2.2 nathanw (pos2 & FAIRNESS_ENABLE) ? "On" : "Off",
219 1.9.2.2 nathanw (pos4 & RELEASE_1) ? "6ms"
220 1.9.2.2 nathanw : ((pos4 & RELEASE_2) ? "3ms" : "Immediate")
221 1.9.2.2 nathanw );
222 1.9.2.2 nathanw if ((pos4 & PACING_CTRL_DISABLE) == 0) {
223 1.9.2.2 nathanw static const char * const pacint[] =
224 1.9.2.2 nathanw { "disabled", "16ms", "24ms", "31ms"};
225 1.9.2.2 nathanw printf("DMA burst pacing interval %s\n",
226 1.9.2.2 nathanw pacint[(pos3 & PACING_INT_MASK) >> 4]);
227 1.9.2.2 nathanw } else
228 1.9.2.2 nathanw printf("DMA pacing control disabled\n");
229 1.9.2.2 nathanw
230 1.9.2.2 nathanw sc->sc_iot = ma->ma_iot;
231 1.9.2.2 nathanw sc->sc_drq = drq;
232 1.9.2.2 nathanw
233 1.9.2.2 nathanw if (bus_space_map(sc->sc_iot, iobase,
234 1.9.2.2 nathanw ESDIC_REG_NPORTS, 0, &sc->sc_ioh)) {
235 1.9.2.2 nathanw printf("%s: couldn't map registers\n",
236 1.9.2.2 nathanw sc->sc_dev.dv_xname);
237 1.9.2.2 nathanw return;
238 1.9.2.2 nathanw }
239 1.9.2.2 nathanw
240 1.9.2.2 nathanw if (bus_space_map(sc->sc_iot, DMA_EXTCMD, 1, 0, &sc->sc_dmaextcmdh)) {
241 1.9.2.2 nathanw printf("%s: couldn't map registers\n",
242 1.9.2.2 nathanw sc->sc_dev.dv_xname);
243 1.9.2.2 nathanw return;
244 1.9.2.2 nathanw }
245 1.9.2.2 nathanw if (bus_space_map(sc->sc_iot, DMA_EXEC, 1, 0, &sc->sc_dmaexech)) {
246 1.9.2.2 nathanw printf("%s: couldn't map registers\n",
247 1.9.2.2 nathanw sc->sc_dev.dv_xname);
248 1.9.2.2 nathanw return;
249 1.9.2.2 nathanw }
250 1.9.2.2 nathanw
251 1.9.2.2 nathanw sc->sc_dmat = ma->ma_dmat;
252 1.9.2.2 nathanw
253 1.9.2.2 nathanw sc->sc_ih = mca_intr_establish(ma->ma_mc, irq, IPL_BIO, edc_intr, sc);
254 1.9.2.2 nathanw if (sc->sc_ih == NULL) {
255 1.9.2.2 nathanw printf("%s: couldn't establish interrupt handler\n",
256 1.9.2.2 nathanw sc->sc_dev.dv_xname);
257 1.9.2.2 nathanw return;
258 1.9.2.2 nathanw }
259 1.9.2.2 nathanw
260 1.9.2.2 nathanw /*
261 1.9.2.2 nathanw * Integrated ESDI controller supports only one disk, other
262 1.9.2.2 nathanw * controllers support two disks.
263 1.9.2.2 nathanw */
264 1.9.2.2 nathanw if (ma->ma_id == MCA_PRODUCT_IBM_ESDIC_IG)
265 1.9.2.2 nathanw maxdevs = 1;
266 1.9.2.2 nathanw else
267 1.9.2.2 nathanw maxdevs = 2;
268 1.9.2.2 nathanw
269 1.9.2.2 nathanw /*
270 1.9.2.2 nathanw * Initialize the controller ed softc. We could do without this,
271 1.9.2.2 nathanw * but absence of checks for controller devno simplifies code logic
272 1.9.2.2 nathanw * somewhat.
273 1.9.2.2 nathanw */
274 1.9.2.2 nathanw sc->sc_ed[DASD_DEVNO_CONTROLLER] = &sc->sc_controller;
275 1.9.2.2 nathanw strcpy(sc->sc_controller.sc_dev.dv_xname, sc->sc_dev.dv_xname);/*safe*/
276 1.9.2.2 nathanw
277 1.9.2.2 nathanw /*
278 1.9.2.2 nathanw * Reset controller and attach individual disks. ed attach routine
279 1.9.2.2 nathanw * uses polling so that this works with interrupts disabled.
280 1.9.2.2 nathanw */
281 1.9.2.2 nathanw
282 1.9.2.2 nathanw /* Do a reset to ensure sane state after warm boot. */
283 1.9.2.2 nathanw if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR) & BSR_BUSY) {
284 1.9.2.2 nathanw /* hard reset */
285 1.9.2.2 nathanw printf("%s: controller busy, performing hardware reset ...\n",
286 1.9.2.2 nathanw sc->sc_dev.dv_xname);
287 1.9.2.2 nathanw bus_space_write_1(sc->sc_iot, sc->sc_ioh, BCR,
288 1.9.2.2 nathanw BCR_INT_ENABLE|BCR_RESET);
289 1.9.2.2 nathanw } else {
290 1.9.2.2 nathanw /* "SOFT" reset */
291 1.9.2.2 nathanw edc_do_attn(sc, ATN_RESET_ATTACHMENT, DASD_DEVNO_CONTROLLER,0);
292 1.9.2.2 nathanw }
293 1.9.2.2 nathanw
294 1.9.2.2 nathanw /*
295 1.9.2.2 nathanw * Since interrupts are disabled ATM, it's necessary
296 1.9.2.2 nathanw * to detect the interrupt request and call edc_intr()
297 1.9.2.2 nathanw * explicitly. See also edc_run_cmd().
298 1.9.2.2 nathanw */
299 1.9.2.2 nathanw while(bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR) & BSR_BUSY) {
300 1.9.2.2 nathanw if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR) & BSR_INTR)
301 1.9.2.2 nathanw edc_intr(sc);
302 1.9.2.2 nathanw
303 1.9.2.2 nathanw delay(100);
304 1.9.2.2 nathanw }
305 1.9.2.2 nathanw
306 1.9.2.2 nathanw /*
307 1.9.2.2 nathanw * Get dummy ed_softc to be used during probe. Once a disk is
308 1.9.2.2 nathanw * found, ed_mca_attach() calls edc_add_disk() to insert the
309 1.9.2.2 nathanw * right pointer into sc->sc_ed[] array.
310 1.9.2.2 nathanw */
311 1.9.2.2 nathanw MALLOC(ed, struct ed_softc *, sizeof(struct ed_softc),
312 1.9.2.2 nathanw M_TEMP, M_WAITOK);
313 1.9.2.2 nathanw
314 1.9.2.2 nathanw /* be quiet duting probes */
315 1.9.2.2 nathanw sc->sc_flags |= DASD_QUIET;
316 1.9.2.2 nathanw
317 1.9.2.2 nathanw /* check for attached disks */
318 1.9.2.2 nathanw for(devno=0; devno < maxdevs; devno++) {
319 1.9.2.2 nathanw eda.sc_devno = devno;
320 1.9.2.2 nathanw eda.sc_dmat = sc->sc_dmat;
321 1.9.2.2 nathanw sc->sc_ed[devno] = ed;
322 1.9.2.2 nathanw (void *) config_found_sm(self, &eda, NULL, NULL);
323 1.9.2.2 nathanw }
324 1.9.2.2 nathanw
325 1.9.2.2 nathanw /* enable full error dumps again */
326 1.9.2.2 nathanw sc->sc_flags &= ~DASD_QUIET;
327 1.9.2.2 nathanw
328 1.9.2.2 nathanw /* cleanup */
329 1.9.2.2 nathanw FREE(ed, M_TEMP);
330 1.9.2.2 nathanw
331 1.9.2.2 nathanw /*
332 1.9.2.2 nathanw * Check if there are any disks attached. If not, disestablish
333 1.9.2.2 nathanw * the interrupt.
334 1.9.2.2 nathanw */
335 1.9.2.2 nathanw for(devno=0; devno < maxdevs; devno++) {
336 1.9.2.2 nathanw if (sc->sc_ed[devno] && (sc->sc_ed[devno]->sc_flags & EDF_INIT))
337 1.9.2.2 nathanw break;
338 1.9.2.2 nathanw }
339 1.9.2.2 nathanw if (devno == maxdevs) {
340 1.9.2.2 nathanw printf("%s: disabling controller (no drives attached)\n",
341 1.9.2.2 nathanw sc->sc_dev.dv_xname);
342 1.9.2.2 nathanw mca_intr_disestablish(ma->ma_mc, sc->sc_ih);
343 1.9.2.2 nathanw }
344 1.9.2.2 nathanw }
345 1.9.2.2 nathanw
346 1.9.2.2 nathanw void
347 1.9.2.2 nathanw edc_add_disk(sc, ed, devno)
348 1.9.2.2 nathanw struct edc_mca_softc *sc;
349 1.9.2.2 nathanw struct ed_softc *ed;
350 1.9.2.2 nathanw int devno;
351 1.9.2.2 nathanw {
352 1.9.2.2 nathanw sc->sc_ed[devno] = ed;
353 1.9.2.2 nathanw }
354 1.9.2.2 nathanw
355 1.9.2.2 nathanw static int
356 1.9.2.2 nathanw edc_intr(arg)
357 1.9.2.2 nathanw void *arg;
358 1.9.2.2 nathanw {
359 1.9.2.2 nathanw struct edc_mca_softc *sc = arg;
360 1.9.2.2 nathanw u_int8_t isr, intr_id;
361 1.9.2.2 nathanw u_int16_t sifr;
362 1.9.2.2 nathanw int cmd=-1, devno, bioerror=0;
363 1.9.2.2 nathanw struct ed_softc *ed=NULL;
364 1.9.2.2 nathanw
365 1.9.2.2 nathanw /*
366 1.9.2.2 nathanw * Check if the interrupt was for us.
367 1.9.2.2 nathanw */
368 1.9.2.2 nathanw if ((bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR) & BSR_INTR) == 0)
369 1.9.2.2 nathanw return (0);
370 1.9.2.2 nathanw
371 1.9.2.2 nathanw /*
372 1.9.2.2 nathanw * Read ISR to find out interrupt type. This also clears the interrupt
373 1.9.2.2 nathanw * condition and BSR_INTR flag. Accordings to docs interrupt ID of 0, 2
374 1.9.2.2 nathanw * and 4 are reserved and not used.
375 1.9.2.2 nathanw */
376 1.9.2.2 nathanw isr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ISR);
377 1.9.2.2 nathanw intr_id = isr & ISR_INTR_ID_MASK;
378 1.9.2.2 nathanw
379 1.9.2.2 nathanw #ifdef DEBUG
380 1.9.2.2 nathanw if (intr_id == 0 || intr_id == 2 || intr_id == 4) {
381 1.9.2.2 nathanw printf("%s: bogus interrupt id %d\n", sc->sc_dev.dv_xname,
382 1.9.2.2 nathanw (int) intr_id);
383 1.9.2.2 nathanw return (0);
384 1.9.2.2 nathanw }
385 1.9.2.2 nathanw #endif
386 1.9.2.2 nathanw
387 1.9.2.2 nathanw /* Get number of device whose intr this was */
388 1.9.2.2 nathanw devno = (isr & 0xe0) >> 5;
389 1.9.2.2 nathanw
390 1.9.2.2 nathanw /*
391 1.9.2.2 nathanw * Get Status block. Higher byte always says how long the status
392 1.9.2.2 nathanw * block is, rest is device number and command code.
393 1.9.2.2 nathanw * Check the status block length against our supported maximum length
394 1.9.2.2 nathanw * and fetch the data.
395 1.9.2.2 nathanw */
396 1.9.2.2 nathanw if (bus_space_read_1(sc->sc_iot, sc->sc_ioh,BSR) & BSR_SIFR_FULL) {
397 1.9.2.2 nathanw size_t len;
398 1.9.2.2 nathanw int i;
399 1.9.2.2 nathanw
400 1.9.2.2 nathanw sifr = le16toh(bus_space_read_2(sc->sc_iot, sc->sc_ioh, SIFR));
401 1.9.2.2 nathanw len = (sifr & 0xff00) >> 8;
402 1.9.2.2 nathanw #ifdef DEBUG
403 1.9.2.2 nathanw if (len > DASD_MAX_CMD_RES_LEN)
404 1.9.2.2 nathanw panic("%s: maximum Status Length exceeded: %d > %d",
405 1.9.2.2 nathanw sc->sc_dev.dv_xname,
406 1.9.2.2 nathanw len, DASD_MAX_CMD_RES_LEN);
407 1.9.2.2 nathanw #endif
408 1.9.2.2 nathanw
409 1.9.2.2 nathanw /* Get command code */
410 1.9.2.2 nathanw cmd = sifr & SIFR_CMD_MASK;
411 1.9.2.2 nathanw
412 1.9.2.2 nathanw /* Read whole status block */
413 1.9.2.2 nathanw ed = sc->sc_ed[devno];
414 1.9.2.2 nathanw ed->sc_status_block[0] = sifr;
415 1.9.2.2 nathanw for(i=1; i < len; i++) {
416 1.9.2.2 nathanw while((bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR)
417 1.9.2.2 nathanw & BSR_SIFR_FULL) == 0)
418 1.9.2.2 nathanw delay(1);
419 1.9.2.2 nathanw
420 1.9.2.2 nathanw ed->sc_status_block[i] = le16toh(
421 1.9.2.2 nathanw bus_space_read_2(sc->sc_iot, sc->sc_ioh, SIFR));
422 1.9.2.2 nathanw }
423 1.9.2.2 nathanw }
424 1.9.2.2 nathanw
425 1.9.2.2 nathanw switch (intr_id) {
426 1.9.2.2 nathanw case ISR_DATA_TRANSFER_RDY:
427 1.9.2.2 nathanw /*
428 1.9.2.2 nathanw * Ready to do DMA, setup DMA controller and kick DASD
429 1.9.2.2 nathanw * controller to do the transfer.
430 1.9.2.2 nathanw */
431 1.9.2.2 nathanw ed = sc->sc_ed[devno];
432 1.9.2.2 nathanw if (!edc_setup_dma(sc, ed->sc_read,
433 1.9.2.2 nathanw ed->dmamap_xfer->dm_segs[0].ds_addr,
434 1.9.2.2 nathanw ed->dmamap_xfer->dm_segs[0].ds_len)) {
435 1.9.2.2 nathanw /* XXX bail out? */
436 1.9.2.2 nathanw printf("%s: edc_setup_dma() failed\n",
437 1.9.2.2 nathanw ed->sc_dev.dv_xname);
438 1.9.2.2 nathanw bus_space_write_1(sc->sc_iot, sc->sc_ioh, BCR,
439 1.9.2.2 nathanw BCR_INT_ENABLE);
440 1.9.2.2 nathanw } else {
441 1.9.2.2 nathanw /* OK, proceed with DMA */
442 1.9.2.2 nathanw bus_space_write_1(sc->sc_iot, sc->sc_ioh, BCR,
443 1.9.2.2 nathanw BCR_INT_ENABLE|BCR_DMA_ENABLE);
444 1.9.2.2 nathanw }
445 1.9.2.2 nathanw break;
446 1.9.2.2 nathanw case ISR_COMPLETED:
447 1.9.2.2 nathanw case ISR_COMPLETED_WITH_ECC:
448 1.9.2.2 nathanw case ISR_COMPLETED_RETRIES:
449 1.9.2.2 nathanw case ISR_COMPLETED_WARNING:
450 1.9.2.2 nathanw bioerror = 0;
451 1.9.2.2 nathanw break;
452 1.9.2.2 nathanw case ISR_RESET_COMPLETED:
453 1.9.2.2 nathanw case ISR_ABORT_COMPLETED:
454 1.9.2.2 nathanw /* nothing to do */
455 1.9.2.2 nathanw break;
456 1.9.2.2 nathanw default:
457 1.9.2.2 nathanw if ((sc->sc_flags & DASD_QUIET) == 0)
458 1.9.2.2 nathanw edc_dump_status_block(sc, devno, intr_id);
459 1.9.2.2 nathanw
460 1.9.2.2 nathanw bioerror = EIO;
461 1.9.2.2 nathanw break;
462 1.9.2.2 nathanw }
463 1.9.2.2 nathanw
464 1.9.2.2 nathanw /*
465 1.9.2.2 nathanw * Unless the interrupt is for Data Transfer Ready or
466 1.9.2.2 nathanw * Attention Error, finish by assertion EOI. This makes
467 1.9.2.2 nathanw * attachment aware the interrupt is processed and system
468 1.9.2.2 nathanw * is ready to accept another one.
469 1.9.2.2 nathanw */
470 1.9.2.2 nathanw if (intr_id != ISR_DATA_TRANSFER_RDY && intr_id != ISR_ATTN_ERROR)
471 1.9.2.2 nathanw edc_do_attn(sc, ATN_END_INT, devno, intr_id);
472 1.9.2.2 nathanw
473 1.9.2.2 nathanw /* If Read or Write Data, wakeup worker thread to finish it */
474 1.9.2.2 nathanw if (intr_id != ISR_DATA_TRANSFER_RDY
475 1.9.2.2 nathanw && (cmd == CMD_READ_DATA || cmd == CMD_WRITE_DATA)) {
476 1.9.2.2 nathanw sc->sc_ed[devno]->sc_error = bioerror;
477 1.9.2.2 nathanw wakeup_one(&sc->sc_ed[devno]->edc_softc);
478 1.9.2.2 nathanw }
479 1.9.2.2 nathanw
480 1.9.2.2 nathanw return (1);
481 1.9.2.2 nathanw }
482 1.9.2.2 nathanw
483 1.9.2.2 nathanw /*
484 1.9.2.2 nathanw * This follows the exact order for Attention Request as
485 1.9.2.2 nathanw * written in DASD Storage Interface Specification MC (Rev 2.2).
486 1.9.2.2 nathanw */
487 1.9.2.2 nathanw static int
488 1.9.2.2 nathanw edc_do_attn(sc, attn_type, devno, intr_id)
489 1.9.2.2 nathanw struct edc_mca_softc *sc;
490 1.9.2.2 nathanw int attn_type, devno, intr_id;
491 1.9.2.2 nathanw {
492 1.9.2.2 nathanw int tries;
493 1.9.2.2 nathanw
494 1.9.2.2 nathanw /* 1. Disable interrupts in BCR. */
495 1.9.2.2 nathanw bus_space_write_1(sc->sc_iot, sc->sc_ioh, BCR, 0);
496 1.9.2.2 nathanw
497 1.9.2.2 nathanw /*
498 1.9.2.2 nathanw * 2. Assure NOT BUSY and NO INTERRUPT PENDING, unless acknowledging
499 1.9.2.2 nathanw * a RESET COMPLETED interrupt.
500 1.9.2.2 nathanw */
501 1.9.2.2 nathanw if (intr_id != ISR_RESET_COMPLETED) {
502 1.9.2.2 nathanw for(tries=1; tries < EDC_ATTN_MAXTRIES; tries++) {
503 1.9.2.2 nathanw if ((bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR)
504 1.9.2.2 nathanw & BSR_BUSY) == 0) {
505 1.9.2.2 nathanw #ifdef DEBUG
506 1.9.2.2 nathanw if ((bus_space_read_1(sc->sc_iot, sc->sc_ioh,
507 1.9.2.2 nathanw BSR) & BSR_INT_PENDING) && intr_id)
508 1.9.2.2 nathanw panic("foobar");
509 1.9.2.2 nathanw #endif
510 1.9.2.2 nathanw break;
511 1.9.2.2 nathanw }
512 1.9.2.2 nathanw }
513 1.9.2.2 nathanw
514 1.9.2.2 nathanw if (tries == EDC_ATTN_MAXTRIES) {
515 1.9.2.2 nathanw printf("%s: edc_do_attn: timeout waiting for attachment to become available\n",
516 1.9.2.2 nathanw sc->sc_ed[devno]->sc_dev.dv_xname);
517 1.9.2.2 nathanw return (EAGAIN);
518 1.9.2.2 nathanw }
519 1.9.2.2 nathanw }
520 1.9.2.2 nathanw
521 1.9.2.2 nathanw /*
522 1.9.2.2 nathanw * 3. Write proper DEVICE NUMBER and Attention number to ATN.
523 1.9.2.2 nathanw */
524 1.9.2.2 nathanw bus_space_write_1(sc->sc_iot, sc->sc_ioh, ATN,
525 1.9.2.2 nathanw attn_type | (devno << 5));
526 1.9.2.2 nathanw
527 1.9.2.2 nathanw /*
528 1.9.2.2 nathanw * 4. Enable interrupts via BCR.
529 1.9.2.2 nathanw */
530 1.9.2.2 nathanw bus_space_write_1(sc->sc_iot, sc->sc_ioh, BCR, BCR_INT_ENABLE);
531 1.9.2.2 nathanw
532 1.9.2.2 nathanw return (0);
533 1.9.2.2 nathanw }
534 1.9.2.2 nathanw
535 1.9.2.2 nathanw /*
536 1.9.2.2 nathanw * Wait until command is processed, timeout after 'secs' seconds.
537 1.9.2.2 nathanw * We use mono_time, since we don't need actual RTC, just time
538 1.9.2.2 nathanw * interval.
539 1.9.2.2 nathanw */
540 1.9.2.2 nathanw static int
541 1.9.2.2 nathanw edc_cmd_wait(sc, devno, secs, poll)
542 1.9.2.2 nathanw struct edc_mca_softc *sc;
543 1.9.2.2 nathanw int devno, secs, poll;
544 1.9.2.2 nathanw {
545 1.9.2.2 nathanw int val, delayed;
546 1.9.2.2 nathanw
547 1.9.2.2 nathanw delayed = 0;
548 1.9.2.2 nathanw do {
549 1.9.2.2 nathanw val = bus_space_read_1(sc->sc_iot,sc->sc_ioh, BSR);
550 1.9.2.2 nathanw if ((val & BSR_CMD_INPROGRESS) == 0)
551 1.9.2.2 nathanw break;
552 1.9.2.2 nathanw
553 1.9.2.2 nathanw if (poll && (val & BSR_INTR))
554 1.9.2.2 nathanw goto out;
555 1.9.2.2 nathanw
556 1.9.2.2 nathanw if (secs == 0)
557 1.9.2.2 nathanw break;
558 1.9.2.2 nathanw
559 1.9.2.2 nathanw delay(1);
560 1.9.2.2 nathanw
561 1.9.2.2 nathanw /*
562 1.9.2.2 nathanw * This is not as accurate as checking mono_time, but
563 1.9.2.2 nathanw * it works with hardclock interrupts disabled too.
564 1.9.2.2 nathanw */
565 1.9.2.2 nathanw delayed++;
566 1.9.2.2 nathanw if (delayed == 1000000) {
567 1.9.2.2 nathanw delayed = 0;
568 1.9.2.2 nathanw secs--;
569 1.9.2.2 nathanw }
570 1.9.2.2 nathanw #if 0
571 1.9.2.2 nathanw if (delayed % 1000)
572 1.9.2.2 nathanw printf("looping ...");
573 1.9.2.2 nathanw #endif
574 1.9.2.2 nathanw } while(1);
575 1.9.2.2 nathanw
576 1.9.2.2 nathanw if (secs == 0 &&
577 1.9.2.2 nathanw bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR) & BSR_CMD_INPROGRESS){
578 1.9.2.2 nathanw printf("%s: timed out waiting for previous cmd to finish\n",
579 1.9.2.2 nathanw sc->sc_ed[devno]->sc_dev.dv_xname);
580 1.9.2.2 nathanw return (EAGAIN);
581 1.9.2.2 nathanw }
582 1.9.2.2 nathanw
583 1.9.2.2 nathanw out:
584 1.9.2.2 nathanw return (0);
585 1.9.2.2 nathanw }
586 1.9.2.2 nathanw
587 1.9.2.2 nathanw int
588 1.9.2.2 nathanw edc_run_cmd(sc, cmd, devno, cmd_args, cmd_len, async, poll)
589 1.9.2.2 nathanw struct edc_mca_softc *sc;
590 1.9.2.2 nathanw int cmd;
591 1.9.2.2 nathanw int devno;
592 1.9.2.2 nathanw u_int16_t cmd_args[];
593 1.9.2.2 nathanw int cmd_len, async, poll;
594 1.9.2.2 nathanw {
595 1.9.2.2 nathanw int i, error, tries;
596 1.9.2.2 nathanw u_int16_t cmd0;
597 1.9.2.2 nathanw
598 1.9.2.2 nathanw /*
599 1.9.2.2 nathanw * If there has been an asynchronous command executed, first wait for it
600 1.9.2.2 nathanw * to finish.
601 1.9.2.2 nathanw */
602 1.9.2.2 nathanw if (sc->sc_cmd_async) {
603 1.9.2.2 nathanw /* Wait maximum 15s */
604 1.9.2.2 nathanw if (edc_cmd_wait(sc, devno, 15, 0))
605 1.9.2.2 nathanw return (EAGAIN); /* Busy */
606 1.9.2.2 nathanw
607 1.9.2.2 nathanw sc->sc_cmd_async = 0;
608 1.9.2.2 nathanw }
609 1.9.2.2 nathanw
610 1.9.2.2 nathanw /* Do Attention Request for Command Request. */
611 1.9.2.2 nathanw if ((error = edc_do_attn(sc, ATN_CMD_REQ, devno, 0)))
612 1.9.2.2 nathanw return (error);
613 1.9.2.2 nathanw
614 1.9.2.2 nathanw /*
615 1.9.2.2 nathanw * Construct the command. The bits are like this:
616 1.9.2.2 nathanw *
617 1.9.2.2 nathanw * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
618 1.9.2.2 nathanw * \_/ 0 0 1 0 \__/ \_____/
619 1.9.2.2 nathanw * \ \__________/ \ \_ Command Code (see CMD_*)
620 1.9.2.2 nathanw * \ \ \__ Device: 0 common, 7 controller
621 1.9.2.2 nathanw * \ \__ Options: reserved, bit 10=cache bypass bit
622 1.9.2.2 nathanw * \_ Type: 00=2B, 01=4B, 10 and 11 reserved
623 1.9.2.2 nathanw *
624 1.9.2.2 nathanw * We always use device 0 or 1, so difference is made only by Command
625 1.9.2.2 nathanw * Code, Command Options and command length.
626 1.9.2.2 nathanw */
627 1.9.2.2 nathanw cmd0 = ((cmd_len == 4) ? (CIFR_LONG_CMD) : 0)
628 1.9.2.2 nathanw | (devno << 5)
629 1.9.2.2 nathanw | (cmd_args[0] << 8) | cmd;
630 1.9.2.2 nathanw cmd_args[0] = cmd0;
631 1.9.2.2 nathanw
632 1.9.2.2 nathanw /*
633 1.9.2.2 nathanw * Write word of CMD to the CIFR. This sets "Command
634 1.9.2.2 nathanw * Interface Register Full (CMD IN)" in BSR. Once the attachment
635 1.9.2.2 nathanw * detects it, it reads the word and clears CMD IN.
636 1.9.2.2 nathanw */
637 1.9.2.2 nathanw for(i=0; i < cmd_len; i++) {
638 1.9.2.2 nathanw bus_space_write_2(sc->sc_iot, sc->sc_ioh, CIFR,
639 1.9.2.2 nathanw htole16(cmd_args[i]));
640 1.9.2.2 nathanw
641 1.9.2.2 nathanw /*
642 1.9.2.2 nathanw * Wait until CMD IN is cleared. The 1ms delay for polling
643 1.9.2.2 nathanw * case is necessary, otherwise e.g. system dump gets stuck
644 1.9.2.2 nathanw * soon. Quirky hw ?
645 1.9.2.2 nathanw */
646 1.9.2.2 nathanw tries = 0;
647 1.9.2.2 nathanw while(bus_space_read_1(sc->sc_iot, sc->sc_ioh, BSR) & BSR_CIFR_FULL)
648 1.9.2.2 nathanw delay(poll ? 1000 : 1);
649 1.9.2.2 nathanw }
650 1.9.2.2 nathanw
651 1.9.2.2 nathanw /*
652 1.9.2.2 nathanw * Attachment is now executing the command. Unless we are executing
653 1.9.2.2 nathanw * command asynchronously, wait until it finishes.
654 1.9.2.2 nathanw */
655 1.9.2.2 nathanw if (async) {
656 1.9.2.2 nathanw sc->sc_cmd_async = 1;
657 1.9.2.2 nathanw return (0);
658 1.9.2.2 nathanw }
659 1.9.2.2 nathanw
660 1.9.2.2 nathanw /* Wait for command to complete, but maximum 15 seconds. */
661 1.9.2.2 nathanw if (edc_cmd_wait(sc, devno, 15, poll))
662 1.9.2.2 nathanw return (EAGAIN);
663 1.9.2.2 nathanw
664 1.9.2.2 nathanw /* If polling, call edc_intr() explicitly */
665 1.9.2.2 nathanw if (poll) {
666 1.9.2.2 nathanw edc_intr(sc);
667 1.9.2.2 nathanw
668 1.9.2.2 nathanw /*
669 1.9.2.2 nathanw * If got attention id DATA TRANSFER READY, wait for
670 1.9.2.2 nathanw * the transfer to finish.
671 1.9.2.2 nathanw */
672 1.9.2.2 nathanw if (sc->sc_ed[devno]->sc_error == 0
673 1.9.2.2 nathanw && (cmd == CMD_READ_DATA || cmd == CMD_WRITE_DATA)) {
674 1.9.2.2 nathanw if (edc_cmd_wait(sc, devno, 15, 1))
675 1.9.2.2 nathanw return (EAGAIN);
676 1.9.2.2 nathanw edc_intr(sc);
677 1.9.2.2 nathanw }
678 1.9.2.2 nathanw
679 1.9.2.2 nathanw if (edc_cmd_wait(sc, devno, 15, 0))
680 1.9.2.2 nathanw return (EAGAIN);
681 1.9.2.2 nathanw }
682 1.9.2.2 nathanw
683 1.9.2.2 nathanw /* Check if the command completed successfully; if not, return error */
684 1.9.2.2 nathanw switch(SB_GET_CMD_STATUS(sc->sc_ed[devno]->sc_status_block)) {
685 1.9.2.2 nathanw case ISR_COMPLETED:
686 1.9.2.2 nathanw case ISR_COMPLETED_WITH_ECC:
687 1.9.2.2 nathanw case ISR_COMPLETED_RETRIES:
688 1.9.2.2 nathanw case ISR_COMPLETED_WARNING:
689 1.9.2.2 nathanw return (0);
690 1.9.2.2 nathanw default:
691 1.9.2.2 nathanw return (EIO);
692 1.9.2.2 nathanw }
693 1.9.2.2 nathanw }
694 1.9.2.2 nathanw
695 1.9.2.2 nathanw static int
696 1.9.2.2 nathanw edc_setup_dma(sc, isread, phys, cnt)
697 1.9.2.2 nathanw struct edc_mca_softc *sc;
698 1.9.2.2 nathanw int isread;
699 1.9.2.2 nathanw bus_addr_t phys;
700 1.9.2.2 nathanw bus_size_t cnt;
701 1.9.2.2 nathanw {
702 1.9.2.2 nathanw /* XXX magic constants, should be moved to device-independant location*/
703 1.9.2.2 nathanw /* The exact sequence to setup MCA DMA controller is taken from Minix */
704 1.9.2.2 nathanw
705 1.9.2.2 nathanw bus_space_write_1(sc->sc_iot, sc->sc_dmaextcmdh, 0,
706 1.9.2.2 nathanw 0x90 + sc->sc_drq);
707 1.9.2.2 nathanw /* Disable access to dma channel */
708 1.9.2.2 nathanw bus_space_write_1(sc->sc_iot, sc->sc_dmaextcmdh, 0,
709 1.9.2.2 nathanw 0x20 + sc->sc_drq);
710 1.9.2.2 nathanw /* Clear the address byte pointer */
711 1.9.2.2 nathanw bus_space_write_1(sc->sc_iot, sc->sc_dmaexech, 0,
712 1.9.2.2 nathanw (phys >> 0) & 0xff); /* address bits 0..7 */
713 1.9.2.2 nathanw bus_space_write_1(sc->sc_iot, sc->sc_dmaexech, 0,
714 1.9.2.2 nathanw (phys >> 8) & 0xff); /* address bits 8..15 */
715 1.9.2.2 nathanw bus_space_write_1(sc->sc_iot, sc->sc_dmaexech, 0,
716 1.9.2.2 nathanw (phys >> 16) & 0xff); /* address bits 16..23 */
717 1.9.2.2 nathanw bus_space_write_1(sc->sc_iot, sc->sc_dmaextcmdh, 0,
718 1.9.2.2 nathanw 0x40 + sc->sc_drq);
719 1.9.2.2 nathanw /* Clear the count byte pointer */
720 1.9.2.2 nathanw bus_space_write_1(sc->sc_iot, sc->sc_dmaexech, 0,
721 1.9.2.2 nathanw ((cnt - 1) >> 0) & 0xff); /* count bits 0..7 */
722 1.9.2.2 nathanw bus_space_write_1(sc->sc_iot, sc->sc_dmaexech, 0,
723 1.9.2.2 nathanw ((cnt - 1) >> 8) & 0xff); /* count bits 8..15 */
724 1.9.2.2 nathanw bus_space_write_1(sc->sc_iot, sc->sc_dmaextcmdh, 0,
725 1.9.2.2 nathanw 0x70 + sc->sc_drq);
726 1.9.2.2 nathanw /* Set the transfer mode */
727 1.9.2.2 nathanw bus_space_write_1(sc->sc_iot, sc->sc_dmaexech, 0,
728 1.9.2.2 nathanw (isread) ? 0x4C : 0x44);
729 1.9.2.2 nathanw bus_space_write_1(sc->sc_iot, sc->sc_dmaextcmdh, 0,
730 1.9.2.2 nathanw 0xA0 + sc->sc_drq);
731 1.9.2.2 nathanw /* Enable access to dma channel */
732 1.9.2.2 nathanw
733 1.9.2.2 nathanw return (1);
734 1.9.2.2 nathanw }
735 1.9.2.2 nathanw
736 1.9.2.2 nathanw static const char * const edc_commands[] = {
737 1.9.2.2 nathanw "Invalid Command",
738 1.9.2.2 nathanw "Read Data",
739 1.9.2.2 nathanw "Write Data",
740 1.9.2.2 nathanw "Read Verify",
741 1.9.2.2 nathanw "Write with Verify",
742 1.9.2.2 nathanw "Seek",
743 1.9.2.2 nathanw "Park Head",
744 1.9.2.2 nathanw "Get Command Complete Status",
745 1.9.2.2 nathanw "Get Device Status",
746 1.9.2.2 nathanw "Get Device Configuration",
747 1.9.2.2 nathanw "Get POS Information",
748 1.9.2.2 nathanw "Translate RBA",
749 1.9.2.2 nathanw "Write Attachment Buffer",
750 1.9.2.2 nathanw "Read Attachment Buffer",
751 1.9.2.2 nathanw "Run Diagnostic Test",
752 1.9.2.2 nathanw "Get Diagnostic Status Block",
753 1.9.2.2 nathanw "Get MFG Header",
754 1.9.2.2 nathanw "Format Unit",
755 1.9.2.2 nathanw "Format Prepare",
756 1.9.2.2 nathanw "Set MAX RBA",
757 1.9.2.2 nathanw "Set Power Saving Mode",
758 1.9.2.2 nathanw "Power Conservation Command",
759 1.9.2.2 nathanw };
760 1.9.2.2 nathanw
761 1.9.2.2 nathanw static const char * const edc_cmd_status[256] = {
762 1.9.2.2 nathanw "Reserved",
763 1.9.2.2 nathanw "Command completed successfully",
764 1.9.2.2 nathanw "Reserved",
765 1.9.2.2 nathanw "Command completed successfully with ECC applied",
766 1.9.2.2 nathanw "Reserved",
767 1.9.2.2 nathanw "Command completed successfully with retries",
768 1.9.2.2 nathanw "Format Command partially completed", /* Status available */
769 1.9.2.2 nathanw "Command completed successfully with ECC and retries",
770 1.9.2.2 nathanw "Command completed with Warning", /* Command Error is available */
771 1.9.2.2 nathanw "Aborted",
772 1.9.2.2 nathanw "Reset completed",
773 1.9.2.2 nathanw "Data Transfer Ready", /* No Status Block available */
774 1.9.2.2 nathanw "Command terminated with failure", /* Device Error is available */
775 1.9.2.2 nathanw "DMA Error", /* Retry entire command as recovery */
776 1.9.2.2 nathanw "Command Block Error",
777 1.9.2.2 nathanw "Attention Error (Illegal Attention Code)",
778 1.9.2.2 nathanw /* 0x14 - 0xff reserved */
779 1.9.2.2 nathanw };
780 1.9.2.2 nathanw
781 1.9.2.2 nathanw static const char * const edc_cmd_error[256] = {
782 1.9.2.2 nathanw "No Error",
783 1.9.2.2 nathanw "Invalid parameter in the command block",
784 1.9.2.2 nathanw "Reserved",
785 1.9.2.2 nathanw "Command not supported",
786 1.9.2.2 nathanw "Command Aborted per request",
787 1.9.2.2 nathanw "Reserved",
788 1.9.2.2 nathanw "Command rejected", /* Attachment diagnostic failure */
789 1.9.2.2 nathanw "Format Rejected", /* Prepare Format command is required */
790 1.9.2.2 nathanw "Format Error (Primary Map is not readable)",
791 1.9.2.2 nathanw "Format Error (Secondary map is not readable)",
792 1.9.2.2 nathanw "Format Error (Diagnostic Failure)",
793 1.9.2.2 nathanw "Format Warning (Secondary Map Overflow)",
794 1.9.2.2 nathanw "Reserved"
795 1.9.2.2 nathanw "Format Error (Host Checksum Error)",
796 1.9.2.2 nathanw "Reserved",
797 1.9.2.2 nathanw "Format Warning (Push table overflow)",
798 1.9.2.2 nathanw "Format Warning (More pushes than allowed)",
799 1.9.2.2 nathanw "Reserved",
800 1.9.2.2 nathanw "Format Warning (Error during verifying)",
801 1.9.2.2 nathanw "Invalid device number for the command",
802 1.9.2.2 nathanw /* 0x14-0xff reserved */
803 1.9.2.2 nathanw };
804 1.9.2.2 nathanw
805 1.9.2.2 nathanw static const char * const edc_dev_errors[] = {
806 1.9.2.2 nathanw "No Error",
807 1.9.2.2 nathanw "Seek Fault", /* Device report */
808 1.9.2.2 nathanw "Interface Fault (Parity, Attn, or Cmd Complete Error)",
809 1.9.2.2 nathanw "Block not found (ID not found)",
810 1.9.2.2 nathanw "Block not found (AM not found)",
811 1.9.2.2 nathanw "Data ECC Error (hard error)",
812 1.9.2.2 nathanw "ID CRC Error",
813 1.9.2.2 nathanw "RBA Out of Range",
814 1.9.2.2 nathanw "Reserved",
815 1.9.2.2 nathanw "Defective Block",
816 1.9.2.2 nathanw "Reserved",
817 1.9.2.2 nathanw "Selection Error",
818 1.9.2.2 nathanw "Reserved",
819 1.9.2.2 nathanw "Write Fault",
820 1.9.2.2 nathanw "No index or sector pulse",
821 1.9.2.2 nathanw "Device Not Ready",
822 1.9.2.2 nathanw "Seek Error", /* Attachment report */
823 1.9.2.2 nathanw "Bad Format",
824 1.9.2.2 nathanw "Volume Overflow",
825 1.9.2.2 nathanw "No Data AM Found",
826 1.9.2.2 nathanw "Block not found (No ID AM or ID CRC error occurred)",
827 1.9.2.2 nathanw "Reserved",
828 1.9.2.2 nathanw "Reserved",
829 1.9.2.2 nathanw "No ID found on track (ID search)",
830 1.9.2.2 nathanw /* 0x19 - 0xff reserved */
831 1.9.2.2 nathanw };
832 1.9.2.2 nathanw
833 1.9.2.2 nathanw static void
834 1.9.2.2 nathanw edc_dump_status_block(sc, devno, intr_id)
835 1.9.2.2 nathanw struct edc_mca_softc *sc;
836 1.9.2.2 nathanw int devno, intr_id;
837 1.9.2.2 nathanw {
838 1.9.2.2 nathanw struct ed_softc *ed = sc->sc_ed[devno];
839 1.9.2.2 nathanw printf("%s: Command: %s, Status: %s\n",
840 1.9.2.2 nathanw ed->sc_dev.dv_xname,
841 1.9.2.2 nathanw edc_commands[ed->sc_status_block[0] & 0x1f],
842 1.9.2.2 nathanw edc_cmd_status[SB_GET_CMD_STATUS(ed->sc_status_block)]
843 1.9.2.2 nathanw );
844 1.9.2.2 nathanw printf("%s: # left blocks: %u, last processed RBA: %u\n",
845 1.9.2.2 nathanw ed->sc_dev.dv_xname,
846 1.9.2.2 nathanw ed->sc_status_block[SB_RESBLKCNT_IDX],
847 1.9.2.2 nathanw (ed->sc_status_block[5] << 16) | ed->sc_status_block[4]);
848 1.9.2.2 nathanw
849 1.9.2.2 nathanw if (intr_id == ISR_COMPLETED_WARNING) {
850 1.9.2.2 nathanw printf("%s: Command Error Code: %s\n",
851 1.9.2.2 nathanw ed->sc_dev.dv_xname,
852 1.9.2.2 nathanw edc_cmd_error[ed->sc_status_block[1] & 0xff]);
853 1.9.2.2 nathanw }
854 1.9.2.2 nathanw
855 1.9.2.2 nathanw if (intr_id == ISR_CMD_FAILED) {
856 1.9.2.2 nathanw char buf[100];
857 1.9.2.2 nathanw
858 1.9.2.2 nathanw printf("%s: Device Error Code: %s\n",
859 1.9.2.2 nathanw ed->sc_dev.dv_xname,
860 1.9.2.2 nathanw edc_dev_errors[ed->sc_status_block[2] & 0xff]);
861 1.9.2.2 nathanw bitmask_snprintf((ed->sc_status_block[2] & 0xff00) >> 8,
862 1.9.2.2 nathanw "\20"
863 1.9.2.2 nathanw "\01SeekOrCmdComplete"
864 1.9.2.2 nathanw "\02Track0Flag"
865 1.9.2.2 nathanw "\03WriteFault"
866 1.9.2.2 nathanw "\04Selected"
867 1.9.2.2 nathanw "\05Ready"
868 1.9.2.2 nathanw "\06Reserved0"
869 1.9.2.2 nathanw "\07STANDBY"
870 1.9.2.2 nathanw "\010Reserved0",
871 1.9.2.2 nathanw buf, sizeof(buf));
872 1.9.2.2 nathanw printf("%s: Device Status: %s\n",
873 1.9.2.2 nathanw ed->sc_dev.dv_xname, buf);
874 1.9.2.2 nathanw }
875 1.9.2.2 nathanw }
876