* Copyright (c) 1987 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
* @(#)uda.c 7.10 (Berkeley) %G%
* UDA50/MSCP device driver
* write bad block forwarding code
* CONFIGURATION OPTIONS. The next three defines are tunable -- tune away!
* COMPAT_42 enables 4.2/4.3 compatibility (label mapping)
* NRSPL2 and NCMDL2 control the number of response and command
* packets respectively. They may be any value from 0 to 7, though
* setting them higher than 5 is unlikely to be of any value.
* If you get warnings about your command ring being too small,
* try increasing the values by one.
* MAXUNIT controls the maximum unit number (number of drives per
* controller) we are prepared to handle.
* DEFAULT_BURST must be at least 1.
#define NRSPL2 5 /* log2 number of response packets */
#define NCMDL2 5 /* log2 number of command packets */
#define MAXUNIT 8 /* maximum allowed unit number */
#define DEFAULT_BURST 4 /* default DMA burst size */
#include "../machine/pte.h"
#define NRSP (1 << NRSPL2)
#define NCMD (1 << NCMDL2)
#include "../vax/mscpvar.h"
* Backwards compatibility: Reuse the old names. Should fix someday.
#define udaattach udattach
#define udastrategy udstrategy
* UDA communications area and MSCP packet pools, per controller.
struct udaca uda_ca
; /* communications area */
struct mscp uda_rsp
[NRSP
]; /* response packets */
struct mscp uda_cmd
[NCMD
]; /* command packets */
* Software status, per controller.
struct uda
*sc_uda
; /* Unibus address of uda struct */
short sc_state
; /* UDA50 state; see below */
short sc_flags
; /* flags; see below */
int sc_micro
; /* microcode revision */
int sc_ivec
; /* interrupt vector address */
struct mscp_info sc_mi
;/* MSCP info (per mscpvar.h) */
int sc_wticks
; /* watchdog timer ticks */
} udastats
= { NCMD
+ 1 };
#define ST_IDLE 0 /* uninitialised */
#define ST_STEP1 1 /* in `STEP 1' */
#define ST_STEP2 2 /* in `STEP 2' */
#define ST_STEP3 3 /* in `STEP 3' */
#define ST_SETCHAR 4 /* in `Set Controller Characteristics' */
#define ST_RUN 5 /* up and running */
#define SC_MAPPED 0x01 /* mapped in Unibus I/O space */
#define SC_INSTART 0x02 /* inside udastart() */
#define SC_GRIPED 0x04 /* griped about cmd ring too small */
#define SC_INSLAVE 0x08 /* inside udaslave() */
#define SC_DOWAKE 0x10 /* wakeup when ctlr init done */
#define SC_STARTPOLL 0x20 /* need to initiate polling */
* Device to unit number and partition and back
#define udaunit(dev) (minor(dev) >> UNITSHIFT)
#define udapart(dev) (minor(dev) & UNITMASK)
#define udaminor(u, p) (((u) << UNITSHIFT) | (p))
* Drive status, per drive
daddr_t ra_dsize
; /* size in sectors */
u_long ra_type
; /* drive type */
u_long ra_mediaid
; /* media id */
int ra_state
; /* open/closed state */
struct ra_geom
{ /* geometry information */
u_short rg_nsectors
; /* sectors/track */
u_short rg_ngroups
; /* track groups */
u_short rg_ngpc
; /* groups/cylinder */
u_short rg_ntracks
; /* ngroups*ngpc */
u_short rg_ncyl
; /* ra_dsize/ntracks/nsectors */
u_short rg_rctsize
; /* size of rct */
u_short rg_rbns
; /* replacement blocks per track */
u_short rg_nrct
; /* number of rct copies */
u_long ra_openpart
; /* partitions open */
u_long ra_bopenpart
; /* block partitions open */
u_long ra_copenpart
; /* character partitions open */
* Software state, per drive
* Definition of the driver for autoconf.
int udaprobe(), udaslave(), udaattach(), udadgo(), udaintr();
struct uba_ctlr
*udaminfo
[NUDA
];
struct uba_device
*udadinfo
[NRA
];
struct disklabel udalabel
[NRA
];
u_short udastd
[] = { 0772150, 0772550, 0777550, 0 };
struct uba_driver udadriver
=
{ udaprobe
, udaslave
, udaattach
, udadgo
, udastd
, "ra", udadinfo
, "uda",
* More driver definitions, for generic MSCP code.
int udadgram(), udactlrdone(), udaunconf(), udaiodone();
int udaonline(), udagotstatus(), udaioerror(), udareplace(), udabb();
struct buf udautab
[NRA
]; /* per drive transfer queue */
struct mscp_driver udamscpdriver
=
{ MAXUNIT
, NRA
, UNITSHIFT
, udautab
, udadinfo
,
udadgram
, udactlrdone
, udaunconf
, udaiodone
,
udaonline
, udagotstatus
, udareplace
, udaioerror
, udabb
,
* Miscellaneous private variables.
char udasr_bits
[] = UDASR_BITS
;
struct uba_device
*udaip
[NUDA
][MAXUNIT
];
/* inverting pointers: ctlr & unit => Unibus
int udaburst
[NUDA
] = { 0 }; /* burst size, per UDA50, zero => default;
in data space so patchable via adb */
struct mscp udaslavereply
; /* get unit status response packet, set
for udaslave by udaunconf, via udaintr */
static struct uba_ctlr
*probeum
;/* this is a hack---autoconf should pass ctlr
info to slave routine; instead, we remember
the last ctlr argument to probe */
int udawstart
, udawatch(); /* watchdog timer */
* Poke at a supposed UDA50 to see if it is there.
* This routine duplicates some of the code in udainit() only
* because autoconf has not set up the right information yet.
* We have to do everything `by hand'.
register struct uda_softc
*sc
;
register struct udadevice
*udaddr
;
register struct mscp_info
*mi
;
* The UDA50 wants to share BDPs on 750s, but not on 780s or
* 8600s. (730s have no BDPs anyway.) Toward this end, we
* here set the `keep bdp' flag in the per-driver information
* if this is a 750. (We just need to do it once, but it is
* easiest to do it now, for each UDA50.)
udadriver
.ud_keepbdp
= 1;
probeum
= um
; /* remember for udaslave() */
br
= 0; cvec
= br
; br
= cvec
; udaintr(0);
* Set up the controller-specific generic MSCP driver info.
* Note that this should really be done in the (nonexistent)
* controller attach routine.
mi
->mi_md
= &udamscpdriver
;
mi
->mi_ctlr
= um
->um_ctlr
;
mi
->mi_tab
= &um
->um_tab
;
mi
->mi_cmd
.mri_size
= NCMD
;
mi
->mi_cmd
.mri_desc
= uda
[ctlr
].uda_ca
.ca_cmddsc
;
mi
->mi_cmd
.mri_ring
= uda
[ctlr
].uda_cmd
;
mi
->mi_rsp
.mri_size
= NRSP
;
mi
->mi_rsp
.mri_desc
= uda
[ctlr
].uda_ca
.ca_rspdsc
;
mi
->mi_rsp
.mri_ring
= uda
[ctlr
].uda_rsp
;
mi
->mi_wtab
.av_forw
= mi
->mi_wtab
.av_back
= &mi
->mi_wtab
;
* More controller specific variables. Again, this should
* be in the controller attach routine.
udaburst
[ctlr
] = DEFAULT_BURST
;
* Get an interrupt vector. Note that even if the controller
* does not respond, we keep the vector. This is not a serious
* problem; but it would be easily fixed if we had a controller
sc
->sc_ivec
= (uba_hd
[numuba
].uh_lastiv
-= 4);
udaddr
= (struct udadevice
*) reg
;
* Initialise the controller (partially). The UDA50 programmer's
* manual states that if initialisation fails, it should be retried
* at least once, but after a second failure the port should be
* considered `down'; it also mentions that the controller should
* initialise within ten seconds. Or so I hear; I have not seen
udaddr
->udaip
= 0; /* start initialisation */
timeout
= todr() + 1000; /* timeout in 10 seconds */
while ((udaddr
->udasa
& UDA_STEP1
) == 0)
udaddr
->udasa
= UDA_ERR
| (NCMDL2
<< 11) | (NRSPL2
<< 8) | UDA_IE
|
while ((udaddr
->udasa
& UDA_STEP2
) == 0)
/* should have interrupted by now */
br
= 0x15; /* screwy interrupt structure */
return (sizeof (struct udadevice
));
* Find a slave. We allow wildcard slave numbers (something autoconf
* is not really prepared to deal with); and we need to know the
* controller number to talk to the UDA. For the latter, we keep
* track of the last controller probed, since a controller probe
* immediately precedes all slave probes for that controller. For the
* former, we simply put the unit number into ui->ui_slave after we
* Note that by the time udaslave is called, the interrupt vector
* for the UDA50 has been set up (so that udaunconf() will be called).
register struct uba_device
*ui
;
register struct uba_ctlr
*um
= probeum
;
register struct mscp
*mp
;
register struct uda_softc
*sc
;
register struct ra_info
*ra
;
int next
= 0, type
, timeout
, tries
, i
;
* Make sure the controller is fully initialised, by waiting
sc
= &uda_softc
[um
->um_ctlr
];
if (sc
->sc_state
== ST_RUN
)
if (udainit(ui
->ui_ctlr
))
timeout
= todr() + 1000; /* 10 seconds */
if (sc
->sc_state
== ST_RUN
) /* made it */
printf("uda%d: controller hung\n", um
->um_ctlr
);
* The controller is all set; go find the unit. Grab an
* MSCP packet and send out a Get Unit Status command, with
* the `next unit' modifier if we are looking for a generic
* unit. We set the `in slave' flag so that udaunconf()
* knows to copy the response to `udaslavereply'.
udaslavereply
.mscp_opcode
= 0;
sc
->sc_flags
|= SC_INSLAVE
;
if ((mp
= mscp_getcp(&sc
->sc_mi
, MSCP_DONTWAIT
)) == NULL
)
panic("udaslave"); /* `cannot happen' */
mp
->mscp_opcode
= M_OP_GETUNITST
;
if (ui
->ui_slave
== '?') {
mp
->mscp_modifier
= M_GUM_NEXTUNIT
;
mp
->mscp_unit
= ui
->ui_slave
;
*mp
->mscp_addr
|= MSCP_OWN
| MSCP_INT
;
i
= ((struct udadevice
*) reg
)->udaip
; /* initiate polling */
printf("uda%d: no response to Get Unit Status request\n",
sc
->sc_flags
&= ~SC_INSLAVE
;
sc
->sc_flags
&= ~SC_INSLAVE
;
* Got a slave response. If the unit is there, use it.
switch (mp
->mscp_status
& M_ST_MASK
) {
case M_ST_SUCCESS
: /* worked */
case M_ST_AVAILABLE
: /* found another drive */
* Figure out why it is off line. It may be because
* it is nonexistent, or because it is spun down, or
switch (mp
->mscp_status
& ~M_ST_MASK
) {
* No such drive, and there are none with
* higher unit numbers either, if we are
case M_OFFLINE_UNMOUNTED
:
* The drive is not spun up. Use it anyway.
* N.B.: this seems to be a common occurrance
* after a power failure. The first attempt
* to bring it on line seems to spin it up
* (and thus takes several minutes). Perhaps
* we should note here that the on-line may
* take longer than usual.
* In service, or something else equally unusable.
printf("uda%d: unit %d off line: ", um
->um_ctlr
,
printf("uda%d: unable to get unit status: ", um
->um_ctlr
);
* Does this ever happen? What (if anything) does it mean?
if (mp
->mscp_unit
< next
) {
printf("uda%d: unit %d, next %d\n",
um
->um_ctlr
, mp
->mscp_unit
, next
);
if (mp
->mscp_unit
>= MAXUNIT
) {
printf("uda%d: cannot handle unit number %d (max is %d)\n",
um
->um_ctlr
, mp
->mscp_unit
, MAXUNIT
- 1);
* See if we already handle this drive.
* (Only likely if ui->ui_slave=='?'.)
if (udaip
[um
->um_ctlr
][mp
->mscp_unit
] != NULL
) {
next
= mp
->mscp_unit
+ 1;
uda_rasave(ui
->ui_unit
, mp
, 0);
ui
->ui_flags
= 0; /* not on line, nor anything else */
ui
->ui_slave
= mp
->mscp_unit
;
* Attach a found slave. Make sure the watchdog timer is running.
* If this disk is being profiled, fill in the `mspw' value (used by
* what?). Set up the inverting pointer, and attempt to bring the
* drive on line and read its label.
register struct uba_device
*ui
;
register int unit
= ui
->ui_unit
;
timeout(udawatch
, (caddr_t
) 0, hz
);
dk_mspw
[ui
->ui_dk
] = 1.0 / (60 * 31 * 256); /* approx */
udaip
[ui
->ui_ctlr
][ui
->ui_slave
] = ui
;
printf("ra%d: offline\n", unit
);
printf("ra%d: %s\n", unit
, udalabel
[unit
].d_typename
);
addswap(makedev(UDADEVNUM
, udaminor(unit
, 0)), &udalabel
[unit
]);
* Initialise a UDA50. Return true iff something goes wrong.
register struct uda_softc
*sc
;
register struct udadevice
*udaddr
;
if ((sc
->sc_flags
& SC_MAPPED
) == 0) {
* Map the communication area and command and
* response packets into Unibus space.
ubinfo
= uballoc(um
->um_ubanum
, (caddr_t
) &uda
[ctlr
],
sizeof (struct uda
), UBA_CANTWAIT
);
printf("uda%d: uballoc map failed\n", ctlr
);
sc
->sc_uda
= (struct uda
*) (ubinfo
& 0x3ffff);
sc
->sc_flags
|= SC_MAPPED
;
* While we are thinking about it, reset the next command
sc
->sc_mi
.mi_cmd
.mri_next
= 0;
sc
->sc_mi
.mi_rsp
.mri_next
= 0;
* Start up the hardware initialisation sequence.
#define STEP0MASK (UDA_ERR | UDA_STEP4 | UDA_STEP3 | UDA_STEP2 | \
sc
->sc_state
= ST_IDLE
; /* in case init fails */
udaddr
= (struct udadevice
*) um
->um_addr
;
while ((udaddr
->udasa
& STEP0MASK
) == 0) {
printf("uda%d: timeout during init\n", ctlr
);
if ((udaddr
->udasa
& STEP0MASK
) != UDA_STEP1
) {
printf("uda%d: init failed, sa=%b\n", ctlr
,
udaddr
->udasa
, udasr_bits
);
* Success! Record new state, and start step 1 initialisation.
* The rest is done in the interrupt handler.
udaddr
->udasa
= UDA_ERR
| (NCMDL2
<< 11) | (NRSPL2
<< 8) | UDA_IE
|
register struct uba_device
*ui
;
register struct uda_softc
*sc
;
register struct disklabel
*lp
;
register struct partition
*pp
;
register struct ra_info
*ra
;
int s
, i
, part
, mask
, error
= 0;
* Make sure this is a reasonable open request.
if (unit
>= NRA
|| (ui
= udadinfo
[unit
]) == 0 || ui
->ui_alive
== 0)
* Make sure the controller is running, by (re)initialising it if
sc
= &uda_softc
[ui
->ui_ctlr
];
if (sc
->sc_state
!= ST_RUN
) {
if (sc
->sc_state
== ST_IDLE
&& udainit(ui
->ui_ctlr
)) {
* In case it does not come up, make sure we will be
* restarted in 10 seconds. This corresponds to the
* 10 second timeouts in udaprobe() and udaslave().
sc
->sc_flags
|= SC_DOWAKE
;
timeout(wakeup
, (caddr_t
) sc
, 10 * hz
);
sleep((caddr_t
) sc
, PRIBIO
);
if (sc
->sc_state
!= ST_RUN
) {
printf("uda%d: controller hung\n", ui
->ui_ctlr
);
untimeout(wakeup
, (caddr_t
) sc
);
* Wait for the state to settle
while (ra
->ra_state
!= OPEN
&& ra
->ra_state
!= OPENRAW
&&
sleep((caddr_t
)ra
, PZERO
+ 1);
* If not on line, or we are not sure of the label, reinitialise
if ((ui
->ui_flags
& UNIT_ONLINE
) == 0 ||
(ra
->ra_state
!= OPEN
&& ra
->ra_state
!= OPENRAW
))
error
= uda_rainit(ui
, flag
);
if (part
>= lp
->d_npartitions
)
* Warn if a partition is opened that overlaps another
* already open, unless either is the `raw' partition
#define RAWPART 2 /* 'c' partition */ /* XXX */
if ((ra
->ra_openpart
& mask
) == 0 && part
!= RAWPART
) {
pp
= &lp
->d_partitions
[part
];
end
= pp
->p_offset
+ pp
->p_size
;
for (pp
= lp
->d_partitions
, i
= 0;
i
< lp
->d_npartitions
; pp
++, i
++) {
if (pp
->p_offset
+ pp
->p_size
<= start
||
pp
->p_offset
>= end
|| i
== RAWPART
)
if (ra
->ra_openpart
& (1 << i
))
"ra%d%c: overlaps open partition (%c)\n",
unit
, part
+ 'a', i
+ 'a');
ra
->ra_copenpart
|= mask
;
ra
->ra_bopenpart
|= mask
;
udaclose(dev
, flags
, fmt
)
register int unit
= udaunit(dev
);
register struct ra_info
*ra
= &ra_info
[unit
];
int s
, mask
= (1 << udapart(dev
));
ra
->ra_copenpart
&= ~mask
;
ra
->ra_bopenpart
&= ~mask
;
ra
->ra_openpart
= ra
->ra_copenpart
| ra
->ra_bopenpart
;
* Should wait for I/O to complete on this partition even if
* others are open, but wait for work on blkflush().
if (ra
->ra_openpart
== 0) {
while (udautab
[unit
].b_actf
)
sleep((caddr_t
)&udautab
[unit
], PZERO
- 1);
* Initialise a drive. If it is not already, bring it on line,
* and set a timeout on it in case it fails to respond.
* When on line, read in the pack label.
register struct uba_device
*ui
;
register struct uda_softc
*sc
= &uda_softc
[ui
->ui_ctlr
];
register struct disklabel
*lp
;
register struct mscp
*mp
;
register int unit
= ui
->ui_unit
;
register struct ra_info
*ra
;
char *msg
, *readdisklabel();
if ((ui
->ui_flags
& UNIT_ONLINE
) == 0) {
mp
= mscp_getcp(&sc
->sc_mi
, MSCP_WAIT
);
mp
->mscp_opcode
= M_OP_ONLINE
;
mp
->mscp_unit
= ui
->ui_slave
;
mp
->mscp_cmdref
= (long)&ui
->ui_flags
;
*mp
->mscp_addr
|= MSCP_OWN
| MSCP_INT
;
i
= ((struct udadevice
*)ui
->ui_addr
)->udaip
;
while ((ui
->ui_flags
& UNIT_ONLINE
) == 0)
timeout(wakeup
, (caddr_t
)&ui
->ui_flags
, 10 * hz
);
sleep((caddr_t
)&ui
->ui_flags
, PSWP
+ 1);
untimeout(wakeup
, (caddr_t
)&ui
->ui_flags
);
if (ra
->ra_state
!= OPENRAW
) {
lp
->d_secsize
= DEV_BSIZE
;
lp
->d_secperunit
= ra
->ra_dsize
;
* Set up default sizes until we have the label, or longer
* if there is none. Set secpercyl, as readdisklabel wants
* to compute b_cylin (although we do not need it).
lp
->d_partitions
[0].p_size
= lp
->d_secperunit
;
lp
->d_partitions
[0].p_offset
= 0;
if ((msg
= readdisklabel(udaminor(unit
, 0), udastrategy
, lp
)) != NULL
) {
log(LOG_ERR
, "ra%d: %s\n", unit
, msg
);
if (udamaptype(unit
, lp
))
/* uda_makefakelabel(ra, lp); */
* Copy the geometry information for the given ra from a
* GET UNIT STATUS response. If check, see if it changed.
uda_rasave(unit
, mp
, check
)
register struct mscp
*mp
;
register struct ra_info
*ra
= &ra_info
[unit
];
if (check
&& ra
->ra_type
!= mp
->mscp_guse
.guse_drivetype
) {
printf("ra%d: changed types! was %d now %d\n",
ra
->ra_type
, mp
->mscp_guse
.guse_drivetype
);
ra
->ra_state
= CLOSED
; /* ??? */
ra
->ra_type
= mp
->mscp_guse
.guse_drivetype
;
ra
->ra_mediaid
= mp
->mscp_guse
.guse_mediaid
;
ra
->ra_geom
.rg_nsectors
= mp
->mscp_guse
.guse_nspt
;
ra
->ra_geom
.rg_ngroups
= mp
->mscp_guse
.guse_group
;
ra
->ra_geom
.rg_ngpc
= mp
->mscp_guse
.guse_ngpc
;
ra
->ra_geom
.rg_ntracks
= ra
->ra_geom
.rg_ngroups
* ra
->ra_geom
.rg_ngpc
;
/* ra_geom.rg_ncyl cannot be computed until we have ra_dsize */
ra
->ra_geom
.rg_rctsize
= mp
->mscp_guse
.guse_rctsize
;
ra
->ra_geom
.rg_rbns
= mp
->mscp_guse
.guse_nrpt
;
ra
->ra_geom
.rg_nrct
= mp
->mscp_guse
.guse_nrct
;
* Queue a transfer request, and if possible, hand it to the controller.
* This routine is broken into two so that the internal version
* udastrat1() can be called by the (nonexistent, as yet) bad block
register struct uba_device
*ui
;
register struct disklabel
*lp
;
register struct ra_info
*ra
;
* Make sure this is a reasonable drive to use.
if ((unit
= udaunit(bp
->b_dev
)) >= NRA
||
(ui
= udadinfo
[unit
]) == NULL
|| ui
->ui_alive
== 0 ||
(ra
= &ra_info
[unit
])->ra_state
== CLOSED
) {
* If drive is open `raw' or reading label, let it at it.
if (ra
->ra_state
< OPEN
) {
if ((ra
->ra_openpart
& (1 << p
)) == 0) /* can't happen? */
/* alternatively, ENODEV */
* Determine the size of the transfer, and make sure it is
* within the boundaries of the partition.
pp
= &udalabel
[unit
].d_partitions
[p
];
if (pp
->p_offset
+ pp
->p_size
> ra
->ra_dsize
)
maxsz
= ra
->ra_dsize
- pp
->p_offset
;
sz
= (bp
->b_bcount
+ DEV_BSIZE
- 1) >> DEV_BSHIFT
;
if (bp
->b_blkno
< 0 || bp
->b_blkno
+ sz
> maxsz
) {
/* if exactly at end of disk, return an EOF */
if (bp
->b_blkno
== maxsz
) {
bp
->b_resid
= bp
->b_bcount
;
/* or truncate if part of it fits */
sz
= maxsz
- bp
->b_blkno
;
bp
->b_error
= EINVAL
; /* or hang it up */
bp
->b_bcount
= sz
<< DEV_BSHIFT
;
* Work routine for udastrategy.
register int unit
= udaunit(bp
->b_dev
);
register struct uba_ctlr
*um
;
* Append the buffer to the drive queue, and if it is not
* already there, the drive to the controller queue. (However,
* if the drive queue is marked to be requeued, we must be
* awaiting an on line or get unit status command; in this
* case, leave it off the controller queue.)
um
= (ui
= udadinfo
[unit
])->ui_mi
;
if (dp
->b_active
== 0 && (ui
->ui_flags
& UNIT_REQUEUE
) == 0) {
APPEND(dp
, &um
->um_tab
, b_forw
);
* Start activity on the controller. Note that unlike other
* Unibus drivers, we must always do this, not just when the
* controller is not active.
* Start up whatever transfers we can find.
* Note that udastart() must be called at spl5().
register struct uba_ctlr
*um
;
register struct uda_softc
*sc
= &uda_softc
[um
->um_ctlr
];
register struct buf
*bp
, *dp
;
register struct mscp
*mp
;
struct udadevice
*udaddr
;
* If it is not running, try (again and again...) to initialise
* it. If it is currently initialising just ignore it for now.
if (sc
->sc_state
!= ST_RUN
) {
if (sc
->sc_state
== ST_IDLE
&& udainit(um
->um_ctlr
))
printf("uda%d: still hung\n", um
->um_ctlr
);
* If um_cmd is nonzero, this controller is on the Unibus
* resource wait queue. It will not help to try more requests;
* instead, when the Unibus unblocks and calls udadgo(), we
* will call udastart() again.
sc
->sc_flags
|= SC_INSTART
;
udaddr
= (struct udadevice
*) um
->um_addr
;
* Service the drive at the head of the queue. It may not
* need anything, in which case it might be shutting down
if ((dp
= um
->um_tab
.b_actf
) == NULL
)
if ((bp
= dp
->b_actf
) == NULL
) {
um
->um_tab
.b_actf
= dp
->b_forw
;
if (ra_info
[dp
- udautab
].ra_openpart
== 0)
wakeup((caddr_t
)dp
); /* finish close protocol */
if (udaddr
->udasa
& UDA_ERR
) { /* ctlr fatal error */
* Get an MSCP packet, then figure out what to do. If
* we cannot get a command packet, the command ring may
* be too small: We should have at least as many command
* packets as credits, for best performance.
if ((mp
= mscp_getcp(&sc
->sc_mi
, MSCP_DONTWAIT
)) == NULL
) {
if (sc
->sc_mi
.mi_credits
> MSCP_MINCREDITS
&&
(sc
->sc_flags
& SC_GRIPED
) == 0) {
log(LOG_NOTICE
, "uda%d: command ring too small\n",
sc
->sc_flags
|= SC_GRIPED
;/* complain only once */
* Bring the drive on line if it is not already. Get its status
* if we do not already have it. Otherwise just start the transfer.
ui
= udadinfo
[udaunit(bp
->b_dev
)];
if ((ui
->ui_flags
& UNIT_ONLINE
) == 0) {
mp
->mscp_opcode
= M_OP_ONLINE
;
if ((ui
->ui_flags
& UNIT_HAVESTATUS
) == 0) {
mp
->mscp_opcode
= M_OP_GETUNITST
;
if (ui
->ui_flags
& UNIT_REQUEUE
) panic("udastart");
* Take the drive off the controller queue. When the
* command finishes, make sure the drive is requeued.
um
->um_tab
.b_actf
= dp
->b_forw
;
ui
->ui_flags
|= UNIT_REQUEUE
;
mp
->mscp_unit
= ui
->ui_slave
;
*mp
->mscp_addr
|= MSCP_OWN
| MSCP_INT
;
sc
->sc_flags
|= SC_STARTPOLL
;
pp
= &udalabel
[ui
->ui_unit
].d_partitions
[udapart(bp
->b_dev
)];
mp
->mscp_opcode
= (bp
->b_flags
& B_READ
) ? M_OP_READ
: M_OP_WRITE
;
mp
->mscp_unit
= ui
->ui_slave
;
mp
->mscp_seq
.seq_lbn
= bp
->b_blkno
+ pp
->p_offset
;
sz
= (bp
->b_bcount
+ DEV_BSIZE
- 1) >> DEV_BSHIFT
;
mp
->mscp_seq
.seq_bytecount
= bp
->b_blkno
+ sz
> pp
->p_size
?
(pp
->p_size
- bp
->b_blkno
) >> DEV_BSHIFT
: bp
->b_bcount
;
/* mscp_cmdref is filled in by mscp_go() */
* Drop the packet pointer into the `command' field so udadgo()
* can tell what to start. If ubago returns 1, we can do another
* transfer. If not, um_cmd will still point at mp, so we will
* know that we are waiting for resources.
* All done, or blocked in ubago(). If we managed to
* issue some commands, start up the beast.
if (sc
->sc_flags
& SC_STARTPOLL
) {
udastats
.cmd
[sc
->sc_ncmd
]++;
i
= ((struct udadevice
*) um
->um_addr
)->udaip
;
sc
->sc_flags
&= ~(SC_INSTART
| SC_STARTPOLL
);
* If we are not called from within udastart(), we must have been
* blocked, so call udastart to do more requests (if any). If
* this calls us again immediately we will not recurse, because
* that time we will be in udastart(). Clever....
register struct uba_ctlr
*um
;
struct uda_softc
*sc
= &uda_softc
[um
->um_ctlr
];
struct mscp
*mp
= (struct mscp
*)um
->um_cmd
;
um
->um_tab
.b_active
++; /* another transfer going */
* Fill in the MSCP packet and move the buffer to the
* I/O wait queue. Mark the controller as no longer on
* the resource queue, and remember to initiate polling.
mp
->mscp_seq
.seq_buffer
= (um
->um_ubinfo
& 0x3ffff) |
(UBAI_BDP(um
->um_ubinfo
) << 24);
mscp_go(&sc
->sc_mi
, mp
, um
->um_ubinfo
);
um
->um_ubinfo
= 0; /* tyke it awye */
sc
->sc_flags
|= SC_STARTPOLL
;
if ((sc
->sc_flags
& SC_INSTART
) == 0)
register struct mscp_info
*mi
;
register struct uba_ctlr
*um
= udaminfo
[mi
->mi_ctlr
];
if (um
->um_bdp
&& mi
->mi_wtab
.av_forw
== &mi
->mi_wtab
)
ubarelse(um
->um_ubanum
, &um
->um_bdp
);
um
->um_tab
.b_active
--; /* another transfer done */
* The error bit was set in the controller status register. Gripe,
* reset the controller, requeue pending transfers.
register struct uba_ctlr
*um
;
printf("uda%d: controller error, sa=%b\n", um
->um_ctlr
,
((struct udadevice
*) um
->um_addr
)->udasa
, udasr_bits
);
mscp_requeue(&uda_softc
[um
->um_ctlr
].sc_mi
);
(void) udainit(um
->um_ctlr
);
* Interrupt routine. Depending on the state of the controller,
* continue initialisation, or acknowledge command and response
* interrupts, and process responses.
register struct uba_ctlr
*um
= udaminfo
[ctlr
];
register struct uda_softc
*sc
= &uda_softc
[ctlr
];
register struct udadevice
*udaddr
= (struct udadevice
*) um
->um_addr
;
register struct mscp
*mp
;
(void) spl5(); /* Qbus interrupt protocol is odd */
sc
->sc_wticks
= 0; /* reset interrupt watchdog */
* Combinations during steps 1, 2, and 3: STEPnMASK
* corresponds to which bits should be tested;
* STEPnGOOD corresponds to the pattern that should
* appear after the interrupt from STEPn initialisation.
* All steps test the bits in ALLSTEPS.
#define ALLSTEPS (UDA_ERR|UDA_STEP4|UDA_STEP3|UDA_STEP2|UDA_STEP1)
#define STEP1MASK (ALLSTEPS | UDA_IE | UDA_NCNRMASK)
#define STEP1GOOD (UDA_STEP2 | UDA_IE | (NCMDL2 << 3) | NRSPL2)
#define STEP2MASK (ALLSTEPS | UDA_IE | UDA_IVECMASK)
#define STEP2GOOD (UDA_STEP3 | UDA_IE | (sc->sc_ivec >> 2))
#define STEP3MASK ALLSTEPS
#define STEP3GOOD UDA_STEP4
* Ignore unsolicited interrupts.
log(LOG_WARNING
, "uda%d: stray intr\n", ctlr
);
* Begin step two initialisation.
if ((udaddr
->udasa
& STEP1MASK
) != STEP1GOOD
) {
printf("uda%d: init step %d failed, sa=%b\n",
ctlr
, i
, udaddr
->udasa
, udasr_bits
);
if (sc
->sc_flags
& SC_DOWAKE
) {
sc
->sc_flags
&= ~SC_DOWAKE
;
udaddr
->udasa
= (int) &sc
->sc_uda
->uda_ca
.ca_rspdsc
[0] |
(cpu
== VAX_780
|| cpu
== VAX_8600
? UDA_PI
: 0);
* Begin step 3 initialisation.
if ((udaddr
->udasa
& STEP2MASK
) != STEP2GOOD
) {
udaddr
->udasa
= ((int) &sc
->sc_uda
->uda_ca
.ca_rspdsc
[0]) >> 16;
* Set controller characteristics (finish initialisation).
if ((udaddr
->udasa
& STEP3MASK
) != STEP3GOOD
) {
i
= udaddr
->udasa
& 0xff;
printf("uda%d: version %d model %d\n",
* Present the burst size, then remove it. Why this
* should be done this way, I have no idea.
* Note that this assumes udaburst[ctlr] > 0.
udaddr
->udasa
= UDA_GO
| (udaburst
[ctlr
] - 1) << 2;
printf("uda%d: DMA burst size set to %d\n",
udainitds(ctlr
); /* initialise data structures */
* Before we can get a command packet, we need some
* credits. Fake some up to keep mscp_getcp() happy,
* get a packet, and cancel all credits (the right
* number should come back in the response to the
sc
->sc_mi
.mi_credits
= MSCP_MINCREDITS
+ 1;
mp
= mscp_getcp(&sc
->sc_mi
, MSCP_DONTWAIT
);
if (mp
== NULL
) /* `cannot happen' */
sc
->sc_mi
.mi_credits
= 0;
mp
->mscp_opcode
= M_OP_SETCTLRC
;
mp
->mscp_sccc
.sccc_ctlrflags
= M_CF_ATTN
| M_CF_MISC
|
*mp
->mscp_addr
|= MSCP_OWN
| MSCP_INT
;
sc
->sc_state
= ST_SETCHAR
;
* Handle Set Ctlr Characteristics responses and operational
* responses (via mscp_dorsp).
printf("uda%d: driver bug, state %d\n", ctlr
, sc
->sc_state
);
if (udaddr
->udasa
& UDA_ERR
) { /* ctlr fatal error */
* Handle buffer purge requests.
* I have never seen these to work usefully, thus the log().
log(LOG_DEBUG
, "uda%d: purge bdp %d\n",
ctlr
, ud
->uda_ca
.ca_bdp
);
UBAPURGE(um
->um_hd
->uh_uba
, ud
->uda_ca
.ca_bdp
);
udaddr
->udasa
= 0; /* signal purge complete */
* Check for response and command ring transitions.
if (ud
->uda_ca
.ca_rspint
) {
ud
->uda_ca
.ca_rspint
= 0;
if (ud
->uda_ca
.ca_cmdint
) {
ud
->uda_ca
.ca_cmdint
= 0;
return (physio(udastrategy
, &rudabuf
[udaunit(dev
)], dev
, B_READ
,
return (physio(udastrategy
, &rudabuf
[udaunit(dev
)], dev
, B_WRITE
,
* Initialise the various data structures that control the UDA50.
register struct uda
*ud
= &uda
[ctlr
];
register struct uda
*uud
= uda_softc
[ctlr
].sc_uda
;
register struct mscp
*mp
;
for (i
= 0, mp
= ud
->uda_rsp
; i
< NRSP
; i
++, mp
++) {
ud
->uda_ca
.ca_rspdsc
[i
] = MSCP_OWN
| MSCP_INT
|
(long)&uud
->uda_rsp
[i
].mscp_cmdref
;
mp
->mscp_addr
= &ud
->uda_ca
.ca_rspdsc
[i
];
mp
->mscp_msglen
= MSCP_MSGLEN
;
for (i
= 0, mp
= ud
->uda_cmd
; i
< NCMD
; i
++, mp
++) {
ud
->uda_ca
.ca_cmddsc
[i
] = MSCP_INT
|
(long)&uud
->uda_cmd
[i
].mscp_cmdref
;
mp
->mscp_addr
= &ud
->uda_ca
.ca_cmddsc
[i
];
mp
->mscp_msglen
= MSCP_MSGLEN
;
* Handle an error datagram. All we do now is decode it.
mscp_decodeerror(mi
->mi_md
->md_mname
, mi
->mi_ctlr
, mp
);
* The Set Controller Characteristics command finished.
* Record the new state of the controller.
register struct mscp_info
*mi
;
register struct uda_softc
*sc
= &uda_softc
[mi
->mi_ctlr
];
if ((mp
->mscp_status
& M_ST_MASK
) == M_ST_SUCCESS
)
printf("uda%d: SETCTLRC failed: ",
mi
->mi_ctlr
, mp
->mscp_status
);
if (sc
->sc_flags
& SC_DOWAKE
) {
sc
->sc_flags
&= ~SC_DOWAKE
;
* Received a response from an as-yet unconfigured drive. Configure it
register struct mscp
*mp
;
* If it is a slave response, copy it to udaslavereply for
if (mp
->mscp_opcode
== (M_OP_GETUNITST
| M_OP_END
) &&
(uda_softc
[mi
->mi_ctlr
].sc_flags
& SC_INSLAVE
) != 0) {
* Otherwise, it had better be an available attention response.
if (mp
->mscp_opcode
!= M_OP_AVAILATTN
)
/* do what autoconf does */
return (MSCP_FAILED
); /* not yet, arwhite, not yet */
* A drive came on line. Check its type and size. Return DONE if
* we think the drive is truly on line. In any case, awaken anyone
* sleeping on the drive on-line-ness.
register struct uba_device
*ui
;
register struct ra_info
*ra
= &ra_info
[ui
->ui_unit
];
wakeup((caddr_t
)&ui
->ui_flags
);
if ((mp
->mscp_status
& M_ST_MASK
) != M_ST_SUCCESS
) {
printf("uda%d: attempt to bring ra%d on line failed: ",
ui
->ui_ctlr
, ui
->ui_unit
);
ra
->ra_dsize
= (daddr_t
)mp
->mscp_onle
.onle_unitsize
;
printf("ra%d: uda%d, unit %d, size = %d sectors\n", ui
->ui_unit
,
ui
->ui_ctlr
, mp
->mscp_unit
, ra
->ra_dsize
);
/* can now compute ncyl */
ra
->ra_geom
.rg_ncyl
= ra
->ra_dsize
/ ra
->ra_geom
.rg_ntracks
/
* We got some (configured) unit's status. Return DONE if it succeeded.
register struct uba_device
*ui
;
register struct mscp
*mp
;
if ((mp
->mscp_status
& M_ST_MASK
) != M_ST_SUCCESS
) {
printf("uda%d: attempt to get status for ra%d failed: ",
ui
->ui_ctlr
, ui
->ui_unit
);
/* record for (future) bad block forwarding and whatever else */
uda_rasave(ui
->ui_unit
, mp
, 1);
* A transfer failed. We get a chance to fix or restart it.
* Need to write the bad block forwaring code first....
register struct uba_device
*ui
;
register struct mscp
*mp
;
if (mp
->mscp_flags
& M_EF_BBLKR
) {
* A bad block report. Eventually we will
* restart this transfer, but for now, just
log(LOG_ERR
, "ra%d: bad block report: %d%s\n",
ui
->ui_unit
, mp
->mscp_seq
.seq_lbn
,
mp
->mscp_flags
& M_EF_BBLKU
? " + others" : "");
* What the heck IS a `serious exception' anyway?
* IT SURE WOULD BE NICE IF DEC SOLD DOCUMENTATION
* FOR THEIR OWN CONTROLLERS.
if (mp
->mscp_flags
& M_EF_SEREX
)
log(LOG_ERR
, "ra%d: serious exception reported\n",
* A replace operation finished.
* A bad block related operation finished.
udaioctl(dev
, cmd
, data
, flag
)
register int unit
= udaunit(dev
);
register struct disklabel
*lp
;
*(struct disklabel
*)data
= *lp
;
((struct partinfo
*)data
)->disklab
= lp
;
((struct partinfo
*)data
)->part
=
&lp
->d_partitions
[udapart(dev
)];
if ((flag
& FWRITE
) == 0)
error
= setdisklabel(lp
, (struct disklabel
*)data
,
ra_info
[unit
].ra_openpart
);
if ((flag
& FWRITE
) == 0)
else if ((error
= setdisklabel(lp
, (struct disklabel
*)data
,
ra_info
[unit
].ra_openpart
)) == 0)
error
= writedisklabel(dev
, udastrategy
, lp
);
* Initiate bad block replacement for the given LBN.
* (Should we allow modifiers?)
* Return the microcode revision for the UDA50 running
*(int *) data
= uda_softc
[uddinfo
[unit
]->ui_ctlr
].sc_micro
;
* A Unibus reset has occurred on UBA uban. Reinitialise the controller(s)
* on that Unibus, and requeue outstanding I/O.
register struct uba_ctlr
*um
;
register struct uda_softc
*sc
;
for (ctlr
= 0, sc
= uda_softc
; ctlr
< NUDA
; ctlr
++, sc
++) {
if ((um
= udaminfo
[ctlr
]) == NULL
|| um
->um_ubanum
!= uban
||
* Our BDP (if any) is gone; our command (if any) is
* flushed; the device is no longer mapped; and the
* UDA50 is not yet initialised.
printf("<%d>", UBAI_BDP(um
->um_bdp
));
sc
->sc_flags
&= ~SC_MAPPED
;
/* reset queues and requeue pending transfers */
mscp_requeue(&sc
->sc_mi
);
* If it fails to initialise we will notice later and
* try again (and again...). Do not call udastart()
* here; it will be done after the controller finishes
* Watchdog timer: If the controller is active, and no interrupts
* have occurred for 30 seconds, assume it has gone away.
register struct uba_ctlr
*um
;
register struct uda_softc
*sc
;
timeout(udawatch
, (caddr_t
) 0, hz
); /* every second */
for (i
= 0, sc
= uda_softc
; i
< NUDA
; i
++, sc
++) {
if ((um
= udaminfo
[i
]) == 0 || !um
->um_alive
)
if (sc
->sc_state
== ST_IDLE
)
if (sc
->sc_state
== ST_RUN
&& !um
->um_tab
.b_active
)
else if (++sc
->sc_wticks
>= 30) {
printf("uda%d: lost interrupt\n", i
);
* Do a panic dump. We set up the controller for one command packet
* and one response packet, for which we use `struct uda1'.
struct uda1ca uda1_ca
; /* communications area */
struct mscp uda1_rsp
; /* response packet */
struct mscp uda1_cmd
; /* command packet */
#define DBSIZE 32 /* dump 16K at a time */
struct udadevice
*udaddr
;
int num
, blk
, unit
, maxsz
, blkoff
, reg
;
register struct uba_regs
*uba
;
register struct uba_device
*ui
;
register struct uda1
*ud
;
* Make sure the device is a reasonable place on which to dump.
#define phys(cast, addr) ((cast) ((int) addr & 0x7fffffff))
ui
= phys(struct uba_device
*, udadinfo
[unit
]);
if (ui
== NULL
|| ui
->ui_alive
== 0)
* Find and initialise the UBA; get the physical address of the
* device registers, and of communications area and command and
uba
= phys(struct uba_hd
*, ui
->ui_hd
)->uh_physuba
;
udaddr
= (struct udadevice
*)ui
->ui_physaddr
;
ud
= phys(struct uda1
*, &uda1
);
* Map the ca+packets into Unibus I/O space so the UDA50 can get
* at them. Use the registers at the end of the Unibus map (since
* we will use the registers at the beginning to map the memory
num
= btoc(sizeof(struct uda1
)) + 1;
for (i
= 0; i
< num
; i
++)
*(int *)io
++ = UBAMR_MRV
| (btop(ud
) + i
);
ud_ubaddr
= (struct uda1
*)(((int)ud
& PGOFSET
) | (reg
<< 9));
* Initialise the controller, with one command and one response
if (udadumpwait(udaddr
, UDA_STEP1
))
if (udadumpwait(udaddr
, UDA_STEP2
))
udaddr
->udasa
= (int)&ud_ubaddr
->uda1_ca
.ca_rspdsc
;
if (udadumpwait(udaddr
, UDA_STEP3
))
udaddr
->udasa
= ((int)&ud_ubaddr
->uda1_ca
.ca_rspdsc
) >> 16;
if (udadumpwait(udaddr
, UDA_STEP4
))
uda_softc
[ui
->ui_ctlr
].sc_micro
= udaddr
->udasa
& 0xff;
* Set up the command and response descriptor, then set the
* controller characteristics and bring the drive on line.
* Note that all uninitialised locations in uda1_cmd are zero.
ud
->uda1_ca
.ca_rspdsc
= (long)&ud_ubaddr
->uda1_rsp
.mscp_cmdref
;
ud
->uda1_ca
.ca_cmddsc
= (long)&ud_ubaddr
->uda1_cmd
.mscp_cmdref
;
/* ud->uda1_cmd.mscp_sccc.sccc_ctlrflags = 0; */
/* ud->uda1_cmd.mscp_sccc.sccc_version = 0; */
if (udadumpcmd(M_OP_SETCTLRC
, ud
, ui
))
ud
->uda1_cmd
.mscp_unit
= ui
->ui_slave
;
if (udadumpcmd(M_OP_ONLINE
, ud
, ui
))
pp
= phys(struct partition
*,
&udalabel
[unit
].d_partitions
[udapart(dev
)]);
* Dump all of physical memory, or as much as will fit in the
if (dumplo
+ num
>= maxsz
)
* Write out memory, DBSIZE pages at a time.
* N.B.: this code depends on the fact that the sector
blk
= num
> DBSIZE
? DBSIZE
: num
;
* Map in the pages to write, leaving an invalid entry
* at the end to guard against wild Unibus transfers.
for (i
= 0; i
< blk
; i
++)
*(int *) io
++ = UBAMR_MRV
| (btop(start
) + i
);
ud
->uda1_cmd
.mscp_unit
= ui
->ui_slave
;
ud
->uda1_cmd
.mscp_seq
.seq_lbn
= btop(start
) + blkoff
;
ud
->uda1_cmd
.mscp_seq
.seq_bytecount
= blk
<< PGSHIFT
;
if (udadumpcmd(M_OP_WRITE
, ud
, ui
))
return (0); /* made it! */
* Wait for some of the bits in `bits' to come on. If the error bit
* comes on, or ten seconds pass without response, return true (error).
udadumpwait(udaddr
, bits
)
register struct udadevice
*udaddr
;
register int timo
= todr() + 1000;
while ((udaddr
->udasa
& bits
) == 0) {
if (udaddr
->udasa
& UDA_ERR
) {
printf("udasa=%b\ndump ", udaddr
->udasa
, udasr_bits
);
printf("timeout\ndump ");
* Feed a command to the UDA50, wait for its response, and return
* true iff something went wrong.
register struct uda1
*ud
;
register struct udadevice
*udaddr
;
#define mp (&ud->uda1_rsp)
udaddr
= (struct udadevice
*) ui
->ui_physaddr
;
ud
->uda1_cmd
.mscp_opcode
= op
;
ud
->uda1_cmd
.mscp_msglen
= MSCP_MSGLEN
;
ud
->uda1_rsp
.mscp_msglen
= MSCP_MSGLEN
;
ud
->uda1_ca
.ca_rspdsc
|= MSCP_OWN
| MSCP_INT
;
ud
->uda1_ca
.ca_cmddsc
|= MSCP_OWN
| MSCP_INT
;
if (udaddr
->udasa
& UDA_ERR
) {
printf("udasa=%b\ndump ", udaddr
->udasa
, udasr_bits
);
printf("timeout\ndump ");
if (ud
->uda1_ca
.ca_cmdint
)
ud
->uda1_ca
.ca_cmdint
= 0;
if (ud
->uda1_ca
.ca_rspint
== 0)
ud
->uda1_ca
.ca_rspint
= 0;
if (mp
->mscp_opcode
== (op
| M_OP_END
))
switch (MSCP_MSGTYPE(mp
->mscp_msgtc
)) {
mscp_decodeerror("uda", ui
->ui_ctlr
, mp
);
printf("unknown (type 0x%x)",
MSCP_MSGTYPE(mp
->mscp_msgtc
));
printf(" ignored\ndump ");
ud
->uda1_ca
.ca_rspdsc
|= MSCP_OWN
| MSCP_INT
;
if ((mp
->mscp_status
& M_ST_MASK
) != M_ST_SUCCESS
) {
printf("error: op 0x%x => 0x%x status 0x%x\ndump ", op
,
mp
->mscp_opcode
, mp
->mscp_status
);
* Return the size of a partition, if known, or -1 if not.
register int unit
= udaunit(dev
);
register struct uba_device
*ui
;
register struct size
*st
;
if (unit
>= NRA
|| (ui
= udadinfo
[unit
]) == NULL
||
ui
->ui_alive
== 0 || (ui
->ui_flags
& UNIT_ONLINE
) == 0 ||
ra_info
[unit
].ra_state
!= OPEN
)
return ((int)udalabel
[unit
].d_partitions
[udapart(dev
)].p_size
);
* Tables mapping unlabelled drives.
15884, 0, /* A=blk 0 thru 15883 */
10032, 15884, /* B=blk 15884 thru 49323 */
-1, 0, /* C=blk 0 thru end */
0, 0, /* D=blk 340670 thru 356553 */
0, 0, /* E=blk 356554 thru 412489 */
0, 0, /* F=blk 412490 thru end */
-1, 25916, /* G=blk 49324 thru 131403 */
0, 0, /* H=blk 131404 thru end */
800, 0, /* A=blk 0 thru 799 */
-1, 0, /* C=blk 0 thru end */
15884, 0, /* A=blk 0 thru 15883 */
9766, 15884, /* B=blk 15884 thru 25649 */
-1, 0, /* C=blk 0 thru end */
-1, 25650, /* G=blk 25650 thru end */
15884, 0, /* A=blk 0 thru 15883 */
33440, 15884, /* B=blk 15884 thru 49323 */
-1, 0, /* C=blk 0 thru end */
33440, 0, /* E=blk 0 thru 33439 */
-1, 33440, /* F=blk 33440 thru end */
-1, 49324, /* G=blk 49324 thru end */
-1, 15884, /* H=blk 15884 thru end */
15884, 0, /* A=sectors 0 thru 15883 */
33440, 15884, /* B=sectors 15884 thru 49323 */
400176, 0, /* C=sectors 0 thru 400175 */
82080, 49324, /* 4.2 G => D=sectors 49324 thru 131403 */
268772, 131404, /* 4.2 H => E=sectors 131404 thru 400175 */
350852, 49324, /* F=sectors 49324 thru 400175 */
157570, 242606, /* UCB G => G=sectors 242606 thru 400175 */
193282, 49324, /* UCB H => H=sectors 49324 thru 242605 */
15884, 0, /* A=sectors 0 thru 15883 */
33440, 15884, /* B=sectors 15884 thru 49323 */
242606, 0, /* C=sectors 0 thru 242605 */
193282, 49324, /* UCB H => E=sectors 49324 thru 242605 */
82080, 49324, /* 4.2 G => F=sectors 49324 thru 131403 */
192696, 49910, /* G=sectors 49910 thru 242605 */
111202, 131404, /* 4.2 H => H=sectors 131404 thru 242605 */
* These are the new standard partition sizes for ra81's.
* An RA_COMPAT system is compiled with D, E, and F corresponding
* to the 4.2 partitions for G, H, and F respectively.
15884, 0, /* A=sectors 0 thru 15883 */
66880, 16422, /* B=sectors 16422 thru 83301 */
891072, 0, /* C=sectors 0 thru 891071 */
82080, 49324, /* 4.2 G => D=sectors 49324 thru 131403 */
759668, 131404, /* 4.2 H => E=sectors 131404 thru 891071 */
478582, 412490, /* 4.2 F => F=sectors 412490 thru 891071 */
15884, 375564, /* D=sectors 375564 thru 391447 */
307200, 391986, /* E=sectors 391986 thru 699185 */
191352, 699720, /* F=sectors 699720 thru 891071 */
515508, 375564, /* G=sectors 375564 thru 891071 */
291346, 83538, /* H=sectors 83538 thru 374883 */
* These partitions correspond to the sizes used by sites at Berkeley,
* and by those sites that have received copies of the Berkeley driver
* with deltas 6.2 or greater (11/15/83).
15884, 0, /* A=sectors 0 thru 15883 */
33440, 15884, /* B=sectors 15884 thru 49323 */
891072, 0, /* C=sectors 0 thru 891071 */
15884, 242606, /* D=sectors 242606 thru 258489 */
307200, 258490, /* E=sectors 258490 thru 565689 */
325382, 565690, /* F=sectors 565690 thru 891071 */
648466, 242606, /* G=sectors 242606 thru 891071 */
193282, 49324, /* H=sectors 49324 thru 242605 */
* Drive type index decoding table. `ut_name' is null iff the
char *ut_name
; /* drive type name */
struct size
*ut_sizes
; /* partition tables */
int ut_nsectors
, ut_ntracks
, ut_ncylinders
;
"ra80", ra80_sizes
, /* 1 = ra80 */
"rc25-removable", ra25_sizes
, /* 2 = rc25-r */
"rc25-fixed", ra25_sizes
, /* 3 = rc25-f */
"ra60", ra60_sizes
, /* 4 = ra60 */
"ra81", ra81_sizes
, /* 5 = ra81 */
"rx50", rx50_sizes
, /* 7 = rx50 */
"rd52", rd52_sizes
, /* 8 = rd52 */
"rd53", rd53_sizes
, /* 9 = rd53 */
#define NTYPES (sizeof(udatypes) / sizeof(*udatypes))
register struct disklabel
*lp
;
register struct udatypes
*ut
;
register struct size
*sz
;
register struct partition
*pp
;
register struct ra_info
*ra
= &ra_info
[unit
];
lp
->d_secperunit
= ra
->ra_dsize
;
if ((u_long
)ra
->ra_type
>= NTYPES
) {
printf("ra%d: don't have a partition table for", unit
);
mscp_printmedia(ra
->ra_mediaid
);
lp
->d_nsectors
= ra
->ra_geom
.rg_nsectors
;
lp
->d_ntracks
= ra
->ra_geom
.rg_ntracks
;
lp
->d_ncylinders
= ra
->ra_geom
.rg_ncyl
;
printf(";\nusing (t,s,c)=(%d,%d,%d)\n", lp
->d_nsectors
,
lp
->d_ntracks
, lp
->d_ncylinders
);
lp
->d_secpercyl
= lp
->d_nsectors
* lp
->d_ntracks
;
lp
->d_partitions
[0].p_offset
= 0;
lp
->d_partitions
[0].p_size
= lp
->d_secperunit
;
ut
= &udatypes
[ra
->ra_type
];
for (i
= 0; i
< sizeof(lp
->d_typename
) - 1 && *p
; i
++)
lp
->d_typename
[i
] = *p
++;
/* GET nsectors, ntracks, ncylinders FROM SAVED GEOMETRY? */
lp
->d_nsectors
= ut
->ut_nsectors
;
lp
->d_ntracks
= ut
->ut_ntracks
;
lp
->d_ncylinders
= ut
->ut_ncylinders
;
lp
->d_secpercyl
= lp
->d_nsectors
* lp
->d_ntracks
;
for (pp
= lp
->d_partitions
; pp
< &lp
->d_partitions
[8]; pp
++, sz
++) {
pp
->p_offset
= sz
->blkoff
;
if ((pp
->p_size
= sz
->nblocks
) == (u_long
)-1)
pp
->p_size
= ra
->ra_dsize
- sz
->blkoff
;