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