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