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