** 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)
** Unit specific information.
** Controller specific information.
unsigned char initialized
;
unsigned char ctlr_started
;
#define VDADDR(ctlr) ((cdr *)(vddcaddr[(ctlr)]+VBIOBASE))
register int ctlr
= VDCTLR(io
->i_unit
);
register int unit
= VDUNIT(io
->i_unit
);
/* Make sure controller number is in range */
printf("vd%d: Unit number can't be greater than %x!\n",
io
->i_unit
, (NVD
* 4) - 1);
/* check file system for validity */
if((io
->i_boff
< 0) || (io
->i_boff
> 5)) {
printf("vd%d: File system #%d, should be less than #6.\n",
if(!ctlr_info
[ctlr
].initialized
) {
vdinit(io
); /* initialize controller/drive */
ctlr_info
[ctlr
].initialized
= TRUE
;
unit_info
[i
][j
].configured
= FALSE
;
if(!unit_info
[ctlr
][unit
].configured
) {
unit_info
[ctlr
][unit
].configured
= TRUE
;
io
->i_boff
= unit_info
[ctlr
][unit
].info
.partition
[io
->i_boff
].par_start
;
register int ctlr
= VDCTLR(io
->i_unit
);
register int unit
= VDUNIT(io
->i_unit
);
register cdr
*ctlr_addr
= VDADDR(ctlr
);
register char *ctlr_type
;
/* Check to see if controller is really there */
if(badaddr(ctlr_addr
, 2)) {
printf("vd%d: Controller %d is non-existant!\n",
/* Probe further to find what kind of controller it is */
ctlr_addr
->cdr_reset
= 0xffffffff;
/* Probe further to find what kind of controller it is */
if(ctlr_addr
->cdr_reset
!= 0xffffffff) {
ctlr_info
[ctlr
].ctlr_type
= SMDCTLR
;
ctlr_info
[ctlr
].ctlr_name
= "SMD";
ctlr_info
[ctlr
].ctlr_type
= SMD_ECTLR
;
ctlr_info
[ctlr
].ctlr_name
= "SMD/E";
ctlr_addr
->cdr_reserved
= 0x0;
if(ctlr_info
[ctlr
].ctlr_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(vdaccess_with_no_trailer(io
, INIT
, 8) & HRDERR
) {
vdprint_error(io
->i_unit
, "Initialization error",
dcb
.operrsta
,dcb
.err_code
);
if(vdaccess_with_no_trailer(io
, DIAG
, 8) & HRDERR
) {
vdprint_error(io
->i_unit
, "Diagnostic error",
dcb
.operrsta
, dcb
.err_code
);
register int ctlr
= VDCTLR(io
->i_unit
);
register int unit
= VDUNIT(io
->i_unit
);
register fs_tab
*file_sys
;
for(i
=0; i
< nvddrv
; i
++) {
unit_info
[ctlr
][unit
].info
= vdst
[i
];
if(ctlr_info
[ctlr
].ctlr_type
== SMDCTLR
)
if(unit_info
[ctlr
][unit
].info
.nsec
!= 32)
daddr
.cylinder
= unit_info
[ctlr
][unit
].info
.ncyl
- 2;
daddr
.track
= unit_info
[ctlr
][unit
].info
.ntrak
- 1;
daddr
.sector
= unit_info
[ctlr
][unit
].info
.nsec
- 1;
io
->i_cc
= unit_info
[ctlr
][unit
].info
.secsize
;
if(!(vdaccess(io
, &daddr
, RD
) & HRDERR
))
printf("vd%d: Unrecognizable drive; controller %d, unit %d!\n",
register int ctlr
= VDCTLR(io
->i_unit
);
register int unit
= VDUNIT(io
->i_unit
);
register int io_unit_save
= io
->i_unit
;
if(ctlr_info
[ctlr
].ctlr_started
) {
if(vdaccess_with_no_trailer(io
, VDSTART
, ((unit
* 6) + 62)) & HRDERR
) {
vdprint_error(io
->i_unit
, "Start error",
dcb
.operrsta
, dcb
.err_code
);
ctlr_info
[ctlr
].ctlr_started
= TRUE
;
io
->i_unit
= io_unit_save
;
DELAY((unit
* 5500000) + 62000000);
** 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
** In the stand-alone spirit of things the system is halted if an error
** occurs during this operation.
register int ctlr
= VDCTLR(io
->i_unit
);
register int 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
= unit_info
[ctlr
][unit
].info
.ncyl
;
dcb
.trail
.rstrail
.nsurfaces
= unit_info
[ctlr
][unit
].info
.ntrak
;
if(ctlr_info
[ctlr
].ctlr_type
== SMD_ECTLR
) {
dcb
.trail
.rstrail
.nsectors
= unit_info
[ctlr
][unit
].info
.nsec
;
dcb
.trail
.rstrail
.slip_sec
= unit_info
[ctlr
][unit
].info
.nslip
;
VDDC_ATTENTION(ctlr_addr
, &mdcb
, ctlr_info
[ctlr
].ctlr_type
);
if (!vdpoll(ctlr_addr
,&dcb
,5,ctlr_info
[ctlr
].ctlr_type
))
_stop(" during drive configuration.\n");
if(dcb
.operrsta
& (NOTCYLERR
| DRVNRDY
))
if(dcb
.operrsta
& HRDERR
) {
vdprint_error(io
->i_unit
, "Configuration error",
dcb
.operrsta
, dcb
.err_code
);
** Strategy is called to the actual I/O to the disk drives.
** Some simple checks are made to make sure we don't do anything rediculus,
** 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
);
register int unit
= VDUNIT(io
->i_unit
);
register fs_tab
*u_info
= &unit_info
[ctlr
][unit
].info
;
register int op
= (func
== READ
) ? RD
: WD
;
_stop("vd: Can't transfer zero length records!\n");
_stop("vd: Can't transfer greater than 2 to the 16th bytes!\n");
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
,dcb
.err_code
);
vdprint_error(unit
, str
, status
, smde_status
)
unsigned long smde_status
;
printf("vd%d: %s; ", unit
, str
);
printf("Drive is not ready");
else if(status
& INVDADR
)
printf("Invalid disk address issued");
printf("Non-existent memory error");
printf("Main memory parity error");
printf("Program aborted operation");
printf("Drive is write protected");
else if(status
& DSEEKERR
)
printf("Disk seek error");
else if(status
& UCDATERR
)
printf("Uncorrectable data error");
else if(status
& CTLRERR
)
printf("Controller faulted");
else if(status
& NOTCYLERR
)
printf("Not on cylinder error");
printf("Invalid command issued to controller");
printf("Controller error");
printf("! Status = 0x%x", status
);
printf(" Error code = %x", smde_status
);
vdaccess_with_no_trailer(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
, ctlr_info
[ctlr
].ctlr_type
);
if (!vdpoll(ctlr_addr
,&dcb
,time
,ctlr_info
[ctlr
].ctlr_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
, ctlr_info
[ctlr
].ctlr_type
);
if (!vdpoll(ctlr_addr
, &dcb
, 60, ctlr_info
[ctlr
].ctlr_type
))
_stop(" during I/O operation.\n");
** Print_dcb() dumps the MDCB and DCB for diagnostic purposes. This
** routine is called whenever a fatal error is encountered.
register long trailer_count
;
printf("Dump of MDCB: ");
printf(" %lx", *(ptr
+i
));
trailer_count
= *(ptr
+3) & 0xff;
for(i
=0; i
<7+trailer_count
; i
++) {
printf(" %lx", *(ptr
+i
));
for(i
=0; i
<5000000; i
++) ;
* Poll controller until operation completes
vdpoll(addr
, dcb
, t
, type
)
while ((dcb
->operrsta
&(DCBCMP
|DCBABT
)) == 0) {
printf("vd: controller timeout");
while (addr
->cdr_csr
&CS_GO
) {