2.11BSD/sys/pdpstand/xp.c
/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*
* @(#)xp.c 2.3 (2.11BSD) 1996/3/8
*/
/*
* SMD disk driver
*/
#include "../h/param.h"
#include "../pdpuba/hpreg.h"
#include "../machine/iopage.h"
#include "saio.h"
#define NXP 2
struct hpdevice *XPcsr[NXP + 1] =
{
(struct hpdevice *)0176700,
(struct hpdevice *)0,
(struct hpdevice *)-1
};
static char xpinit[NXP][8]; /* XXX */
xpopen(io)
register struct iob *io;
{
register struct disklabel *lp = &io->i_label;
register struct hpdevice *xpaddr;
int dummy;
if (genopen(NXP, io) < 0)
return(-1);
/*
* If this is the first access for the drive check to see if it is
* present. If the drive is present then read the label.
*/
if (xpinit[io->i_ctlr][io->i_unit] == 0)
{
xpaddr = XPcsr[io->i_ctlr];
xpaddr->hpcs1.w = HP_NOP;
xpaddr->hpcs2.w = io->i_unit;
xpaddr->hpcs1.w = HP_GO;
delay(6000);
dummy = xpaddr->hpds;
if (xpaddr->hpcs2.w & HPCS2_NED)
{
xpaddr->hpcs2.w = HPCS2_CLR;
return(-1);
}
if (devlabel(io, READLABEL) == -1)
return(-1);
xpinit[io->i_ctlr][io->i_unit] = 1;
}
io->i_boff = lp->d_partitions[io->i_part].p_offset;
return(0);
}
xpclose(io)
struct iob *io;
{
xpinit[io->i_ctlr][io->i_unit] = 0;
return(0);
}
xpstrategy(io, func)
register struct iob *io;
{
int i;
daddr_t bn;
int sn, cn, tn, bae, lo16;
register struct hpdevice *xpaddr = XPcsr[io->i_ctlr];
register struct disklabel *lp = &io->i_label;
i = deveovchk(io);
if (i <= 0)
return(i);
bn = io->i_bn;
xpaddr->hpcs2.w = io->i_unit;
if ((xpaddr->hpds & HPDS_VV) == 0) {
xpaddr->hpcs1.c[0] = HP_PRESET|HP_GO;
xpaddr->hpof = HPOF_FMT22;
}
cn = bn / lp->d_secpercyl;
sn = bn % lp->d_secpercyl;
tn = sn / lp->d_nsectors;
sn = sn % lp->d_nsectors;
iomapadr(io->i_ma, &bae, &lo16);
xpaddr->hpdc = cn;
xpaddr->hpda = (tn << 8) + sn;
xpaddr->hpba = (caddr_t)lo16;
xpaddr->hpwc = -(io->i_cc>>1);
i = (bae << 8) | HP_GO;
if (func == READ)
i |= HP_RCOM;
else if (func == WRITE)
i |= HP_WCOM;
xpaddr->hpcs1.w = i;
while ((xpaddr->hpcs1.w & HP_RDY) == 0)
continue;
if (xpaddr->hpcs1.w & HP_TRE) {
printf("%s err cy=%d tr=%d sc=%d cs2=%o er1=%o\n",
devname(io), cn, tn, sn, xpaddr->hpcs2,
xpaddr->hper1);
return(-1);
}
return(io->i_cc);
}
/*
* ALL drive type identification has been removed from the kernel's XP
* driver and placed here.
*
* These tables are used to provide "the best guess" of the geometry
* of the drive. DEC RP0{4,5,6,7} and RM0{3,5} drives will match exactly.
* Non DEC controllers (performing an emulation) often use the DEC drive
* type to mean completely different geometry/capacity drives.
*/
struct xpst
{
int flags; /* flags: XP_CC, XP_NOSEARCH */
int ncyl; /* number of cylinders */
int nspc; /* number of sectors per cylinder */
int ntpc; /* number of tracks per cylinder */
int nspt; /* number of sectors per track */
daddr_t nspd; /* number of sectors per drive */
};
static struct xpst rp04_st = { XP_CC, 411, 22 * 19, 19, 22, 411L * 22 * 19 };
/* rp05 uses same table as rp04 */
static struct xpst rp06_st = { XP_CC, 815, 22 * 19, 19, 22, 815L * 22 * 19 };
static struct xpst rp07_st = { XP_CC, 630, 50 * 32, 32, 50, 630L * 50 * 32 };
static struct xpst rm02_st; /* filled in dynamically */
static struct xpst rm03_st = { 0, 823, 32 * 5, 5, 32, 823L * 32 * 5 };
static struct xpst rm05_st = { 0, 823, 32 * 19, 19, 32, 823L * 32 * 19 };
static struct xpst rm80_st = { 0, 559, 31 * 14, 14, 31, 559L * 31 * 14 };
/*
* SI controller stuff - likely not used any longer and will probably go away
* eventually (when the D space is needed for something more important).
*/
static struct xpst cdc9775_st = { 0, 843, 32 * 40, 40, 32, 843L * 32 * 40 };
static struct xpst cdc9730_st = { 0, 823, 32 * 10, 10, 32, 823L * 32 * 10 };
static struct xpst cdc9766_st = { 0, 823, 32 * 19, 19, 32, 823L * 32 * 19 };
static struct xpst cdc9762_st = { 0, 823, 32 * 5, 5, 32, 823L * 32 * 5 };
static struct xpst capric_st = { 0, 1024, 32 * 16, 16, 32, 1024L * 32 * 16 };
static struct xpst eagle_st = { 0, 842, 48 * 20, 20, 48, 842L * 48 * 20 };
/*
* A "default". If none of the above are useable then a default geometry
* suitable for writing a label (sector 1) is used.
*/
static struct xpst default_st = { 0, 1, 2 * 1, 1, 2, 2 };
/*
* This routine does not return an error (-1). If the drive is totally
* unrecognizeable then the default above is used.
*/
xplabel(io)
struct iob *io;
{
register struct xpst *st = NULL;
int type, xpsn;
register struct hpdevice *xpaddr = XPcsr[io->i_ctlr];
register struct disklabel *lp;
type = xpaddr->hpdt & 077;
switch (type)
{
case HPDT_RP04: /* 020 */
case HPDT_RP05: /* 021 */
st = &rp04_st;
break;
case HPDT_RP06: /* 022 */
st = &rp06_st;
break;
case HPDT_RP07: /* 042 */
st = &rp07_st;
break;
case HPDT_RM80: /* 026 */
st = &rm80_st;
break;
case HPDT_RM05: /* 027 */
st = &rm05_st;
break;
case HPDT_RM03: /* 024 */
st = &rm03_st;
break;
case HPDT_RM02: /* 025 */
/*
* Borrowing a quote from 4BSD:
* "We know this isn't a dec controller, so we can assume sanity."
*/
st = &rm02_st;
xpaddr->hpcs1.w = HP_NOP;
xpaddr->hpcs2.w = io->i_unit;
xpaddr->rmhr = HPHR_MAXTRAK;
st->ntpc = xpaddr->rmhr + 1;
xpaddr->rmhr = HPHR_MAXSECT;
st->nspt = xpaddr->rmhr + 1;
xpaddr->rmhr = HPHR_MAXCYL;
st->ncyl = xpaddr->rmhr + 1;
xpaddr->hpcs1.w = HP_DCLR | HP_GO;
st->nspc = st->nspt * st->ntpc;
st->nspd = (long)st->nspc * st->ncyl;
printf("type: RM02 c=%d t/c=%d s/t=%d\n", st->ncyl,
st->ntpc, st->nspt);
break;
default:
printf("%s unknown drive type: %d -- ",
devname(io), type);
printf("using 1 cyl, 1 trk, 2 sec/trk\n");
st = &default_st;
break;
}
/*
* Handle SI model byte stuff when we think it's an RM05 or RM03. Is any
* one still using one of these? Is it worth all this code?
*/
if (type == HPDT_RM05 || type == HPDT_RM03)
{
xpsn = xpaddr->hpsn;
if ((xpsn & SIMB_LU) != io->i_unit)
goto notsi;
switch ((xpsn & SIMB_MB) &~ (SIMB_S6|SIRM03|SIRM05))
{
case SI9775D:
st = &cdc9775_st;
break;
case SI9730D:
st = &cdc9730_st;
break;
case SI9766:
st = &cdc9766_st;
break;
case SI9762:
st = &cdc9762_st;
break;
case SICAPD:
st = &capric_st;
break;
case SI9751D:
st = &eagle_st;
break;
default:
printf("%s unknown SI drive model %d -- ",
devname(io), xpsn);
printf("using 1 cyl, 1 trk, 2 sec/trk\n");
st = &default_st;
break;
}
}
notsi:
lp = &io->i_label;
lp->d_type = DTYPE_SMD;
lp->d_secsize = 512; /* XXX */
lp->d_secperunit = st->nspd;
lp->d_partitions[0].p_size = st->nspd;
lp->d_nsectors = st->nspt;
lp->d_ntracks = st->ntpc;
lp->d_secpercyl = st->nspc;
lp->d_ncylinders = st->ncyl;
lp->d_drivedata[0] = st->flags;
strcpy(lp->d_typename, "SMD");
return(0);
}