6c3038d7ce10a3d816dc755c299fa075f0eb5e63
* VDDC - Versabus SMD/ESMD driver.
#include "../tahoe/mtpr.h"
#include "../tahoe/pte.h"
#include "../tahoevba/vbavar.h"
#include "../tahoevba/vddcreg.h"
#define MAX_BLOCKSIZE (MAXBPTE*NBPG)
#define DUMPSIZE 64 /* controller limit */
#define VDUNIT(x) (minor(x) >> 3)
#define FILSYS(x) (minor(x) & 0x07)
#define PHYS(x) (vtoph((struct proc *)0, (unsigned)(x)))
#define HARD_DATA_ERROR 3
#define SOFT_DATA_ERROR 4
struct vba_ctlr
*vdminfo
[NVD
];
struct vba_device
*vddinfo
[NFSD
];
int vdprobe(), vdslave(), vdattach(), vddgo();
struct vba_driver vddriver
=
{ vdprobe
, vdslave
, vdattach
, vddgo
, vddcaddr
, "smd/fsd",
vddinfo
, "vd", vdminfo
};
struct buf raw_q_element
;
char ctlr_type
; /* controller type */
char *map
; /* i/o page map */
char *utl
; /* mapped i/o space */
u_int cur_slave
:8; /* last active unit number */
u_int int_expected
:1; /* expect an interupt */
u_int ctlr_started
:1; /* start command was issued */
u_int overlap_seeks
:1;/* should overlap seeks */
u_int off_cylinder
:16;/* off cylinder bit map */
u_int unit_type
[16]; /* slave types */
u_int cur_cyl
[16]; /* cylinder last selected */
long cur_trk
[16]; /* track last selected */
fmt_mdcb ctlr_mdcb
; /* controller mdcb */
fmt_dcb ctlr_dcb
; /* r/w dcb */
fmt_dcb seek_dcb
[4]; /* dcbs for overlapped seeks */
/* buffer for raw/swap i/o */
char rawbuf
[MAX_BLOCKSIZE
];
#define VDCINIT(map, utl) { \
UNKNOWN, (char *)map, utl, 0, FALSE, FALSE, TRUE, 0, \
{ UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, \
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN } \
ctlr_tab vdctlr_info
[NVD
] = {
unit_tab vdunit_info
[NFSD
];
* See if the controller is really there; if so, initialize it.
register br
, cvec
; /* must be r12, r11 */
register cdr
*cp
= (cdr
*)reg
;
if (badaddr((caddr_t
)reg
, 2))
cp
->cdr_reset
= 0xffffffff;
if (cp
->cdr_reset
!= (unsigned)0xffffffff) {
br
= 0x17, cvec
= 0xe0 + vm
->um_ctlr
; /* XXX */
* See if a drive is really there
* Try to reset/configure the drive, then test its status.
register struct vba_device
*vi
;
register ctlr_tab
*ci
= &vdctlr_info
[vi
->ui_ctlr
];
register unit_tab
*ui
= &vdunit_info
[vi
->ui_unit
];
register fmt_mdcb
*mdcb
= &ci
->ctlr_mdcb
;
register fmt_dcb
*dcb
= &ci
->ctlr_dcb
;
if (ci
->ctlr_type
== UNKNOWN
) {
addr
->cdr_reset
= 0xffffffff;
if (addr
->cdr_reset
!= (unsigned)0xffffffff) {
ci
->ctlr_type
= SMD_ECTLR
;
addr
->cdr_reserved
= 0x0;
addr
->mdcb_tcf
= AM_ENPDA
;
addr
->dcb_tcf
= AM_ENPDA
;
addr
->trail_tcf
= AM_ENPDA
;
addr
->data_tcf
= AM_ENPDA
;
addr
->cdr_ccf
= CCF_STS
| XMD_32BIT
| BSZ_16WRD
|
CCF_ENP
| CCF_EPE
| CCF_EDE
| CCF_ECE
| CCF_ERR
;
vi
->ui_ctlr
, vi
->ui_slave
, INIT
, 10) & HRDERR
) {
printf("vd%d: init error\n", vi
->ui_unit
);
vi
->ui_ctlr
, vi
->ui_slave
, DIAG
, 10) & HRDERR
) {
printf("vd%d: diagnostic error\n", vi
->ui_unit
);
* Seek on all drive types starting from the largest one.
* a successful seek to the last sector/cylinder/track verifies
* the drive type connected to this port.
for (type
= 0; type
< nvddrv
; type
++) {
if (ci
->ctlr_type
== SMDCTLR
&& vdst
[type
].nsec
!= 32)
if (!vdconfigure_drive(addr
, vi
->ui_ctlr
, vi
->ui_slave
, type
,0))
dcb
->nxtdcb
= (fmt_dcb
*)0; /* end of chain */
dcb
->devselect
= (char)(vi
->ui_slave
);
dcb
->trailcnt
= (char)(sizeof (trrw
) / sizeof (long));
dcb
->trail
.rwtrail
.memadr
= (char *)PHYS(ci
->rawbuf
);
dcb
->trail
.rwtrail
.wcount
= vdst
[type
].secsize
/sizeof(short);
dcb
->trail
.rwtrail
.disk
.cylinder
= vdst
[type
].ncyl
- 2;
dcb
->trail
.rwtrail
.disk
.track
= vdst
[type
].ntrak
- 1;
dcb
->trail
.rwtrail
.disk
.sector
= vdst
[type
].nsec
- 1;
mdcb
->firstdcb
= (fmt_dcb
*)(PHYS(dcb
));
VDDC_ATTENTION(addr
, (fmt_mdcb
*)(PHYS(mdcb
)), ci
->ctlr_type
);
POLLTILLDONE(addr
, dcb
, 60, ci
->ctlr_type
);
printf(" during probe\n");
if ((dcb
->operrsta
&HRDERR
) == 0)
* If reached here, a drive which is not defined in the
* 'vdst' tables is connected. Cannot set it's type.
printf("vd%d: unknown drive type\n", vi
->ui_unit
);
ui
->sec_per_blk
= DEV_BSIZE
/ ui
->info
.secsize
;
vddriver
.ud_dname
= ui
->info
.type_name
;
vdconfigure_drive(addr
, ctlr
, slave
, type
, pass
)
int ctlr
, slave
, type
, pass
;
register ctlr_tab
*ci
= &vdctlr_info
[ctlr
];
ci
->ctlr_dcb
.opcode
= RSTCFG
; /* command */
ci
->ctlr_dcb
.intflg
= NOINT
;
ci
->ctlr_dcb
.nxtdcb
= (fmt_dcb
*)0; /* end of chain */
ci
->ctlr_dcb
.operrsta
= 0;
ci
->ctlr_dcb
.devselect
= (char)slave
;
ci
->ctlr_dcb
.trail
.rstrail
.ncyl
= vdst
[type
].ncyl
;
ci
->ctlr_dcb
.trail
.rstrail
.nsurfaces
= vdst
[type
].ntrak
;
if (ci
->ctlr_type
== SMD_ECTLR
) {
ci
->ctlr_dcb
.trailcnt
= (char)4;
ci
->ctlr_dcb
.trail
.rstrail
.nsectors
= vdst
[type
].nsec
;
ci
->ctlr_dcb
.trail
.rstrail
.slip_sec
= vdst
[type
].nslip
;
ci
->ctlr_dcb
.trailcnt
= (char)2;
ci
->ctlr_mdcb
.firstdcb
= (fmt_dcb
*)(PHYS(&ci
->ctlr_dcb
));
ci
->ctlr_mdcb
.vddcstat
= 0;
VDDC_ATTENTION(addr
, (fmt_mdcb
*)(PHYS(&ci
->ctlr_mdcb
)), ci
->ctlr_type
);
POLLTILLDONE(addr
, &ci
->ctlr_dcb
, 5, ci
->ctlr_type
);
printf(" during config\n");
if (ci
->ctlr_dcb
.operrsta
& HRDERR
) {
if ((ci
->ctlr_dcb
.operrsta
& (NOTCYLERR
|DRVNRDY
)) == 0)
printf("vd%d: drive %d: config error\n", ctlr
, slave
);
vdstart_drive(addr
, ctlr
, slave
);
return (vdconfigure_drive(addr
, ctlr
, slave
, type
, 1));
return (vdconfigure_drive(addr
, ctlr
, slave
, type
, 3));
vdstart_drive(addr
, ctlr
, slave
)
register int ctlr
, slave
;
printf("vd%d: starting drive %d, wait...", ctlr
, slave
);
if (vdctlr_info
[ctlr
].ctlr_started
) {
printf("DELAY(5500000)...");
vdctlr_info
[ctlr
].ctlr_started
= 1;
error
= vdnotrailer(addr
, ctlr
, 0, VDSTART
, (slave
*6)+62) & HRDERR
;
printf("DELAY(%d)...", (slave
* 5500000) + 62000000);
DELAY((slave
* 5500000) + 62000000);
vdnotrailer(addr
, ctlr
, unit
, function
, time
)
int ctlr
, unit
, function
, time
;
fmt_mdcb
*mdcb
= &vdctlr_info
[ctlr
].ctlr_mdcb
;
fmt_dcb
*dcb
= &vdctlr_info
[ctlr
].ctlr_dcb
;
int type
= vdctlr_info
[ctlr
].ctlr_type
;
dcb
->opcode
= function
; /* command */
dcb
->nxtdcb
= (fmt_dcb
*)0; /* end of chain */
dcb
->devselect
= (char)unit
;
mdcb
->firstdcb
= (fmt_dcb
*)(PHYS(dcb
));
VDDC_ATTENTION(addr
, (fmt_mdcb
*)(PHYS(mdcb
)), type
);
POLLTILLDONE(addr
, dcb
, time
, type
);
printf(" during init\n");
return (DCBCMP
|ANYERR
|HRDERR
|OPABRT
);
register struct vba_device
*vi
;
register unit_tab
*ui
= &vdunit_info
[vi
->ui_unit
];
register ctlr_tab
*ci
= &vdctlr_info
[vi
->ui_ctlr
];
register struct buf
*cq
= &vi
->ui_mi
->um_tab
;
register struct buf
*uq
= cq
->b_forw
;
register struct buf
*start_queue
= uq
;
register fs_tab
*fs
= &ui
->info
;
ui
->info
= vdst
[vi
->ui_type
];
ui
->sec_per_blk
= DEV_BSIZE
/ ui
->info
.secsize
;
ui
->sec_per_cyl
= ui
->info
.nsec
* ui
->info
.ntrak
;
ui
->xfer_queue
.b_dev
= vi
->ui_slave
;
ci
->unit_type
[vi
->ui_slave
] = vi
->ui_type
;
/* load unit into controller's active unit list */
cq
->b_forw
= &ui
->xfer_queue
;
ui
->xfer_queue
.b_forw
= &ui
->xfer_queue
;
ui
->xfer_queue
.b_back
= &ui
->xfer_queue
;
while (uq
->b_forw
!= start_queue
)
ui
->xfer_queue
.b_forw
= start_queue
;
ui
->xfer_queue
.b_back
= uq
;
uq
->b_forw
= &ui
->xfer_queue
;
start_queue
->b_back
= &ui
->xfer_queue
;
* (60 / rpm) / (number of sectors per track * (bytes per sector / 2))
dk_mspw
[vi
->ui_unit
] = 120.0 / (fs
->rpm
* fs
->nsec
* fs
->secsize
);
register int unit
= VDUNIT(bp
->b_dev
);
register struct vba_device
*vi
= vddinfo
[unit
];
register int blks
, bn
, s
;
if (bp
->b_bcount
== 0 || vi
== 0 || vi
->ui_alive
== 0)
par
= &fs
->partition
[FILSYS(bp
->b_dev
)];
blks
= (bp
->b_bcount
+ DEV_BSIZE
-1) >> DEV_BSHIFT
;
if (bp
->b_blkno
+ blks
>= par
->par_len
) {
blks
= par
->par_len
- bp
->b_blkno
;
bp
->b_bcount
= blks
* DEV_BSIZE
;
bn
= bp
->b_blkno
+ par
->par_start
;
bp
->b_daddr
= (bn
/ fs
->nsec
) % fs
->ntrak
;
bp
->b_cylin
= bn
/ ui
->sec_per_cyl
;
vbasetup(bp
, ui
->info
.secsize
);
if (ui
->xfer_queue
.av_forw
== NULL
) {
register ctlr_tab
*ci
= &vdctlr_info
[vi
->ui_ctlr
];
int slave
= vi
->ui_slave
;
if (bp
->b_cylin
!= ci
->cur_cyl
[slave
] ||
bp
->b_daddr
!= ci
->cur_trk
[slave
])
ci
->off_cylinder
|= 1 << slave
;
bp
->b_daddr
|= (bn
% fs
->nsec
) << 8;
disksort(&ui
->xfer_queue
, bp
);
if (!vddinfo
[unit
]->ui_mi
->um_tab
.b_active
++) {
vdstart(vddinfo
[unit
]->ui_mi
);
bp
->b_flags
|= B_ERROR
, bp
->b_error
= ENXIO
;
bp
->b_resid
= bp
->b_bcount
;
* Start up a transfer on a drive.
register struct vba_ctlr
*ci
;
register struct buf
*cq
= &ci
->um_tab
;
register struct buf
*uq
= cq
->b_forw
;
/* search for next ready unit */
cq
->b_forw
= cq
->b_forw
->b_forw
;
if (uq
->av_forw
!= NULL
) {
} while (uq
!= cq
->b_forw
);
* Initiate seeks for all drives off-cylinder.
register int unit
, slave
, nseeks
;
register struct buf
*start_queue
= uq
;
unit
= VDUNIT(bp
->b_dev
);
slave
= vddinfo
[unit
]->ui_slave
;
if (ci
->off_cylinder
& (1 << slave
)) {
ci
->off_cylinder
&= ~(1 << slave
);
if (ci
->cur_cyl
[slave
] != bp
->b_cylin
) {
ci
->cur_cyl
[slave
] = bp
->b_cylin
;
ci
->cur_trk
[slave
] = bp
->b_daddr
&0xff;
dcb
= &ci
->seek_dcb
[nseeks
++];
dcb
->intflg
= NOINT
| INT_PBA
;
dcb
->devselect
= (char)slave
;
dcb
->trail
.sktrail
.skaddr
.cylinder
=
dcb
->trail
.sktrail
.skaddr
.track
=
dcb
->trail
.sktrail
.skaddr
.sector
= 0;
} while (uq
!= start_queue
&& nseeks
< 4);
* Execute the next command on the unit queue uq.
vdexecute(controller_info
, uq
)
register struct vba_ctlr
*controller_info
;
register struct buf
*bp
= uq
->av_forw
;
register int ctlr
= controller_info
->um_ctlr
;
register ctlr_tab
*ci
= &vdctlr_info
[ctlr
];
register int unit
= VDUNIT(bp
->b_dev
);
register int slave
= vddinfo
[unit
]->ui_slave
;
register fmt_mdcb
*mdcb
= &ci
->ctlr_mdcb
;
register fmt_dcb
*dcb
= &ci
->ctlr_dcb
;
* If there are overlapped seeks to perform, shuffle
* them to the front of the queue and get them started
* before any data transfers (to get some parallelism).
if ((ci
->off_cylinder
& ~(1<<slave
)) && ci
->overlap_seeks
) {
/* setup seek requests in seek-q */
nseeks
= vdload_seeks(ci
, uq
);
/* place at the front of the master q */
mdcb
->firstdcb
= (fmt_dcb
*)PHYS(&ci
->seek_dcb
[0]);
/* shuffle any remaining seeks up in the seek-q */
for (i
= 1; i
< nseeks
; i
++)
ci
->seek_dcb
[i
-1].nxtdcb
=
(fmt_dcb
*)PHYS(&ci
->seek_dcb
[i
]);
ci
->seek_dcb
[nseeks
-1].nxtdcb
= (fmt_dcb
*)PHYS(dcb
);
if (bp
->b_cylin
!= ci
->cur_cyl
[slave
]) {
ci
->cur_cyl
[slave
] = bp
->b_cylin
;
ci
->cur_trk
[slave
] = bp
->b_daddr
& 0xff;
mdcb
->firstdcb
= (fmt_dcb
*)(PHYS(dcb
));
dcb
->opcode
= (bp
->b_flags
& B_READ
) ? RD
: WD
;
dcb
->nxtdcb
= (fmt_dcb
*)0; /* end of chain */
dcb
->devselect
= (char)slave
;
dcb
->trailcnt
= (char)(sizeof (trrw
) / sizeof (long));
dcb
->trail
.rwtrail
.memadr
= (char *)
vbastart(bp
, ci
->rawbuf
, (long *)ci
->map
, ci
->utl
);
dcb
->trail
.rwtrail
.wcount
= (short)((bp
->b_bcount
+1) / sizeof (short));
dcb
->trail
.rwtrail
.disk
.cylinder
= bp
->b_cylin
;
dcb
->trail
.rwtrail
.disk
.track
= bp
->b_daddr
& 0xff;
dcb
->trail
.rwtrail
.disk
.sector
= bp
->b_daddr
>> 8;
dk_wds
[unit
] += bp
->b_bcount
/ 32;
timeout(vd_int_timeout
, (caddr_t
)ctlr
, 20*60);
VDDC_ATTENTION((cdr
*)(vdminfo
[ctlr
]->um_addr
),
(fmt_mdcb
*)(PHYS(mdcb
)), ci
->ctlr_type
);
* Watch for lost interrupts.
register ctlr_tab
*ci
= &vdctlr_info
[ctlr
];
register fmt_dcb
*dcb
= &ci
->ctlr_dcb
;
printf("vd%d: lost interupt, status %x", ctlr
, dcb
->operrsta
);
if (ci
->ctlr_type
== SMD_ECTLR
) {
printf(", error code %x", dcb
->err_code
);
if ((dcb
->operrsta
&DCBCMP
) == 0) {
VDDC_ABORT((cdr
*)(vdminfo
[ctlr
]->um_addr
), ci
->ctlr_type
);
dcb
->operrsta
|= DCBUSC
| DCBABT
| ANYERR
| HRDERR
| CTLRERR
;
* Handle a disk interrupt.
register struct buf
*cq
, *uq
, *bp
;
register int slave
, unit
;
untimeout(vd_int_timeout
, (caddr_t
)ctlr
);
printf("vd%d: stray interrupt\n", ctlr
);
* Take first request off controller's queue.
cq
= &vdminfo
[ctlr
]->um_tab
;
unit
= VDUNIT(bp
->b_dev
);
/* find associated control blocks */
mdcb
= &ci
->ctlr_mdcb
, uncache(&mdcb
->intdcb
);
dcb
= &ci
->ctlr_dcb
, uncache(&dcb
->operrsta
);
if (ci
->ctlr_type
== SMD_ECTLR
)
switch (code
= vddecode_error(dcb
)) {
vdhard_error(ci
, bp
, dcb
);
vdreset_ctlr((cdr
*)vdminfo
[ctlr
]->um_addr
, ctlr
);
reset_drive((cdr
*)vdminfo
[ctlr
]->um_addr
, ctlr
,
if (cq
->b_errcnt
++ < 2) { /* retry error */
bp
->b_resid
= bp
->b_bcount
;
vdhard_error(ci
, bp
, dcb
);
vdsoft_error(ci
, bp
, dcb
);
default: /* operation completed */
vbadone(bp
, ci
->rawbuf
, (long *)ci
->map
, ci
->utl
);
* Take next request on this unit q, or, if none,
* the next request on the next active unit q.
uq
->av_forw
= bp
->av_forw
;
register struct buf
*next
;
unit
= VDUNIT(uq
->av_forw
->b_dev
);
slave
= vddinfo
[unit
]->ui_slave
;
if (next
->b_cylin
!= ci
->cur_cyl
[slave
] ||
(next
->b_daddr
& 0xff) != ci
->cur_trk
[slave
])
ci
->off_cylinder
|= 1 << slave
;
/* reset controller state */
if (bp
->b_flags
& B_ERROR
)
* Convert controller status to internal operation/error code.
if (dcb
->operrsta
& HRDERR
) {
if (dcb
->operrsta
& (HCRCERR
| HCMPERR
| UCDATERR
| WPTERR
|
DSEEKERR
| NOTCYLERR
|DRVNRDY
| INVDADR
))
if (dcb
->operrsta
& (CTLRERR
| OPABRT
| INVCMD
| DNEMEM
))
return (HARD_DATA_ERROR
);
if (dcb
->operrsta
& SFTERR
)
return (SOFT_DATA_ERROR
);
vdhard_error(ci
, bp
, dcb
)
unit_tab
*ui
= &vdunit_info
[VDUNIT(bp
->b_dev
)];
harderr(bp
, ui
->info
.type_name
);
printf("status %x", dcb
->operrsta
);
if (ci
->ctlr_type
== SMD_ECTLR
)
printf(" ecode %x", dcb
->err_code
);
vdsoft_error(ci
, bp
, dcb
)
unit_tab
*ui
= &vdunit_info
[VDUNIT(bp
->b_dev
)];
printf("%s%d%c: soft error sn%d status %x", ui
->info
.type_name
,
minor(bp
->b_dev
) >> 3, 'a'+(minor(bp
->b_dev
)&07), bp
->b_blkno
,
if (ci
->ctlr_type
== SMD_ECTLR
)
printf(" ecode %x", dcb
->err_code
);
register unit
= VDUNIT(dev
);
register struct vba_device
*vi
= vddinfo
[unit
];
if (vi
== 0 || vi
->ui_alive
== 0 || vi
->ui_type
>= nvddrv
)
if (vdunit_info
[unit
].info
.partition
[FILSYS(dev
)].par_len
== 0)
register int unit
= VDUNIT(dev
);
register unit_tab
*ui
= &vdunit_info
[unit
];
return (physio(vdstrategy
, &ui
->raw_q_element
, dev
, B_READ
,
register int unit
= VDUNIT(dev
);
register unit_tab
*ui
= &vdunit_info
[unit
];
return (physio(vdstrategy
, &ui
->raw_q_element
, dev
, B_WRITE
,
register int unit
= VDUNIT(dev
);
register unit_tab
*ui
= &vdunit_info
[unit
];
register fs_tab
*fs
= &ui
->info
;
register int ctlr
= vddinfo
[unit
]->ui_ctlr
;
register struct vba_ctlr
*vba_vdctlr_info
= vdminfo
[ctlr
];
register int filsys
= FILSYS(dev
);
register cdr
*addr
= (cdr
*)(vba_vdctlr_info
->um_addr
);
register int cur_blk
, blkcount
, blocks
;
vdreset_ctlr(addr
, ctlr
);
blkcount
= maxfree
- 2; /* In 1k byte pages */
if (dumplo
+ blkcount
> fs
->partition
[filsys
].par_len
) {
blkcount
= fs
->partition
[filsys
].par_len
- dumplo
;
printf("vd%d: Dump truncated to %dMB\n", unit
, blkcount
/1024);
cur_blk
= fs
->partition
[filsys
].par_start
+ dumplo
;
blocks
= MIN(blkcount
, DUMPSIZE
);
if (!vdwrite_block(addr
, ctlr
, unit
, memaddr
, cur_blk
, blocks
))
memaddr
+= blocks
* NBPG
;
* Write a block to disk during a crash dump.
vdwrite_block(caddr
, ctlr
, unit
, addr
, block
, blocks
)
register int block
, blocks
;
register fmt_mdcb
*mdcb
= &vdctlr_info
[ctlr
].ctlr_mdcb
;
register fmt_dcb
*dcb
= &vdctlr_info
[ctlr
].ctlr_dcb
;
register unit_tab
*ui
= &vdunit_info
[unit
];
register fs_tab
*fs
= &ui
->info
;
block
*= (int)ui
->sec_per_blk
;
blocks
*= (int)ui
->sec_per_blk
;
mdcb
->firstdcb
= (fmt_dcb
*)(PHYS(dcb
));
dcb
->devselect
= (char)(vddinfo
[unit
])->ui_slave
;
dcb
->trailcnt
= (char)(sizeof (trrw
) / sizeof (long));
dcb
->trail
.rwtrail
.memadr
= addr
;
dcb
->trail
.rwtrail
.wcount
= (short)
((blocks
* fs
->secsize
)/ sizeof (short));
dcb
->trail
.rwtrail
.disk
.cylinder
= (short)(block
/ ui
->sec_per_cyl
);
dcb
->trail
.rwtrail
.disk
.track
= (char)((block
/ fs
->nsec
) % fs
->ntrak
);
dcb
->trail
.rwtrail
.disk
.sector
= (char)(block
% fs
->nsec
);
VDDC_ATTENTION(caddr
, (fmt_mdcb
*)(PHYS(mdcb
)),
vdctlr_info
[ctlr
].ctlr_type
);
POLLTILLDONE(caddr
, dcb
, 5, vdctlr_info
[ctlr
].ctlr_type
);
printf(" during dump\n");
if (dcb
->operrsta
& HRDERR
) {
printf("vd%d: hard error, status %x\n", unit
, dcb
->operrsta
);
struct vba_device
*vi
= vddinfo
[VDUNIT(dev
)];
if (vi
== 0 || vi
->ui_alive
== 0 || vi
->ui_type
>= nvddrv
)
return (vdunit_info
[VDUNIT(dev
)].info
.partition
[FILSYS(dev
)].par_len
);
* Perform a controller reset.
register struct buf
*cq
= &vdminfo
[ctlr
]->um_tab
;
register struct buf
*uq
= cq
->b_forw
;
register ctlr_tab
*ci
= &vdctlr_info
[ctlr
];
VDDC_RESET(addr
, ci
->ctlr_type
);
if (ci
->ctlr_type
== SMD_ECTLR
) {
addr
->mdcb_tcf
= AM_ENPDA
;
addr
->dcb_tcf
= AM_ENPDA
;
addr
->trail_tcf
= AM_ENPDA
;
addr
->data_tcf
= AM_ENPDA
;
addr
->cdr_ccf
= CCF_STS
| XMD_32BIT
| BSZ_16WRD
|
CCF_ENP
| CCF_EPE
| CCF_EDE
| CCF_ECE
| CCF_ERR
;
if (vdnotrailer(addr
, ctlr
, 0, INIT
, 10) & HRDERR
) {
printf("failed to init\n");
if (vdnotrailer(addr
, ctlr
, 0, DIAG
, 10) & HRDERR
) {
printf("diagnostic error\n");
/* reset all units attached to controller */
reset_drive(addr
, ctlr
, uq
->b_dev
, 0);
} while (uq
!= cq
->b_forw
);
* Perform a reset on a drive.
reset_drive(addr
, ctlr
, slave
, start
)
register int ctlr
, slave
, start
;
register int type
= vdctlr_info
[ctlr
].unit_type
[slave
];
if (!vdconfigure_drive(addr
, ctlr
, slave
, type
, start
))
printf("vd%d: drive %d: couldn't reset\n", ctlr
, slave
);
* Dump the mdcb and DCB for diagnostic purposes.
for (dcb
= 0; lp
; lp
= (long *)(*lp
), dcb
++) {
lp
= (long *)((long)lp
| 0xc0000000);
printf("\nDump of dcb%d@%x:", dcb
, lp
);
for (i
= 0, tc
= lp
[3] & 0xff; i
< tc
+7; i
++)