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