1 /* $NetBSD: xy.c,v 1.70 2009/01/12 08:27:26 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>
39 * id: &Id: xy.c,v 1.1 1995/09/25 20:35:14 chuck Exp &
41 * references: [1] Xylogics Model 753 User's Manual
42 * part number: 166-753-001, Revision B, May 21, 1988.
43 * "Your Partner For Performance"
44 * [2] other NetBSD disk device drivers
45 * [3] Xylogics Model 450 User's Manual
46 * part number: 166-017-001, Revision B, 1983.
47 * [4] Addendum to Xylogics Model 450 Disk Controller User's
49 * [5] The 451 Controller, Rev. B3, September 2, 1986.
50 * [6] David Jones <dej@achilles.net>'s unfinished 450/451 driver
54 #include <sys/cdefs.h>
55 __KERNEL_RCSID(0, "$NetBSD: xy.c,v 1.70 2009/01/12 08:27:26 cegger Exp $");
57 #undef XYC_DEBUG /* full debug */
58 #undef XYC_DIAG /* extra sanity checks */
59 #if defined(DIAGNOSTIC) && !defined(XYC_DIAG)
60 #define XYC_DIAG /* link in with master DIAG option */
63 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/kernel.h>
69 #include <sys/ioctl.h>
73 #include <sys/malloc.h>
74 #include <sys/device.h>
75 #include <sys/disklabel.h>
77 #include <sys/syslog.h>
78 #include <sys/dkbad.h>
80 #include <sys/kauth.h>
82 #include <uvm/uvm_extern.h>
84 #include <dev/sun/disklabel.h>
86 #include <machine/autoconf.h>
87 #include <machine/dvma.h>
89 #include <sun3/dev/xyreg.h>
90 #include <sun3/dev/xyvar.h>
91 #include <sun3/dev/xio.h>
97 * Print a complaint when no xy children were specified
98 * in the config file. Better than a link error...
100 * XXX: Some folks say this driver should be split in two,
101 * but that seems pointless with ONLY one type of child.
105 #error "xyc but no xy?"
113 * XYC_GO: start iopb ADDR (DVMA addr in a u_long) on XYC
115 #define XYC_GO(XYC, ADDR) \
117 (XYC)->xyc_addr_lo = ((ADDR) & 0xff); \
118 (ADDR) = ((ADDR) >> 8); \
119 (XYC)->xyc_addr_hi = ((ADDR) & 0xff); \
120 (ADDR) = ((ADDR) >> 8); \
121 (XYC)->xyc_reloc_lo = ((ADDR) & 0xff); \
122 (ADDR) = ((ADDR) >> 8); \
123 (XYC)->xyc_reloc_hi = (ADDR); \
124 (XYC)->xyc_csr = XYC_GBSY; /* go! */ \
125 } while (/* CONSTCOND */ 0)
128 * XYC_DONE: don't need IORQ, get error code and free (done after xyc_cmd)
131 #define XYC_DONE(SC,ER) \
133 if ((ER) == XY_ERR_AOK) { \
134 (ER) = (SC)->ciorq->errno; \
135 (SC)->ciorq->mode = XY_SUB_FREE; \
136 wakeup((SC)->ciorq); \
138 } while (/* CONSTCOND */ 0)
141 * XYC_ADVANCE: advance iorq's pointers by a number of sectors
144 #define XYC_ADVANCE(IORQ, N) \
147 (IORQ)->sectcnt -= (N); \
148 (IORQ)->blockno += (N); \
149 (IORQ)->dbuf += ((N) * XYFM_BPS); \
151 } while (/* CONSTCOND */ 0)
154 * note - addresses you can sleep on:
155 * [1] & of xy_softc's "state" (waiting for a chance to attach a drive)
156 * [2] & an iorq (waiting for an XY_SUB_WAIT iorq to finish)
161 * function prototypes
162 * "xyc_*" functions are internal, all others are external interfaces
166 struct xy_iopb
*xyc_chain(struct xyc_softc
*, struct xy_iorq
*);
167 int xyc_cmd(struct xyc_softc
*, int, int, int, int, int, char *, int);
168 const char *xyc_e2str(int);
169 int xyc_entoact(int);
170 int xyc_error(struct xyc_softc
*, struct xy_iorq
*, struct xy_iopb
*, int);
171 int xyc_ioctlcmd(struct xy_softc
*, dev_t dev
, struct xd_iocmd
*);
172 void xyc_perror(struct xy_iorq
*, struct xy_iopb
*, int);
173 int xyc_piodriver(struct xyc_softc
*, struct xy_iorq
*);
174 int xyc_remove_iorq(struct xyc_softc
*);
175 int xyc_reset(struct xyc_softc
*, int, struct xy_iorq
*, int,
177 inline void xyc_rqinit(struct xy_iorq
*, struct xyc_softc
*, struct xy_softc
*,
178 int, u_long
, int, void *, struct buf
*);
179 void xyc_rqtopb(struct xy_iorq
*, struct xy_iopb
*, int, int);
180 void xyc_start(struct xyc_softc
*, struct xy_iorq
*);
181 int xyc_startbuf(struct xyc_softc
*, struct xy_softc
*, struct buf
*);
182 int xyc_submit_iorq(struct xyc_softc
*, struct xy_iorq
*, int);
183 void xyc_tick(void *);
184 int xyc_unbusy(struct xyc
*, int);
185 void xyc_xyreset(struct xyc_softc
*, struct xy_softc
*);
187 /* machine interrupt hook */
191 static int xycmatch(device_t
, cfdata_t
, void *);
192 static void xycattach(device_t
, device_t
, void *);
193 static int xyc_print(void *, const char *);
195 static int xymatch(device_t
, cfdata_t
, void *);
196 static void xyattach(device_t
, device_t
, void *);
197 static void xy_init(struct xy_softc
*);
199 static void xydummystrat(struct buf
*);
200 int xygetdisklabel(struct xy_softc
*, void *);
203 * cfattach's: device driver interface to autoconfig
206 CFATTACH_DECL_NEW(xyc
, sizeof(struct xyc_softc
),
207 xycmatch
, xycattach
, NULL
, NULL
);
209 CFATTACH_DECL_NEW(xy
, sizeof(struct xy_softc
),
210 xymatch
, xyattach
, NULL
, NULL
);
212 struct xyc_attach_args
{ /* this is the "aux" args to xyattach */
213 int driveno
; /* unit number */
216 dev_type_open(xyopen
);
217 dev_type_close(xyclose
);
218 dev_type_read(xyread
);
219 dev_type_write(xywrite
);
220 dev_type_ioctl(xyioctl
);
221 dev_type_strategy(xystrategy
);
222 dev_type_dump(xydump
);
223 dev_type_size(xysize
);
225 const struct bdevsw xy_bdevsw
= {
226 xyopen
, xyclose
, xystrategy
, xyioctl
, xydump
, xysize
, D_DISK
229 const struct cdevsw xy_cdevsw
= {
230 xyopen
, xyclose
, xyread
, xywrite
, xyioctl
,
231 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_DISK
238 struct dkdriver xydkdriver
= { xystrategy
};
241 * start: disk label fix code (XXX)
244 static void *xy_labeldata
;
247 xydummystrat(struct buf
*bp
)
250 if (bp
->b_bcount
!= XYFM_BPS
)
251 panic("%s: b_bcount", __func__
);
252 memcpy(bp
->b_data
, xy_labeldata
, XYFM_BPS
);
253 bp
->b_oflags
|= BO_DONE
;
254 bp
->b_cflags
&= ~BC_BUSY
;
258 xygetdisklabel(struct xy_softc
*xy
, void *b
)
261 struct sun_disklabel
*sdl
;
263 /* We already have the label data in `b'; setup for dummy strategy */
266 /* Required parameter for readdisklabel() */
267 xy
->sc_dk
.dk_label
->d_secsize
= XYFM_BPS
;
269 err
= readdisklabel(MAKEDISKDEV(0, device_unit(xy
->sc_dev
), RAW_PART
),
270 xydummystrat
, xy
->sc_dk
.dk_label
, xy
->sc_dk
.dk_cpulabel
);
272 printf("%s: %s\n", device_xname(xy
->sc_dev
), err
);
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_pcyl
;
281 printf("%s: WARNING: no `pcyl' in disk label.\n",
282 device_xname(xy
->sc_dev
));
283 xy
->pcyl
= xy
->sc_dk
.dk_label
->d_ncylinders
+
284 xy
->sc_dk
.dk_label
->d_acylinders
;
285 printf("%s: WARNING: guessing pcyl=%d (ncyl+acyl)\n",
286 device_xname(xy
->sc_dev
), xy
->pcyl
);
289 xy
->ncyl
= xy
->sc_dk
.dk_label
->d_ncylinders
;
290 xy
->acyl
= xy
->sc_dk
.dk_label
->d_acylinders
;
291 xy
->nhead
= xy
->sc_dk
.dk_label
->d_ntracks
;
292 xy
->nsect
= xy
->sc_dk
.dk_label
->d_nsectors
;
293 xy
->sectpercyl
= xy
->nhead
* xy
->nsect
;
294 xy
->sc_dk
.dk_label
->d_secsize
= XYFM_BPS
; /* not handled by
300 * end: disk label fix code (XXX)
304 * a u t o c o n f i g f u n c t i o n s
308 * xycmatch: determine if xyc is present or not. we do a
309 * soft reset to detect the xyc.
312 xycmatch(device_t parent
, cfdata_t cf
, void *aux
)
314 struct confargs
*ca
= aux
;
316 /* No default VME address. */
317 if (ca
->ca_paddr
== -1)
320 /* Make sure something is there... */
321 if (bus_peek(ca
->ca_bustype
, ca
->ca_paddr
+ 5, 1) == -1)
324 /* Default interrupt priority. */
325 if (ca
->ca_intpri
== -1)
332 * xycattach: attach controller
335 xycattach(device_t parent
, device_t self
, void *aux
)
337 struct xyc_softc
*xyc
= device_private(self
);
338 struct confargs
*ca
= aux
;
339 struct xyc_attach_args xa
;
340 int lcv
, err
, res
, pbsz
;
344 /* get addressing and intr level stuff from autoconfig and load it
345 * into our xyc_softc. */
348 xyc
->xyc
= (struct xyc
*)bus_mapin(ca
->ca_bustype
, ca
->ca_paddr
,
350 xyc
->bustype
= ca
->ca_bustype
;
351 xyc
->ipl
= ca
->ca_intpri
;
352 xyc
->vector
= ca
->ca_intvec
;
353 xyc
->no_ols
= 0; /* XXX should be from config */
355 for (lcv
= 0; lcv
< XYC_MAXDEV
; lcv
++)
356 xyc
->sc_drives
[lcv
] = NULL
;
359 * allocate and zero buffers
360 * check boundaries of the KVA's ... all IOPBs must reside in
361 * the same 64K region.
364 pbsz
= XYC_MAXIOPB
* sizeof(struct xy_iopb
);
365 tmp
= tmp2
= (struct xy_iopb
*)dvma_malloc(pbsz
); /* KVA */
367 if ((ultmp
& 0xffff0000) != ((ultmp
+ pbsz
) & 0xffff0000)) {
368 tmp
= (struct xy_iopb
*)dvma_malloc(pbsz
); /* retry! */
369 dvma_free(tmp2
, pbsz
);
370 ultmp
= (u_long
) tmp
;
371 if ((ultmp
& 0xffff0000) != ((ultmp
+ pbsz
) & 0xffff0000)) {
372 aprint_error(": can't alloc IOPB mem in 64K\n");
376 memset(tmp
, 0, pbsz
);
379 (struct xy_iopb
*)dvma_kvtopa(xyc
->iopbase
, xyc
->bustype
);
380 xyc
->reqs
= malloc(XYC_MAXIOPB
* sizeof(struct xy_iorq
),
381 M_DEVBUF
, M_NOWAIT
| M_ZERO
);
382 if (xyc
->reqs
== NULL
)
386 * init iorq to iopb pointers, and non-zero fields in the
387 * iopb which never change.
390 for (lcv
= 0; lcv
< XYC_MAXIOPB
; lcv
++) {
391 xyc
->xy_chain
[lcv
] = NULL
;
392 xyc
->reqs
[lcv
].iopb
= &xyc
->iopbase
[lcv
];
393 xyc
->iopbase
[lcv
].asr
= 1; /* always the same */
394 xyc
->iopbase
[lcv
].eef
= 1; /* always the same */
395 xyc
->iopbase
[lcv
].ecm
= XY_ECM
; /* always the same */
396 xyc
->iopbase
[lcv
].aud
= 1; /* always the same */
397 xyc
->iopbase
[lcv
].relo
= 1; /* always the same */
398 xyc
->iopbase
[lcv
].thro
= XY_THRO
;/* always the same */
400 xyc
->ciorq
= &xyc
->reqs
[XYC_CTLIOPB
]; /* short hand name */
401 xyc
->ciopb
= &xyc
->iopbase
[XYC_CTLIOPB
]; /* short hand name */
404 /* read controller parameters and insure we have a 450/451 */
406 err
= xyc_cmd(xyc
, XYCMD_ST
, 0, 0, 0, 0, 0, XY_SUB_POLL
);
407 res
= xyc
->ciopb
->ctyp
;
409 if (res
!= XYCT_450
) {
411 aprint_error(": %s: ", xyc_e2str(err
));
412 aprint_error(": doesn't identify as a 450/451\n");
415 aprint_normal(": Xylogics 450/451");
417 /* 450 doesn't overlap seek right */
418 aprint_normal(" [OLS disabled]");
421 aprint_error_dev(self
, "error: %s\n", xyc_e2str(err
));
424 if ((xyc
->xyc
->xyc_csr
& XYC_ADRM
) == 0) {
425 aprint_error_dev(self
, "24 bit addressing turned off\n");
426 printf("please set hardware jumpers JM1-JM2=in, JM3-JM4=out\n");
427 printf("to enable 24 bit mode and this driver\n");
431 /* link in interrupt with higher level software */
432 isr_add_vectored(xycintr
, xyc
, ca
->ca_intpri
, ca
->ca_intvec
);
433 evcnt_attach_dynamic(&xyc
->sc_intrcnt
, EVCNT_TYPE_INTR
, NULL
,
434 device_xname(self
), "intr");
436 callout_init(&xyc
->sc_tick_ch
, 0);
438 /* now we must look for disks using autoconfig */
439 for (xa
.driveno
= 0; xa
.driveno
< XYC_MAXDEV
; xa
.driveno
++)
440 (void)config_found(self
, (void *)&xa
, xyc_print
);
442 /* start the watchdog clock */
443 callout_reset(&xyc
->sc_tick_ch
, XYC_TICKCNT
, xyc_tick
, xyc
);
447 xyc_print(void *aux
, const char *name
)
449 struct xyc_attach_args
*xa
= aux
;
452 aprint_normal("%s: ", name
);
454 if (xa
->driveno
!= -1)
455 aprint_normal(" drive %d", xa
->driveno
);
461 * xymatch: probe for disk.
463 * note: we almost always say disk is present. this allows us to
464 * spin up and configure a disk after the system is booted (we can
465 * call xyattach!). Also, wire down the relationship between the
466 * xy* and xyc* devices, to simplify boot device identification.
469 xymatch(device_t parent
, cfdata_t cf
, void *aux
)
471 struct xyc_attach_args
*xa
= aux
;
474 /* Match only on the "wired-down" controller+disk. */
475 xy_unit
= device_unit(parent
) * 2 + xa
->driveno
;
476 if (cf
->cf_unit
!= xy_unit
)
483 * xyattach: attach a disk.
486 xyattach(device_t parent
, device_t self
, void *aux
)
488 struct xy_softc
*xy
= device_private(self
);
489 struct xyc_softc
*xyc
= device_private(parent
);
490 struct xyc_attach_args
*xa
= aux
;
496 * Always re-initialize the disk structure. We want statistics
497 * to start with a clean slate.
499 memset(&xy
->sc_dk
, 0, sizeof(xy
->sc_dk
));
500 disk_init(&xy
->sc_dk
, device_xname(self
), &xydkdriver
);
502 xy
->state
= XY_DRIVE_UNKNOWN
; /* to start */
506 /* init queue of waiting bufs */
507 bufq_alloc(&xy
->xyq
, "disksort", BUFQ_SORT_RAWBLOCK
);
508 xy
->xyrq
= &xyc
->reqs
[xa
->driveno
];
510 xy
->xy_drive
= xa
->driveno
;
511 xyc
->sc_drives
[xa
->driveno
] = xy
;
513 /* Do init work common to attach and open. */
518 * end of autoconfig functions
522 * Initialize a disk. This can be called from both autoconf and
523 * also from xyopen/xystrategy.
526 xy_init(struct xy_softc
*xy
)
528 struct xyc_softc
*xyc
;
531 int err
, spt
, mb
, blk
, lcv
, fullmode
, newstate
;
534 xy
->state
= XY_DRIVE_ATTACHING
;
535 newstate
= XY_DRIVE_UNKNOWN
;
536 fullmode
= (cold
) ? XY_SUB_POLL
: XY_SUB_WAIT
;
537 dvmabuf
= dvma_malloc(XYFM_BPS
);
539 /* first try and reset the drive */
541 err
= xyc_cmd(xyc
, XYCMD_RST
, 0, xy
->xy_drive
, 0, 0, 0, fullmode
);
543 if (err
== XY_ERR_DNRY
) {
544 printf("%s: drive %d: off-line\n",
545 device_xname(xy
->sc_dev
), xy
->xy_drive
);
549 printf("%s: ERROR 0x%02x (%s)\n",
550 device_xname(xy
->sc_dev
), err
, xyc_e2str(err
));
553 printf("%s: drive %d ready",
554 device_xname(xy
->sc_dev
), xy
->xy_drive
);
557 * now set drive parameters (to semi-bogus values) so we can read the
560 xy
->pcyl
= xy
->ncyl
= 1;
565 for (lcv
= 0; lcv
< 126; lcv
++) /* init empty bad144 table */
566 xy
->dkb
.bt_bad
[lcv
].bt_cyl
=
567 xy
->dkb
.bt_bad
[lcv
].bt_trksec
= 0xffff;
569 /* read disk label */
570 for (xy
->drive_type
= 0; xy
->drive_type
<= XYC_MAXDT
;
572 err
= xyc_cmd(xyc
, XYCMD_RD
, 0, xy
->xy_drive
, 0, 1,
575 if (err
== XY_ERR_AOK
)
579 if (err
!= XY_ERR_AOK
) {
580 printf("%s: reading disk label failed: %s\n",
581 device_xname(xy
->sc_dev
), xyc_e2str(err
));
584 printf("%s: drive type %d\n",
585 device_xname(xy
->sc_dev
), xy
->drive_type
);
587 newstate
= XY_DRIVE_NOLABEL
;
589 xy
->hw_spt
= spt
= 0; /* XXX needed ? */
590 /* Attach the disk: must be before getdisklabel to malloc label */
591 disk_attach(&xy
->sc_dk
);
593 if (xygetdisklabel(xy
, dvmabuf
) != XY_ERR_AOK
)
596 /* inform the user of what is up */
597 printf("%s: <%s>, pcyl %d\n",
598 device_xname(xy
->sc_dev
),
599 (char *)dvmabuf
, xy
->pcyl
);
600 mb
= xy
->ncyl
* (xy
->nhead
* xy
->nsect
) / (1048576 / XYFM_BPS
);
601 printf("%s: %dMB, %d cyl, %d head, %d sec\n",
602 device_xname(xy
->sc_dev
), mb
, xy
->ncyl
, xy
->nhead
, xy
->nsect
);
605 * 450/451 stupidity: the drive type is encoded into the format
606 * of the disk. the drive type in the IOPB must match the drive
607 * type in the format, or you will not be able to do I/O to the
608 * disk (you get header not found errors). if you have two drives
609 * of different sizes that have the same drive type in their
610 * formatting then you are out of luck.
612 * this problem was corrected in the 753/7053.
615 for (lcv
= 0 ; lcv
< XYC_MAXDEV
; lcv
++) {
616 struct xy_softc
*oxy
;
618 oxy
= xyc
->sc_drives
[lcv
];
619 if (oxy
== NULL
|| oxy
== xy
)
621 if (oxy
->drive_type
!= xy
->drive_type
)
623 if (xy
->nsect
!= oxy
->nsect
|| xy
->pcyl
!= oxy
->pcyl
||
624 xy
->nhead
!= oxy
->nhead
) {
625 printf("%s: %s and %s must be the same size!\n",
626 device_xname(xyc
->sc_dev
),
627 device_xname(xy
->sc_dev
),
628 device_xname(oxy
->sc_dev
));
629 panic("xy drive size mismatch");
634 /* now set the real drive parameters! */
635 blk
= (xy
->nsect
- 1) +
636 ((xy
->nhead
- 1) * xy
->nsect
) +
637 ((xy
->pcyl
- 1) * xy
->nsect
* xy
->nhead
);
638 err
= xyc_cmd(xyc
, XYCMD_SDS
, 0, xy
->xy_drive
, blk
, 0, 0, fullmode
);
641 printf("%s: write drive size failed: %s\n",
642 device_xname(xy
->sc_dev
), xyc_e2str(err
));
645 newstate
= XY_DRIVE_ONLINE
;
648 * read bad144 table. this table resides on the first sector of the
649 * last track of the disk (i.e. second cyl of "acyl" area).
651 blk
= (xy
->ncyl
+ xy
->acyl
- 1) * (xy
->nhead
* xy
->nsect
) +
653 (xy
->nhead
- 1) * xy
->nsect
; /* last head */
654 err
= xyc_cmd(xyc
, XYCMD_RD
, 0, xy
->xy_drive
, blk
, 1,
658 printf("%s: reading bad144 failed: %s\n",
659 device_xname(xy
->sc_dev
), xyc_e2str(err
));
663 /* check dkbad for sanity */
664 dkb
= (struct dkbad
*)dvmabuf
;
665 for (lcv
= 0; lcv
< 126; lcv
++) {
666 if ((dkb
->bt_bad
[lcv
].bt_cyl
== 0xffff ||
667 dkb
->bt_bad
[lcv
].bt_cyl
== 0) &&
668 dkb
->bt_bad
[lcv
].bt_trksec
== 0xffff)
669 continue; /* blank */
670 if (dkb
->bt_bad
[lcv
].bt_cyl
>= xy
->ncyl
)
672 if ((dkb
->bt_bad
[lcv
].bt_trksec
>> 8) >= xy
->nhead
)
674 if ((dkb
->bt_bad
[lcv
].bt_trksec
& 0xff) >= xy
->nsect
)
678 printf("%s: warning: invalid bad144 sector!\n",
679 device_xname(xy
->sc_dev
));
681 memcpy(&xy
->dkb
, dvmabuf
, XYFM_BPS
);
685 xy
->state
= newstate
;
686 dvma_free(dvmabuf
, XYFM_BPS
);
690 * { b , c } d e v s w f u n c t i o n s
694 * xyclose: close device
697 xyclose(dev_t dev
, int flag
, int fmt
, struct lwp
*l
)
699 struct xy_softc
*xy
= device_lookup_private(&xy_cd
, DISKUNIT(dev
));
700 int part
= DISKPART(dev
);
702 /* clear mask bits */
706 xy
->sc_dk
.dk_copenmask
&= ~(1 << part
);
709 xy
->sc_dk
.dk_bopenmask
&= ~(1 << part
);
712 xy
->sc_dk
.dk_openmask
= xy
->sc_dk
.dk_copenmask
| xy
->sc_dk
.dk_bopenmask
;
718 * xydump: crash dump system
721 xydump(dev_t dev
, daddr_t blkno
, void *va
, size_t sz
)
726 unit
= DISKUNIT(dev
);
727 part
= DISKPART(dev
);
729 xy
= device_lookup_private(&xy_cd
, unit
);
733 printf("%s%c: crash dump not supported (yet)\n",
734 device_xname(xy
->sc_dev
), 'a' + part
);
738 /* outline: globals: "dumplo" == sector number of partition to start
739 * dump at (convert to physical sector with partition table)
740 * "dumpsize" == size of dump in clicks "physmem" == size of physical
741 * memory (clicks, ctob() to get bytes) (normal case: dumpsize ==
744 * dump a copy of physical memory to the dump device starting at sector
745 * "dumplo" in the swap partition (make sure > 0). map in pages as
746 * we go. use polled I/O.
748 * XXX how to handle NON_CONTIG?
752 static enum kauth_device_req
753 xy_getkauthreq(u_char cmd
)
755 enum kauth_device_req req
;
762 req
= KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_WRITE
;
768 req
= KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READ
;
773 req
= KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF
;
779 req
= KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_WRITECONF
;
795 * xyioctl: ioctls on XY drives. based on ioctl's of other netbsd disks.
798 xyioctl(dev_t dev
, u_long command
, void *addr
, int flag
, struct lwp
*l
)
801 struct xd_iocmd
*xio
;
804 unit
= DISKUNIT(dev
);
806 xy
= device_lookup_private(&xy_cd
, unit
);
810 /* switch on ioctl type */
813 case DIOCSBAD
: /* set bad144 info */
814 if ((flag
& FWRITE
) == 0)
817 memcpy(&xy
->dkb
, addr
, sizeof(xy
->dkb
));
821 case DIOCGDINFO
: /* get disk label */
822 memcpy(addr
, xy
->sc_dk
.dk_label
, sizeof(struct disklabel
));
825 case DIOCGPART
: /* get partition info */
826 ((struct partinfo
*)addr
)->disklab
= xy
->sc_dk
.dk_label
;
827 ((struct partinfo
*)addr
)->part
=
828 &xy
->sc_dk
.dk_label
->d_partitions
[DISKPART(dev
)];
831 case DIOCSDINFO
: /* set disk label */
832 if ((flag
& FWRITE
) == 0)
834 error
= setdisklabel(xy
->sc_dk
.dk_label
,
835 (struct disklabel
*)addr
, /* xy->sc_dk.dk_openmask : */ 0,
836 xy
->sc_dk
.dk_cpulabel
);
838 if (xy
->state
== XY_DRIVE_NOLABEL
)
839 xy
->state
= XY_DRIVE_ONLINE
;
843 case DIOCWLABEL
: /* change write status of disk label */
844 if ((flag
& FWRITE
) == 0)
847 xy
->flags
|= XY_WLABEL
;
849 xy
->flags
&= ~XY_WLABEL
;
852 case DIOCWDINFO
: /* write disk label */
853 if ((flag
& FWRITE
) == 0)
855 error
= setdisklabel(xy
->sc_dk
.dk_label
,
856 (struct disklabel
*)addr
, /* xy->sc_dk.dk_openmask : */ 0,
857 xy
->sc_dk
.dk_cpulabel
);
859 if (xy
->state
== XY_DRIVE_NOLABEL
)
860 xy
->state
= XY_DRIVE_ONLINE
;
862 /* Simulate opening partition 0 so write succeeds. */
863 xy
->sc_dk
.dk_openmask
|= (1 << 0);
864 error
= writedisklabel(MAKEDISKDEV(major(dev
),
865 DISKUNIT(dev
), RAW_PART
),
866 xystrategy
, xy
->sc_dk
.dk_label
,
867 xy
->sc_dk
.dk_cpulabel
);
868 xy
->sc_dk
.dk_openmask
=
869 xy
->sc_dk
.dk_copenmask
| xy
->sc_dk
.dk_bopenmask
;
874 enum kauth_device_req req
;
876 xio
= (struct xd_iocmd
*)addr
;
877 req
= xy_getkauthreq(xio
->cmd
);
878 if ((error
= kauth_authorize_device_passthru(l
->l_cred
,
879 dev
, req
, xio
)) != 0)
881 return xyc_ioctlcmd(xy
, dev
, xio
);
893 xyopen(dev_t dev
, int flag
, int fmt
, struct lwp
*l
)
895 int err
, unit
, part
, s
;
898 /* first, could it be a valid target? */
899 unit
= DISKUNIT(dev
);
900 xy
= device_lookup_private(&xy_cd
, unit
);
903 part
= DISKPART(dev
);
907 * If some other processing is doing init, sleep.
910 while (xy
->state
== XY_DRIVE_ATTACHING
) {
911 if (tsleep(&xy
->state
, PRIBIO
, "xyopen", 0)) {
916 /* Do we need to init the drive? */
917 if (xy
->state
== XY_DRIVE_UNKNOWN
) {
921 /* Was the init successful? */
922 if (xy
->state
== XY_DRIVE_UNKNOWN
) {
927 /* check for partition */
928 if (part
!= RAW_PART
&&
929 (part
>= xy
->sc_dk
.dk_label
->d_npartitions
||
930 xy
->sc_dk
.dk_label
->d_partitions
[part
].p_fstype
== FS_UNUSED
)) {
938 xy
->sc_dk
.dk_copenmask
|= (1 << part
);
941 xy
->sc_dk
.dk_bopenmask
|= (1 << part
);
944 xy
->sc_dk
.dk_openmask
= xy
->sc_dk
.dk_copenmask
| xy
->sc_dk
.dk_bopenmask
;
952 xyread(dev_t dev
, struct uio
*uio
, int flags
)
955 return physio(xystrategy
, NULL
, dev
, B_READ
, minphys
, uio
);
959 xywrite(dev_t dev
, struct uio
*uio
, int flags
)
962 return physio(xystrategy
, NULL
, dev
, B_WRITE
, minphys
, uio
);
967 * xysize: return size of a partition for a dump
973 struct xy_softc
*xysc
;
974 int unit
, part
, size
, omask
;
977 unit
= DISKUNIT(dev
);
978 xysc
= device_lookup_private(&xy_cd
, unit
);
982 part
= DISKPART(dev
);
983 omask
= xysc
->sc_dk
.dk_openmask
& (1 << part
);
985 if (omask
== 0 && xyopen(dev
, 0, S_IFBLK
, NULL
) != 0)
989 if (xysc
->sc_dk
.dk_label
->d_partitions
[part
].p_fstype
!= FS_SWAP
)
990 size
= -1; /* only give valid size for swap partitions */
992 size
= xysc
->sc_dk
.dk_label
->d_partitions
[part
].p_size
*
993 (xysc
->sc_dk
.dk_label
->d_secsize
/ DEV_BSIZE
);
994 if (omask
== 0 && xyclose(dev
, 0, S_IFBLK
, NULL
) != 0)
1000 * xystrategy: buffering system interface to xy.
1003 xystrategy(struct buf
*bp
)
1005 struct xy_softc
*xy
;
1007 struct disklabel
*lp
;
1010 unit
= DISKUNIT(bp
->b_dev
);
1012 /* check for live device */
1014 xy
= device_lookup_private(&xy_cd
, unit
);
1017 (bp
->b_bcount
% xy
->sc_dk
.dk_label
->d_secsize
) != 0) {
1018 bp
->b_error
= EINVAL
;
1022 /* There should always be an open first. */
1023 if (xy
->state
== XY_DRIVE_UNKNOWN
) {
1027 if (xy
->state
!= XY_DRIVE_ONLINE
&& DISKPART(bp
->b_dev
) != RAW_PART
) {
1028 /* no I/O to unlabeled disks, unless raw partition */
1032 /* short circuit zero length request */
1034 if (bp
->b_bcount
== 0)
1037 /* check bounds with label (disksubr.c). Determine the size of the
1038 * transfer, and make sure it is within the boundaries of the
1039 * partition. Adjust transfer if needed, and signal errors or early
1042 lp
= xy
->sc_dk
.dk_label
;
1044 if (bounds_check_with_label(&xy
->sc_dk
, bp
,
1045 (xy
->flags
& XY_WLABEL
) != 0) <= 0)
1049 * Now convert the block number to absolute and put it in
1050 * terms of the device's logical block size.
1052 blkno
= bp
->b_blkno
/ (lp
->d_secsize
/ DEV_BSIZE
);
1053 if (DISKPART(bp
->b_dev
) != RAW_PART
)
1054 blkno
+= lp
->d_partitions
[DISKPART(bp
->b_dev
)].p_offset
;
1056 bp
->b_rawblkno
= blkno
;
1059 * now we know we have a valid buf structure that we need to do I/O
1063 s
= splbio(); /* protect the queues */
1065 bufq_put(xy
->xyq
, bp
); /* XXX disksort_cylinder */
1069 xyc_start(xy
->parent
, NULL
);
1077 /* tells upper layers we are done with this buf */
1078 bp
->b_resid
= bp
->b_bcount
;
1082 * end of {b,c}devsw functions
1086 * i n t e r r u p t f u n c t i o n
1088 * xycintr: hardware interrupt.
1093 struct xyc_softc
*xycsc
= v
;
1095 /* kick the event counter */
1096 xycsc
->sc_intrcnt
.ev_count
++;
1098 /* remove as many done IOPBs as possible */
1099 xyc_remove_iorq(xycsc
);
1101 /* start any iorq's already waiting */
1102 xyc_start(xycsc
, NULL
);
1107 * end of interrupt function
1111 * i n t e r n a l f u n c t i o n s
1115 * xyc_rqinit: fill out the fields of an I/O request
1119 xyc_rqinit(struct xy_iorq
*rq
, struct xyc_softc
*xyc
, struct xy_softc
*xy
,
1120 int md
, u_long blk
, int cnt
, void *db
, struct buf
*bp
)
1125 rq
->ttl
= XYC_MAXTTL
+ 10;
1127 rq
->tries
= rq
->errno
= rq
->lasterror
= 0;
1130 rq
->dbuf
= rq
->dbufbase
= db
;
1135 * xyc_rqtopb: load up an IOPB based on an iorq
1139 xyc_rqtopb(struct xy_iorq
*iorq
, struct xy_iopb
*iopb
, int cmd
, int subfun
)
1143 /* normal IOPB case, standard stuff */
1145 /* chain bit handled later */
1146 iopb
->ien
= (XY_STATE(iorq
->mode
) == XY_SUB_POLL
) ? 0 : 1;
1152 iopb
->unit
= iorq
->xy
->xy_drive
;
1153 iopb
->dt
= iorq
->xy
->drive_type
;
1158 block
= iorq
->blockno
;
1159 if (iorq
->xy
== NULL
|| block
== 0) {
1160 iopb
->sect
= iopb
->head
= iopb
->cyl
= 0;
1162 iopb
->sect
= block
% iorq
->xy
->nsect
;
1163 block
= block
/ iorq
->xy
->nsect
;
1164 iopb
->head
= block
% iorq
->xy
->nhead
;
1165 block
= block
/ iorq
->xy
->nhead
;
1168 iopb
->scnt
= iorq
->sectcnt
;
1169 if (iorq
->dbuf
== NULL
) {
1173 dp
= dvma_kvtopa(iorq
->dbuf
, iorq
->xyc
->bustype
);
1174 iopb
->dataa
= (dp
& 0xffff);
1175 iopb
->datar
= ((dp
& 0xff0000) >> 16);
1177 iopb
->subfn
= subfun
;
1182 * xyc_unbusy: wait for the xyc to go unbusy, or timeout.
1186 xyc_unbusy(struct xyc
*xyc
, int del
)
1190 if ((xyc
->xyc_csr
& XYC_GBSY
) == 0)
1194 return del
== 0 ? XY_ERR_FAIL
: XY_ERR_AOK
;
1198 * xyc_cmd: front end for POLL'd and WAIT'd commands. Returns 0 or error.
1199 * note that NORM requests are handled separately.
1202 xyc_cmd(struct xyc_softc
*xycsc
, int cmd
, int subfn
, int unit
, int block
,
1203 int scnt
, char *dptr
, int fullmode
)
1205 struct xy_iorq
*iorq
= xycsc
->ciorq
;
1206 struct xy_iopb
*iopb
= xycsc
->ciopb
;
1207 int submode
= XY_STATE(fullmode
);
1210 * is someone else using the control iopq wait for it if we can
1213 if (submode
== XY_SUB_WAIT
&& XY_STATE(iorq
->mode
) != XY_SUB_FREE
) {
1214 if (tsleep(iorq
, PRIBIO
, "xyc_cmd", 0))
1219 if (XY_STATE(iorq
->mode
) != XY_SUB_FREE
) {
1220 DELAY(1000000); /* XY_SUB_POLL: steal the iorq */
1221 iorq
->mode
= XY_SUB_FREE
;
1222 printf("%s: stole control iopb\n", device_xname(xycsc
->sc_dev
));
1225 /* init iorq/iopb */
1227 xyc_rqinit(iorq
, xycsc
,
1228 (unit
== XYC_NOUNIT
) ? NULL
: xycsc
->sc_drives
[unit
],
1229 fullmode
, block
, scnt
, dptr
, NULL
);
1231 /* load IOPB from iorq */
1233 xyc_rqtopb(iorq
, iopb
, cmd
, subfn
);
1235 /* submit it for processing */
1237 xyc_submit_iorq(xycsc
, iorq
, fullmode
); /* error code will be in iorq */
1244 * start a buffer for running
1248 xyc_startbuf(struct xyc_softc
*xycsc
, struct xy_softc
*xysc
, struct buf
*bp
)
1251 struct xy_iorq
*iorq
;
1252 struct xy_iopb
*iopb
;
1262 panic("%s null buf", __func__
);
1264 partno
= DISKPART(bp
->b_dev
);
1266 printf("%s: %s%c: %s block %d\n", __func__
, device_xname(xysc
->sc_dev
),
1267 'a' + partno
, (bp
->b_flags
& B_READ
) ? "read" : "write",
1269 printf("xyc_startbuf: b_bcount %d, b_data 0x%x\n",
1270 bp
->b_bcount
, bp
->b_data
);
1276 * also, note that there are two kinds of buf structures, those with
1277 * B_PHYS set and those without B_PHYS. if B_PHYS is set, then it is
1278 * a raw I/O (to a cdevsw) and we are doing I/O directly to the users'
1279 * buffer which has already been mapped into DVMA space. (Not on sun3)
1280 * However, if B_PHYS is not set, then the buffer is a normal system
1281 * buffer which does *not* live in DVMA space. In that case we call
1282 * dvma_mapin to map it into DVMA space so we can do the DMA to it.
1284 * in cases where we do a dvma_mapin, note that iorq points to the
1285 * buffer as mapped into DVMA space, where as the bp->b_data points
1286 * to its non-DVMA mapping.
1288 * XXX - On the sun3, B_PHYS does NOT mean the buffer is mapped
1289 * into dvma space, only that it was remapped into the kernel.
1290 * We ALWAYS have to remap the kernel buf into DVMA space.
1291 * (It is done inexpensively, using whole segments!)
1294 block
= bp
->b_rawblkno
;
1296 dbuf
= dvma_mapin(bp
->b_data
, bp
->b_bcount
, 0);
1297 if (dbuf
== NULL
) { /* out of DVMA space */
1298 printf("%s: warning: out of DVMA space\n",
1299 device_xname(xycsc
->sc_dev
));
1300 return XY_ERR_FAIL
; /* XXX: need some sort of
1301 * call-back scheme here? */
1304 /* init iorq and load iopb from it */
1306 xyc_rqinit(iorq
, xycsc
, xysc
, XY_SUB_NORM
| XY_MODE_VERBO
, block
,
1307 bp
->b_bcount
/ XYFM_BPS
, dbuf
, bp
);
1309 xyc_rqtopb(iorq
, iopb
, (bp
->b_flags
& B_READ
) ? XYCMD_RD
: XYCMD_WR
, 0);
1311 /* Instrumentation. */
1312 disk_busy(&xysc
->sc_dk
);
1319 * xyc_submit_iorq: submit an iorq for processing. returns XY_ERR_AOK
1320 * if ok. if it fail returns an error code. type is XY_SUB_*.
1322 * note: caller frees iorq in all cases except NORM
1325 * NORM: XY_AOK (req pending), XY_FAIL (couldn't submit request)
1326 * WAIT: XY_AOK (success), <error-code> (failed)
1327 * POLL: <same as WAIT>
1328 * NOQ : <same as NORM>
1330 * there are three sources for i/o requests:
1331 * [1] xystrategy: normal block I/O, using "struct buf" system.
1332 * [2] autoconfig/crash dump: these are polled I/O requests, no interrupts.
1333 * [3] open/ioctl: these are I/O requests done in the context of a process,
1334 * and the process should block until they are done.
1336 * software state is stored in the iorq structure. each iorq has an
1337 * iopb structure. the hardware understands the iopb structure.
1338 * every command must go through an iopb. a 450 handles one iopb at a
1339 * time, where as a 451 can take them in chains. [the 450 claims it
1340 * can handle chains, but is appears to be buggy...] iopb are allocated
1341 * in DVMA space at boot up time. each disk gets one iopb, and the
1342 * controller gets one (for POLL and WAIT commands). what happens if
1343 * the iopb is busy? for i/o type [1], the buffers are queued at the
1344 * "buff" layer and * picked up later by the interrupt routine. for case
1345 * [2] we can only be blocked if there is a WAIT type I/O request being
1346 * run. since this can only happen when we are crashing, we wait a sec
1347 * and then steal the IOPB. for case [3] the process can sleep
1348 * on the iorq free list until some iopbs are available.
1352 xyc_submit_iorq(struct xyc_softc
*xycsc
, struct xy_iorq
*iorq
, int type
)
1354 struct xy_iopb
*iopb
;
1358 printf("%s(%s, addr=0x%x, type=%d)\n", __func__
,
1359 device_xname(xycsc
->sc_dev
), iorq
, type
);
1362 /* first check and see if controller is busy */
1363 if ((xycsc
->xyc
->xyc_csr
& XYC_GBSY
) != 0) {
1365 printf("%s: XYC not ready (BUSY)\n", __func__
);
1367 if (type
== XY_SUB_NOQ
)
1368 return XY_ERR_FAIL
; /* failed */
1371 return XY_ERR_AOK
; /* success */
1373 while (iorq
->iopb
->done
== 0) {
1374 (void)tsleep(iorq
, PRIBIO
, "xyciorq", 0);
1376 return (iorq
->errno
);
1377 case XY_SUB_POLL
: /* steal controller */
1378 iopbaddr
= xycsc
->xyc
->xyc_rsetup
; /* RESET */
1379 if (xyc_unbusy(xycsc
->xyc
, XYC_RESETUSEC
) ==
1381 panic("%s: stuck xyc", __func__
);
1382 printf("%s: stole controller\n",
1383 device_xname(xycsc
->sc_dev
));
1386 panic("%s adding", __func__
);
1390 iopb
= xyc_chain(xycsc
, iorq
); /* build chain */
1391 if (iopb
== NULL
) { /* nothing doing? */
1392 if (type
== XY_SUB_NORM
|| type
== XY_SUB_NOQ
)
1394 panic("xyc_submit_iorq: xyc_chain failed!");
1396 iopbaddr
= dvma_kvtopa(iopb
, xycsc
->bustype
);
1398 XYC_GO(xycsc
->xyc
, iopbaddr
);
1400 /* command now running, wrap it up */
1404 return XY_ERR_AOK
; /* success */
1406 while (iorq
->iopb
->done
== 0) {
1407 (void)tsleep(iorq
, PRIBIO
, "xyciorq", 0);
1411 return xyc_piodriver(xycsc
, iorq
);
1413 panic("%s wrap up", __func__
);
1415 panic("%s impossible", __func__
);
1416 return 0; /* not reached */
1421 * xyc_chain: build a chain. return dvma address of first element in
1422 * the chain. iorq != NULL: means we only want that item on the chain.
1426 xyc_chain(struct xyc_softc
*xycsc
, struct xy_iorq
*iorq
)
1428 int togo
, chain
, hand
;
1429 struct xy_iopb
*iopb
, *prev_iopb
;
1431 memset(xycsc
->xy_chain
, 0, sizeof(xycsc
->xy_chain
));
1434 * promote control IOPB to the top
1437 if ((XY_STATE(xycsc
->reqs
[XYC_CTLIOPB
].mode
) == XY_SUB_POLL
||
1438 XY_STATE(xycsc
->reqs
[XYC_CTLIOPB
].mode
) == XY_SUB_WAIT
) &&
1439 xycsc
->iopbase
[XYC_CTLIOPB
].done
== 0)
1440 iorq
= &xycsc
->reqs
[XYC_CTLIOPB
];
1444 * special case: if iorq != NULL then we have a POLL or WAIT request.
1445 * we let these take priority and do them first.
1448 xycsc
->xy_chain
[0] = iorq
;
1449 iorq
->iopb
->chen
= 0;
1454 * NORM case: do round robin and maybe chain (if allowed and possible)
1458 hand
= xycsc
->xy_hand
;
1459 xycsc
->xy_hand
= (xycsc
->xy_hand
+ 1) % XYC_MAXIOPB
;
1461 for (togo
= XYC_MAXIOPB
; togo
> 0 ;
1462 togo
--, hand
= (hand
+ 1) % XYC_MAXIOPB
) {
1464 if (XY_STATE(xycsc
->reqs
[hand
].mode
) != XY_SUB_NORM
||
1465 xycsc
->iopbase
[hand
].done
)
1466 continue; /* not ready-for-i/o */
1468 xycsc
->xy_chain
[chain
] = &xycsc
->reqs
[hand
];
1469 iopb
= xycsc
->xy_chain
[chain
]->iopb
;
1471 if (chain
!= 0) { /* adding a link to a chain? */
1472 prev_iopb
= xycsc
->xy_chain
[chain
-1]->iopb
;
1473 prev_iopb
->chen
= 1;
1474 prev_iopb
->nxtiopb
= 0xffff &
1475 dvma_kvtopa(iopb
, xycsc
->bustype
);
1476 } else { /* head of chain */
1477 iorq
= xycsc
->xy_chain
[chain
];
1481 break; /* quit if chaining dis-allowed */
1483 return iorq
? iorq
->iopb
: NULL
;
1489 * programmed i/o driver. this function takes over the computer
1490 * and drains off the polled i/o request. it returns the status of the iorq
1491 * the caller is interesting in.
1494 xyc_piodriver(struct xyc_softc
*xycsc
, struct xy_iorq
*iorq
)
1501 printf("%s(%s, 0x%x)\n", __func__
, device_xname(xycsc
->sc_dev
), iorq
);
1504 while (iorq
->iopb
->done
== 0) {
1506 res
= xyc_unbusy(xycsc
->xyc
, XYC_MAXTIME
);
1508 /* we expect some progress soon */
1509 if (res
== XY_ERR_FAIL
&& nreset
>= 2) {
1510 xyc_reset(xycsc
, 0, XY_RSET_ALL
, XY_ERR_FAIL
, 0);
1512 printf("%s: timeout\n", __func__
);
1516 if (res
== XY_ERR_FAIL
) {
1517 if (xyc_reset(xycsc
, 0,
1518 (nreset
++ == 0) ? XY_RSET_NONE
: iorq
,
1519 XY_ERR_FAIL
, 0) == XY_ERR_FAIL
)
1520 return XY_ERR_FAIL
; /* flushes all but POLL
1521 * requests, resets */
1525 xyc_remove_iorq(xycsc
); /* may resubmit request */
1527 if (iorq
->iopb
->done
== 0)
1528 xyc_start(xycsc
, iorq
);
1531 /* get return value */
1533 retval
= iorq
->errno
;
1536 printf("%s: done, retval = 0x%x (%s)\n", __func__
,
1537 iorq
->errno
, xyc_e2str(iorq
->errno
));
1540 /* start up any bufs that have queued */
1542 xyc_start(xycsc
, NULL
);
1548 * xyc_xyreset: reset one drive. NOTE: assumes xyc was just reset.
1549 * we steal iopb[XYC_CTLIOPB] for this, but we put it back when we are done.
1552 xyc_xyreset(struct xyc_softc
*xycsc
, struct xy_softc
*xysc
)
1554 struct xy_iopb tmpiopb
;
1557 memcpy(&tmpiopb
, xycsc
->ciopb
, sizeof(tmpiopb
));
1558 xycsc
->ciopb
->chen
= xycsc
->ciopb
->done
= xycsc
->ciopb
->errs
= 0;
1559 xycsc
->ciopb
->ien
= 0;
1560 xycsc
->ciopb
->com
= XYCMD_RST
;
1561 xycsc
->ciopb
->unit
= xysc
->xy_drive
;
1562 addr
= dvma_kvtopa(xycsc
->ciopb
, xycsc
->bustype
);
1564 XYC_GO(xycsc
->xyc
, addr
);
1566 del
= XYC_RESETUSEC
;
1568 if ((xycsc
->xyc
->xyc_csr
& XYC_GBSY
) == 0)
1574 if (del
<= 0 || xycsc
->ciopb
->errs
) {
1575 printf("%s: off-line: %s\n", device_xname(xycsc
->sc_dev
),
1576 xyc_e2str(xycsc
->ciopb
->errno
));
1577 del
= xycsc
->xyc
->xyc_rsetup
;
1578 if (xyc_unbusy(xycsc
->xyc
, XYC_RESETUSEC
) == XY_ERR_FAIL
)
1579 panic("%s", __func__
);
1581 xycsc
->xyc
->xyc_csr
= XYC_IPND
; /* clear IPND */
1583 memcpy(xycsc
->ciopb
, &tmpiopb
, sizeof(tmpiopb
));
1588 * xyc_reset: reset everything: requests are marked as errors except
1589 * a polled request (which is resubmitted)
1592 xyc_reset(struct xyc_softc
*xycsc
, int quiet
, struct xy_iorq
*blastmode
,
1593 int error
, struct xy_softc
*xysc
)
1595 int del
= 0, lcv
, retval
= XY_ERR_AOK
;
1596 struct xy_iorq
*iorq
;
1598 /* soft reset hardware */
1601 printf("%s: soft reset\n", device_xname(xycsc
->sc_dev
));
1602 del
= xycsc
->xyc
->xyc_rsetup
;
1603 del
= xyc_unbusy(xycsc
->xyc
, XYC_RESETUSEC
);
1604 if (del
== XY_ERR_FAIL
) {
1605 blastmode
= XY_RSET_ALL
; /* dead, flush all requests */
1606 retval
= XY_ERR_FAIL
;
1609 xyc_xyreset(xycsc
, xysc
);
1611 /* fix queues based on "blast-mode" */
1613 for (lcv
= 0; lcv
< XYC_MAXIOPB
; lcv
++) {
1614 iorq
= &xycsc
->reqs
[lcv
];
1616 if (XY_STATE(iorq
->mode
) != XY_SUB_POLL
&&
1617 XY_STATE(iorq
->mode
) != XY_SUB_WAIT
&&
1618 XY_STATE(iorq
->mode
) != XY_SUB_NORM
)
1622 if (blastmode
== XY_RSET_ALL
||
1623 blastmode
!= iorq
) {
1625 iorq
->errno
= error
;
1626 xycsc
->iopbase
[lcv
].done
= xycsc
->iopbase
[lcv
].errs
= 1;
1627 switch (XY_STATE(iorq
->mode
)) {
1629 iorq
->buf
->b_error
= EIO
;
1630 iorq
->buf
->b_resid
= iorq
->sectcnt
* XYFM_BPS
;
1631 /* Sun3: map/unmap regardless of B_PHYS */
1632 dvma_mapout(iorq
->dbufbase
,
1633 iorq
->buf
->b_bcount
);
1634 (void)bufq_get(iorq
->xy
->xyq
);
1635 disk_unbusy(&iorq
->xy
->sc_dk
,
1636 (iorq
->buf
->b_bcount
- iorq
->buf
->b_resid
),
1637 (iorq
->buf
->b_flags
& B_READ
));
1639 iorq
->mode
= XY_SUB_FREE
;
1645 XY_NEWSTATE(iorq
->mode
, XY_SUB_DONE
);
1651 /* resubmit, no need to do anything here */
1656 * now, if stuff is waiting, start it.
1657 * since we just reset it should go
1659 xyc_start(xycsc
, NULL
);
1665 * xyc_start: start waiting buffers
1669 xyc_start(struct xyc_softc
*xycsc
, struct xy_iorq
*iorq
)
1672 struct xy_softc
*xy
;
1675 for (lcv
= 0; lcv
< XYC_MAXDEV
; lcv
++) {
1676 if ((xy
= xycsc
->sc_drives
[lcv
]) == NULL
)
1678 if (bufq_peek(xy
->xyq
) == NULL
)
1680 if (xy
->xyrq
->mode
!= XY_SUB_FREE
)
1682 xyc_startbuf(xycsc
, xy
, bufq_peek(xy
->xyq
));
1685 xyc_submit_iorq(xycsc
, iorq
, XY_SUB_NOQ
);
1689 * xyc_remove_iorq: remove "done" IOPB's.
1693 xyc_remove_iorq(struct xyc_softc
*xycsc
)
1695 int errno
, rq
, comm
, errs
;
1696 struct xyc
*xyc
= xycsc
->xyc
;
1698 struct xy_iopb
*iopb
;
1699 struct xy_iorq
*iorq
;
1702 if (xyc
->xyc_csr
& XYC_DERR
) {
1704 * DOUBLE ERROR: should never happen under normal use. This
1705 * error is so bad, you can't even tell which IOPB is bad, so
1708 errno
= XY_ERR_DERR
;
1709 printf("%s: DOUBLE ERROR!\n", device_xname(xycsc
->sc_dev
));
1710 if (xyc_reset(xycsc
, 0, XY_RSET_ALL
, errno
, 0) != XY_ERR_AOK
) {
1711 printf("%s: soft reset failed!\n",
1712 device_xname(xycsc
->sc_dev
));
1713 panic("%s: controller DEAD", __func__
);
1719 * get iopb that is done, loop down the chain
1722 if (xyc
->xyc_csr
& XYC_ERR
) {
1723 xyc
->xyc_csr
= XYC_ERR
; /* clear error condition */
1725 if (xyc
->xyc_csr
& XYC_IPND
) {
1726 xyc
->xyc_csr
= XYC_IPND
; /* clear interrupt */
1729 for (rq
= 0; rq
< XYC_MAXIOPB
; rq
++) {
1730 iorq
= xycsc
->xy_chain
[rq
];
1731 if (iorq
== NULL
) break; /* done ! */
1732 if (iorq
->mode
== 0 || XY_STATE(iorq
->mode
) == XY_SUB_DONE
)
1733 continue; /* free, or done */
1735 if (iopb
->done
== 0)
1736 continue; /* not done yet */
1742 iorq
->errno
= iopb
->errno
;
1746 /* handle non-fatal errors */
1749 xyc_error(xycsc
, iorq
, iopb
, comm
) == XY_ERR_AOK
)
1750 continue; /* AOK: we resubmitted it */
1753 /* this iorq is now done (hasn't been restarted or anything) */
1755 if ((iorq
->mode
& XY_MODE_VERBO
) && iorq
->lasterror
)
1756 xyc_perror(iorq
, iopb
, 0);
1758 /* now, if read/write check to make sure we got all the data
1759 * we needed. (this may not be the case if we got an error in
1760 * the middle of a multisector request). */
1762 if ((iorq
->mode
& XY_MODE_B144
) != 0 && errs
== 0 &&
1763 (comm
== XYCMD_RD
|| comm
== XYCMD_WR
)) {
1764 /* we just successfully processed a bad144 sector
1765 * note: if we are in bad 144 mode, the pointers have
1766 * been advanced already (see above) and are pointing
1767 * at the bad144 sector. to exit bad144 mode, we
1768 * must advance the pointers 1 sector and issue a new
1769 * request if there are still sectors left to process
1772 XYC_ADVANCE(iorq
, 1); /* advance 1 sector */
1774 /* exit b144 mode */
1775 iorq
->mode
= iorq
->mode
& (~XY_MODE_B144
);
1777 if (iorq
->sectcnt
) { /* more to go! */
1778 iorq
->lasterror
= iorq
->errno
= iopb
->errno
= 0;
1779 iopb
->errs
= iopb
->done
= 0;
1781 iopb
->scnt
= iorq
->sectcnt
;
1783 iorq
->blockno
/ iorq
->xy
->sectpercyl
;
1785 (iorq
->blockno
/ iorq
->xy
->nhead
) %
1787 iopb
->sect
= iorq
->blockno
% XYFM_BPS
;
1788 addr
= dvma_kvtopa(iorq
->dbuf
, xycsc
->bustype
);
1789 iopb
->dataa
= (addr
& 0xffff);
1790 iopb
->datar
= ((addr
& 0xff0000) >> 16);
1791 /* will resubit at end */
1795 /* final cleanup, totally done with this request */
1797 switch (XY_STATE(iorq
->mode
)) {
1802 bp
->b_resid
= iorq
->sectcnt
* XYFM_BPS
;
1804 bp
->b_resid
= 0; /* done */
1806 /* Sun3: map/unmap regardless of B_PHYS */
1807 dvma_mapout(iorq
->dbufbase
, iorq
->buf
->b_bcount
);
1808 (void)bufq_get(iorq
->xy
->xyq
);
1809 disk_unbusy(&iorq
->xy
->sc_dk
,
1810 (bp
->b_bcount
- bp
->b_resid
),
1811 (bp
->b_flags
& B_READ
));
1812 iorq
->mode
= XY_SUB_FREE
;
1816 iorq
->mode
= XY_NEWSTATE(iorq
->mode
, XY_SUB_DONE
);
1820 iorq
->mode
= XY_NEWSTATE(iorq
->mode
, XY_SUB_DONE
);
1829 * xyc_perror: print error.
1830 * - if still_trying is true: we got an error, retried and got a
1831 * different error. in that case lasterror is the old error,
1832 * and errno is the new one.
1833 * - if still_trying is not true, then if we ever had an error it
1834 * is in lasterror. also, if iorq->errno == 0, then we recovered
1835 * from that error (otherwise iorq->errno == iorq->lasterror).
1838 xyc_perror(struct xy_iorq
*iorq
, struct xy_iopb
*iopb
, int still_trying
)
1840 int error
= iorq
->lasterror
;
1842 printf("%s", (iorq
->xy
) ? device_xname(iorq
->xy
->sc_dev
)
1843 : device_xname(iorq
->xyc
->sc_dev
));
1845 printf("%c: ", 'a' + (char)DISKPART(iorq
->buf
->b_dev
));
1846 if (iopb
->com
== XYCMD_RD
|| iopb
->com
== XYCMD_WR
)
1847 printf("%s %d/%d/%d: ",
1848 (iopb
->com
== XYCMD_RD
) ? "read" : "write",
1849 iopb
->cyl
, iopb
->head
, iopb
->sect
);
1850 printf("%s", xyc_e2str(error
));
1853 printf(" [still trying, new error=%s]", xyc_e2str(iorq
->errno
));
1855 if (iorq
->errno
== 0)
1856 printf(" [recovered in %d tries]", iorq
->tries
);
1862 * xyc_error: non-fatal error encountered... recover.
1863 * return AOK if resubmitted, return FAIL if this iopb is done
1866 xyc_error(struct xyc_softc
*xycsc
, struct xy_iorq
*iorq
, struct xy_iopb
*iopb
,
1869 int errno
= iorq
->errno
;
1870 int erract
= xyc_entoact(errno
);
1871 int oldmode
, advance
, i
;
1873 if (erract
== XY_ERA_RSET
) { /* some errors require a reset */
1874 oldmode
= iorq
->mode
;
1875 iorq
->mode
= XY_SUB_DONE
| (~XY_SUB_MASK
& oldmode
);
1876 /* make xyc_start ignore us */
1877 xyc_reset(xycsc
, 1, XY_RSET_NONE
, errno
, iorq
->xy
);
1878 iorq
->mode
= oldmode
;
1880 /* check for read/write to a sector in bad144 table if bad: redirect
1881 * request to bad144 area */
1883 if ((comm
== XYCMD_RD
|| comm
== XYCMD_WR
) &&
1884 (iorq
->mode
& XY_MODE_B144
) == 0) {
1885 advance
= iorq
->sectcnt
- iopb
->scnt
;
1886 XYC_ADVANCE(iorq
, advance
);
1887 if ((i
= isbad(&iorq
->xy
->dkb
,
1888 iorq
->blockno
/ iorq
->xy
->sectpercyl
,
1889 (iorq
->blockno
/ iorq
->xy
->nsect
) % iorq
->xy
->nhead
,
1890 iorq
->blockno
% iorq
->xy
->nsect
)) != -1) {
1891 iorq
->mode
|= XY_MODE_B144
; /* enter bad144 mode &
1893 iopb
->errno
= iopb
->done
= iopb
->errs
= 0;
1895 iopb
->cyl
= (iorq
->xy
->ncyl
+ iorq
->xy
->acyl
) - 2;
1896 /* second to last acyl */
1897 i
= iorq
->xy
->sectpercyl
- 1 - i
; /* follow bad144
1899 iopb
->head
= i
/ iorq
->xy
->nhead
;
1900 iopb
->sect
= i
% iorq
->xy
->nhead
;
1901 /* will resubmit when we come out of remove_iorq */
1902 return XY_ERR_AOK
; /* recovered! */
1907 * it isn't a bad144 sector, must be real error! see if we can retry
1910 if ((iorq
->mode
& XY_MODE_VERBO
) && iorq
->lasterror
)
1911 xyc_perror(iorq
, iopb
, 1); /* inform of error state
1913 iorq
->lasterror
= errno
;
1915 if ((erract
== XY_ERA_RSET
|| erract
== XY_ERA_HARD
)
1916 && iorq
->tries
< XYC_MAXTRIES
) { /* retry? */
1918 iorq
->errno
= iopb
->errno
= iopb
->done
= iopb
->errs
= 0;
1919 /* will resubmit at end of remove_iorq */
1920 return XY_ERR_AOK
; /* recovered! */
1923 /* failed to recover from this error */
1928 * xyc_tick: make sure xy is still alive and ticking (err, kicking).
1933 struct xyc_softc
*xycsc
= arg
;
1934 int lcv
, s
, reset
= 0;
1936 /* reduce ttl for each request if one goes to zero, reset xyc */
1938 for (lcv
= 0; lcv
< XYC_MAXIOPB
; lcv
++) {
1939 if (xycsc
->reqs
[lcv
].mode
== 0 ||
1940 XY_STATE(xycsc
->reqs
[lcv
].mode
) == XY_SUB_DONE
)
1942 xycsc
->reqs
[lcv
].ttl
--;
1943 if (xycsc
->reqs
[lcv
].ttl
== 0)
1947 printf("%s: watchdog timeout\n", device_xname(xycsc
->sc_dev
));
1948 xyc_reset(xycsc
, 0, XY_RSET_NONE
, XY_ERR_FAIL
, NULL
);
1952 /* until next time */
1954 callout_reset(&xycsc
->sc_tick_ch
, XYC_TICKCNT
, xyc_tick
, xycsc
);
1958 * xyc_ioctlcmd: this function provides a user level interface to the
1959 * controller via ioctl. this allows "format" programs to be written
1960 * in user code, and is also useful for some debugging. we return
1961 * an error code. called at user priority.
1963 * XXX missing a few commands (see the 7053 driver for ideas)
1966 xyc_ioctlcmd(struct xy_softc
*xy
, dev_t dev
, struct xd_iocmd
*xio
)
1969 void *dvmabuf
= NULL
;
1970 struct xyc_softc
*xycsc
;
1972 /* check sanity of requested command */
1976 case XYCMD_NOP
: /* no op: everything should be zero */
1977 if (xio
->subfn
|| xio
->dptr
|| xio
->dlen
||
1978 xio
->block
|| xio
->sectcnt
)
1982 case XYCMD_RD
: /* read / write sectors (up to XD_IOCMD_MAXS) */
1984 if (xio
->subfn
|| xio
->sectcnt
> XD_IOCMD_MAXS
||
1985 xio
->sectcnt
* XYFM_BPS
!= xio
->dlen
|| xio
->dptr
== NULL
)
1989 case XYCMD_SK
: /* seek: doesn't seem useful to export this */
1994 return EINVAL
;/* ??? */
1997 /* create DVMA buffer for request if needed */
2000 dvmabuf
= dvma_malloc(xio
->dlen
);
2001 if (xio
->cmd
== XYCMD_WR
) {
2002 err
= copyin(xio
->dptr
, dvmabuf
, xio
->dlen
);
2004 dvma_free(dvmabuf
, xio
->dlen
);
2014 rqno
= xyc_cmd(xycsc
, xio
->cmd
, xio
->subfn
, xy
->xy_drive
, xio
->block
,
2015 xio
->sectcnt
, dvmabuf
, XY_SUB_WAIT
);
2016 if (rqno
== XY_ERR_FAIL
) {
2020 xio
->errno
= xycsc
->ciorq
->errno
;
2021 xio
->tries
= xycsc
->ciorq
->tries
;
2022 XYC_DONE(xycsc
, err
);
2024 if (xio
->cmd
== XYCMD_RD
)
2025 err
= copyout(dvmabuf
, xio
->dptr
, xio
->dlen
);
2030 dvma_free(dvmabuf
, xio
->dlen
);
2035 * xyc_e2str: convert error code number into an error string
2042 return "Software fatal error";
2044 return "DOUBLE ERROR";
2046 return "Successful completion";
2048 return "Interrupt pending";
2050 return "Busy conflict";
2052 return "Operation timeout";
2054 return "Header not found";
2056 return "Hard ECC error";
2058 return "Illegal cylinder address";
2060 return "Illegal sector address";
2062 return "Last sector too small";
2064 return "Slave ACK error (non-existent memory)";
2066 return "Cylinder and head/header error";
2068 return "Auto-seek retry successful";
2070 return "Write-protect error";
2072 return "Unimplemented command";
2074 return "Drive not ready";
2076 return "Sector count zero";
2078 return "Drive faulted";
2080 return "Illegal sector size";
2082 return "Self test A";
2084 return "Self test B";
2086 return "Self test C";
2088 return "Soft ECC error";
2090 return "Soft ECC error recovered";
2092 return "Illegal head";
2094 return "Disk sequencer error";
2096 return "Seek error";
2098 return "Unknown error";
2103 xyc_entoact(int errno
)
2122 return XY_ERA_PROG
; /* program error ! */
2131 return XY_ERA_HARD
; /* hard error, retry */
2135 return XY_ERA_RSET
; /* hard error reset */
2140 return XY_ERA_SOFT
; /* an FYI error */
2143 return XY_ERA_WPRO
; /* write protect */
2146 return XY_ERA_PROG
; /* ??? */