|
|
Power 6/32 Unix version 1.21
#include "fsd.h"
#if NVD > 0
/*
** VDDC Driver - Versabus to SMD direct interface version.
** Written for TAHOE vmunix, CCI-WDC 9/1/83.
*/
#include "../h/param.h"
#include "../h/buf.h"
#include "../h/cmap.h"
#include "../h/conf.h"
#include "../h/dir.h"
#include "../h/dk.h"
#include "../h/map.h"
#include "../machine/mtpr.h"
#include "../machine/pte.h"
#include "../h/systm.h"
#include "../vba/vbavar.h"
#include "../h/user.h"
#include "../h/vmmac.h"
#include "../h/proc.h"
#include "../h/uio.h"
#define VDGENDATA
#include "../vba/vddc.h"
#undef VDGENDATA
#define MAX_BLOCKSIZE MAXBPTE * NBPG
#define DUMPSIZE 64 /* Up to 64k at a time - controller limit */
/*
** Layout of minor number assignments for the VDDC devices.
**
**
** 7 3 2 0
** +--------------+-----+
** | Unit number | FLS |
** +--------------+-----+
** | |_____ File system # ( 0-7 )
** |__________ Unit # in the system
*/
#define VDUNIT(x) (minor(x) >> 3)
#define FILSYS(x) (minor(x) & 0x07)
#define PHYS(x) (vtoph(0, (int)(x)))
#define TRUE 1
#define FALSE 0
#define NOERROR 0
#define CTLR_ERROR 1
#define DRIVE_ERROR 2
#define HARD_DATA_ERROR 3
#define SOFT_DATA_ERROR 4
#define b_cylin b_resid
#define b_daddr b_error
/*
**
*/
struct vba_ctlr *vdminfo[NVD];
/*
**
*/
struct vba_device *vddinfo[NFSD];
/*
**
*/
int vdprobe(); /* See if VDDC is really there */
int vdslave(); /* See if drive is really there */
int vdattach(); /* Enter a drive in internal tables */
int vddgo(); /* Old VAX function, not used. */
/*
**
*/
struct vba_driver vddriver = {
vdprobe, vdslave, vdattach, vddgo, vddcaddr,
"", vddinfo, "", vdminfo
};
/*
**
*/
typedef struct {
struct buf raw_q_element;
short sec_per_blk;
short sec_per_cyl;
char status;
struct buf xfer_queue;
int drive_type;
fs_tab info;
} unit_tab;
/*
**
*/
typedef struct {
char ctlr_type; /* */
char *map; /* */
char *utl; /* */
unsigned cur_slave : 8; /* last active unit number */
unsigned int_expected : 1; /* expect an interupt */
unsigned ctlr_started : 1; /* start command was issued */
unsigned overlap_seeks : 1; /* Should overlap seeks */
unsigned off_cylinder : 16; /* Off cylinder bit map */
unsigned unit_type[16]; /* type of each slave */
long 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 */
char rawbuf[MAX_BLOCKSIZE]; /* buffer for raw/swap i/o */
} ctlr_tab;
/*
**
*/
extern char vd0utl[];
#if NVD > 1
extern char vd1utl[];
#if NVD > 2
extern char vd2utl[];
#if NVD > 3
extern char vd3utl[];
#if NVD > 4
extern char vd4utl[];
#if NVD > 5
extern char vd5utl[];
#if NVD > 6
extern char vd6utl[];
#if NVD > 7
extern char vd7utl[];
#if NVD > 8
error Can only support up to 8 controllers
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
/*
**
*/
ctlr_tab vdctlr_info[NVD] = {
{UNKNOWN, (char *)VD0map, vd0utl, 0, FALSE, FALSE, TRUE, 0,
{UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN}}
#if NVD > 1
,{UNKNOWN, (char *)VD1map, vd1utl, 0, FALSE, FALSE, TRUE, 0,
{UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN}}
#if NVD > 2
,{UNKNOWN, (char *)VD2map, vd2utl, 0, FALSE, FALSE, TRUE, 0,
{UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN}}
#if NVD > 3
,{UNKNOWN, (char *)VD3map, vd3utl, 0, FALSE, FALSE, TRUE, 0,
{UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN}}
#if NVD > 4
,{UNKNOWN, (char *)VD4map, vd4utl, 0, FALSE, FALSE, TRUE, 0,
{UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN}}
#if NVD > 5
,{UNKNOWN, (char *)VD5map, vd5utl, 0, FALSE, FALSE, TRUE, 0,
{UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN}}
#if NVD > 6
,{UNKNOWN, (char *)VD6map, vd6utl, 0, FALSE, FALSE, TRUE, 0,
{UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN}}
#if NVD > 7
,{UNKNOWN, (char *)VD7map, vd7utl, 0, FALSE, FALSE, TRUE, 0,
{UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,
UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN}}
#endif
#endif
#endif
#endif
#endif
#endif
#endif
};
/*
**
*/
unit_tab vdunit_info[NFSD];
/*
** See if the controller is really there.
** if TRUE - initialize the controller.
*/
vdprobe(ctlr_addr)
cdr *ctlr_addr;
{
if(!badaddr(ctlr_addr, 2)) {
ctlr_addr->cdr_reset = 0xffffffff;
DELAY(1000000);
if(ctlr_addr->cdr_reset != 0xffffffff) {
vddriver.ud_mname = "VSMD Controller #";
DELAY(1000000);
}
else {
vddriver.ud_mname = "SMD/E Controller #";
ctlr_addr->cdr_reserved = 0x0;
DELAY(3000000);
}
return TRUE;
}
return FALSE; /* no controller */
}
/*
** See if a drive is really there
** Try to Reset/Configure the drive, then test its status.
*/
vdslave(vba_dev_info, ctlr_addr)
register struct vba_device *vba_dev_info;
register cdr *ctlr_addr;
{
register int ctlr = vba_dev_info->ui_ctlr;
register ctlr_tab *c_info = &vdctlr_info[ctlr];
register int unit = vba_dev_info->ui_unit;
register unit_tab *u_info = &vdunit_info[unit];
register int slave = vba_dev_info->ui_slave;
register int type;
register fmt_mdcb *mdcb = &c_info->ctlr_mdcb;
register fmt_dcb *dcb = &c_info->ctlr_dcb;
if(c_info->ctlr_type == UNKNOWN) {
ctlr_addr->cdr_reset = 0xffffffff;
DELAY(1000000);
if(ctlr_addr->cdr_reset != 0xffffffff) {
c_info->ctlr_type = SMDCTLR;
c_info->overlap_seeks = FALSE;
DELAY(1000000);
}
else {
c_info->overlap_seeks = TRUE;
c_info->ctlr_type = SMD_ECTLR;
ctlr_addr->cdr_reserved = 0x0;
DELAY(3000000);
ctlr_addr->cdr_csr = 0;
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(ctlr_addr,ctlr,slave,INIT,10) &
HRDERR) {
printf("\n VDDC: Controller %d init error.\n", ctlr);
return FALSE;
}
if(vdaccess_with_no_trailer(ctlr_addr,ctlr,slave,DIAG,10) &
HRDERR) {
printf("\n VDDC: Controller %d diagnostic error.\n",ctlr);
return FALSE;
}
}
/*
* 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((c_info->ctlr_type == SMDCTLR) && (vdst[type].nsec != 32))
continue;
if(vdconfigure_drive(ctlr_addr, ctlr, slave, type, 0)) {
dcb->opcode = (short)RD;
dcb->intflg = NOINT;
dcb->nxtdcb = (fmt_dcb *)0; /* end of chain */
dcb->operrsta = 0;
dcb->devselect = (char)slave;
dcb->trailcnt = (char)(sizeof(trrw) / sizeof(long));
dcb->trail.rwtrail.memadr=(char *)PHYS(c_info->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));
mdcb->vddcstat = 0;
VDDC_ATTENTION(ctlr_addr, (fmt_mdcb *)(PHYS(mdcb)),
c_info->ctlr_type);
POLLTILLDONE(ctlr_addr, dcb, 60, c_info->ctlr_type);
if(vdtimeout <= 0) {
printf(" during probe operation.\n");
}
if(!(dcb->operrsta & HRDERR))
break;
}
else
return FALSE;
}
if (type >= nvddrv) {
/*
* If reached here, a drive which is not defined in the
* 'vdst' tables is connected. Cannot set it's type.
*/
printf("VDDC: Could not identify controller %d, drive %d!\n",
ctlr, slave);
return FALSE;
}
u_info->drive_type = type;
u_info->info = vdst[type];
u_info->sec_per_blk = DEV_BSIZE / u_info->info.secsize;
vba_dev_info->ui_type = type;
vba_dev_info->ui_dk = TRUE;
vddriver.ud_dname = u_info->info.type_name;
return TRUE;
}
/*
**
*/
vdconfigure_drive(ctlr_addr, ctlr, slave, type, pass)
cdr *ctlr_addr;
register int ctlr, slave, type, pass;
{
register ctlr_tab *c_info = &vdctlr_info[ctlr];
c_info->ctlr_dcb.opcode = RSTCFG; /* command */
c_info->ctlr_dcb.intflg = NOINT;
c_info->ctlr_dcb.nxtdcb = (fmt_dcb *)0; /* end of chain */
c_info->ctlr_dcb.operrsta = 0;
c_info->ctlr_dcb.devselect = (char)slave;
c_info->ctlr_dcb.trail.rstrail.ncyl = vdst[type].ncyl;
c_info->ctlr_dcb.trail.rstrail.nsurfaces = vdst[type].ntrak;
if(c_info->ctlr_type == SMD_ECTLR) {
c_info->ctlr_dcb.trailcnt = (char)4;
c_info->ctlr_dcb.trail.rstrail.nsectors = vdst[type].nsec;
c_info->ctlr_dcb.trail.rstrail.slip_sec = vdst[type].nslip;
}
else
c_info->ctlr_dcb.trailcnt = (char)2;
c_info->ctlr_mdcb.firstdcb = (fmt_dcb *)(PHYS(&c_info->ctlr_dcb));
c_info->ctlr_mdcb.vddcstat = 0;
VDDC_ATTENTION(ctlr_addr, (fmt_mdcb *)(PHYS(&c_info->ctlr_mdcb)),
c_info->ctlr_type);
POLLTILLDONE(ctlr_addr, &c_info->ctlr_dcb, 5, c_info->ctlr_type);
if(vdtimeout <= 0) {
printf(" during drive configuration.\n");
return FALSE;
}
if(c_info->ctlr_dcb.operrsta & HRDERR) {
if(!(c_info->ctlr_dcb.operrsta & (NOTCYLERR | DRVNRDY)))
printf("\n VDDC: Configuration error.\n");
else if(pass == 0) {
vdstart_drive(ctlr_addr, ctlr, slave);
return vdconfigure_drive(ctlr_addr,ctlr,slave,type,1);
}
else if(pass == 2)
return vdconfigure_drive(ctlr_addr,ctlr,slave,type,3);
return FALSE;
}
return TRUE;
}
/*
**
*/
vdstart_drive(ctlr_addr, ctlr, slave)
cdr *ctlr_addr;
register int ctlr, slave;
{
printf("\n VDDC: Attempting to start drive %d.", slave);
printf(" Please wait...");
if(vdctlr_info[ctlr].ctlr_started) {
DELAY(5500000);
printf("\n");
return TRUE;
}
vdctlr_info[ctlr].ctlr_started = TRUE;
if(vdaccess_with_no_trailer(ctlr_addr, ctlr, 0, VDSTART, (slave*6)+62)
& HRDERR) {
printf("\n");
return FALSE;
}
DELAY((slave * 5500000) + 62000000);
printf("\n");
return TRUE;
}
/*
**
*/
vdaccess_with_no_trailer(ctlr_addr, ctlr, unit, function, time)
register cdr *ctlr_addr;
register int ctlr, unit, function, time;
{
fmt_mdcb *mdcb = &vdctlr_info[ctlr].ctlr_mdcb;
fmt_dcb *dcb = &vdctlr_info[ctlr].ctlr_dcb;
dcb->opcode = function; /* command */
dcb->intflg = NOINT;
dcb->nxtdcb = (fmt_dcb *)0; /* end of chain */
dcb->operrsta = 0;
dcb->devselect = (char)unit;
dcb->trailcnt = (char)0;
mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
mdcb->vddcstat = 0;
VDDC_ATTENTION(ctlr_addr, (fmt_mdcb *)(PHYS(mdcb)),
vdctlr_info[ctlr].ctlr_type);
POLLTILLDONE(ctlr_addr, dcb, time, vdctlr_info[ctlr].ctlr_type);
if(vdtimeout <= 0) {
printf(" during initialization operation.\n");
return (DCBCMP | ANYERR | HRDERR | OPABRT);
}
return dcb->operrsta;
}
/*
**
*/
vdattach(vba_dev_info)
struct vba_device *vba_dev_info;
{
register int unit = vba_dev_info->ui_unit;
register unit_tab *u_info = &vdunit_info[unit];
register ctlr_tab *c_info = &vdctlr_info[vba_dev_info->ui_ctlr];
register struct buf *c_queue = &vba_dev_info->ui_mi->um_tab;
register struct buf *u_queue = c_queue->b_forw;
register struct buf *start_queue = u_queue;
register int type = vba_dev_info->ui_type;
register fs_tab *fs = &u_info->info;
u_info->info = vdst[type];
u_info->sec_per_blk = DEV_BSIZE / u_info->info.secsize;
u_info->sec_per_cyl = u_info->info.nsec * u_info->info.ntrak;
u_info->xfer_queue.b_dev = vba_dev_info->ui_slave;
c_info->unit_type[vba_dev_info->ui_slave] = type;
/* load unit into controller's active unit list */
if(u_queue == NULL) {
c_queue->b_forw = &u_info->xfer_queue;
u_info->xfer_queue.b_forw = &u_info->xfer_queue;
u_info->xfer_queue.b_back = &u_info->xfer_queue;
}
else {
while(u_queue->b_forw != start_queue)
u_queue = u_queue->b_forw;
u_info->xfer_queue.b_forw = start_queue;
u_info->xfer_queue.b_back = u_queue;
u_queue->b_forw = &u_info->xfer_queue;
start_queue->b_back = &u_info->xfer_queue;
}
/*
** (60 / rpm) / (number of sectors per track * (bytes per sector / 2))
*/
dk_mspw[unit] = 120.0 / (fs->rpm * fs->nsec * fs->secsize);
}
/*
** Historic VAX routine.
*/
vddgo(um)
struct vba_ctlr *um;
{
}
/*
** Variables used:
** request -> points to current transaction queue element.
** unit -> contains the system's logical unit number.
** ctlr -> contains the physical controller number.
** slave -> contains the physical unit number on ctlr.
** vba_dev_info -> unix's controller information tables.
** par -> contains the file system number (0-7)
** u_info -> points to internal unit_information table
** c_info -> points to internal controller information table.
** blks -> temporary variable holds number of blocks to xfer.
** blks -> temporary variable holds starting block number.
** priority -> temporary variable holds old cpu priority.
*/
vdstrategy(request)
register struct buf *request;
{
register int unit = VDUNIT(request->b_dev);
register struct vba_device *vba_dev_info = vddinfo[unit];
register int par = FILSYS(request->b_dev);
register unit_tab *u_info = &vdunit_info[unit];
register ctlr_tab *c_info;
register fs_tab *fs = &u_info->info;
register int blks, blk, priority, slave;
if((request->b_bcount != 0) && (vba_dev_info != NULL) &&
(vba_dev_info->ui_alive != 0)&&(fs->partition[par].par_len != 0)) {
slave = vba_dev_info->ui_slave;
c_info = &vdctlr_info[vba_dev_info->ui_ctlr];
blks = (request->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
if(fs->partition[par].par_len < (request->b_blkno + blks)) {
blks = fs->partition[par].par_len - request->b_blkno;
if(blks > 0)
request->b_bcount = blks * DEV_BSIZE;
else
goto error;
}
blk = request->b_blkno + fs->partition[par].par_start;
blk *= u_info->sec_per_blk;
request->b_daddr = (blk / fs->nsec) % fs->ntrak;
request->b_cylin = blk / u_info->sec_per_cyl;
buf_setup (request, u_info->info.secsize);
priority = spl7();
if(u_info->xfer_queue.av_forw == NULL)
if((request->b_cylin != c_info->cur_cyl[slave]) ||
(request->b_daddr)!=(c_info->cur_trk[slave]))
c_info->off_cylinder |= 1 << slave;
request->b_daddr |= (blk % fs->nsec) << 8;
disksort(&u_info->xfer_queue, request);
if(!vddinfo[unit]->ui_mi->um_tab.b_active++) {
splx(priority);
vdstart(vddinfo[unit]->ui_mi);
return;
}
splx(priority);
return;
}
harderr(request, u_info->info.type_name);
printf("- Strategy was passed bad information: " );
printf("b_bcount=%d, dev_info=%x, alive=%x, and partition length=%d.\n",
request->b_bcount, vba_dev_info, vba_dev_info->ui_alive,
fs->partition[par].par_len);
error:
request->b_flags |= B_ERROR;
request->b_error = ENXIO;
request->b_resid = request->b_bcount;
iodone(request);
}
/*
* Start up a transfer on a drive.
*/
vdstart(controller_info)
register struct vba_ctlr *controller_info;
{
register struct buf *c_queue = &controller_info->um_tab;
register struct buf *u_queue = c_queue->b_forw;
/* Search for next ready unit */
c_queue->b_forw = c_queue->b_forw->b_forw;
u_queue = c_queue->b_forw;
do {
if(u_queue->av_forw != NULL) {
c_queue->b_forw = u_queue;
vdexecute(controller_info, c_queue, u_queue);
return;
}
u_queue = u_queue->b_forw;
} while(u_queue != c_queue->b_forw);
}
vdload_seeks(c_info, u_queue)
register ctlr_tab *c_info;
register struct buf *u_queue;
{
register int unit, slave, seek_count = 0;
register fmt_dcb *dcb;
register struct buf *request;
register int new_cyl;
register struct buf *start_queue = u_queue;
do {
if((request = u_queue->av_forw) != NULL) {
unit = VDUNIT(request->b_dev);
slave = vddinfo[unit]->ui_slave;
if(c_info->off_cylinder & (1 << slave)) {
c_info->off_cylinder &= ~(1 << slave);
if(c_info->cur_cyl[slave] != request->b_cylin) {
c_info->cur_cyl[slave]=request->b_cylin;
dk_seek[unit]++;
}
c_info->cur_trk[slave] = request->b_daddr&0xff;
dcb = &c_info->seek_dcb[seek_count++];
dcb->opcode = SEEK;
dcb->intflg = NOINT | INT_PBA;
dcb->operrsta = 0;
dcb->devselect = (char)slave;
dcb->trailcnt = (char)1;
dcb->trail.sktrail.skaddr.cylinder =
request->b_cylin;
dcb->trail.sktrail.skaddr.track =
request->b_daddr & 0xff;
dcb->trail.sktrail.skaddr.sector = 0;
}
}
u_queue = u_queue->b_forw;
} while((u_queue != start_queue) && (seek_count < 4));
return seek_count;
}
/*
**
*/
vdexecute(controller_info, c_queue, u_queue)
register struct vba_ctlr *controller_info;
register struct buf *c_queue, *u_queue;
{
extern vd_int_timeout();
register struct buf *request = u_queue->av_forw;
register int ctlr = controller_info->um_ctlr;
register ctlr_tab *c_info = &vdctlr_info[ctlr];
register int unit = VDUNIT(request->b_dev);
register int slave = vddinfo[unit]->ui_slave;
register fs_tab *fs = &vdunit_info[unit].info;
register fmt_mdcb *mdcb = &c_info->ctlr_mdcb;
register fmt_dcb *dcb = &c_info->ctlr_dcb;
if((c_info->off_cylinder & ~(1<<slave)) && c_info->overlap_seeks) {
register int index;
register int seek_count = vdload_seeks(c_info, u_queue);
mdcb->firstdcb = (fmt_dcb *)PHYS(&c_info->seek_dcb[0]);
for(index = 1; index < seek_count; index++)
c_info->seek_dcb[index-1].nxtdcb =
(fmt_dcb *)PHYS(&c_info->seek_dcb[index]);
c_info->seek_dcb[seek_count-1].nxtdcb = (fmt_dcb *)PHYS(dcb);
}
else {
if(request->b_cylin != c_info->cur_cyl[slave]) {
c_info->cur_cyl[slave] = request->b_cylin;
dk_seek[unit]++;
}
c_info->cur_trk[slave] = request->b_daddr & 0xff;
c_info->off_cylinder = 0;
mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
}
dcb->opcode = (request->b_flags & B_READ) ? RD : WD;
dcb->intflg = INTDONE;
dcb->nxtdcb = (fmt_dcb *)0; /* end of chain */
dcb->operrsta = 0;
dcb->devselect = (char)slave;
dcb->trailcnt = (char)(sizeof(trrw) / sizeof(long));
dcb->trail.rwtrail.memadr = (char *)get_ioadr(request, c_info->rawbuf,
c_info->map, c_info->utl);
dcb->trail.rwtrail.wcount=(short)((request->b_bcount+1)/sizeof(short));
dcb->trail.rwtrail.disk.cylinder = request->b_cylin;
dcb->trail.rwtrail.disk.track = request->b_daddr & 0xff;
dcb->trail.rwtrail.disk.sector = request->b_daddr >> 8;
mdcb->vddcstat = 0;
dk_wds[unit] += request->b_bcount / 32;
c_info->int_expected = TRUE;
timeout(vd_int_timeout, ctlr, 20*60);
dk_busy |= 1 << unit;
#ifdef VDDCPERF
scope_out(1);
#endif
VDDC_ATTENTION((cdr *)(vdminfo[ctlr]->um_addr),(fmt_mdcb *)(PHYS(mdcb)),
c_info->ctlr_type);
}
/*
**
*/
vd_int_timeout(ctlr)
register int ctlr;
{
register ctlr_tab *c_info = &vdctlr_info[ctlr];
register fmt_mdcb *mdcb = &c_info->ctlr_mdcb;
register fmt_dcb *dcb = &c_info->ctlr_dcb;
uncache(&dcb->operrsta);
printf("\nVDDC: Controller %d didn't interupt!", ctlr);
printf(" Status = %x", dcb->operrsta);
if(c_info->ctlr_type == SMD_ECTLR) {
uncache(&dcb->err_code);
printf(" Error code = %x", dcb->err_code);
}
printf("\n");
if(!(dcb->operrsta & DCBCMP)) {
VDDC_ABORT((cdr *)(vdminfo[ctlr]->um_addr), c_info->ctlr_type);
dcb->operrsta |= DCBUSC | DCBABT | ANYERR | HRDERR | CTLRERR;
}
vdintr(ctlr);
}
/*
* Handle a disk interrupt.
*/
vdintr(ctlr)
register int ctlr;
{
extern vd_int_timeout();
register ctlr_tab *c_info = &vdctlr_info[ctlr];
untimeout(vd_int_timeout, ctlr);
#ifdef VDDCPERF
scope_out(2);
#endif
if(c_info->int_expected) {
register struct buf *u_queue=vdminfo[ctlr]->um_tab.b_forw;
register struct buf *request = u_queue->av_forw;
register int slave = u_queue->b_dev;
register int unit = VDUNIT(request->b_dev);
register unit_tab *u_info = &vdunit_info[unit];
register fmt_mdcb *mdcb = &c_info->ctlr_mdcb;
register fmt_dcb *dcb = &c_info->ctlr_dcb;
register int priority;
dk_busy &= ~(1 << unit);
dk_xfer[unit]++;
c_info->int_expected = FALSE;
uncache(&mdcb->intdcb);
uncache(&dcb->operrsta);
if(c_info->ctlr_type == SMD_ECTLR)
uncache(&dcb->err_code);
switch(vddecode_error(request, dcb)) {
case CTLR_ERROR :
vdhard_error(c_info, request, dcb,
(vdminfo[ctlr]->um_tab.b_errcnt < 2),
"Disk controller");
vdreset_ctlr(vdminfo[ctlr]->um_addr,ctlr);
if(vdminfo[ctlr]->um_tab.b_errcnt++ < 2) {
vdminfo[ctlr]->um_tab.b_forw = u_queue->b_back;
vdstart(vdminfo[ctlr]);
return;
}
request->b_resid = request->b_bcount;
break;
case DRIVE_ERROR :
vdhard_error(c_info, request, dcb,
(vdminfo[ctlr]->um_tab.b_errcnt < 2), "Disk drive");
reset_drive(vdminfo[ctlr]->um_addr, ctlr, slave, 2);
if(vdminfo[ctlr]->um_tab.b_errcnt++ < 2) {
vdminfo[ctlr]->um_tab.b_forw = u_queue->b_back;
vdstart(vdminfo[ctlr]);
return;
}
request->b_resid = request->b_bcount;
break;
case HARD_DATA_ERROR :
vdhard_error(c_info, request, dcb,
(vdminfo[ctlr]->um_tab.b_errcnt < 3),
"Uncorrected data");
reset_drive(vdminfo[ctlr]->um_addr, ctlr, slave, 2);
if(vdminfo[ctlr]->um_tab.b_errcnt++ < 3) {
vdminfo[ctlr]->um_tab.b_forw = u_queue->b_back;
vdstart(vdminfo[ctlr]);
return;
}
request->b_resid = 0;
break;
case SOFT_DATA_ERROR :
vdsoft_error(c_info, request, dcb);
default :
if(vdminfo[ctlr]->um_tab.b_errcnt)
printf(" VDDC: Retried successfully.\n");
request->b_error = 0;
request->b_resid = 0;
break;
}
end_transfer(request, c_info->rawbuf, c_info->map, c_info->utl);
priority = spl7();
u_queue->av_forw = request->av_forw;
if(u_queue->av_back == request)
u_queue->av_back = NULL;
else {
register struct buf *next;
unit = VDUNIT(u_queue->av_forw->b_dev);
slave = vddinfo[unit]->ui_slave;
next = u_queue->av_forw;
if((next->b_cylin != c_info->cur_cyl[slave]) ||
((next->b_daddr & 0xff) != c_info->cur_trk[slave]))
c_info->off_cylinder |= 1 << slave;
}
splx(priority);
vdminfo[ctlr]->um_tab.b_errcnt = 0;
vdminfo[ctlr]->um_tab.b_active--;
#ifdef VDDCPERF
scope_out(3);
#endif
if(request->b_flags & B_ERROR)
request->b_error = EIO;
iodone(request);
vdstart(vdminfo[ctlr]);
return;
}
printf("\nVDDC: Unexpected interupt from controller %d!\n", ctlr);
}
/*
**
*/
vddecode_error(request, dcb)
register struct buf *request;
register fmt_dcb *dcb;
{
register int unit = VDUNIT(request->b_dev);
if(dcb->operrsta & HRDERR) {
if (dcb->operrsta & (HCMPERR | WPTERR | DSEEKERR |
NOTCYLERR | DRVNRDY | INVDADR))
return DRIVE_ERROR;
else if(dcb->operrsta & (CTLRERR | OPABRT | INVCMD | DNEMEM))
return CTLR_ERROR;
return HARD_DATA_ERROR;
}
if(dcb->operrsta & SFTERR)
return SOFT_DATA_ERROR;
return NOERROR;
}
/*
**
*/
vdhard_error(c_info, request, dcb, retry, type)
ctlr_tab *c_info;
struct buf *request;
fmt_dcb *dcb;
int retry;
char *type;
{
vdreport(c_info, request, dcb, type);
if(retry)
printf(" VDDC: Retrying failed operation...\n");
else {
request->b_flags |= B_ERROR;
printf(" VDDC: Retries failed to correct error!\n");
}
}
/*
**
*/
vdsoft_error(c_info, request, dcb)
ctlr_tab *c_info;
struct buf *request;
fmt_dcb *dcb;
{
vdreport(c_info, request, dcb, "Corrected data");
}
/*
*/
vdreport(c_info, request, dcb, type)
ctlr_tab *c_info;
register struct buf *request;
register fmt_dcb *dcb;
char *type;
{
register int delta;
register int unit = VDUNIT(request->b_dev);
register unit_tab *u_info = &vdunit_info[unit];
register int blk = request->b_blkno * u_info->sec_per_blk;
register int par = FILSYS(request->b_dev);
harderr(request, u_info->info.type_name);
printf("- %s error. Status = 0x%x", type, dcb->operrsta);
if(c_info->ctlr_type == SMD_ECTLR)
printf(", Error code = 0x%x", dcb->err_code);
printf("\n");
delta = (request->b_bcount - 1) / u_info->info.secsize;
blk = request->b_blkno + u_info->info.partition[par].par_start;
blk *= u_info->sec_per_blk;
if(delta == 0)
printf(" VDDC: Error occured on absolute sector %d.\n", blk);
else {
printf(" VDDC: Error occured between");
printf(" absolute sectors %d and %d.\n", blk, (blk + delta));
}
}
/*
**
*/
vdopen(dev, flag)
register dev_t dev;
int flag;
{
register unit = VDUNIT(dev);
register struct vba_device *vba_dev_info = vddinfo[unit];
if((vba_dev_info == 0) ||
(vba_dev_info->ui_alive == 0) ||
(vba_dev_info->ui_type >= nvddrv))
return ENXIO;
if(vdunit_info[unit].info.partition[FILSYS(dev)].par_len == 0)
return ENXIO;
return NOERROR;
}
/*
**
*/
vdread(dev, uio)
dev_t dev;
struct uio *uio;
{
extern vdstrategy();
register int unit = VDUNIT(dev);
register unit_tab *u_info = &vdunit_info[unit];
if (unit >= NFSD)
return ENXIO;
return physio(vdstrategy, &u_info->raw_q_element, dev, B_READ,
minphys, uio);
}
/*
**
*/
vdwrite(dev, uio)
dev_t dev;
struct uio *uio;
{
extern vdstrategy();
register int unit = VDUNIT(dev);
register unit_tab *u_info = &vdunit_info[unit];
if (unit >= NFSD)
return ENXIO;
return physio(vdstrategy, &u_info->raw_q_element, dev, B_WRITE,
minphys, uio);
}
/*
**
*/
extern int physmem;
vddump(dev)
dev_t dev;
{
register int unit = VDUNIT(dev);
register unit_tab *u_info = &vdunit_info[unit];
register fs_tab *fs = &u_info->info;
register int ctlr = vddinfo[unit]->ui_ctlr;
register struct vba_ctlr *vba_vdctlr_info = vdminfo[ctlr];
register int filsys = FILSYS(dev);
register cdr *ctlr_addr = (cdr *)(vba_vdctlr_info->um_addr);
register int cur_blk, blkcount, blocks;
int dump_short = FALSE;
int memaddr = 0x0;
vdreset_ctlr(ctlr_addr, ctlr);
blkcount = physmem; /* In 1k byte pages */
if ((dumplo + blkcount) > fs->partition[filsys].par_len) {
blkcount = fs->partition[filsys].par_len - dumplo;
printf("\nVDDC: Only dumping first %dmb of memory!\n",
blkcount / 1024);
dump_short = TRUE;
}
cur_blk = fs->partition[filsys].par_start + dumplo;
while (blkcount > 0) {
blocks = MIN(blkcount, DUMPSIZE);
if(!vdwrite_block(ctlr_addr,ctlr,unit,memaddr,cur_blk,blocks))
return EIO;
blkcount -= blocks;
memaddr += blocks * NBPG;
cur_blk += blocks;
}
return dump_short ? ENXIO : NOERROR;
}
/*
**
*/
vdwrite_block(ctlr_addr, ctlr, unit, addr, block, blocks)
register cdr *ctlr_addr;
register int ctlr, unit;
register char *addr;
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 *u_info = &vdunit_info[unit];
register fs_tab *fs = &u_info->info;
block *= (int)u_info->sec_per_blk;
blocks *= (int)u_info->sec_per_blk;
mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
dcb->intflg = NOINT;
dcb->opcode = WD;
dcb->operrsta = 0;
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 / u_info->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(ctlr_addr, (fmt_mdcb *)(PHYS(mdcb)),
vdctlr_info[ctlr].ctlr_type);
POLLTILLDONE(ctlr_addr, dcb, 5, vdctlr_info[ctlr].ctlr_type);
if(vdtimeout <= 0) {
printf(" during dump operation!\n");
return(FALSE);
}
if (dcb->operrsta & HRDERR) {
printf("\nVDDC: Dump error. Status = %x\n", dcb->operrsta);
return(FALSE);
}
return TRUE;
}
/*
**
*/
vdsize(dev)
register dev_t dev;
{
register unit = VDUNIT(dev);
register struct vba_device *vba_dev_info = vddinfo[unit];
if((vba_dev_info == 0) ||
(vba_dev_info->ui_alive == 0) ||
(vba_dev_info->ui_type >= nvddrv))
return -1;
return vdunit_info[unit].info.partition[FILSYS(dev)].par_len;
}
/*
**
*/
vdreset_ctlr(ctlr_addr, ctlr)
register cdr *ctlr_addr;
register int ctlr;
{
register struct buf *c_queue = &vdminfo[ctlr]->um_tab;
register struct buf *u_queue = c_queue->b_forw;
register ctlr_tab *c_info = &vdctlr_info[ctlr];
register int type, priority;
printf("\n VDDC: Resetting controller %d. Please wait...\n", ctlr);
VDDC_RESET(ctlr_addr, type);
c_info->ctlr_started = FALSE;
if(c_info->ctlr_type == SMD_ECTLR) {
ctlr_addr->cdr_csr = 0;
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(ctlr_addr,ctlr,0,INIT,10) & HRDERR) {
printf("\n VDDC: Controller %d failed to initialize!\n",ctlr);
return FALSE;
}
if(vdaccess_with_no_trailer(ctlr_addr,ctlr,0,DIAG,10) & HRDERR) {
printf("\n VDDC: Controller %d diagnostic error!\n",ctlr);
return FALSE;
}
/* reset all units attached to controller */
u_queue = c_queue->b_forw;
do {
reset_drive(ctlr_addr, ctlr, u_queue->b_dev, 0);
u_queue = u_queue->b_forw;
} while(u_queue != c_queue->b_forw);
printf(" VDDC: Controller %d was reset successfully.\n", ctlr);
return TRUE;
}
/*
**
*/
reset_drive(ctlr_addr, ctlr, slave, start)
register cdr *ctlr_addr;
register int ctlr, slave, start;
{
register int type = vdctlr_info[ctlr].unit_type[slave];
if(type != UNKNOWN)
if(!vdconfigure_drive(ctlr_addr, ctlr, slave, type, start)) {
printf("\n VDDC: Could not reset");
printf(" unit %d, controller %d!\n", slave, ctlr);
}
}
/*
Print_dcb() dumps the mdcb and DCB for diagnostic purposes. This
routine is called whenever a fatal error is encountered.
*/
vdprintdcb(ptr)
register long *ptr;
{
register long i, j=0;
register long trailer_count;
ptr = (long *)(*ptr | 0xc0000000);
while(ptr != (long *)NULL) {
ptr = (long *)((long)ptr | 0xc0000000);
printf(" Dump of DCB 0x%x,%d:", ptr, j++);
trailer_count = *(ptr+3) & 0xff;
for(i=0; i<7+trailer_count; i++)
printf(" %lx", *(ptr+i));
ptr = (long *)(*ptr);
printf("\n");
}
printf("\n");
for(i=0; i<5000000; i++) ;
}
#endif NVD > 0
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.