1 /* $NetBSD: xy.c,v 1.89 2009/05/12 13:22:28 cegger Exp $ */
5 * Copyright (c) 1995 Charles D. Cranor
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Charles D. Cranor.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 * x y . c x y l o g i c s 4 5 0 / 4 5 1 s m d d r i v e r
38 * author: Chuck Cranor <chuck@ccrc.wustl.edu>
40 * references: [1] Xylogics Model 753 User's Manual
41 * part number: 166-753-001, Revision B, May 21, 1988.
42 * "Your Partner For Performance"
43 * [2] other NetBSD disk device drivers
44 * [3] Xylogics Model 450 User's Manual
45 * part number: 166-017-001, Revision B, 1983.
46 * [4] Addendum to Xylogics Model 450 Disk Controller User's
48 * [5] The 451 Controller, Rev. B3, September 2, 1986.
49 * [6] David Jones <dej@achilles.net>'s unfinished 450/451 driver
53 #include <sys/cdefs.h>
54 __KERNEL_RCSID(0, "$NetBSD: xy.c,v 1.89 2009/05/12 13:22:28 cegger Exp $");
56 #undef XYC_DEBUG /* full debug */
57 #undef XYC_DIAG /* extra sanity checks */
58 #if defined(DIAGNOSTIC) && !defined(XYC_DIAG)
59 #define XYC_DIAG /* link in with master DIAG option */
62 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/kernel.h>
68 #include <sys/ioctl.h>
72 #include <sys/malloc.h>
73 #include <sys/device.h>
74 #include <sys/disklabel.h>
76 #include <sys/syslog.h>
77 #include <sys/dkbad.h>
79 #include <sys/kauth.h>
84 #if defined(__sparc__) || defined(sun3)
85 #include <dev/sun/disklabel.h>
88 #include <dev/vme/vmereg.h>
89 #include <dev/vme/vmevar.h>
91 #include <dev/vme/xyreg.h>
92 #include <dev/vme/xyvar.h>
93 #include <dev/vme/xio.h>
102 * XYC_GO: start iopb ADDR (DVMA addr in a u_long) on XYC
104 #define XYC_GO(XYC, ADDR) { \
105 u_long addr = (u_long)ADDR; \
106 (XYC)->xyc_addr_lo = ((addr) & 0xff); \
107 (addr) = ((addr) >> 8); \
108 (XYC)->xyc_addr_hi = ((addr) & 0xff); \
109 (addr) = ((addr) >> 8); \
110 (XYC)->xyc_reloc_lo = ((addr) & 0xff); \
111 (addr) = ((addr) >> 8); \
112 (XYC)->xyc_reloc_hi = (addr); \
113 (XYC)->xyc_csr = XYC_GBSY; /* go! */ \
117 * XYC_DONE: don't need IORQ, get error code and free (done after xyc_cmd)
120 #define XYC_DONE(SC,ER) { \
121 if ((ER) == XY_ERR_AOK) { \
122 (ER) = (SC)->ciorq->errnum; \
123 (SC)->ciorq->mode = XY_SUB_FREE; \
124 wakeup((SC)->ciorq); \
129 * XYC_ADVANCE: advance iorq's pointers by a number of sectors
132 #define XYC_ADVANCE(IORQ, N) { \
134 (IORQ)->sectcnt -= (N); \
135 (IORQ)->blockno += (N); \
136 (IORQ)->dbuf += ((N)*XYFM_BPS); \
141 * note - addresses you can sleep on:
142 * [1] & of xy_softc's "state" (waiting for a chance to attach a drive)
143 * [2] & an iorq (waiting for an XY_SUB_WAIT iorq to finish)
148 * function prototypes
149 * "xyc_*" functions are internal, all others are external interfaces
152 extern int pil_to_vme
[]; /* from obio.c */
155 struct xy_iopb
*xyc_chain(struct xyc_softc
*, struct xy_iorq
*);
156 int xyc_cmd(struct xyc_softc
*, int, int, int, int, int, char *, int);
157 const char *xyc_e2str(int);
158 int xyc_entoact(int);
159 int xyc_error(struct xyc_softc
*, struct xy_iorq
*,
160 struct xy_iopb
*, int);
161 int xyc_ioctlcmd(struct xy_softc
*, dev_t dev
, struct xd_iocmd
*);
162 void xyc_perror(struct xy_iorq
*, struct xy_iopb
*, int);
163 int xyc_piodriver(struct xyc_softc
*, struct xy_iorq
*);
164 int xyc_remove_iorq(struct xyc_softc
*);
165 int xyc_reset(struct xyc_softc
*, int, struct xy_iorq
*, int,
167 inline void xyc_rqinit(struct xy_iorq
*, struct xyc_softc
*,
168 struct xy_softc
*, int, u_long
, int,
169 void *, struct buf
*);
170 void xyc_rqtopb(struct xy_iorq
*, struct xy_iopb
*, int, int);
171 void xyc_start(struct xyc_softc
*, struct xy_iorq
*);
172 int xyc_startbuf(struct xyc_softc
*, struct xy_softc
*, struct buf
*);
173 int xyc_submit_iorq(struct xyc_softc
*, struct xy_iorq
*, int);
174 void xyc_tick(void *);
175 int xyc_unbusy(struct xyc
*, int);
176 void xyc_xyreset(struct xyc_softc
*, struct xy_softc
*);
177 int xy_dmamem_alloc(bus_dma_tag_t
, bus_dmamap_t
, bus_dma_segment_t
*,
178 int *, bus_size_t
, void **, bus_addr_t
*);
179 void xy_dmamem_free(bus_dma_tag_t
, bus_dmamap_t
, bus_dma_segment_t
*,
180 int, bus_size_t
, void *);
182 /* machine interrupt hook */
186 int xycmatch(device_t
, cfdata_t
, void *);
187 void xycattach(device_t
, device_t
, void *);
188 int xymatch(device_t
, cfdata_t
, void *);
189 void xyattach(device_t
, device_t
, void *);
190 static int xyc_probe(void *, bus_space_tag_t
, bus_space_handle_t
);
192 static void xydummystrat(struct buf
*);
193 int xygetdisklabel(struct xy_softc
*, void *);
196 * cfattach's: device driver interface to autoconfig
199 CFATTACH_DECL(xyc
, sizeof(struct xyc_softc
),
200 xycmatch
, xycattach
, NULL
, NULL
);
202 CFATTACH_DECL(xy
, sizeof(struct xy_softc
),
203 xymatch
, xyattach
, NULL
, NULL
);
205 extern struct cfdriver xy_cd
;
207 dev_type_open(xyopen
);
208 dev_type_close(xyclose
);
209 dev_type_read(xyread
);
210 dev_type_write(xywrite
);
211 dev_type_ioctl(xyioctl
);
212 dev_type_strategy(xystrategy
);
213 dev_type_dump(xydump
);
214 dev_type_size(xysize
);
216 const struct bdevsw xy_bdevsw
= {
217 xyopen
, xyclose
, xystrategy
, xyioctl
, xydump
, xysize
, D_DISK
220 const struct cdevsw xy_cdevsw
= {
221 xyopen
, xyclose
, xyread
, xywrite
, xyioctl
,
222 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_DISK
225 struct xyc_attach_args
{ /* this is the "aux" args to xyattach */
226 int driveno
; /* unit number */
227 int fullmode
; /* submit mode */
228 int booting
; /* are we booting or not? */
235 struct dkdriver xydkdriver
= { xystrategy
};
238 * start: disk label fix code (XXX)
241 static void *xy_labeldata
;
244 xydummystrat(struct buf
*bp
)
246 if (bp
->b_bcount
!= XYFM_BPS
)
247 panic("xydummystrat");
248 memcpy(bp
->b_data
, xy_labeldata
, XYFM_BPS
);
249 bp
->b_oflags
|= BO_DONE
;
250 bp
->b_cflags
&= ~BC_BUSY
;
254 xygetdisklabel(struct xy_softc
*xy
, void *b
)
257 #if defined(__sparc__) || defined(sun3)
258 struct sun_disklabel
*sdl
;
261 /* We already have the label data in `b'; setup for dummy strategy */
264 /* Required parameter for readdisklabel() */
265 xy
->sc_dk
.dk_label
->d_secsize
= XYFM_BPS
;
267 err
= readdisklabel(MAKEDISKDEV(0, device_unit(&xy
->sc_dev
), RAW_PART
),
269 xy
->sc_dk
.dk_label
, xy
->sc_dk
.dk_cpulabel
);
271 printf("%s: %s\n", device_xname(&xy
->sc_dev
), err
);
275 #if defined(__sparc__) || defined(sun3)
276 /* Ok, we have the label; fill in `pcyl' if there's SunOS magic */
277 sdl
= (struct sun_disklabel
*)xy
->sc_dk
.dk_cpulabel
->cd_block
;
278 if (sdl
->sl_magic
== SUN_DKMAGIC
) {
279 xy
->pcyl
= sdl
->sl_pcylinders
;
283 printf("%s: WARNING: no `pcyl' in disk label.\n",
284 device_xname(&xy
->sc_dev
));
285 xy
->pcyl
= xy
->sc_dk
.dk_label
->d_ncylinders
+
286 xy
->sc_dk
.dk_label
->d_acylinders
;
287 printf("%s: WARNING: guessing pcyl=%d (ncyl+acyl)\n",
288 device_xname(&xy
->sc_dev
), xy
->pcyl
);
291 xy
->ncyl
= xy
->sc_dk
.dk_label
->d_ncylinders
;
292 xy
->acyl
= xy
->sc_dk
.dk_label
->d_acylinders
;
293 xy
->nhead
= xy
->sc_dk
.dk_label
->d_ntracks
;
294 xy
->nsect
= xy
->sc_dk
.dk_label
->d_nsectors
;
295 xy
->sectpercyl
= xy
->nhead
* xy
->nsect
;
296 xy
->sc_dk
.dk_label
->d_secsize
= XYFM_BPS
; /* not handled by
302 * end: disk label fix code (XXX)
306 * Shorthand for allocating, mapping and loading a DMA buffer
309 xy_dmamem_alloc(bus_dma_tag_t tag
, bus_dmamap_t map
, bus_dma_segment_t
*seg
, int *nsegp
, bus_size_t len
, void * *kvap
, bus_addr_t
*dmap
)
314 if ((error
= bus_dmamem_alloc(tag
, len
, 0, 0,
315 seg
, 1, &nseg
, BUS_DMA_NOWAIT
)) != 0) {
319 if ((error
= bus_dmamem_map(tag
, seg
, nseg
,
321 BUS_DMA_NOWAIT
|BUS_DMA_COHERENT
)) != 0) {
322 bus_dmamem_free(tag
, seg
, nseg
);
326 if ((error
= bus_dmamap_load(tag
, map
, *kvap
, len
, NULL
,
327 BUS_DMA_NOWAIT
)) != 0) {
328 bus_dmamem_unmap(tag
, *kvap
, len
);
329 bus_dmamem_free(tag
, seg
, nseg
);
333 *dmap
= map
->dm_segs
[0].ds_addr
;
339 xy_dmamem_free(bus_dma_tag_t tag
, bus_dmamap_t map
, bus_dma_segment_t
*seg
, int nseg
, bus_size_t len
, void * kva
)
342 bus_dmamap_unload(tag
, map
);
343 bus_dmamem_unmap(tag
, kva
, len
);
344 bus_dmamem_free(tag
, seg
, nseg
);
349 * a u t o c o n f i g f u n c t i o n s
353 * xycmatch: determine if xyc is present or not. we do a
354 * soft reset to detect the xyc.
357 xyc_probe(void *arg
, bus_space_tag_t tag
, bus_space_handle_t handle
)
359 struct xyc
*xyc
= (void *)handle
; /* XXX */
361 return ((xyc_unbusy(xyc
, XYC_RESETUSEC
) != XY_ERR_FAIL
) ? 0 : EIO
);
364 int xycmatch(parent
, cf
, aux
)
369 struct vme_attach_args
*va
= aux
;
370 vme_chipset_tag_t ct
= va
->va_vct
;
374 mod
= VME_AM_A16
| VME_AM_MBO
| VME_AM_SUPER
| VME_AM_DATA
;
375 if (vme_space_alloc(ct
, va
->r
[0].offset
, sizeof(struct xyc
), mod
))
378 error
= vme_probe(ct
, va
->r
[0].offset
, sizeof(struct xyc
),
379 mod
, VME_D16
, xyc_probe
, 0);
380 vme_space_free(va
->va_vct
, va
->r
[0].offset
, sizeof(struct xyc
), mod
);
386 * xycattach: attach controller
389 xycattach(device_t parent
, device_t self
, void *aux
)
391 struct xyc_softc
*xyc
= device_private(self
);
392 struct vme_attach_args
*va
= aux
;
393 vme_chipset_tag_t ct
= va
->va_vct
;
395 bus_space_handle_t bh
;
396 vme_intr_handle_t ih
;
398 struct xyc_attach_args xa
;
400 bus_dma_segment_t seg
;
405 /* get addressing and intr level stuff from autoconfig and load it
406 * into our xyc_softc. */
408 mod
= VME_AM_A16
| VME_AM_MBO
| VME_AM_SUPER
| VME_AM_DATA
;
410 if (vme_space_alloc(ct
, va
->r
[0].offset
, sizeof(struct xyc
), mod
))
411 panic("xyc: vme alloc");
413 if (vme_space_map(ct
, va
->r
[0].offset
, sizeof(struct xyc
),
414 mod
, VME_D16
, 0, &bt
, &bh
, &resc
) != 0)
415 panic("xyc: vme_map");
417 xyc
->xyc
= (struct xyc
*) bh
; /* XXX */
418 xyc
->ipl
= va
->ilevel
;
419 xyc
->vector
= va
->ivector
;
420 xyc
->no_ols
= 0; /* XXX should be from config */
422 for (lcv
= 0; lcv
< XYC_MAXDEV
; lcv
++)
423 xyc
->sc_drives
[lcv
] = (struct xy_softc
*) 0;
426 * allocate and zero buffers
427 * check boundaries of the KVA's ... all IOPBs must reside in
428 * the same 64K region.
431 /* Get DMA handle for misc. transfers */
432 if ((error
= vme_dmamap_create(
433 ct
, /* VME chip tag */
435 VME_AM_A24
, /* address modifier */
436 VME_D16
, /* data size */
439 MAXPHYS
, /* maxsegsz */
442 &xyc
->auxmap
)) != 0) {
444 aprint_error_dev(&xyc
->sc_dev
, "DMA buffer map create error %d\n",
449 /* Get DMA handle for mapping iorq descriptors */
450 if ((error
= vme_dmamap_create(
451 ct
, /* VME chip tag */
452 XYC_MAXIOPB
* sizeof(struct xy_iopb
),
453 VME_AM_A24
, /* address modifier */
454 VME_D16
, /* data size */
457 XYC_MAXIOPB
* sizeof(struct xy_iopb
),
458 64*1024, /* boundary */
460 &xyc
->iopmap
)) != 0) {
462 aprint_error_dev(&xyc
->sc_dev
, "DMA buffer map create error %d\n",
467 /* Get DMA buffer for iorq descriptors */
468 if ((error
= xy_dmamem_alloc(xyc
->dmatag
, xyc
->iopmap
, &seg
, &rseg
,
469 XYC_MAXIOPB
* sizeof(struct xy_iopb
),
470 (void **)&xyc
->iopbase
,
472 aprint_error_dev(&xyc
->sc_dev
, "DMA buffer alloc error %d\n",
476 xyc
->dvmaiopb
= (struct xy_iopb
*)(u_long
)BUS_ADDR_PADDR(busaddr
);
478 memset(xyc
->iopbase
, 0, XYC_MAXIOPB
* sizeof(struct xy_iopb
));
480 xyc
->reqs
= (struct xy_iorq
*)
481 malloc(XYC_MAXIOPB
* sizeof(struct xy_iorq
),
482 M_DEVBUF
, M_NOWAIT
|M_ZERO
);
483 if (xyc
->reqs
== NULL
)
487 * init iorq to iopb pointers, and non-zero fields in the
488 * iopb which never change.
491 for (lcv
= 0; lcv
< XYC_MAXIOPB
; lcv
++) {
492 xyc
->xy_chain
[lcv
] = NULL
;
493 xyc
->reqs
[lcv
].iopb
= &xyc
->iopbase
[lcv
];
494 xyc
->reqs
[lcv
].dmaiopb
= &xyc
->dvmaiopb
[lcv
];
495 xyc
->iopbase
[lcv
].asr
= 1; /* always the same */
496 xyc
->iopbase
[lcv
].eef
= 1; /* always the same */
497 xyc
->iopbase
[lcv
].ecm
= XY_ECM
; /* always the same */
498 xyc
->iopbase
[lcv
].aud
= 1; /* always the same */
499 xyc
->iopbase
[lcv
].relo
= 1; /* always the same */
500 xyc
->iopbase
[lcv
].thro
= XY_THRO
;/* always the same */
502 if ((error
= vme_dmamap_create(
503 ct
, /* VME chip tag */
505 VME_AM_A24
, /* address modifier */
506 VME_D16
, /* data size */
509 MAXPHYS
, /* maxsegsz */
512 &xyc
->reqs
[lcv
].dmamap
)) != 0) {
514 aprint_error_dev(&xyc
->sc_dev
, "DMA buffer map create error %d\n",
519 xyc
->ciorq
= &xyc
->reqs
[XYC_CTLIOPB
]; /* short hand name */
520 xyc
->ciopb
= &xyc
->iopbase
[XYC_CTLIOPB
]; /* short hand name */
523 /* read controller parameters and insure we have a 450/451 */
525 error
= xyc_cmd(xyc
, XYCMD_ST
, 0, 0, 0, 0, 0, XY_SUB_POLL
);
526 res
= xyc
->ciopb
->ctyp
;
527 XYC_DONE(xyc
, error
);
528 if (res
!= XYCT_450
) {
530 printf(": %s: ", xyc_e2str(error
));
531 printf(": doesn't identify as a 450/451\n");
534 printf(": Xylogics 450/451");
536 printf(" [OLS disabled]"); /* 450 doesn't overlap seek right */
539 aprint_error_dev(&xyc
->sc_dev
, "error: %s\n",
543 if ((xyc
->xyc
->xyc_csr
& XYC_ADRM
) == 0) {
544 printf("%s: 24 bit addressing turned off\n",
545 device_xname(&xyc
->sc_dev
));
546 printf("please set hardware jumpers JM1-JM2=in, JM3-JM4=out\n");
547 printf("to enable 24 bit mode and this driver\n");
551 /* link in interrupt with higher level software */
552 vme_intr_map(ct
, va
->ilevel
, va
->ivector
, &ih
);
553 vme_intr_establish(ct
, ih
, IPL_BIO
, xycintr
, xyc
);
554 evcnt_attach_dynamic(&xyc
->sc_intrcnt
, EVCNT_TYPE_INTR
, NULL
,
555 device_xname(&xyc
->sc_dev
), "intr");
557 callout_init(&xyc
->sc_tick_ch
, 0);
559 /* now we must look for disks using autoconfig */
560 xa
.fullmode
= XY_SUB_POLL
;
563 for (xa
.driveno
= 0; xa
.driveno
< XYC_MAXDEV
; xa
.driveno
++)
564 (void) config_found(self
, (void *) &xa
, NULL
);
566 /* start the watchdog clock */
567 callout_reset(&xyc
->sc_tick_ch
, XYC_TICKCNT
, xyc_tick
, xyc
);
572 * xymatch: probe for disk.
574 * note: we almost always say disk is present. this allows us to
575 * spin up and configure a disk after the system is booted (we can
579 xymatch(device_t parent
, cfdata_t cf
, void *aux
)
581 struct xyc_attach_args
*xa
= aux
;
583 /* looking for autoconf wildcard or exact match */
585 if (cf
->cf_loc
[XYCCF_DRIVE
] != XYCCF_DRIVE_DEFAULT
&&
586 cf
->cf_loc
[XYCCF_DRIVE
] != xa
->driveno
)
594 * xyattach: attach a disk. this can be called from autoconf and also
595 * from xyopen/xystrategy.
598 xyattach(device_t parent
, device_t self
, void *aux
)
600 struct xy_softc
*xy
= device_private(self
), *oxy
;
601 struct xyc_softc
*xyc
= device_private(parent
);
602 struct xyc_attach_args
*xa
= aux
;
603 int spt
, mb
, blk
, lcv
, fmode
, s
= 0, newstate
;
606 bus_dma_segment_t seg
;
612 * Always re-initialize the disk structure. We want statistics
613 * to start with a clean slate.
615 memset(&xy
->sc_dk
, 0, sizeof(xy
->sc_dk
));
617 /* if booting, init the xy_softc */
620 xy
->state
= XY_DRIVE_UNKNOWN
; /* to start */
624 /* init queue of waiting bufs */
626 bufq_alloc(&xy
->xyq
, "disksort", BUFQ_SORT_RAWBLOCK
);
628 xy
->xyrq
= &xyc
->reqs
[xa
->driveno
];
631 xy
->xy_drive
= xa
->driveno
;
632 fmode
= xa
->fullmode
;
633 xyc
->sc_drives
[xa
->driveno
] = xy
;
635 /* if not booting, make sure we are the only process in the attach for
636 * this drive. if locked out, sleep on it. */
640 while (xy
->state
== XY_DRIVE_ATTACHING
) {
641 if (tsleep(&xy
->state
, PRIBIO
, "xyattach", 0)) {
647 device_xname(&xy
->sc_dev
), device_xname(&xy
->parent
->sc_dev
));
650 /* we now have control */
651 xy
->state
= XY_DRIVE_ATTACHING
;
652 newstate
= XY_DRIVE_UNKNOWN
;
655 if ((error
= xy_dmamem_alloc(xyc
->dmatag
, xyc
->auxmap
, &seg
, &rseg
,
659 aprint_error_dev(&xyc
->sc_dev
, "DMA buffer alloc error %d\n",
663 dmaddr
= (void *)(u_long
)BUS_ADDR_PADDR(busaddr
);
665 /* first try and reset the drive */
666 error
= xyc_cmd(xyc
, XYCMD_RST
, 0, xy
->xy_drive
, 0, 0, 0, fmode
);
667 XYC_DONE(xyc
, error
);
668 if (error
== XY_ERR_DNRY
) {
669 printf(" drive %d: off-line\n", xa
->driveno
);
673 printf(": ERROR 0x%02x (%s)\n", error
, xyc_e2str(error
));
676 printf(" drive %d: ready", xa
->driveno
);
679 * now set drive parameters (to semi-bogus values) so we can read the
682 xy
->pcyl
= xy
->ncyl
= 1;
687 for (lcv
= 0; lcv
< 126; lcv
++) /* init empty bad144 table */
688 xy
->dkb
.bt_bad
[lcv
].bt_cyl
=
689 xy
->dkb
.bt_bad
[lcv
].bt_trksec
= 0xffff;
691 /* read disk label */
692 for (xy
->drive_type
= 0 ; xy
->drive_type
<= XYC_MAXDT
;
694 error
= xyc_cmd(xyc
, XYCMD_RD
, 0, xy
->xy_drive
, 0, 1,
696 XYC_DONE(xyc
, error
);
697 if (error
== XY_ERR_AOK
) break;
700 if (error
!= XY_ERR_AOK
) {
702 aprint_error_dev(&xy
->sc_dev
, "reading disk label failed: %s\n",
706 printf(" (drive type %d)\n", xy
->drive_type
);
708 newstate
= XY_DRIVE_NOLABEL
;
710 xy
->hw_spt
= spt
= 0; /* XXX needed ? */
711 /* Attach the disk: must be before getdisklabel to malloc label */
712 disk_init(&xy
->sc_dk
, device_xname(&xy
->sc_dev
), &xydkdriver
);
713 disk_attach(&xy
->sc_dk
);
715 if (xygetdisklabel(xy
, buf
) != XY_ERR_AOK
)
718 /* inform the user of what is up */
719 printf("%s: <%s>, pcyl %d\n", device_xname(&xy
->sc_dev
),
721 mb
= xy
->ncyl
* (xy
->nhead
* xy
->nsect
) / (1048576 / XYFM_BPS
);
722 printf("%s: %dMB, %d cyl, %d head, %d sec, %d bytes/sec\n",
723 device_xname(&xy
->sc_dev
), mb
, xy
->ncyl
, xy
->nhead
, xy
->nsect
,
727 * 450/451 stupidity: the drive type is encoded into the format
728 * of the disk. the drive type in the IOPB must match the drive
729 * type in the format, or you will not be able to do I/O to the
730 * disk (you get header not found errors). if you have two drives
731 * of different sizes that have the same drive type in their
732 * formatting then you are out of luck.
734 * this problem was corrected in the 753/7053.
737 for (lcv
= 0 ; lcv
< XYC_MAXDEV
; lcv
++) {
738 oxy
= xyc
->sc_drives
[lcv
];
739 if (oxy
== NULL
|| oxy
== xy
) continue;
740 if (oxy
->drive_type
!= xy
->drive_type
) continue;
741 if (xy
->nsect
!= oxy
->nsect
|| xy
->pcyl
!= oxy
->pcyl
||
742 xy
->nhead
!= oxy
->nhead
) {
743 printf("%s: %s and %s must be the same size!\n",
744 device_xname(&xyc
->sc_dev
), device_xname(&xy
->sc_dev
),
745 device_xname(&oxy
->sc_dev
));
746 panic("xy drive size mismatch");
751 /* now set the real drive parameters! */
753 blk
= (xy
->nsect
- 1) +
754 ((xy
->nhead
- 1) * xy
->nsect
) +
755 ((xy
->pcyl
- 1) * xy
->nsect
* xy
->nhead
);
756 error
= xyc_cmd(xyc
, XYCMD_SDS
, 0, xy
->xy_drive
, blk
, 0, 0, fmode
);
757 XYC_DONE(xyc
, error
);
759 aprint_error_dev(&xy
->sc_dev
, "write drive size failed: %s\n",
763 newstate
= XY_DRIVE_ONLINE
;
766 * read bad144 table. this table resides on the first sector of the
767 * last track of the disk (i.e. second cyl of "acyl" area).
770 blk
= (xy
->ncyl
+ xy
->acyl
- 1) * (xy
->nhead
* xy
->nsect
) +
772 (xy
->nhead
- 1) * xy
->nsect
; /* last head */
773 error
= xyc_cmd(xyc
, XYCMD_RD
, 0, xy
->xy_drive
, blk
, 1,
775 XYC_DONE(xyc
, error
);
777 aprint_error_dev(&xy
->sc_dev
, "reading bad144 failed: %s\n",
782 /* check dkbad for sanity */
783 dkb
= (struct dkbad
*) buf
;
784 for (lcv
= 0; lcv
< 126; lcv
++) {
785 if ((dkb
->bt_bad
[lcv
].bt_cyl
== 0xffff ||
786 dkb
->bt_bad
[lcv
].bt_cyl
== 0) &&
787 dkb
->bt_bad
[lcv
].bt_trksec
== 0xffff)
788 continue; /* blank */
789 if (dkb
->bt_bad
[lcv
].bt_cyl
>= xy
->ncyl
)
791 if ((dkb
->bt_bad
[lcv
].bt_trksec
>> 8) >= xy
->nhead
)
793 if ((dkb
->bt_bad
[lcv
].bt_trksec
& 0xff) >= xy
->nsect
)
797 aprint_error_dev(&xy
->sc_dev
, "warning: invalid bad144 sector!\n");
799 memcpy(&xy
->dkb
, buf
, XYFM_BPS
);
804 xy_dmamem_free(xyc
->dmatag
, xyc
->auxmap
,
805 &seg
, rseg
, XYFM_BPS
, buf
);
808 xy
->state
= newstate
;
816 * end of autoconfig functions
820 * { b , c } d e v s w f u n c t i o n s
824 * xyclose: close device
827 xyclose(dev
, flag
, fmt
, l
)
833 struct xy_softc
*xy
= device_lookup_private(&xy_cd
, DISKUNIT(dev
));
834 int part
= DISKPART(dev
);
836 /* clear mask bits */
840 xy
->sc_dk
.dk_copenmask
&= ~(1 << part
);
843 xy
->sc_dk
.dk_bopenmask
&= ~(1 << part
);
846 xy
->sc_dk
.dk_openmask
= xy
->sc_dk
.dk_copenmask
| xy
->sc_dk
.dk_bopenmask
;
852 * xydump: crash dump system
855 xydump(dev_t dev
, daddr_t blkno
, void *va
, size_t size
)
860 unit
= DISKUNIT(dev
);
861 part
= DISKPART(dev
);
863 xy
= device_lookup_private(&xy_cd
, unit
);
867 printf("%s%c: crash dump not supported (yet)\n", device_xname(&xy
->sc_dev
),
872 /* outline: globals: "dumplo" == sector number of partition to start
873 * dump at (convert to physical sector with partition table)
874 * "dumpsize" == size of dump in clicks "physmem" == size of physical
875 * memory (clicks, ctob() to get bytes) (normal case: dumpsize ==
878 * dump a copy of physical memory to the dump device starting at sector
879 * "dumplo" in the swap partition (make sure > 0). map in pages as
880 * we go. use polled I/O.
882 * XXX how to handle NON_CONTIG? */
886 static enum kauth_device_req
887 xy_getkauthreq(u_char cmd
)
889 enum kauth_device_req req
;
896 req
= KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_WRITE
;
902 req
= KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READ
;
907 req
= KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF
;
913 req
= KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_WRITECONF
;
929 * xyioctl: ioctls on XY drives. based on ioctl's of other netbsd disks.
932 xyioctl(dev
, command
, addr
, flag
, l
)
941 struct xd_iocmd
*xio
;
943 #ifdef __HAVE_OLD_DISKLABEL
944 struct disklabel newlabel
;
946 struct disklabel
*lp
;
948 unit
= DISKUNIT(dev
);
950 if ((xy
= device_lookup_private(&xy_cd
, unit
)) == NULL
)
953 /* switch on ioctl type */
956 case DIOCSBAD
: /* set bad144 info */
957 if ((flag
& FWRITE
) == 0)
960 memcpy(&xy
->dkb
, addr
, sizeof(xy
->dkb
));
964 case DIOCGDINFO
: /* get disk label */
965 memcpy(addr
, xy
->sc_dk
.dk_label
, sizeof(struct disklabel
));
967 #ifdef __HAVE_OLD_DISKLABEL
969 newlabel
= *(xy
->sc_dk
.dk_label
);
970 if (newlabel
.d_npartitions
> OLDMAXPARTITIONS
)
972 memcpy(addr
, &newlabel
, sizeof (struct olddisklabel
));
976 case DIOCGPART
: /* get partition info */
977 ((struct partinfo
*) addr
)->disklab
= xy
->sc_dk
.dk_label
;
978 ((struct partinfo
*) addr
)->part
=
979 &xy
->sc_dk
.dk_label
->d_partitions
[DISKPART(dev
)];
982 case DIOCSDINFO
: /* set disk label */
983 #ifdef __HAVE_OLD_DISKLABEL
985 if (command
== ODIOCSDINFO
) {
986 memset(&newlabel
, 0, sizeof newlabel
);
987 memcpy(&newlabel
, addr
, sizeof (struct olddisklabel
));
991 lp
= (struct disklabel
*)addr
;
993 if ((flag
& FWRITE
) == 0)
995 error
= setdisklabel(xy
->sc_dk
.dk_label
,
996 lp
, /* xy->sc_dk.dk_openmask : */ 0,
997 xy
->sc_dk
.dk_cpulabel
);
999 if (xy
->state
== XY_DRIVE_NOLABEL
)
1000 xy
->state
= XY_DRIVE_ONLINE
;
1004 case DIOCWLABEL
: /* change write status of disk label */
1005 if ((flag
& FWRITE
) == 0)
1008 xy
->flags
|= XY_WLABEL
;
1010 xy
->flags
&= ~XY_WLABEL
;
1013 case DIOCWDINFO
: /* write disk label */
1014 #ifdef __HAVE_OLD_DISKLABEL
1016 if (command
== ODIOCWDINFO
) {
1017 memset(&newlabel
, 0, sizeof newlabel
);
1018 memcpy(&newlabel
, addr
, sizeof (struct olddisklabel
));
1022 lp
= (struct disklabel
*)addr
;
1024 if ((flag
& FWRITE
) == 0)
1026 error
= setdisklabel(xy
->sc_dk
.dk_label
,
1027 lp
, /* xy->sc_dk.dk_openmask : */ 0,
1028 xy
->sc_dk
.dk_cpulabel
);
1030 if (xy
->state
== XY_DRIVE_NOLABEL
)
1031 xy
->state
= XY_DRIVE_ONLINE
;
1033 /* Simulate opening partition 0 so write succeeds. */
1034 xy
->sc_dk
.dk_openmask
|= (1 << 0);
1035 error
= writedisklabel(MAKEDISKDEV(major(dev
), DISKUNIT(dev
), RAW_PART
),
1036 xystrategy
, xy
->sc_dk
.dk_label
,
1037 xy
->sc_dk
.dk_cpulabel
);
1038 xy
->sc_dk
.dk_openmask
=
1039 xy
->sc_dk
.dk_copenmask
| xy
->sc_dk
.dk_bopenmask
;
1044 enum kauth_device_req req
;
1046 xio
= (struct xd_iocmd
*) addr
;
1047 req
= xy_getkauthreq(xio
->cmd
);
1048 if ((error
= kauth_authorize_device_passthru(l
->l_cred
,
1049 dev
, req
, xio
)) != 0)
1051 return (xyc_ioctlcmd(xy
, dev
, xio
));
1060 * xyopen: open drive
1064 xyopen(dev_t dev
, int flag
, int fmt
, struct lwp
*l
)
1067 struct xy_softc
*xy
;
1068 struct xyc_attach_args xa
;
1070 /* first, could it be a valid target? */
1072 unit
= DISKUNIT(dev
);
1073 if ((xy
= device_lookup_private(&xy_cd
, unit
)) == NULL
)
1075 part
= DISKPART(dev
);
1077 /* do we need to attach the drive? */
1079 if (xy
->state
== XY_DRIVE_UNKNOWN
) {
1080 xa
.driveno
= xy
->xy_drive
;
1081 xa
.fullmode
= XY_SUB_WAIT
;
1083 xyattach((device_t
) xy
->parent
,
1084 (device_t
) xy
, &xa
);
1085 if (xy
->state
== XY_DRIVE_UNKNOWN
) {
1089 /* check for partition */
1091 if (part
!= RAW_PART
&&
1092 (part
>= xy
->sc_dk
.dk_label
->d_npartitions
||
1093 xy
->sc_dk
.dk_label
->d_partitions
[part
].p_fstype
== FS_UNUSED
)) {
1096 /* set open masks */
1100 xy
->sc_dk
.dk_copenmask
|= (1 << part
);
1103 xy
->sc_dk
.dk_bopenmask
|= (1 << part
);
1106 xy
->sc_dk
.dk_openmask
= xy
->sc_dk
.dk_copenmask
| xy
->sc_dk
.dk_bopenmask
;
1112 xyread(dev_t dev
, struct uio
*uio
, int flags
)
1115 return (physio(xystrategy
, NULL
, dev
, B_READ
, minphys
, uio
));
1119 xywrite(dev_t dev
, struct uio
*uio
, int flags
)
1122 return (physio(xystrategy
, NULL
, dev
, B_WRITE
, minphys
, uio
));
1127 * xysize: return size of a partition for a dump
1135 struct xy_softc
*xysc
;
1136 int unit
, part
, size
, omask
;
1139 unit
= DISKUNIT(dev
);
1140 if ((xysc
= device_lookup_private(&xy_cd
, unit
)) == NULL
)
1143 part
= DISKPART(dev
);
1144 omask
= xysc
->sc_dk
.dk_openmask
& (1 << part
);
1146 if (omask
== 0 && xyopen(dev
, 0, S_IFBLK
, NULL
) != 0)
1150 if (xysc
->sc_dk
.dk_label
->d_partitions
[part
].p_fstype
!= FS_SWAP
)
1151 size
= -1; /* only give valid size for swap partitions */
1153 size
= xysc
->sc_dk
.dk_label
->d_partitions
[part
].p_size
*
1154 (xysc
->sc_dk
.dk_label
->d_secsize
/ DEV_BSIZE
);
1155 if (omask
== 0 && xyclose(dev
, 0, S_IFBLK
, NULL
) != 0)
1161 * xystrategy: buffering system interface to xy.
1169 struct xy_softc
*xy
;
1171 struct xyc_attach_args xa
;
1172 struct disklabel
*lp
;
1175 unit
= DISKUNIT(bp
->b_dev
);
1177 /* check for live device */
1179 if (!(xy
= device_lookup_private(&xy_cd
, unit
)) ||
1181 (bp
->b_bcount
% xy
->sc_dk
.dk_label
->d_secsize
) != 0) {
1182 bp
->b_error
= EINVAL
;
1185 /* do we need to attach the drive? */
1187 if (xy
->state
== XY_DRIVE_UNKNOWN
) {
1188 xa
.driveno
= xy
->xy_drive
;
1189 xa
.fullmode
= XY_SUB_WAIT
;
1191 xyattach((device_t
)xy
->parent
, (device_t
)xy
, &xa
);
1192 if (xy
->state
== XY_DRIVE_UNKNOWN
) {
1197 if (xy
->state
!= XY_DRIVE_ONLINE
&& DISKPART(bp
->b_dev
) != RAW_PART
) {
1198 /* no I/O to unlabeled disks, unless raw partition */
1202 /* short circuit zero length request */
1204 if (bp
->b_bcount
== 0)
1207 /* check bounds with label (disksubr.c). Determine the size of the
1208 * transfer, and make sure it is within the boundaries of the
1209 * partition. Adjust transfer if needed, and signal errors or early
1212 lp
= xy
->sc_dk
.dk_label
;
1214 if (bounds_check_with_label(&xy
->sc_dk
, bp
,
1215 (xy
->flags
& XY_WLABEL
) != 0) <= 0)
1219 * Now convert the block number to absolute and put it in
1220 * terms of the device's logical block size.
1222 blkno
= bp
->b_blkno
/ (lp
->d_secsize
/ DEV_BSIZE
);
1223 if (DISKPART(bp
->b_dev
) != RAW_PART
)
1224 blkno
+= lp
->d_partitions
[DISKPART(bp
->b_dev
)].p_offset
;
1226 bp
->b_rawblkno
= blkno
;
1229 * now we know we have a valid buf structure that we need to do I/O
1232 s
= splbio(); /* protect the queues */
1234 bufq_put(xy
->xyq
, bp
);
1238 xyc_start(xy
->parent
, NULL
);
1245 done
: /* tells upper layers we are done with this
1247 bp
->b_resid
= bp
->b_bcount
;
1251 * end of {b,c}devsw functions
1255 * i n t e r r u p t f u n c t i o n
1257 * xycintr: hardware interrupt.
1264 struct xyc_softc
*xycsc
= v
;
1266 /* kick the event counter */
1268 xycsc
->sc_intrcnt
.ev_count
++;
1270 /* remove as many done IOPBs as possible */
1272 xyc_remove_iorq(xycsc
);
1274 /* start any iorq's already waiting */
1276 xyc_start(xycsc
, NULL
);
1281 * end of interrupt function
1285 * i n t e r n a l f u n c t i o n s
1289 * xyc_rqinit: fill out the fields of an I/O request
1293 xyc_rqinit(struct xy_iorq
*rq
, struct xyc_softc
*xyc
, struct xy_softc
*xy
, int md
, u_long blk
, int cnt
, void *db
, struct buf
*bp
)
1297 rq
->ttl
= XYC_MAXTTL
+ 10;
1299 rq
->tries
= rq
->errnum
= rq
->lasterror
= 0;
1307 * xyc_rqtopb: load up an IOPB based on an iorq
1311 xyc_rqtopb(iorq
, iopb
, cmd
, subfun
)
1312 struct xy_iorq
*iorq
;
1313 struct xy_iopb
*iopb
;
1319 /* normal IOPB case, standard stuff */
1321 /* chain bit handled later */
1322 iopb
->ien
= (XY_STATE(iorq
->mode
) == XY_SUB_POLL
) ? 0 : 1;
1328 iopb
->unit
= iorq
->xy
->xy_drive
;
1329 iopb
->dt
= iorq
->xy
->drive_type
;
1334 block
= iorq
->blockno
;
1335 if (iorq
->xy
== NULL
|| block
== 0) {
1336 iopb
->sect
= iopb
->head
= iopb
->cyl
= 0;
1338 iopb
->sect
= block
% iorq
->xy
->nsect
;
1339 block
= block
/ iorq
->xy
->nsect
;
1340 iopb
->head
= block
% iorq
->xy
->nhead
;
1341 block
= block
/ iorq
->xy
->nhead
;
1344 iopb
->scnt
= iorq
->sectcnt
;
1345 dp
= (u_long
) iorq
->dbuf
;
1346 if (iorq
->dbuf
== NULL
) {
1350 iopb
->dataa
= (dp
& 0xffff);
1351 iopb
->datar
= ((dp
& 0xff0000) >> 16);
1353 iopb
->subfn
= subfun
;
1358 * xyc_unbusy: wait for the xyc to go unbusy, or timeout.
1362 xyc_unbusy(xyc
, del
)
1369 if ((xyc
->xyc_csr
& XYC_GBSY
) == 0)
1373 return(del
== 0 ? XY_ERR_FAIL
: XY_ERR_AOK
);
1377 * xyc_cmd: front end for POLL'd and WAIT'd commands. Returns 0 or error.
1378 * note that NORM requests are handled separately.
1381 xyc_cmd(xycsc
, cmd
, subfn
, unit
, block
, scnt
, dptr
, fullmode
)
1382 struct xyc_softc
*xycsc
;
1383 int cmd
, subfn
, unit
, block
, scnt
;
1388 int submode
= XY_STATE(fullmode
);
1389 struct xy_iorq
*iorq
= xycsc
->ciorq
;
1390 struct xy_iopb
*iopb
= xycsc
->ciopb
;
1393 * is someone else using the control iopq wait for it if we can
1396 if (submode
== XY_SUB_WAIT
&& XY_STATE(iorq
->mode
) != XY_SUB_FREE
) {
1397 if (tsleep(iorq
, PRIBIO
, "xyc_cmd", 0))
1398 return(XY_ERR_FAIL
);
1402 if (XY_STATE(iorq
->mode
) != XY_SUB_FREE
) {
1403 DELAY(1000000); /* XY_SUB_POLL: steal the iorq */
1404 iorq
->mode
= XY_SUB_FREE
;
1405 printf("%s: stole control iopb\n", device_xname(&xycsc
->sc_dev
));
1408 /* init iorq/iopb */
1410 xyc_rqinit(iorq
, xycsc
,
1411 (unit
== XYC_NOUNIT
) ? NULL
: xycsc
->sc_drives
[unit
],
1412 fullmode
, block
, scnt
, dptr
, NULL
);
1414 /* load IOPB from iorq */
1416 xyc_rqtopb(iorq
, iopb
, cmd
, subfn
);
1418 /* submit it for processing */
1420 xyc_submit_iorq(xycsc
, iorq
, fullmode
); /* error code will be in iorq */
1427 * start a buffer for running
1431 xyc_startbuf(xycsc
, xysc
, bp
)
1432 struct xyc_softc
*xycsc
;
1433 struct xy_softc
*xysc
;
1438 struct xy_iorq
*iorq
;
1439 struct xy_iopb
*iopb
;
1448 panic("xyc_startbuf null buf");
1450 partno
= DISKPART(bp
->b_dev
);
1452 printf("xyc_startbuf: %s%c: %s block %d\n", device_xname(&xysc
->sc_dev
),
1453 'a' + partno
, (bp
->b_flags
& B_READ
) ? "read" : "write", bp
->b_blkno
);
1454 printf("xyc_startbuf: b_bcount %d, b_data 0x%x\n",
1455 bp
->b_bcount
, bp
->b_data
);
1461 * note that iorq points to the buffer as mapped into DVMA space,
1462 * where as the bp->b_data points to its non-DVMA mapping.
1465 block
= bp
->b_rawblkno
;
1467 error
= bus_dmamap_load(xycsc
->dmatag
, iorq
->dmamap
,
1468 bp
->b_data
, bp
->b_bcount
, 0, BUS_DMA_NOWAIT
);
1470 aprint_error_dev(&xycsc
->sc_dev
, "warning: cannot load DMA map\n");
1471 return (XY_ERR_FAIL
); /* XXX: need some sort of
1472 * call-back scheme here? */
1475 bus_dmamap_sync(xycsc
->dmatag
, iorq
->dmamap
, 0,
1476 iorq
->dmamap
->dm_mapsize
, (bp
->b_flags
& B_READ
)
1477 ? BUS_DMASYNC_PREREAD
1478 : BUS_DMASYNC_PREWRITE
);
1480 /* init iorq and load iopb from it */
1481 xyc_rqinit(iorq
, xycsc
, xysc
, XY_SUB_NORM
| XY_MODE_VERBO
, block
,
1482 bp
->b_bcount
/ XYFM_BPS
,
1483 (void *)(u_long
)iorq
->dmamap
->dm_segs
[0].ds_addr
,
1486 xyc_rqtopb(iorq
, iopb
, (bp
->b_flags
& B_READ
) ? XYCMD_RD
: XYCMD_WR
, 0);
1488 /* Instrumentation. */
1489 disk_busy(&xysc
->sc_dk
);
1491 return (XY_ERR_AOK
);
1496 * xyc_submit_iorq: submit an iorq for processing. returns XY_ERR_AOK
1497 * if ok. if it fail returns an error code. type is XY_SUB_*.
1499 * note: caller frees iorq in all cases except NORM
1502 * NORM: XY_AOK (req pending), XY_FAIL (couldn't submit request)
1503 * WAIT: XY_AOK (success), <error-code> (failed)
1504 * POLL: <same as WAIT>
1505 * NOQ : <same as NORM>
1507 * there are three sources for i/o requests:
1508 * [1] xystrategy: normal block I/O, using "struct buf" system.
1509 * [2] autoconfig/crash dump: these are polled I/O requests, no interrupts.
1510 * [3] open/ioctl: these are I/O requests done in the context of a process,
1511 * and the process should block until they are done.
1513 * software state is stored in the iorq structure. each iorq has an
1514 * iopb structure. the hardware understands the iopb structure.
1515 * every command must go through an iopb. a 450 handles one iopb at a
1516 * time, where as a 451 can take them in chains. [the 450 claims it
1517 * can handle chains, but is appears to be buggy...] iopb are allocated
1518 * in DVMA space at boot up time. each disk gets one iopb, and the
1519 * controller gets one (for POLL and WAIT commands). what happens if
1520 * the iopb is busy? for i/o type [1], the buffers are queued at the
1521 * "buff" layer and * picked up later by the interrupt routine. for case
1522 * [2] we can only be blocked if there is a WAIT type I/O request being
1523 * run. since this can only happen when we are crashing, we wait a sec
1524 * and then steal the IOPB. for case [3] the process can sleep
1525 * on the iorq free list until some iopbs are available.
1530 xyc_submit_iorq(xycsc
, iorq
, type
)
1531 struct xyc_softc
*xycsc
;
1532 struct xy_iorq
*iorq
;
1536 struct xy_iopb
*dmaiopb
;
1539 printf("xyc_submit_iorq(%s, addr=0x%x, type=%d)\n",
1540 device_xname(&xycsc
->sc_dev
), iorq
, type
);
1543 /* first check and see if controller is busy */
1544 if ((xycsc
->xyc
->xyc_csr
& XYC_GBSY
) != 0) {
1546 printf("xyc_submit_iorq: XYC not ready (BUSY)\n");
1548 if (type
== XY_SUB_NOQ
)
1549 return (XY_ERR_FAIL
); /* failed */
1552 return XY_ERR_AOK
; /* success */
1554 while (iorq
->iopb
->done
== 0) {
1555 (void) tsleep(iorq
, PRIBIO
, "xyciorq", 0);
1557 return (iorq
->errnum
);
1558 case XY_SUB_POLL
: /* steal controller */
1559 (void)xycsc
->xyc
->xyc_rsetup
; /* RESET */
1560 if (xyc_unbusy(xycsc
->xyc
,XYC_RESETUSEC
) == XY_ERR_FAIL
)
1561 panic("xyc_submit_iorq: stuck xyc");
1562 printf("%s: stole controller\n",
1563 device_xname(&xycsc
->sc_dev
));
1566 panic("xyc_submit_iorq adding");
1570 dmaiopb
= xyc_chain(xycsc
, iorq
); /* build chain */
1571 if (dmaiopb
== NULL
) { /* nothing doing? */
1572 if (type
== XY_SUB_NORM
|| type
== XY_SUB_NOQ
)
1574 panic("xyc_submit_iorq: xyc_chain failed!");
1577 XYC_GO(xycsc
->xyc
, dmaiopb
);
1579 /* command now running, wrap it up */
1583 return (XY_ERR_AOK
); /* success */
1585 while (iorq
->iopb
->done
== 0) {
1586 (void) tsleep(iorq
, PRIBIO
, "xyciorq", 0);
1588 return (iorq
->errnum
);
1590 return (xyc_piodriver(xycsc
, iorq
));
1592 panic("xyc_submit_iorq wrap up");
1594 panic("xyc_submit_iorq");
1595 return 0; /* not reached */
1600 * xyc_chain: build a chain. return dvma address of first element in
1601 * the chain. iorq != NULL: means we only want that item on the chain.
1605 xyc_chain(xycsc
, iorq
)
1606 struct xyc_softc
*xycsc
;
1607 struct xy_iorq
*iorq
;
1610 int togo
, chain
, hand
;
1612 memset(xycsc
->xy_chain
, 0, sizeof(xycsc
->xy_chain
));
1615 * promote control IOPB to the top
1618 if ((XY_STATE(xycsc
->reqs
[XYC_CTLIOPB
].mode
) == XY_SUB_POLL
||
1619 XY_STATE(xycsc
->reqs
[XYC_CTLIOPB
].mode
) == XY_SUB_WAIT
) &&
1620 xycsc
->iopbase
[XYC_CTLIOPB
].done
== 0)
1621 iorq
= &xycsc
->reqs
[XYC_CTLIOPB
];
1625 * special case: if iorq != NULL then we have a POLL or WAIT request.
1626 * we let these take priority and do them first.
1629 xycsc
->xy_chain
[0] = iorq
;
1630 iorq
->iopb
->chen
= 0;
1631 return(iorq
->dmaiopb
);
1635 * NORM case: do round robin and maybe chain (if allowed and possible)
1638 hand
= xycsc
->xy_hand
;
1639 xycsc
->xy_hand
= (xycsc
->xy_hand
+ 1) % XYC_MAXIOPB
;
1641 for (togo
= XYC_MAXIOPB
; togo
> 0;
1642 togo
--, hand
= (hand
+ 1) % XYC_MAXIOPB
) {
1643 struct xy_iopb
*iopb
, *prev_iopb
, *dmaiopb
;
1645 if (XY_STATE(xycsc
->reqs
[hand
].mode
) != XY_SUB_NORM
||
1646 xycsc
->iopbase
[hand
].done
)
1647 continue; /* not ready-for-i/o */
1649 xycsc
->xy_chain
[chain
] = &xycsc
->reqs
[hand
];
1650 iopb
= xycsc
->xy_chain
[chain
]->iopb
;
1653 /* adding a link to a chain */
1654 prev_iopb
= xycsc
->xy_chain
[chain
-1]->iopb
;
1655 prev_iopb
->chen
= 1;
1656 dmaiopb
= xycsc
->xy_chain
[chain
]->dmaiopb
;
1657 prev_iopb
->nxtiopb
= ((u_long
)dmaiopb
) & 0xffff;
1660 iorq
= xycsc
->xy_chain
[chain
];
1664 /* quit if chaining dis-allowed */
1669 return(iorq
? iorq
->dmaiopb
: NULL
);
1675 * programmed i/o driver. this function takes over the computer
1676 * and drains off the polled i/o request. it returns the status of the iorq
1677 * the caller is interesting in.
1680 xyc_piodriver(xycsc
, iorq
)
1681 struct xyc_softc
*xycsc
;
1682 struct xy_iorq
*iorq
;
1689 printf("xyc_piodriver(%s, 0x%x)\n", device_xname(&xycsc
->sc_dev
), iorq
);
1692 while (iorq
->iopb
->done
== 0) {
1694 res
= xyc_unbusy(xycsc
->xyc
, XYC_MAXTIME
);
1696 /* we expect some progress soon */
1697 if (res
== XY_ERR_FAIL
&& nreset
>= 2) {
1698 xyc_reset(xycsc
, 0, XY_RSET_ALL
, XY_ERR_FAIL
, 0);
1700 printf("xyc_piodriver: timeout\n");
1702 return (XY_ERR_FAIL
);
1704 if (res
== XY_ERR_FAIL
) {
1705 if (xyc_reset(xycsc
, 0,
1706 (nreset
++ == 0) ? XY_RSET_NONE
: iorq
,
1709 return (XY_ERR_FAIL
); /* flushes all but POLL
1710 * requests, resets */
1714 xyc_remove_iorq(xycsc
); /* may resubmit request */
1716 if (iorq
->iopb
->done
== 0)
1717 xyc_start(xycsc
, iorq
);
1720 /* get return value */
1722 retval
= iorq
->errnum
;
1725 printf("xyc_piodriver: done, retval = 0x%x (%s)\n",
1726 iorq
->errnum
, xyc_e2str(iorq
->errnum
));
1729 /* start up any bufs that have queued */
1731 xyc_start(xycsc
, NULL
);
1737 * xyc_xyreset: reset one drive. NOTE: assumes xyc was just reset.
1738 * we steal iopb[XYC_CTLIOPB] for this, but we put it back when we are done.
1741 xyc_xyreset(xycsc
, xysc
)
1742 struct xyc_softc
*xycsc
;
1743 struct xy_softc
*xysc
;
1746 struct xy_iopb tmpiopb
;
1747 struct xy_iopb
*iopb
;
1750 iopb
= xycsc
->ciopb
;
1753 memcpy(&tmpiopb
, iopb
, sizeof(struct xy_iopb
));
1755 iopb
->chen
= iopb
->done
= iopb
->errs
= 0;
1757 iopb
->com
= XYCMD_RST
;
1758 iopb
->unit
= xysc
->xy_drive
;
1760 XYC_GO(xycsc
->xyc
, xycsc
->ciorq
->dmaiopb
);
1762 del
= XYC_RESETUSEC
;
1764 if ((xycsc
->xyc
->xyc_csr
& XYC_GBSY
) == 0)
1770 if (del
<= 0 || iopb
->errs
) {
1771 printf("%s: off-line: %s\n", device_xname(&xycsc
->sc_dev
),
1772 xyc_e2str(iopb
->errnum
));
1773 del
= xycsc
->xyc
->xyc_rsetup
;
1774 if (xyc_unbusy(xycsc
->xyc
, XYC_RESETUSEC
) == XY_ERR_FAIL
)
1777 xycsc
->xyc
->xyc_csr
= XYC_IPND
; /* clear IPND */
1780 /* Restore contents */
1781 memcpy(iopb
, &tmpiopb
, sizeof(struct xy_iopb
));
1786 * xyc_reset: reset everything: requests are marked as errors except
1787 * a polled request (which is resubmitted)
1790 xyc_reset(xycsc
, quiet
, blastmode
, error
, xysc
)
1791 struct xyc_softc
*xycsc
;
1793 struct xy_iorq
*blastmode
;
1794 struct xy_softc
*xysc
;
1797 int del
= 0, lcv
, retval
= XY_ERR_AOK
;
1799 /* soft reset hardware */
1802 printf("%s: soft reset\n", device_xname(&xycsc
->sc_dev
));
1803 del
= xycsc
->xyc
->xyc_rsetup
;
1804 del
= xyc_unbusy(xycsc
->xyc
, XYC_RESETUSEC
);
1805 if (del
== XY_ERR_FAIL
) {
1806 blastmode
= XY_RSET_ALL
; /* dead, flush all requests */
1807 retval
= XY_ERR_FAIL
;
1810 xyc_xyreset(xycsc
, xysc
);
1812 /* fix queues based on "blast-mode" */
1814 for (lcv
= 0; lcv
< XYC_MAXIOPB
; lcv
++) {
1815 register struct xy_iorq
*iorq
= &xycsc
->reqs
[lcv
];
1817 if (XY_STATE(iorq
->mode
) != XY_SUB_POLL
&&
1818 XY_STATE(iorq
->mode
) != XY_SUB_WAIT
&&
1819 XY_STATE(iorq
->mode
) != XY_SUB_NORM
)
1823 if (blastmode
== XY_RSET_ALL
||
1824 blastmode
!= iorq
) {
1826 iorq
->errnum
= error
;
1827 xycsc
->iopbase
[lcv
].done
= xycsc
->iopbase
[lcv
].errs
= 1;
1828 switch (XY_STATE(iorq
->mode
)) {
1830 iorq
->buf
->b_error
= EIO
;
1831 iorq
->buf
->b_resid
= iorq
->sectcnt
* XYFM_BPS
;
1833 bus_dmamap_sync(xycsc
->dmatag
, iorq
->dmamap
, 0,
1834 iorq
->dmamap
->dm_mapsize
,
1835 (iorq
->buf
->b_flags
& B_READ
)
1836 ? BUS_DMASYNC_POSTREAD
1837 : BUS_DMASYNC_POSTWRITE
);
1839 bus_dmamap_unload(xycsc
->dmatag
, iorq
->dmamap
);
1841 (void)bufq_get(iorq
->xy
->xyq
);
1842 disk_unbusy(&xycsc
->reqs
[lcv
].xy
->sc_dk
,
1843 (xycsc
->reqs
[lcv
].buf
->b_bcount
-
1844 xycsc
->reqs
[lcv
].buf
->b_resid
),
1845 (xycsc
->reqs
[lcv
].buf
->b_flags
& B_READ
));
1847 iorq
->mode
= XY_SUB_FREE
;
1853 XY_NEWSTATE(iorq
->mode
, XY_SUB_DONE
);
1859 /* resubmit, no need to do anything here */
1864 * now, if stuff is waiting, start it.
1865 * since we just reset it should go
1867 xyc_start(xycsc
, NULL
);
1873 * xyc_start: start waiting buffers
1877 xyc_start(xycsc
, iorq
)
1878 struct xyc_softc
*xycsc
;
1879 struct xy_iorq
*iorq
;
1883 struct xy_softc
*xy
;
1886 for (lcv
= 0; lcv
< XYC_MAXDEV
; lcv
++) {
1887 if ((xy
= xycsc
->sc_drives
[lcv
]) == NULL
) continue;
1888 if (bufq_peek(xy
->xyq
) == NULL
) continue;
1889 if (xy
->xyrq
->mode
!= XY_SUB_FREE
) continue;
1890 xyc_startbuf(xycsc
, xy
, bufq_peek(xy
->xyq
));
1893 xyc_submit_iorq(xycsc
, iorq
, XY_SUB_NOQ
);
1897 * xyc_remove_iorq: remove "done" IOPB's.
1901 xyc_remove_iorq(xycsc
)
1902 struct xyc_softc
*xycsc
;
1905 int errnum
, rq
, comm
, errs
;
1906 struct xyc
*xyc
= xycsc
->xyc
;
1908 struct xy_iopb
*iopb
;
1909 struct xy_iorq
*iorq
;
1912 if (xyc
->xyc_csr
& XYC_DERR
) {
1914 * DOUBLE ERROR: should never happen under normal use. This
1915 * error is so bad, you can't even tell which IOPB is bad, so
1918 errnum
= XY_ERR_DERR
;
1919 aprint_error_dev(&xycsc
->sc_dev
, "DOUBLE ERROR!\n");
1920 if (xyc_reset(xycsc
, 0, XY_RSET_ALL
, errnum
, 0) != XY_ERR_AOK
) {
1921 aprint_error_dev(&xycsc
->sc_dev
, "soft reset failed!\n");
1922 panic("xyc_remove_iorq: controller DEAD");
1924 return (XY_ERR_AOK
);
1928 * get iopb that is done, loop down the chain
1931 if (xyc
->xyc_csr
& XYC_ERR
) {
1932 xyc
->xyc_csr
= XYC_ERR
; /* clear error condition */
1934 if (xyc
->xyc_csr
& XYC_IPND
) {
1935 xyc
->xyc_csr
= XYC_IPND
; /* clear interrupt */
1938 for (rq
= 0; rq
< XYC_MAXIOPB
; rq
++) {
1939 iorq
= xycsc
->xy_chain
[rq
];
1940 if (iorq
== NULL
) break; /* done ! */
1941 if (iorq
->mode
== 0 || XY_STATE(iorq
->mode
) == XY_SUB_DONE
)
1942 continue; /* free, or done */
1944 if (iopb
->done
== 0)
1945 continue; /* not done yet */
1951 iorq
->errnum
= iopb
->errnum
;
1955 /* handle non-fatal errors */
1958 xyc_error(xycsc
, iorq
, iopb
, comm
) == XY_ERR_AOK
)
1959 continue; /* AOK: we resubmitted it */
1962 /* this iorq is now done (hasn't been restarted or anything) */
1964 if ((iorq
->mode
& XY_MODE_VERBO
) && iorq
->lasterror
)
1965 xyc_perror(iorq
, iopb
, 0);
1967 /* now, if read/write check to make sure we got all the data
1968 * we needed. (this may not be the case if we got an error in
1969 * the middle of a multisector request). */
1971 if ((iorq
->mode
& XY_MODE_B144
) != 0 && errs
== 0 &&
1972 (comm
== XYCMD_RD
|| comm
== XYCMD_WR
)) {
1973 /* we just successfully processed a bad144 sector
1974 * note: if we are in bad 144 mode, the pointers have
1975 * been advanced already (see above) and are pointing
1976 * at the bad144 sector. to exit bad144 mode, we
1977 * must advance the pointers 1 sector and issue a new
1978 * request if there are still sectors left to process
1981 XYC_ADVANCE(iorq
, 1); /* advance 1 sector */
1983 /* exit b144 mode */
1984 iorq
->mode
= iorq
->mode
& (~XY_MODE_B144
);
1986 if (iorq
->sectcnt
) { /* more to go! */
1987 iorq
->lasterror
= iorq
->errnum
= iopb
->errnum
= 0;
1988 iopb
->errs
= iopb
->done
= 0;
1990 iopb
->scnt
= iorq
->sectcnt
;
1991 iopb
->cyl
= iorq
->blockno
/
1992 iorq
->xy
->sectpercyl
;
1994 (iorq
->blockno
/ iorq
->xy
->nhead
) %
1996 iopb
->sect
= iorq
->blockno
% XYFM_BPS
;
1997 addr
= (u_long
) iorq
->dbuf
;
1998 iopb
->dataa
= (addr
& 0xffff);
1999 iopb
->datar
= ((addr
& 0xff0000) >> 16);
2000 /* will resubit at end */
2004 /* final cleanup, totally done with this request */
2006 switch (XY_STATE(iorq
->mode
)) {
2011 bp
->b_resid
= iorq
->sectcnt
* XYFM_BPS
;
2013 bp
->b_resid
= 0; /* done */
2015 bus_dmamap_sync(xycsc
->dmatag
, iorq
->dmamap
, 0,
2016 iorq
->dmamap
->dm_mapsize
,
2017 (iorq
->buf
->b_flags
& B_READ
)
2018 ? BUS_DMASYNC_POSTREAD
2019 : BUS_DMASYNC_POSTWRITE
);
2021 bus_dmamap_unload(xycsc
->dmatag
, iorq
->dmamap
);
2023 (void)bufq_get(iorq
->xy
->xyq
);
2024 disk_unbusy(&iorq
->xy
->sc_dk
,
2025 (bp
->b_bcount
- bp
->b_resid
),
2026 (bp
->b_flags
& B_READ
));
2027 iorq
->mode
= XY_SUB_FREE
;
2031 iorq
->mode
= XY_NEWSTATE(iorq
->mode
, XY_SUB_DONE
);
2035 iorq
->mode
= XY_NEWSTATE(iorq
->mode
, XY_SUB_DONE
);
2040 return (XY_ERR_AOK
);
2044 * xyc_perror: print error.
2045 * - if still_trying is true: we got an error, retried and got a
2046 * different error. in that case lasterror is the old error,
2047 * and errnum is the new one.
2048 * - if still_trying is not true, then if we ever had an error it
2049 * is in lasterror. also, if iorq->errnum == 0, then we recovered
2050 * from that error (otherwise iorq->errnum == iorq->lasterror).
2053 xyc_perror(iorq
, iopb
, still_trying
)
2054 struct xy_iorq
*iorq
;
2055 struct xy_iopb
*iopb
;
2060 int error
= iorq
->lasterror
;
2062 printf("%s", (iorq
->xy
) ? device_xname(&iorq
->xy
->sc_dev
)
2063 : device_xname(&iorq
->xyc
->sc_dev
));
2065 printf("%c: ", 'a' + (char)DISKPART(iorq
->buf
->b_dev
));
2066 if (iopb
->com
== XYCMD_RD
|| iopb
->com
== XYCMD_WR
)
2067 printf("%s %d/%d/%d: ",
2068 (iopb
->com
== XYCMD_RD
) ? "read" : "write",
2069 iopb
->cyl
, iopb
->head
, iopb
->sect
);
2070 printf("%s", xyc_e2str(error
));
2073 printf(" [still trying, new error=%s]", xyc_e2str(iorq
->errnum
));
2075 if (iorq
->errnum
== 0)
2076 printf(" [recovered in %d tries]", iorq
->tries
);
2082 * xyc_error: non-fatal error encountered... recover.
2083 * return AOK if resubmitted, return FAIL if this iopb is done
2086 xyc_error(xycsc
, iorq
, iopb
, comm
)
2087 struct xyc_softc
*xycsc
;
2088 struct xy_iorq
*iorq
;
2089 struct xy_iopb
*iopb
;
2093 int errnum
= iorq
->errnum
;
2094 int erract
= xyc_entoact(errnum
);
2095 int oldmode
, advance
;
2100 if (erract
== XY_ERA_RSET
) { /* some errors require a reset */
2101 oldmode
= iorq
->mode
;
2102 iorq
->mode
= XY_SUB_DONE
| (~XY_SUB_MASK
& oldmode
);
2103 /* make xyc_start ignore us */
2104 xyc_reset(xycsc
, 1, XY_RSET_NONE
, errnum
, iorq
->xy
);
2105 iorq
->mode
= oldmode
;
2107 /* check for read/write to a sector in bad144 table if bad: redirect
2108 * request to bad144 area */
2110 if ((comm
== XYCMD_RD
|| comm
== XYCMD_WR
) &&
2111 (iorq
->mode
& XY_MODE_B144
) == 0) {
2112 advance
= iorq
->sectcnt
- iopb
->scnt
;
2113 XYC_ADVANCE(iorq
, advance
);
2115 if ((i
= isbad(&iorq
->xy
->dkb
, iorq
->blockno
/ iorq
->xy
->sectpercyl
,
2116 (iorq
->blockno
/ iorq
->xy
->nsect
) % iorq
->xy
->nhead
,
2117 iorq
->blockno
% iorq
->xy
->nsect
)) != -1) {
2118 iorq
->mode
|= XY_MODE_B144
; /* enter bad144 mode &
2120 iopb
->errnum
= iopb
->done
= iopb
->errs
= 0;
2122 iopb
->cyl
= (iorq
->xy
->ncyl
+ iorq
->xy
->acyl
) - 2;
2123 /* second to last acyl */
2124 i
= iorq
->xy
->sectpercyl
- 1 - i
; /* follow bad144
2126 iopb
->head
= i
/ iorq
->xy
->nhead
;
2127 iopb
->sect
= i
% iorq
->xy
->nhead
;
2128 /* will resubmit when we come out of remove_iorq */
2129 return (XY_ERR_AOK
); /* recovered! */
2135 * it isn't a bad144 sector, must be real error! see if we can retry
2138 if ((iorq
->mode
& XY_MODE_VERBO
) && iorq
->lasterror
)
2139 xyc_perror(iorq
, iopb
, 1); /* inform of error state
2141 iorq
->lasterror
= errnum
;
2143 if ((erract
== XY_ERA_RSET
|| erract
== XY_ERA_HARD
)
2144 && iorq
->tries
< XYC_MAXTRIES
) { /* retry? */
2146 iorq
->errnum
= iopb
->errnum
= iopb
->done
= iopb
->errs
= 0;
2147 /* will resubmit at end of remove_iorq */
2148 return (XY_ERR_AOK
); /* recovered! */
2151 /* failed to recover from this error */
2152 return (XY_ERR_FAIL
);
2156 * xyc_tick: make sure xy is still alive and ticking (err, kicking).
2163 struct xyc_softc
*xycsc
= arg
;
2164 int lcv
, s
, reset
= 0;
2166 /* reduce ttl for each request if one goes to zero, reset xyc */
2168 for (lcv
= 0; lcv
< XYC_MAXIOPB
; lcv
++) {
2169 if (xycsc
->reqs
[lcv
].mode
== 0 ||
2170 XY_STATE(xycsc
->reqs
[lcv
].mode
) == XY_SUB_DONE
)
2172 xycsc
->reqs
[lcv
].ttl
--;
2173 if (xycsc
->reqs
[lcv
].ttl
== 0)
2177 printf("%s: watchdog timeout\n", device_xname(&xycsc
->sc_dev
));
2178 xyc_reset(xycsc
, 0, XY_RSET_NONE
, XY_ERR_FAIL
, NULL
);
2182 /* until next time */
2184 callout_reset(&xycsc
->sc_tick_ch
, XYC_TICKCNT
, xyc_tick
, xycsc
);
2188 * xyc_ioctlcmd: this function provides a user level interface to the
2189 * controller via ioctl. this allows "format" programs to be written
2190 * in user code, and is also useful for some debugging. we return
2191 * an error code. called at user priority.
2193 * XXX missing a few commands (see the 7053 driver for ideas)
2196 xyc_ioctlcmd(xy
, dev
, xio
)
2197 struct xy_softc
*xy
;
2199 struct xd_iocmd
*xio
;
2202 int s
, rqno
, dummy
= 0;
2203 char *dvmabuf
= NULL
, *buf
= NULL
;
2204 struct xyc_softc
*xycsc
;
2206 bus_dma_segment_t seg
;
2208 /* check sanity of requested command */
2212 case XYCMD_NOP
: /* no op: everything should be zero */
2213 if (xio
->subfn
|| xio
->dptr
|| xio
->dlen
||
2214 xio
->block
|| xio
->sectcnt
)
2218 case XYCMD_RD
: /* read / write sectors (up to XD_IOCMD_MAXS) */
2220 if (xio
->subfn
|| xio
->sectcnt
> XD_IOCMD_MAXS
||
2221 xio
->sectcnt
* XYFM_BPS
!= xio
->dlen
|| xio
->dptr
== NULL
)
2225 case XYCMD_SK
: /* seek: doesn't seem useful to export this */
2231 return (EINVAL
);/* ??? */
2236 /* create DVMA buffer for request if needed */
2240 if ((error
= xy_dmamem_alloc(xycsc
->dmatag
, xycsc
->auxmap
,
2242 xio
->dlen
, (void **)&buf
,
2246 dvmabuf
= (void *)(u_long
)BUS_ADDR_PADDR(busbuf
);
2248 if (xio
->cmd
== XYCMD_WR
) {
2249 if ((error
= copyin(xio
->dptr
, buf
, xio
->dlen
)) != 0) {
2250 bus_dmamem_unmap(xycsc
->dmatag
, buf
, xio
->dlen
);
2251 bus_dmamem_free(xycsc
->dmatag
, &seg
, rseg
);
2260 rqno
= xyc_cmd(xycsc
, xio
->cmd
, xio
->subfn
, xy
->xy_drive
, xio
->block
,
2261 xio
->sectcnt
, dvmabuf
, XY_SUB_WAIT
);
2262 if (rqno
== XY_ERR_FAIL
) {
2266 xio
->errnum
= xycsc
->ciorq
->errnum
;
2267 xio
->tries
= xycsc
->ciorq
->tries
;
2268 XYC_DONE(xycsc
, dummy
);
2270 if (xio
->cmd
== XYCMD_RD
)
2271 error
= copyout(buf
, xio
->dptr
, xio
->dlen
);
2276 xy_dmamem_free(xycsc
->dmatag
, xycsc
->auxmap
, &seg
, rseg
,
2283 * xyc_e2str: convert error code number into an error string
2290 return ("Software fatal error");
2292 return ("DOUBLE ERROR");
2294 return ("Successful completion");
2296 return("Interrupt pending");
2298 return("Busy conflict");
2300 return("Operation timeout");
2302 return("Header not found");
2304 return("Hard ECC error");
2306 return("Illegal cylinder address");
2308 return("Illegal sector address");
2310 return("Last sector too small");
2312 return("Slave ACK error (non-existent memory)");
2314 return("Cylinder and head/header error");
2316 return("Auto-seek retry successful");
2318 return("Write-protect error");
2320 return("Unimplemented command");
2322 return("Drive not ready");
2324 return("Sector count zero");
2326 return("Drive faulted");
2328 return("Illegal sector size");
2330 return("Self test A");
2332 return("Self test B");
2334 return("Self test C");
2336 return("Soft ECC error");
2338 return("Soft ECC error recovered");
2340 return("Illegal head");
2342 return("Disk sequencer error");
2344 return("Seek error");
2346 return ("Unknown error");
2357 case XY_ERR_FAIL
: case XY_ERR_DERR
: case XY_ERR_IPEN
:
2358 case XY_ERR_BCFL
: case XY_ERR_ICYL
: case XY_ERR_ISEC
:
2359 case XY_ERR_UIMP
: case XY_ERR_SZER
: case XY_ERR_ISSZ
:
2360 case XY_ERR_SLTA
: case XY_ERR_SLTB
: case XY_ERR_SLTC
:
2361 case XY_ERR_IHED
: case XY_ERR_SACK
: case XY_ERR_SMAL
:
2363 return(XY_ERA_PROG
); /* program error ! */
2365 case XY_ERR_TIMO
: case XY_ERR_NHDR
: case XY_ERR_HARD
:
2366 case XY_ERR_DNRY
: case XY_ERR_CHER
: case XY_ERR_SEEK
:
2369 return(XY_ERA_HARD
); /* hard error, retry */
2371 case XY_ERR_DFLT
: case XY_ERR_DSEQ
:
2373 return(XY_ERA_RSET
); /* hard error reset */
2375 case XY_ERR_SRTR
: case XY_ERR_SFOK
: case XY_ERR_AOK
:
2377 return(XY_ERA_SOFT
); /* an FYI error */
2381 return(XY_ERA_WPRO
); /* write protect */
2384 return(XY_ERA_PROG
); /* ??? */