* Stand alone driver for the VDDC controller
* TAHOE Version, Oct 1983.
#include "../machine/mtpr.h"
#include "../tahoevba/vdreg.h"
#include "../tahoevba/vbaparam.h"
#define NVD 4 /* Max number of controllers */
#define VDUNIT(x) (minor(x) & 0x3)
#define VDCTLR(x) (minor(x) >> 2)
* Drive specific information.
* Controller specific information.
#define VDF_INIT 0x1 /* controller initialized */
#define VDF_BUSY 0x2 /* controller running */
u_short vd_type
; /* smd or smde */
#define VDADDR(ctlr) ((cdr *)vddcaddr[(ctlr)])
register int ctlr
= VDCTLR(io
->i_unit
), unit
= VDUNIT(io
->i_unit
);
/* Make sure controller number is in range */
"dk%d: invalid controller (only configured for %d vd's)\n",
/* check file system for validity */
if ((unsigned)io
->i_boff
>= 8) {
printf("dk%d: invalid partition number (%d)\n",
if ((vd
->vd_flags
&VDF_INIT
) == 0) {
vdinit(io
); /* initialize controller/drive */
vd
->vd_flags
|= VDF_INIT
;
dkinfo
[ctlr
][j
].configured
= 0;
if (!dkinfo
[ctlr
][unit
].configured
) {
dkinfo
[ctlr
][unit
].configured
= 1;
io
->i_boff
= dkinfo
[ctlr
][unit
].info
.partition
[io
->i_boff
].par_start
;
register int ctlr
= VDCTLR(io
->i_unit
), unit
= VDUNIT(io
->i_unit
);
register cdr
*ctlr_addr
= VDADDR(ctlr
);
register struct vdinfo
*vd
= &vdinfo
[ctlr
];
/* Check to see if controller is really there */
if (badaddr(ctlr_addr
, 2)) {
printf("dk%d: vd%d csr doesn't respond\n", io
->i_unit
, ctlr
);
/* Probe further to find what kind of controller it is */
ctlr_addr
->cdr_reset
= 0xffffffff;
if (ctlr_addr
->cdr_reset
!= 0xffffffff) {
ctlr_addr
->cdr_reserved
= 0x0;
if (vd
->vd_type
== SMD_ECTLR
) {
ctlr_addr
->mdcb_tcf
= AM_ENPDA
;
ctlr_addr
->dcb_tcf
= AM_ENPDA
;
ctlr_addr
->trail_tcf
= AM_ENPDA
;
ctlr_addr
->data_tcf
= AM_ENPDA
;
ctlr_addr
->cdr_ccf
= CCF_STS
| XMD_32BIT
| BSZ_16WRD
|
CCF_ENP
| CCF_EPE
/* | CCF_EDE */ | CCF_ECE
| CCF_ERR
;
if (vdnotrailer(io
, INIT
, 8) & HRDERR
) {
vdprint_error(io
->i_unit
, "init error",
dcb
.operrsta
, dcb
.err_code
);
if (vdnotrailer(io
, DIAG
, 8) & HRDERR
) {
vdprint_error(io
->i_unit
, "diagnostic error",
dcb
.operrsta
, dcb
.err_code
);
register int ctlr
= VDCTLR(io
->i_unit
), unit
= VDUNIT(io
->i_unit
);
register fs_tab
*file_sys
;
register struct dkinfo
*dk
= &dkinfo
[ctlr
][unit
];
for (i
= 0; i
< nvddrv
; i
++) {
if (vdinfo
[ctlr
].vd_type
== SMDCTLR
)
daddr
.cylinder
= dk
->info
.ncyl
- 2;
daddr
.track
= dk
->info
.ntrak
- 1;
daddr
.sector
= dk
->info
.nsec
- 1;
io
->i_cc
= dk
->info
.secsize
;
if ((vdaccess(io
, &daddr
, RD
) & HRDERR
) == 0)
printf("dk%d: unknown drive type\n", io
->i_unit
);
register int ctlr
= VDCTLR(io
->i_unit
), unit
= VDUNIT(io
->i_unit
);
if (vdnotrailer(io
, VDSTART
, 62) & HRDERR
) {
vdprint_error(io
->i_unit
, "start error",
dcb
.operrsta
, dcb
.err_code
);
vdinfo
[ctlr
].vd_flags
|= VDF_BUSY
;
* This routine actually configures a particular drive.
* If the controller is an SMD/E controller then the number of sectors per
* track is loaded into the appropriate register, otherwise it is left
* alone because the old SMD controller requires a constant 32 sectors
* per track for it's drives. (an error would be returned if the value is
register int ctlr
= VDCTLR(io
->i_unit
), unit
= VDUNIT(io
->i_unit
);
register cdr
*ctlr_addr
= VDADDR(ctlr
);
dcb
.opcode
= RSTCFG
; /* command */
dcb
.nxtdcb
= (fmt_dcb
*)0; /* end of chain */
dcb
.devselect
= (char)unit
;
dcb
.trail
.rstrail
.ncyl
= dkinfo
[ctlr
][unit
].info
.ncyl
;
dcb
.trail
.rstrail
.nsurfaces
= dkinfo
[ctlr
][unit
].info
.ntrak
;
if (vdinfo
[ctlr
].vd_type
== SMD_ECTLR
) {
dcb
.trail
.rstrail
.nsectors
= dkinfo
[ctlr
][unit
].info
.nsec
;
dcb
.trail
.rstrail
.slip_sec
= dkinfo
[ctlr
][unit
].info
.nslip
;
dcb
.trail
.rstrail
.recovery
= 0x18f;
VDDC_ATTENTION(ctlr_addr
, &mdcb
, vdinfo
[ctlr
].vd_type
);
if (!vdpoll(ctlr_addr
,&dcb
,10,vdinfo
[ctlr
].vd_type
)) {
VDDC_RESET(ctlr_addr
, vdinfo
[ctlr
].vd_type
);
_stop(" during drive configuration.\n");
if (dcb
.operrsta
& HRDERR
) {
if (vdinfo
[ctlr
].vd_type
== SMD_ECTLR
&&
(ctlr_addr
->cdr_status
[io
->i_unit
] & STA_US
) == 0) {
printf("dk%d: ", io
->i_unit
);
_stop("nonexistent drive");
if ((dcb
.operrsta
& (NOTCYLERR
|DRVNRDY
)) == 0) {
vdprint_error(io
->i_unit
, "configuration error",
dcb
.operrsta
, dcb
.err_code
);
* Strategy is called to do the actual I/O to the disk drives.
* Some simple checks are made to make sure we don't do anything rediculous,
* If everything is sane then the request is issued.
* If no errors occured then the original byte count is returned,
* otherwise -1 is returned to indicate an error occured.
register int ctlr
= VDCTLR(io
->i_unit
), unit
= VDUNIT(io
->i_unit
);
register fs_tab
*u_info
= &dkinfo
[ctlr
][unit
].info
;
register int op
= (func
== READ
) ? RD
: WD
;
if (io
->i_cc
== 0 || io
->i_cc
> 65535) {
printf("dk%d: invalid transfer size %d\n", io
->i_unit
,
blk
= io
->i_bn
* DEV_BSIZE
/ u_info
->secsize
;
daddr
.sector
= blk
% u_info
->nsec
;
daddr
.track
= (blk
/ u_info
->nsec
) % u_info
->ntrak
;
daddr
.cylinder
= (blk
/u_info
->nsec
) / u_info
->ntrak
;
if (vdaccess(io
, &daddr
, op
) & HRDERR
) {
vdprint_error(io
->i_unit
, "i/o error", dcb
.operrsta
,
vdprint_error(unit
, str
, status
, smde_status
)
register struct vdstatus
*sp
;
printf("dk%d: %s; status %b", unit
, str
, status
, ERRBITS
);
printf(", code %x", smde_status
);
vdnotrailer(io
, function
, time
)
register int function
, time
;
register int ctlr
= VDCTLR(io
->i_unit
);
register cdr
*ctlr_addr
= VDADDR(ctlr
);
dcb
.opcode
= function
; /* command */
dcb
.nxtdcb
= (fmt_dcb
*)0; /* end of chain */
dcb
.devselect
= (char)VDUNIT(io
->i_unit
);
VDDC_ATTENTION(ctlr_addr
, &mdcb
, vdinfo
[ctlr
].vd_type
);
if (!vdpoll(ctlr_addr
, &dcb
, time
, vdinfo
[ctlr
].vd_type
))
_stop(" during initialization operation.\n");
vdaccess(io
, daddr
, func
)
register int ctlr
= VDCTLR(io
->i_unit
);
register cdr
*ctlr_addr
= VDADDR(ctlr
);
dcb
.opcode
= (short)func
; /* format sector command */
dcb
.nxtdcb
= (fmt_dcb
*)0; /* end of chain */
dcb
.devselect
= (char)VDUNIT(io
->i_unit
);
dcb
.trailcnt
= (char)(sizeof(trrw
) / 4);
dcb
.trail
.rwtrail
.memadr
= io
->i_ma
;
dcb
.trail
.rwtrail
.wcount
= ((io
->i_cc
+ 1) / sizeof(short));
dcb
.trail
.rwtrail
.disk
.cylinder
= daddr
->cylinder
;
dcb
.trail
.rwtrail
.disk
.track
= daddr
->track
;
dcb
.trail
.rwtrail
.disk
.sector
= daddr
->sector
;
VDDC_ATTENTION(ctlr_addr
, &mdcb
, vdinfo
[ctlr
].vd_type
);
if (!vdpoll(ctlr_addr
, &dcb
, 60, vdinfo
[ctlr
].vd_type
))
_stop(" during i/o operation.\n");
* Dump the MDCB and DCB for diagnostic purposes. This
* routine is called whenever a fatal error is encountered.
register long i
, trailer_count
;
printf("mdcb: %lx %lx %lx %lx\n", ptr
[0], ptr
[1], ptr
[2], ptr
[3]);
if (ptr
= (long *)*ptr
) {
trailer_count
= ptr
[3] & 0xff;
for (i
=0; i
<7+trailer_count
; i
++) {
* Poll controller until operation completes
vdpoll(addr
, dcb
, t
, type
)
if (dcb
->operrsta
& (DCBCMP
|DCBABT
))
printf("vd: controller timeout");
if ((addr
->cdr_csr
& CS_GO
) == 0)