256d5c9f475eb255d90774f6868dab57f08ce13f
* HP disk driver for RP0x+RMxx+ML11
* check RM80 skip sector handling when ECC's occur later
* check offset recovery handling
* see if DCLR and/or RELEASE set attention status
* print bits of mr && mr2 symbolically
#include "../machine/pte.h"
#include "../vaxmba/mbareg.h"
#include "../vaxmba/mbavar.h"
#include "../vaxmba/hpreg.h"
/* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
15884, 0, /* A=cyl 0 thru 37 */
33440, 38, /* B=cyl 38 thru 117 */
340670, 0, /* C=cyl 0 thru 814 */
15884, 118, /* D=cyl 118 thru 155 */
55936, 156, /* E=cyl 156 thru 289 */
219384, 290, /* F=cyl 290 thru 814 */
291280, 118, /* G=cyl 118 thru 814 */
15884, 0, /* A=cyl 0 thru 37 */
33440, 38, /* B=cyl 38 thru 117 */
171798, 0, /* C=cyl 0 thru 410 */
15884, 118, /* D=cyl 118 thru 155 */
55936, 156, /* E=cyl 156 thru 289 */
50512, 290, /* F=cyl 290 thru 410 */
122408, 118, /* G=cyl 118 thru 410 */
15884, 0, /* A=cyl 0 thru 99 */
33440, 100, /* B=cyl 100 thru 308 */
131680, 0, /* C=cyl 0 thru 822 */
15884, 309, /* D=cyl 309 thru 408 */
55936, 409, /* E=cyl 409 thru 758 */
10144, 759, /* F=cyl 759 thru 822 */
82144, 309, /* G=cyl 309 thru 822 */
15884, 0, /* A=cyl 0 thru 26 */
33440, 27, /* B=cyl 27 thru 81 */
500384, 0, /* C=cyl 0 thru 822 */
15884, 562, /* D=cyl 562 thru 588 */
55936, 589, /* E=cyl 589 thru 680 */
86240, 681, /* F=cyl 681 thru 822 */
158592, 562, /* G=cyl 562 thru 822 */
291346, 82, /* H=cyl 82 thru 561 */
15884, 0, /* A=cyl 0 thru 36 */
33440, 37, /* B=cyl 37 thru 114 */
242606, 0, /* C=cyl 0 thru 558 */
15884, 115, /* D=cyl 115 thru 151 */
55936, 152, /* E=cyl 152 thru 280 */
120559, 281, /* F=cyl 281 thru 558 */
192603, 115, /* G=cyl 115 thru 558 */
15884, 0, /* A=cyl 0 thru 9 */
66880, 10, /* B=cyl 10 thru 51 */
1008000, 0, /* C=cyl 0 thru 629 */
15884, 235, /* D=cyl 235 thru 244 */
307200, 245, /* E=cyl 245 thru 436 */
308650, 437, /* F=cyl 437 thru 629 */
631850, 235, /* G=cyl 235 thru 629 */
291346, 52, /* H=cyl 52 thru 234 */
15884, 0, /* A=cyl 0 thru 12 */
66880, 13, /* B=cyl 13 thru 65 */
1079040, 0, /* C=cyl 0 thru 842 */
15884, 294, /* D=cyl 294 thru 306 */
307200, 307, /* E=cyl 307 thru 546 */
378784, 547, /* F=cyl 547 thru 842 */
702624, 294, /* G=cyl 294 thru 842 */
291346, 66, /* H=cyl 66 thru 293 */
15884, 0, /* A=cyl 0 thru 49 */
33440, 50, /* B=cyl 50 thru 154 */
263360, 0, /* C=cyl 0 thru 822 */
15884, 155, /* D=cyl 155 thru 204 */
55936, 205, /* E=cyl 205 thru 379 */
141664, 380, /* F=cyl 380 thru 822 */
213664, 155, /* G=cyl 155 thru 822 */
}, capricorn_sizes
[8] = {
15884, 0, /* A=cyl 0 thru 31 */
33440, 32, /* B=cyl 32 thru 97 */
524288, 0, /* C=cyl 0 thru 1023 */
15884, 668, /* D=cyl 668 thru 699 */
55936, 700, /* E=cyl 700 thru 809 */
109472, 810, /* F=cyl 810 thru 1023 */
182176, 668, /* G=cyl 668 thru 1023 */
291346, 98, /* H=cyl 98 thru 667 */
15884, 0, /* A=cyl 0 thru 16 */
66880, 17, /* B=cyl 17 thru 86 */
808320, 0, /* C=cyl 0 thru 841 */
15884, 391, /* D=cyl 391 thru 407 */
307200, 408, /* E=cyl 408 thru 727 */
109296, 728, /* F=cyl 728 thru 841 */
432816, 391, /* G=cyl 391 thru 841 */
291346, 87, /* H=cyl 87 thru 390 */
15884, 0, /* A=cyl 0 thru 26 */
33440, 27, /* B=cyl 27 thru 81 */
495520, 0, /* C=cyl 0 thru 814 */
15884, 562, /* D=cyl 562 thru 588 */
55936, 589, /* E=cyl 589 thru 680 */
81312, 681, /* F=cyl 681 thru 814 */
153664, 562, /* G=cyl 562 thru 814 */
291346, 82, /* H=cyl 82 thru 561 */
/* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
* Table for converting Massbus drive types into
* indices into the partition tables. Slots are
* left for those drives devined from other means
* (e.g. SI, AMPEX, etc.).
#define HPDT_CAPRICORN 11
MBDT_RM02
, /* beware, actually capricorn or eagle */
struct mba_device
*hpinfo
[NHP
];
int hpattach(),hpustart(),hpstart(),hpdtint();
struct mba_driver hpdriver
=
{ hpattach
, 0, hpustart
, hpstart
, hpdtint
, 0,
hptypes
, "hp", 0, hpinfo
};
* Beware, sdist and rdist are not well tuned
* for many of the drives listed in this table.
* Try patching things with something i/o intensive
* running and watch iostat.
short nsect
; /* # sectors/track */
short ntrak
; /* # tracks/cylinder */
short nspc
; /* # sector/cylinders */
short ncyl
; /* # cylinders */
struct size
*sizes
; /* partition tables */
short sdist
; /* seek distance metric */
short rdist
; /* rotational distance metric */
{ 32, 5, 32*5, 823, rm03_sizes
, 3, 4 }, /* RM03 */
{ 32, 19, 32*19, 823, rm05_sizes
, 3, 4 }, /* RM05 */
{ 22, 19, 22*19, 815, rp06_sizes
, 3, 4 }, /* RP06 */
{ 31, 14, 31*14, 559, rm80_sizes
, 3, 4 }, /* RM80 */
{ 22, 19, 22*19, 411, rp05_sizes
, 3, 4 }, /* RP04 */
{ 22, 19, 22*19, 411, rp05_sizes
, 3, 4 }, /* RP05 */
{ 50, 32, 50*32, 630, rp07_sizes
, 7, 8 }, /* RP07 */
{ 1, 1, 1, 1, 0, 0, 0 }, /* ML11A */
{ 1, 1, 1, 1, 0, 0, 0 }, /* ML11B */
{ 32, 40, 32*40, 843, cdc9775_sizes
, 3, 4 }, /* 9775 */
{ 32, 10, 32*10, 823, cdc9730_sizes
, 3, 4 }, /* 9730 */
{ 32, 16, 32*16, 1024, capricorn_sizes
,7, 8 }, /* Capricorn */
{ 48, 20, 48*20, 842, eagle_sizes
, 7, 8 }, /* EAGLE */
{ 32, 19, 32*19, 815, ampex_sizes
, 3, 4 }, /* 9300 */
HPOF_P400
, HPOF_M400
, HPOF_P400
, HPOF_M400
,
HPOF_P800
, HPOF_M800
, HPOF_P800
, HPOF_M800
,
HPOF_P1200
, HPOF_M1200
, HPOF_P1200
, HPOF_M1200
,
u_char sc_hpinit
; /* drive initialized */
u_char sc_recal
; /* recalibrate state */
u_char sc_hdr
; /* next i/o includes header */
u_char sc_doseeks
; /* perform explicit seeks */
daddr_t sc_mlsize
; /* ML11 size */
/* #define ML11 0 to remove ML11 support */
#define ML11 (hptypes[mi->mi_type] == MBDT_ML11A)
#define RP06 (hptypes[mi->mi_type] <= MBDT_RP06)
#define RM80 (hptypes[mi->mi_type] == MBDT_RM80)
#define MASKREG(reg) ((reg)&0xffff)
register struct mba_device
*mi
;
mi
->mi_type
= hpmaptype(mi
);
if (!ML11
&& mi
->mi_dk
>= 0) {
struct hpst
*st
= &hpst
[mi
->mi_type
];
dk_mspw
[mi
->mi_dk
] = 1.0 / 60 / (st
->nsect
* 256);
* Map apparent MASSBUS drive type into manufacturer
* specific configuration. For SI controllers this is done
* based on codes in the serial number register. For
* EMULEX controllers, the track and sector attributes are
* used when the drive type is an RM02 (not supported by DEC).
register struct mba_device
*mi
;
register struct hpdevice
*hpaddr
= (struct hpdevice
*)mi
->mi_drv
;
register int type
= mi
->mi_type
;
* Model-byte processing for SI controllers.
* NB: Only deals with RM03 and RM05 emulations.
if (type
== HPDT_RM03
|| type
== HPDT_RM05
) {
if ((hpsn
& SIMB_LU
) != mi
->mi_drive
)
switch ((hpsn
& SIMB_MB
) & ~(SIMB_S6
|SIRM03
|SIRM05
)) {
printf("hp%d: 9775 (direct)\n", mi
->mi_unit
);
printf("hp%d: 9730 (direct)\n", mi
->mi_unit
);
* Beware, since the only SI controller we
* have has a 9300 instead of a 9766, we map the
* drive type into the 9300. This means that
* on a 9766 you lose the last 8 cylinders (argh).
printf("hp%d: 9300\n", mi
->mi_unit
);
printf("hp%d: 9762\n", mi
->mi_unit
);
printf("hp%d: capricorn\n", mi
->mi_unit
);
printf("hp%d: eagle\n", mi
->mi_unit
);
* EMULEX SC750 or SC780. Poke the holding register.
hpaddr
->hpof
= HPOF_FMT22
;
hpaddr
->hphr
= HPHR_MAXTRAK
;
ntracks
= MASKREG(hpaddr
->hphr
) + 1;
printf("hp%d: capricorn\n", mi
->mi_unit
);
printf("hp%d: 9300\n", mi
->mi_unit
);
hpaddr
->hphr
= HPHR_MAXSECT
;
nsectors
= MASKREG(hpaddr
->hphr
) + 1;
if (ntracks
== 20 && nsectors
== 48) {
printf("hp%d: eagle\n", mi
->mi_unit
);
printf("hp%d: ntracks %d, nsectors %d: unknown device\n",
mi
->mi_unit
, ntracks
, nsectors
);
hpaddr
->hpcs1
= HP_DCLR
|HP_GO
;
mbclrattn(mi
); /* conservative */
* Map all ML11's to the same type. Also calculate
* transfer rates based on device characteristics.
if (type
== HPDT_ML11A
|| type
== HPDT_ML11B
) {
register struct hpsoftc
*sc
= &hpsoftc
[mi
->mi_unit
];
sc
->sc_mlsize
= hpaddr
->hpmr
& HPMR_SZ
;
if ((hpaddr
->hpmr
& HPMR_ARRTYP
) == 0)
trt
= (hpaddr
->hpmr
& HPMR_TRT
) >> 8;
dk_mspw
[mi
->mi_dk
] = 1.0 / (1<<(20-trt
));
register int unit
= minor(dev
) >> 3;
register struct mba_device
*mi
;
if (unit
>= NHP
|| (mi
= hpinfo
[unit
]) == 0 || mi
->mi_alive
== 0)
register struct mba_device
*mi
;
register struct hpst
*st
;
int xunit
= minor(bp
->b_dev
) & 07;
if (mi
== 0 || mi
->mi_alive
== 0)
struct hpsoftc
*sc
= &hpsoftc
[unit
];
dkblock(bp
)+sz
> sc
->sc_mlsize
)
(bn
= dkblock(bp
))+sz
> st
->sizes
[xunit
].nblocks
)
bp
->b_cylin
= bn
/st
->nspc
+ st
->sizes
[xunit
].cyloff
;
disksort(&mi
->mi_tab
, bp
);
if (mi
->mi_tab
.b_active
== 0)
register struct mba_device
*mi
;
register struct hpdevice
*hpaddr
= (struct hpdevice
*)mi
->mi_drv
;
register struct buf
*bp
= mi
->mi_tab
.b_actf
;
register struct hpst
*st
;
struct hpsoftc
*sc
= &hpsoftc
[mi
->mi_unit
];
if ((hpaddr
->hpcs1
&HP_DVA
) == 0)
if ((hpaddr
->hpds
& HPDS_VV
) == 0 || !sc
->sc_hpinit
) {
struct buf
*bbp
= &bhpbuf
[mi
->mi_unit
];
hpaddr
->hpcs1
= HP_DCLR
|HP_GO
;
if (mi
->mi_mba
->mba_drv
[0].mbd_as
& (1<<mi
->mi_drive
))
hpaddr
->hpcs1
= HP_PRESET
|HP_GO
;
hpaddr
->hpof
= HPOF_FMT22
;
bbp
->b_flags
= B_READ
|B_BUSY
;
bbp
->b_un
.b_addr
= (caddr_t
)&hpbad
[mi
->mi_unit
];
bbp
->b_blkno
= st
->ncyl
*st
->nspc
- st
->nsect
;
bbp
->b_cylin
= st
->ncyl
- 1;
if (mi
->mi_tab
.b_active
|| mi
->mi_hd
->mh_ndrive
== 1)
if ((hpaddr
->hpds
& HPDS_DREADY
) != HPDS_DREADY
)
sn
= (sn
+ st
->nsect
- st
->sdist
) % st
->nsect
;
if (bp
->b_cylin
== MASKREG(hpaddr
->hpdc
)) {
dist
= (MASKREG(hpaddr
->hpla
) >> 6) - st
->nsect
+ 1;
if (dist
> st
->nsect
- st
->rdist
)
hpaddr
->hpdc
= bp
->b_cylin
;
hpaddr
->hpcs1
= HP_SEEK
|HP_GO
;
hpaddr
->hpcs1
= HP_SEARCH
|HP_GO
;
register struct mba_device
*mi
;
register struct hpdevice
*hpaddr
= (struct hpdevice
*)mi
->mi_drv
;
register struct buf
*bp
= mi
->mi_tab
.b_actf
;
register struct hpst
*st
= &hpst
[mi
->mi_type
];
struct hpsoftc
*sc
= &hpsoftc
[mi
->mi_unit
];
hpaddr
->hpdc
= bp
->b_cylin
;
hpaddr
->hpda
= (tn
<< 8) + sn
;
if (bp
->b_flags
& B_READ
)
register struct mba_device
*mi
;
register struct hpdevice
*hpaddr
= (struct hpdevice
*)mi
->mi_drv
;
register struct buf
*bp
= mi
->mi_tab
.b_actf
;
register struct hpst
*st
;
struct hpsoftc
*sc
= &hpsoftc
[mi
->mi_unit
];
if (bp
->b_flags
&B_BAD
&& hpecc(mi
, CONT
))
if (hpaddr
->hpds
&HPDS_ERR
|| mbsr
&MBSR_EBITS
) {
int dc
= hpaddr
->hpdc
, da
= hpaddr
->hpda
;
printf("hperr: bp %x cyl %d blk %d as %o ",
bp
, bp
->b_cylin
, bp
->b_blkno
,
printf("dc %x da %x\n",MASKREG(dc
), MASKREG(da
));
printf("errcnt %d ", mi
->mi_tab
.b_errcnt
);
printf("mbsr=%b ", mbsr
, mbsr_bits
);
printf("er1=%b er2=%b\n", MASKREG(er1
), HPER1_BITS
,
MASKREG(er2
), HPER2_BITS
);
er1
&= ~(HPER1_HCE
|HPER1_FER
);
printf("hp%d: write locked\n", dkunit(bp
));
} else if (MASKREG(er1
) == HPER1_FER
&& RP06
&& !sc
->sc_hdr
) {
} else if (++mi
->mi_tab
.b_errcnt
> 27 ||
(!ML11
&& (er2
& HPER2_HARD
))) {
* HCRC means the header is screwed up and the sector
* might well exist in the bad sector table,
!ML11
&& !sc
->sc_hdr
&& hpecc(mi
, BSE
))
bp
->b_blkno
= MASKREG(hpaddr
->hpda
);
bp
->b_blkno
= MASKREG(hpaddr
->hpdc
) * st
->nspc
+
(MASKREG(hpaddr
->hpda
) >> 8) * st
->nsect
+
* If we have a data check error or a hard
* ecc error the bad sector has been read/written,
* and the controller registers are pointing to
if (er1
&(HPER1_DCK
|HPER1_ECH
) || sc
->sc_hdr
)
if (mbsr
& (MBSR_EBITS
&~ (MBSR_DTABT
|MBSR_MBEXC
)))
printf("mbsr=%b ", mbsr
, mbsr_bits
);
MASKREG(hpaddr
->hper1
), HPER1_BITS
,
MASKREG(hpaddr
->hper2
), HPER2_BITS
);
printf(" mr=%o", MASKREG(hpaddr
->hpmr
));
printf(" mr2=%o", MASKREG(hpaddr
->hpmr2
));
} else if ((er2
& HPER2_BSE
) && !ML11
) {
} else if (RM80
&& er2
&HPER2_SSE
) {
} else if ((er1
&(HPER1_DCK
|HPER1_ECH
))==HPER1_DCK
) {
hpaddr
->hpcs1
= HP_DCLR
|HP_GO
;
if (mi
->mi_tab
.b_errcnt
>= 16)
} else if ((mi
->mi_tab
.b_errcnt
&07) == 4) {
hpaddr
->hpcs1
= HP_RECAL
|HP_GO
;
if (hpdebug
&& sc
->sc_recal
) {
printf("recal %d ", sc
->sc_recal
);
printf("errcnt %d\n", mi
->mi_tab
.b_errcnt
);
printf("mbsr=%b ", mbsr
, mbsr_bits
);
printf("er1=%b er2=%b\n",
hpaddr
->hper1
, HPER1_BITS
,
hpaddr
->hper2
, HPER2_BITS
);
hpaddr
->hpdc
= bp
->b_cylin
;
hpaddr
->hpcs1
= HP_SEEK
|HP_GO
;
if (mi
->mi_tab
.b_errcnt
< 16 ||
(bp
->b_flags
& B_READ
) == 0)
hpaddr
->hpof
= hp_offset
[mi
->mi_tab
.b_errcnt
& 017]|HPOF_FMT22
;
hpaddr
->hpcs1
= HP_OFFSET
|HP_GO
;
bp
->b_resid
= MASKREG(-mi
->mi_mba
->mba_bcr
);
if (mi
->mi_tab
.b_errcnt
>= 16) {
* This is fast and occurs rarely; we don't
* bother with interrupts.
hpaddr
->hpcs1
= HP_RTC
|HP_GO
;
while (hpaddr
->hpds
& HPDS_PIP
)
hpaddr
->hpof
= HPOF_FMT22
;
hpaddr
->hpcs1
= HP_RELEASE
|HP_GO
;
register int unit
= minor(dev
) >> 3;
return (physio(hpstrategy
, &rhpbuf
[unit
], dev
, B_READ
, minphys
, uio
));
register int unit
= minor(dev
) >> 3;
return (physio(hpstrategy
, &rhpbuf
[unit
], dev
, B_WRITE
, minphys
, uio
));
hpioctl(dev
, cmd
, data
, flag
)
case DKIOCHDR
: /* do header read/write */
hpsoftc
[minor(dev
) >> 3].sc_hdr
= 1;
register struct mba_device
*mi
;
register struct mba_regs
*mbp
= mi
->mi_mba
;
register struct hpdevice
*rp
= (struct hpdevice
*)mi
->mi_drv
;
register struct buf
*bp
= mi
->mi_tab
.b_actf
;
register struct hpst
*st
= &hpst
[mi
->mi_type
];
bcr
= MASKREG(mbp
->mba_bcr
);
bcr
|= 0xffff0000; /* sxt */
npf
= btop(bcr
+ bp
->b_bcount
);
o
= (int)bp
->b_un
.b_addr
& PGOFSET
;
sn
= bn
%(st
->nspc
) + npf
;
npf
--; /* because block in error is previous block */
printf("hp%d%c: soft ecc sn%d\n", dkunit(bp
),
'a'+(minor(bp
->b_dev
)&07), bp
->b_blkno
+ npf
);
mask
= MASKREG(rp
->hpec2
);
i
= MASKREG(rp
->hpec1
) - 1; /* -1 makes 0 origin */
while (i
< 512 && (int)ptob(npf
)+i
< bp
->b_bcount
&& bit
> -11) {
mpte
= mbp
->mba_map
[npf
+btop(byte
)];
addr
= ptob(mpte
.pg_pfnum
) + (byte
& PGOFSET
);
putmemc(addr
, getmemc(addr
)^(mask
<<bit
));
mbp
->mba_bcr
= -(bp
->b_bcount
- (int)ptob(npf
));
printf("hpecc, BSE: bn %d cn %d tn %d sn %d\n", bn
, cn
, tn
, sn
);
if ((bn
= isbad(&hpbad
[mi
->mi_unit
], cn
, tn
, sn
)) < 0)
bn
= st
->ncyl
*st
->nspc
- st
->nsect
- 1 - bn
;
printf("revector to cn %d tn %d sn %d\n", cn
, tn
, sn
);
printf("hpecc, CONT: bn %d cn %d tn %d sn %d\n", bn
,cn
,tn
,sn
);
mbp
->mba_bcr
= -(bp
->b_bcount
- (int)ptob(npf
));
if (MASKREG(mbp
->mba_bcr
) == 0)
rp
->hpcs1
= HP_DCLR
|HP_GO
;
mbp
->mba_var
= (int)ptob(npf
) + o
;
rp
->hpcs1
= bp
->b_flags
&B_READ
? HP_RCOM
|HP_GO
: HP_WCOM
|HP_GO
;
mi
->mi_tab
.b_errcnt
= 0; /* error has been corrected */
register struct mba_device
*mi
;
register struct mba_regs
*mba
;
register struct hpst
*st
;
#define phys(a,b) ((b)((int)(a)&0x7fffffff))
mi
= phys(hpinfo
[unit
],struct mba_device
*);
if (mi
== 0 || mi
->mi_alive
== 0)
mba
= phys(mi
->mi_hd
, struct mba_hd
*)->mh_physmba
;
hpaddr
= (struct hpdevice
*)&mba
->mba_drv
[mi
->mi_drive
];
if ((hpaddr
->hpds
& HPDS_VV
) == 0) {
hpaddr
->hpcs1
= HP_DCLR
|HP_GO
;
hpaddr
->hpcs1
= HP_PRESET
|HP_GO
;
hpaddr
->hpof
= HPOF_FMT22
;
if (dumplo
< 0 || dumplo
+ num
>= st
->sizes
[minor(dev
)&07].nblocks
)
register struct pte
*hpte
= mba
->mba_map
;
blk
= num
> DBSIZE
? DBSIZE
: num
;
bn
= dumplo
+ btop(start
);
cn
= bn
/st
->nspc
+ st
->sizes
[minor(dev
)&07].cyloff
;
hpaddr
->hpda
= (tn
<< 8) + sn
;
for (i
= 0; i
< blk
; i
++)
*(int *)hpte
++ = (btop(start
)+i
) | PG_V
;
mba
->mba_bcr
= -(blk
*NBPG
);
hpaddr
->hpcs1
= HP_WCOM
| HP_GO
;
while ((hpaddr
->hpds
& HPDS_DRY
) == 0)
if (hpaddr
->hpds
&HPDS_ERR
)
int unit
= minor(dev
) >> 3;
if (unit
>= NHP
|| (mi
= hpinfo
[unit
]) == 0 || mi
->mi_alive
== 0)
return ((int)st
->sizes
[minor(dev
) & 07].nblocks
);