* Stand alone driver for the VDDC/SMDE controller
#include "../machine/mtpr.h"
#include "../tahoevba/vdreg.h"
#include "../tahoevba/vbaparam.h"
#define NDRIVE 8 /* drives per controller */
#define VDSLAVE(x) ((x) % NDRIVE)
#define VDCTLR(x) ((x) / NDRIVE)
#define VDADDR(ctlr) ((struct vddevice *)vdaddrs[ctlr])
long vdaddrs
[NVD
] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300 };
u_char vdinit
[NVD
]; /* controller initialized */
u_char vdtype
[NVD
]; /* controller type */
u_char dkconfigured
[NVD
*NDRIVE
]; /* unit configured */
struct disklabel dklabel
[NVD
*NDRIVE
]; /* pack label */
register int ctlr
= VDCTLR(io
->i_unit
);
register struct dkinfo
*dk
;
register struct disklabel
*lp
;
printf("invalid controller number\n");
if (!vdinit
[ctlr
] && (error
= vdreset_ctlr(ctlr
, io
->i_unit
)))
lp
= &dklabel
[io
->i_unit
];
if (!dkconfigured
[io
->i_unit
]) {
* Read in the pack label.
if (vdstrategy(&tio
, READ
) != DEV_BSIZE
) {
printf("can't read disk label");
*lp
= *(struct disklabel
*)(lbuf
+ LABELOFFSET
);
if (lp
->d_magic
!= DISKMAGIC
|| lp
->d_magic2
!= DISKMAGIC
) {
printf("dk%d: unlabeled\n", io
->i_unit
);
if (error
= vdmaptype(io
))
dkconfigured
[io
->i_unit
] = 1;
if (io
->i_boff
< 0 || io
->i_boff
>= lp
->d_npartitions
||
lp
->d_partitions
[io
->i_boff
].p_size
== 0) {
(lp
->d_partitions
[io
->i_boff
].p_offset
* lp
->d_secsize
) / DEV_BSIZE
;
* Reset and initialize the controller.
register struct vddevice
*vdaddr
= VDADDR(ctlr
);
if (badaddr(vdaddr
, 2)) {
printf("vd%d: %x: invalid csr\n", ctlr
, vdaddr
);
/* probe further to find what kind of controller it is */
vdaddr
->vdreset
= 0xffffffff;
if (vdaddr
->vdreset
!= 0xffffffff) {
vdtype
[ctlr
] = VDTYPE_VDDC
;
vdtype
[ctlr
] = VDTYPE_SMDE
;
vdaddr
->vdtcf_mdcb
= AM_ENPDA
;
vdaddr
->vdtcf_dcb
= AM_ENPDA
;
vdaddr
->vdtcf_trail
= AM_ENPDA
;
vdaddr
->vdtcf_data
= AM_ENPDA
;
vdaddr
->vdccf
= CCF_SEN
| CCF_DER
| CCF_STS
|
CCF_ENP
| CCF_EPE
| CCF_EDE
| CCF_ECE
| CCF_ERR
;
if (!vdcmd(ctlr
, 0, VDOP_INIT
, 10) ||
!vdcmd(ctlr
, 0, VDOP_DIAG
, 10)) {
vderror(unit
, dcb
.opcode
== VDOP_INIT
? "init" : "diag", &dcb
);
for (i
= unit
= ctlr
* NDRIVE
; i
< unit
+ NDRIVE
; i
++)
* Reset and configure a drive's parameters.
register int ctlr
= VDCTLR(io
->i_unit
), slave
= VDSLAVE(io
->i_unit
);
register struct disklabel
*lp
;
register struct vddevice
*vdaddr
= VDADDR(ctlr
);
int pass
= 0, type
= vdtype
[ctlr
], error
;
lp
= &dklabel
[io
->i_unit
];
dcb
.opcode
= VDOP_CONFIG
; /* command */
dcb
.intflg
= DCBINT_NONE
;
dcb
.nxtdcb
= (struct dcb
*)0; /* end of chain */
dcb
.trail
.rstrail
.ncyl
= lp
->d_ncylinders
;
dcb
.trail
.rstrail
.nsurfaces
= lp
->d_ntracks
;
if (type
== VDTYPE_SMDE
) {
dcb
.trailcnt
= sizeof (treset
) / sizeof (long);
dcb
.trail
.rstrail
.nsectors
= lp
->d_nsectors
;
dcb
.trail
.rstrail
.slip_sec
= 0; /* XXX */
dcb
.trail
.rstrail
.recovery
= 0x18f; /* ??? */
dcb
.trailcnt
= 2; /* XXX */
VDGO(vdaddr
, (u_long
)&mdcb
, type
);
if (!vdpoll(vdaddr
, &dcb
, 10, type
)) {
printf(" during drive configuration.\n");
if (error
= vdreset_ctlr(ctlr
, io
->i_unit
))
if ((dcb
.operrsta
& VDERR_HARD
) == 0) /* success */
if (type
== VDTYPE_SMDE
&& (vdaddr
->vdstatus
[slave
] & STA_US
) == 0) {
printf("dk%d: nonexistent drive\n", io
->i_unit
);
if ((dcb
.operrsta
& (DCBS_OCYL
|DCBS_NRDY
)) == 0) {
vderror(io
->i_unit
, "config", &dcb
);
if (pass
++) /* give up */
* Try to spin up drive with remote command.
if (!vdcmd(ctlr
, 0, VDOP_START
, 62)) {
vderror(io
->i_unit
, "start", &dcb
);
vdcmd(ctlr
, unit
, cmd
, time
)
register struct vddevice
*vdaddr
= VDADDR(ctlr
);
dcb
.intflg
= DCBINT_NONE
;
dcb
.nxtdcb
= (struct dcb
*)0; /* end of chain */
VDGO(vdaddr
, (u_long
)&mdcb
, vdtype
[ctlr
]);
if (!vdpoll(vdaddr
, &dcb
, time
, vdtype
[ctlr
]))
_stop(" during initialization operation.\n");
return ((dcb
.operrsta
& VDERR_HARD
) == 0);
register struct disklabel
*lp
;
if (io
->i_cc
== 0 || io
->i_cc
> 65535) {
printf("dk%d: invalid transfer size %d\n", io
->i_unit
,
lp
= &dklabel
[io
->i_unit
];
bn
= io
->i_bn
* (DEV_BSIZE
/ lp
->d_secsize
);
cn
= bn
/ lp
->d_secpercyl
;
sn
= bn
% lp
->d_secpercyl
;
tn
= sn
/ lp
->d_nsectors
;
sn
= sn
% lp
->d_nsectors
;
dcb
.opcode
= (cmd
== READ
? VDOP_RD
: VDOP_WD
);
dcb
.intflg
= DCBINT_NONE
;
dcb
.nxtdcb
= (struct dcb
*)0; /* end of chain */
dcb
.devselect
= VDSLAVE(io
->i_unit
);
dcb
.trailcnt
= sizeof (trrw
) / sizeof (int);
dcb
.trail
.rwtrail
.memadr
= io
->i_ma
;
dcb
.trail
.rwtrail
.wcount
= (io
->i_cc
+ 1) / sizeof (short);
dcb
.trail
.rwtrail
.disk
.cylinder
= cn
;
dcb
.trail
.rwtrail
.disk
.track
= tn
;
dcb
.trail
.rwtrail
.disk
.sector
= sn
;
ctlr
= VDCTLR(io
->i_unit
);
VDGO(vdaddr
, (u_long
)&mdcb
, vdtype
[ctlr
]);
if (!vdpoll(vdaddr
, &dcb
, 60, vdtype
[ctlr
]))
_stop(" during i/o operation.\n");
if (dcb
.operrsta
& VDERR_HARD
) {
vderror(io
->i_unit
, cmd
== READ
? "read" : "write", &dcb
);
printf("dk%d: %s error; status %b", unit
, cmd
,
dcb
->operrsta
, VDERRBITS
);
printf(", code %x", dcb
->err_code
);
* Poll controller until operation
* completes or timeout expires.
vdpoll(vdaddr
, dcb
, t
, type
)
register struct vddevice
*vdaddr
;
register struct dcb
*dcb
;
if (dcb
->operrsta
& (DCBS_DONE
|DCBS_ABORT
))
printf("vd: controller timeout");
if (type
== VDTYPE_SMDE
) {
if ((vdaddr
->vdcsr
& CS_GO
) == 0)
int nsectors
; /* sectors per track */
int ntracks
; /* tracks per cylinder */
int ncylinders
; /* cylinders per drive */
int poff
[NPART
]; /* [a+b] for bootstrapping */
{ 48, 24, 711, 0, 61056 }, /* xsd */
{ 44, 20, 842, 0, 52800 }, /* eagle */
{ 64, 10, 823, 0, 38400 }, /* fuji 360 */
{ 32, 24, 711, 0, 40704 }, /* xfd */
{ 32, 19, 823, 0, 40128 }, /* smd */
{ 32, 10, 823, 0, 19200 }, /* fsd */
#define NDKCOMPAT (sizeof (dkcompat) / sizeof (dkcompat[0]))
* Identify and configure drive from above table
* by trying to read the last sector until a description
* is found for which we're successful.
register struct disklabel
*lp
= &dklabel
[io
->i_unit
];
register struct dkcompat
*dp
;
ctlr
= VDCTLR(io
->i_unit
);
for (dp
= dkcompat
; dp
< &dkcompat
[NDKCOMPAT
]; dp
++) {
if (type
== VDTYPE_VDDC
&& dp
->nsectors
!= 32)
lp
->d_nsectors
= dp
->nsectors
;
lp
->d_ntracks
= dp
->ntracks
;
lp
->d_ncylinders
= dp
->ncylinders
;
if (!vdreset_drive(io
)) /* set drive parameters */
dcb
.intflg
= DCBINT_NONE
;
dcb
.nxtdcb
= (struct dcb
*)0; /* end of chain */
dcb
.devselect
= VDSLAVE(io
->i_unit
);
dcb
.trailcnt
= sizeof (trrw
) / sizeof (long);
dcb
.trail
.rwtrail
.memadr
= lbuf
;
dcb
.trail
.rwtrail
.wcount
= sizeof (lbuf
) / sizeof (short);
dcb
.trail
.rwtrail
.disk
.cylinder
= dp
->ncylinders
- 2;
dcb
.trail
.rwtrail
.disk
.track
= dp
->ntracks
- 1;
dcb
.trail
.rwtrail
.disk
.sector
= dp
->nsectors
- 1;
VDGO(vdaddr
, (u_long
)&mdcb
, type
);
if (!vdpoll(vdaddr
, &dcb
, 60, type
))
_stop(" during i/o operation.\n");
if (dcb
.operrsta
& VDERR_HARD
)
/* simulate necessary parts of disk label */
lp
->d_secpercyl
= lp
->d_nsectors
* lp
->d_ntracks
;
lp
->d_secperunit
= lp
->d_secpercyl
* lp
->d_ncylinders
;
lp
->d_npartitions
= NPART
;
for (i
= 0; i
< NPART
; i
++) {
lp
->d_partitions
[i
].p_offset
= dp
->poff
[i
];
lp
->d_partitions
[i
].p_size
=
lp
->d_secperunit
- dp
->poff
[i
];
printf("dk%d: unknown drive type\n", io
->i_unit
);