* @(#)uda.c 7.1 (Berkeley) 6/5/86
/************************************************************************
* Copyright (c) 1983 by *
* Digital Equipment Corporation, Maynard, MA *
************************************************************************/
#define UDADEVNUM (9) /* entry in bdevsw */
* UDA50/RAxx disk device driver
* Unit numbers must be less than 8.
#include "../machine/pte.h"
#define NRSPL2 3 /* log2 number of response packets */
#define NCMDL2 3 /* log2 number of command packets */
#define UDABURST 4 /* default for DMA burst size */
#include "../vaxuba/udareg.h"
short sc_state
; /* state of controller */
short sc_mapped
; /* Unibus map allocated for uda struct? */
int sc_ubainfo
; /* Unibus mapping info */
struct uda
*sc_uda
; /* Unibus address of uda struct */
int sc_ivec
; /* interrupt vector address */
short sc_credits
; /* transfer credits */
short sc_lastcmd
; /* pointer into command ring */
short sc_lastrsp
; /* pointer into response ring */
struct udaca uda_ca
; /* communications area */
struct mscp uda_rsp
[NRSP
]; /* response packets */
struct mscp uda_cmd
[NCMD
]; /* command packets */
#define udunit(dev) (minor(dev) >> 3)
/* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
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 */
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 */
struct size
*ra_sizes
; /* Partion tables for drive */
daddr_t radsize
; /* Max user size form online pkt */
unsigned ratype
; /* Drive type int field */
unsigned rastatus
; /* Command status from */
/* last onlin or GTUNT */
/* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
struct uba_ctlr
*udminfo
[NUDA
];
struct uba_device
*uddinfo
[NRA
];
struct uba_device
*udip
[NUDA
][8]; /* 8 == max number of drives */
struct buf udwtab
[NUDA
]; /* I/O wait queue, per controller */
int udamicro
[NUDA
]; /* to store microcode level */
int udaburst
[NUDA
] = { 0 }; /* DMA burst size, 0 is default */
#define S_IDLE 0 /* hasn't been initialized */
#define S_STEP1 1 /* doing step 1 init */
#define S_STEP2 2 /* doing step 2 init */
#define S_STEP3 3 /* doing step 3 init */
#define S_SCHAR 4 /* doing "set controller characteristics" */
#define S_RUN 5 /* running */
int udaerror
= 0; /* causes hex dump of packets */
int uda_cp_wait
= 0; /* Something to wait on for command */
/* packets and or credits. */
extern int hz
; /* Should find the right include */
#define printd if (udadebug) printf
#define printd10 if(udadebug >= 10) printf
#define mprintf printf /* temporary JG hack until Rich fixes*/
int udprobe(), udslave(), udattach(), udintr();
u_short udstd
[] = { 0772150, 0772550, 0777550, 0 };
struct uba_driver udadriver
=
{ udprobe
, udslave
, udattach
, 0, udstd
, "ra", uddinfo
, "uda", udminfo
, 0 };
#define b_qsize b_resid /* queue size per drive, in udutab */
#define b_ubinfo b_resid /* Unibus mapping info, per buffer */
register struct uda_softc
*sc
= &uda_softc
[ctlr
];
struct udadevice
*udaddr
;
br
= 0; cvec
= br
; br
= cvec
;
udaddr
= (struct udadevice
*) reg
;
sc
->sc_ivec
= (uba_hd
[numuba
].uh_lastiv
-= 4);
return(sizeof (struct udadevice
));
udaddr
->udaip
= 0; /* start initialization */
cur_time
= mfpr(TODR
); /* Time of day */
while(cur_time
+ TENSEC
> mfpr(TODR
)){ /* wait for at most 10 secs */
if((udaddr
->udasa
& UDA_STEP1
) != 0)
if(cur_time
+ TENSEC
<= mfpr(TODR
))
return(0); /* Not a uda or it won't init as it */
/* should within ten seconds. */
udaddr
->udasa
=UDA_ERR
|(NCMDL2
<<11)|(NRSPL2
<<8)|UDA_IE
|(sc
->sc_ivec
/4);
while((udaddr
->udasa
&UDA_STEP2
)==0)
DELAY(1000); /* intr should have */
/* have happened by now */
return(sizeof (struct udadevice
));
register struct uba_ctlr
*um
= udminfo
[ui
->ui_ctlr
];
register struct uda_softc
*sc
= &uda_softc
[ui
->ui_ctlr
];
struct udadevice
*udaddr
;
int i
; /* Something to write into to start */
udaddr
= (struct udadevice
*)um
->um_addr
;
if(sc
->sc_state
!= S_RUN
){
/* Here we will wait for the controller */
/* to come into the run state or go idle. If we go idle we are in */
/* touble and I don't yet know what to do so I will punt */
while(sc
->sc_state
!= S_RUN
&& sc
->sc_state
!= S_IDLE
); /* spin */
if(sc
->sc_state
== S_IDLE
){ /* The Uda failed to initialize */
printf("UDA failed to init\n");
/* The controller is up so let see if the drive is there! */
if(0 == (mp
= udgetcp(um
))){ /* ditto */
printf("UDA can't get command packet\n");
mp
->mscp_opcode
= M_OP_GTUNT
; /* This should give us the drive type*/
mp
->mscp_unit
= ui
->ui_slave
;
mp
->mscp_cmdref
= (long) ui
->ui_slave
;
printd("uda%d Get unit status slave %d\n",ui
->ui_ctlr
,ui
->ui_slave
);
ra_info
[ui
->ui_unit
].rastatus
= 0; /* set to zero */
udip
[ui
->ui_ctlr
][ui
->ui_slave
] = ui
;
*((long *) mp
->mscp_dscptr
) |= UDA_OWN
| UDA_INT
;/* maybe we should poll*/
while(!ra_info
[ui
->ui_unit
].rastatus
); /* Wait for some status */
udip
[ui
->ui_ctlr
][ui
->ui_slave
] = 0;
if(!ra_info
[ui
->ui_unit
].ratype
) /* packet from a GTUNT */
return(0); /* Failed No such drive */
return(1); /* Got it and it is there */
register struct uba_device
*ui
;
register struct uba_ctlr
*um
= ui
->ui_mi
;
struct udadevice
*udaddr
= (struct udadevice
*) um
->um_addr
;
int i
; /* Something to write into to start */
dk_mspw
[ui
->ui_dk
] = 1.0 / (60 * 31 * 256); /* approx */
udip
[ui
->ui_ctlr
][ui
->ui_slave
] = ui
;
/* check to see if the drive is a available if it is bring it online */
/* if not then just return. open will try an online later */
if(ra_info
[ui
->ui_unit
].rastatus
!= M_ST_AVLBL
)
return; /* status was set by a GTUNT */
if(0 == (mp
= udgetcp(um
))){ /* ditto */
printf("UDA can't get command packet\n");
mp
->mscp_opcode
= M_OP_ONLIN
;
mp
->mscp_unit
= ui
->ui_slave
;
mp
->mscp_cmdref
= (long) ui
->ui_slave
;
printd("uda%d ONLIN slave %d\n",ui
->ui_ctlr
,ui
->ui_slave
);
*((long *) mp
->mscp_dscptr
) |= UDA_OWN
| UDA_INT
;
while(ui
->ui_flags
== 0 && ra_info
[ui
->ui_unit
].ratype
!= 0);
* Open a UDA. Initialize the device and
register struct uba_device
*ui
;
register struct uda_softc
*sc
;
register struct mscp
*mp
;
register struct uba_ctlr
*um
;
struct udadevice
*udaddr
;
if (unit
>= NRA
|| (ui
= uddinfo
[unit
]) == 0 || ui
->ui_alive
== 0)
sc
= &uda_softc
[ui
->ui_ctlr
];
if (sc
->sc_state
!= S_RUN
) {
if (sc
->sc_state
== S_IDLE
)
if(!udinit(ui
->ui_ctlr
)){
printf("uda: Controller failed to init\n");
/* wait for initialization to complete */
timeout(wakeup
,(caddr_t
)ui
->ui_mi
,11*hz
); /* to be sure*/
sleep((caddr_t
)ui
->ui_mi
, 0);
if (sc
->sc_state
!= S_RUN
)
(void) splx(s
); /* added by Rich */
/* check to see if the device is really there. */
/* this code was taken from Fred Canters 11 driver */
udaddr
= (struct udadevice
*) um
->um_addr
;
while(0 ==(mp
= udgetcp(um
))){
sleep((caddr_t
)&uda_cp_wait
,PSWP
+1);
mp
->mscp_opcode
= M_OP_ONLIN
;
mp
->mscp_unit
= ui
->ui_slave
;
mp
->mscp_cmdref
= (long) & ra_info
[ui
->ui_unit
].ratype
;
/* need to sleep on something */
printd("uda: bring unit %d online\n",ui
->ui_unit
);
*((long *) mp
->mscp_dscptr
) |= UDA_OWN
| UDA_INT
;
timeout(wakeup
,(caddr_t
) mp
->mscp_cmdref
,10 * hz
);
/* make sure we wake up */
sleep((caddr_t
) mp
->mscp_cmdref
,PSWP
+1); /*wakeup in udrsp() */
return(ENXIO
); /* Didn't go online */
* Initialize a UDA. Set up UBA mapping registers,
* initialize data structures, and start hardware
* initialization sequence.
register struct uda_softc
*sc
;
struct udadevice
*udaddr
;
udaddr
= (struct udadevice
*)um
->um_addr
;
if (sc
->sc_mapped
== 0) {
* Map the communications area and command
* and response packets into Unibus address
sc
->sc_ubainfo
= uballoc(um
->um_ubanum
, (caddr_t
)ud
,
sc
->sc_uda
= (struct uda
*)(sc
->sc_ubainfo
& 0x3ffff);
* Start the hardware initialization sequence.
udaddr
->udaip
= 0; /* start initialization */
while((udaddr
->udasa
& UDA_STEP1
) == 0){
if(udaddr
->udasa
& UDA_ERR
)
udaddr
->udasa
=UDA_ERR
|(NCMDL2
<<11)|(NRSPL2
<<8)|UDA_IE
|(sc
->sc_ivec
/4);
* Initialization continues in interrupt routine.
register struct uba_device
*ui
;
register struct uba_ctlr
*um
;
register struct size
*rasizes
;
int xunit
= minor(bp
->b_dev
) & 07;
sz
= (bp
->b_bcount
+511) >> 9;
unit
= udunit(bp
->b_dev
);
rasizes
= ra_info
[unit
].ra_sizes
;
if (ui
== 0 || ui
->ui_alive
== 0) {
if ((maxsz
= rasizes
[xunit
].nblocks
) < 0)
maxsz
= ra_info
[unit
].radsize
- rasizes
[xunit
].blkoff
;
if (bp
->b_blkno
< 0 || bp
->b_blkno
+sz
> maxsz
||
rasizes
[xunit
].blkoff
>= ra_info
[unit
].radsize
) {
if (bp
->b_blkno
== maxsz
) {
bp
->b_resid
= bp
->b_bcount
;
* Link the buffer onto the drive queue
dp
= &udutab
[ui
->ui_unit
];
dp
->b_actl
->av_forw
= bp
;
* Link the drive onto the controller queue
if (um
->um_tab
.b_actf
== NULL
)
um
->um_tab
.b_actl
->b_forw
= dp
;
if (um
->um_tab
.b_active
== 0) {
&& udwtab
[um
->um_ctlr
].av_forw
== &udwtab
[um
->um_ctlr
]) {
if (um
->um_ubinfo
!= 0) {
printd("udastrat: ubinfo 0x%x\n",um
->um_ubinfo
);
uballoc(um
->um_ubanum
, (caddr_t
)0, 0,
register struct uba_ctlr
*um
;
register struct buf
*bp
, *dp
;
register struct mscp
*mp
;
register struct uda_softc
*sc
;
register struct uba_device
*ui
;
struct udadevice
*udaddr
;
struct uda
*ud
= &uda
[um
->um_ctlr
];
sc
= &uda_softc
[um
->um_ctlr
];
if ((dp
= um
->um_tab
.b_actf
) == NULL
) {
* Release uneeded UBA resources and return
/* Check for response ring transitions lost in the
for (i
= sc
->sc_lastrsp
;; i
++) {
if (ud
->uda_ca
.ca_rspdsc
[i
]&UDA_OWN
)
ud
->uda_ca
.ca_rspdsc
[i
] |= UDA_OWN
;
if ((bp
= dp
->b_actf
) == NULL
) {
* No more requests for this drive, remove
* from controller queue and look at next drive.
* We know we're at the head of the controller queue.
um
->um_tab
.b_actf
= dp
->b_forw
;
goto loop
; /* Need to check for loop */
udaddr
= (struct udadevice
*)um
->um_addr
;
if ((udaddr
->udasa
&UDA_ERR
) || sc
->sc_state
!= S_RUN
) {
mprintf("Uda%d udasa %o, state %d\n",um
->um_ctlr
, udaddr
->udasa
&0xffff, sc
->sc_state
);
(void)udinit(um
->um_ctlr
);
/* SHOULD REQUEUE OUTSTANDING REQUESTS, LIKE UDRESET */
ui
= uddinfo
[udunit(bp
->b_dev
)];
rasizes
= ra_info
[ui
->ui_unit
].ra_sizes
;
if (ui
->ui_flags
== 0) { /* not online */
if ((mp
= udgetcp(um
)) == NULL
){
mp
->mscp_opcode
= M_OP_ONLIN
;
mp
->mscp_unit
= ui
->ui_slave
;
um
->um_tab
.b_actf
= dp
->b_forw
; /* remove from controller q */
printd("uda: bring unit %d online\n", ui
->ui_slave
);
*((long *)mp
->mscp_dscptr
) |= UDA_OWN
|UDA_INT
;
if (udaddr
->udasa
&UDA_ERR
)
printf("Uda (%d) Error (%x)\n",um
->um_ctlr
, udaddr
->udasa
&0xffff);
i
= UBA_NEEDBDP
|UBA_CANTWAIT
;
i
= um
->um_ubinfo
|UBA_HAVEBDP
|UBA_CANTWAIT
;
if ((i
= ubasetup(um
->um_ubanum
, bp
, i
)) == 0)
if ((mp
= udgetcp(um
)) == NULL
) {
i
&= 0xfffffff; /* mask off bdp */
ubarelse(um
->um_ubanum
,&i
);
mp
->mscp_cmdref
= (long)bp
; /* pointer to get back */
mp
->mscp_opcode
= bp
->b_flags
&B_READ
? M_OP_READ
: M_OP_WRITE
;
mp
->mscp_unit
= ui
->ui_slave
;
mp
->mscp_lbn
= bp
->b_blkno
+ rasizes
[minor(bp
->b_dev
)&7].blkoff
;
mp
->mscp_bytecnt
= bp
->b_bcount
;
mp
->mscp_buffer
= (i
& 0x3ffff) | (((i
>>28)&0xf)<<24);
i
&= 0xfffffff; /* mask off bdp */
bp
->b_ubinfo
= i
; /* save mapping info */
*((long *)mp
->mscp_dscptr
) |= UDA_OWN
|UDA_INT
;
if (udaddr
->udasa
&UDA_ERR
)
printf("Uda(%d) udasa (%x)\n",um
->um_ctlr
, udaddr
->udasa
&0xffff);
i
= udaddr
->udaip
; /* initiate polling */
dk_wds
[ui
->ui_dk
] += bp
->b_bcount
>>6;
* Move drive to the end of the controller queue
if (dp
->b_forw
!= NULL
) {
um
->um_tab
.b_actf
= dp
->b_forw
;
um
->um_tab
.b_actl
->b_forw
= dp
;
* Move buffer to I/O wait queue
dp
->b_actf
= bp
->av_forw
;
dp
= &udwtab
[um
->um_ctlr
];
bp
->av_back
= dp
->av_back
;
dp
->av_back
->av_forw
= bp
;
register struct uba_ctlr
*um
= udminfo
[d
];
register struct udadevice
*udaddr
= (struct udadevice
*)um
->um_addr
;
register struct uda_softc
*sc
= &uda_softc
[d
];
register struct uda
*ud
= &uda
[d
];
printd10("udintr: state %d, udasa %o\n", sc
->sc_state
, udaddr
->udasa
);
printf("uda%d: random interrupt ignored\n", d
);
#define STEP1MASK 0174377
#define STEP1GOOD (UDA_STEP2|UDA_IE|(NCMDL2<<3)|NRSPL2)
if ((udaddr
->udasa
&STEP1MASK
) != STEP1GOOD
) {
udaddr
->udasa
= ((int)&sc
->sc_uda
->uda_ca
.ca_ringbase
)|
((cpu
== VAX_780
) || (cpu
== VAX_8600
) ? UDA_PI
: 0);
#define STEP2MASK 0174377
#define STEP2GOOD (UDA_STEP3|UDA_IE|(sc->sc_ivec/4))
if ((udaddr
->udasa
&STEP2MASK
) != STEP2GOOD
) {
udaddr
->udasa
= ((int)&sc
->sc_uda
->uda_ca
.ca_ringbase
)>>16;
#define STEP3MASK 0174000
#define STEP3GOOD UDA_STEP4
if ((udaddr
->udasa
&STEP3MASK
) != STEP3GOOD
) {
udamicro
[d
] = udaddr
->udasa
;
printd("Uda%d Version %d model %d\n",d
,udamicro
[d
]&0xF,
* Requesting the error status (|= 2)
* may hang older controllers.
i
= UDA_GO
| (udaerror
? 2 : 0);
i
|= (udaburst
[d
] - 1) << 2;
* Initialize the data structures.
for (i
= 0; i
< NRSP
; i
++) {
ud
->uda_ca
.ca_rspdsc
[i
] = UDA_OWN
|UDA_INT
|
(long)&uud
->uda_rsp
[i
].mscp_cmdref
;
ud
->uda_rsp
[i
].mscp_dscptr
= &ud
->uda_ca
.ca_rspdsc
[i
];
ud
->uda_rsp
[i
].mscp_header
.uda_msglen
= mscp_msglen
;
for (i
= 0; i
< NCMD
; i
++) {
ud
->uda_ca
.ca_cmddsc
[i
] = UDA_INT
|
(long)&uud
->uda_cmd
[i
].mscp_cmdref
;
ud
->uda_cmd
[i
].mscp_dscptr
= &ud
->uda_ca
.ca_cmddsc
[i
];
ud
->uda_cmd
[i
].mscp_header
.uda_msglen
= mscp_msglen
;
bp
->av_forw
= bp
->av_back
= bp
;
mp
= &uda
[um
->um_ctlr
].uda_cmd
[0];
mp
->mscp_unit
= mp
->mscp_modifier
= 0;
mp
->mscp_bytecnt
= mp
->mscp_buffer
= 0;
mp
->mscp_errlgfl
= mp
->mscp_copyspd
= 0;
mp
->mscp_opcode
= M_OP_STCON
;
mp
->mscp_cntflgs
= M_CF_ATTN
|M_CF_MISC
|M_CF_THIS
;
*((long *)mp
->mscp_dscptr
) |= UDA_OWN
|UDA_INT
;
i
= udaddr
->udaip
; /* initiate polling */
printf("uda%d: interrupt in unknown state %d ignored\n",
if (udaddr
->udasa
&UDA_ERR
) {
printf("uda(%d): fatal error (%o)\n", d
, udaddr
->udasa
&0xffff);
* Check for a buffer purge request.
printd("uda: purge bdp %d\n", 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 ring transition.
if (ud
->uda_ca
.ca_rspint
) {
ud
->uda_ca
.ca_rspint
= 0;
for (i
= sc
->sc_lastrsp
;; i
++) {
if (ud
->uda_ca
.ca_rspdsc
[i
]&UDA_OWN
)
ud
->uda_ca
.ca_rspdsc
[i
] |= UDA_OWN
;
* Check for command ring transition.
if (ud
->uda_ca
.ca_cmdint
) {
printd("uda: command ring transition\n");
ud
->uda_ca
.ca_cmdint
= 0;
wakeup((caddr_t
)&uda_cp_wait
);
* Process a response packet
register struct uba_ctlr
*um
;
register struct uda_softc
*sc
;
register struct mscp
*mp
;
struct buf
*dp
, *bp
,nullbp
;
mp
->mscp_header
.uda_msglen
= mscp_msglen
;
sc
->sc_credits
+= mp
->mscp_header
.uda_credits
& 0xf; /* just 4 bits?*/
if ((mp
->mscp_header
.uda_credits
& 0xf0) > 0x10) /* Check */
printd10("udarsp, opcode 0x%x status 0x%x\n",mp
->mscp_opcode
,mp
->mscp_status
);
* If it's an error log message (datagram),
* pass it on for more extensive processing.
if ((mp
->mscp_header
.uda_credits
& 0xf0) == 0x10) { /* check */
uderror(um
, (struct mslg
*)mp
);
st
= mp
->mscp_status
&M_ST_MASK
;
/* The controller interrupts as drive 0 */
/* this means that you must check for controller interrupts */
/* before you check to see if there is a drive 0 */
if((M_OP_STCON
|M_OP_END
) == mp
->mscp_opcode
){
if ((ui
= udip
[um
->um_ctlr
][mp
->mscp_unit
]) == 0)
switch (mp
->mscp_opcode
) {
case M_OP_ONLIN
|M_OP_END
:
ra_info
[ui
->ui_unit
].rastatus
= st
;
ra_info
[ui
->ui_unit
].ratype
= mp
->mscp_mediaid
;
dp
= &udutab
[ui
->ui_unit
];
* Link the drive onto the controller queue
if (um
->um_tab
.b_actf
== NULL
)
um
->um_tab
.b_actl
->b_forw
= dp
;
ui
->ui_flags
= 1; /* mark it online */
ra_info
[ui
->ui_unit
].radsize
=(daddr_t
)mp
->mscp_untsize
;
printd("uda: unit %d online\n", mp
->mscp_unit
);
#define F_to_C(x,i) ( ((x)->mscp_mediaid) >> (i*5+7) & 0x1f ? ( ( (((x)->mscp_mediaid) >>( i*5 + 7)) & 0x1f) + 'A' - 1): ' ')
/* this mess decodes the Media type identifier */
printd("uda: unit %d online %x %c%c %c%c%c%d\n"
,mp
->mscp_unit
, mp
->mscp_mediaid
,F_to_C(mp
,4),F_to_C(mp
,3),F_to_C(mp
,2)
,F_to_C(mp
,1),F_to_C(mp
,0)
,mp
->mscp_mediaid
& 0x7f);
switch((int)(mp
->mscp_mediaid
& 0x7f)){
ra_info
[ui
->ui_unit
].ra_sizes
= ra25_sizes
;
ra_info
[ui
->ui_unit
].ra_sizes
= rd52_sizes
;
ra_info
[ui
->ui_unit
].ra_sizes
= rd53_sizes
;
ra_info
[ui
->ui_unit
].ra_sizes
= ra60_sizes
;
ra_info
[ui
->ui_unit
].ra_sizes
= ra80_sizes
;
ra_info
[ui
->ui_unit
].ra_sizes
= ra81_sizes
;
ui
->ui_flags
= 0; /* mark it offline */
ra_info
[ui
->ui_unit
].ratype
= 0;
printf("Don't have a parition table for ");
printf("a %c%c %c%c%c%d\n"
,F_to_C(mp
,4),F_to_C(mp
,3),F_to_C(mp
,2)
,F_to_C(mp
,1),F_to_C(mp
,0)
,mp
->mscp_mediaid
& 0x7f);
while (bp
= dp
->b_actf
) {
dp
->b_actf
= bp
->av_forw
;
harderr(dp
->b_actf
,"ra");
nullbp
.b_dev
= makedev(UDADEVNUM
,ui
->ui_unit
);
while (bp
= dp
->b_actf
) {
dp
->b_actf
= bp
->av_forw
;
if(mp
->mscp_cmdref
!=NULL
){/* Seems to get lost sometimes */
wakeup((caddr_t
)mp
->mscp_cmdref
);
* The AVAILABLE ATTENTION messages occurs when the
* unit becomes available after spinup,
* marking the unit offline will force an online command
* prior to using the unit.
printd("uda: unit %d attention\n", mp
->mscp_unit
);
ui
->ui_flags
= 0; /* it went offline and we didn't notice */
ra_info
[ui
->ui_unit
].ratype
= mp
->mscp_mediaid
;
* An endcode without an opcode (0200) is an invalid command.
* The mscp specification states that this would be a protocol
* type error, such as illegal opcodes. The mscp spec. also
* states that parameter error type of invalid commands should
* return the normal end message for the command. This does not appear
* to be the case. An invalid logical block number returned an endcode
* of 0200 instead of the 0241 (read) that was expected.
printf("endcd=%o, stat=%o\n", mp
->mscp_opcode
, mp
->mscp_status
);
case M_OP_WRITE
|M_OP_END
:
bp
= (struct buf
*)mp
->mscp_cmdref
;
ubarelse(um
->um_ubanum
, (int *)&bp
->b_ubinfo
);
* Unlink buffer from I/O wait queue.
bp
->av_back
->av_forw
= bp
->av_forw
;
bp
->av_forw
->av_back
= bp
->av_back
;
if (cpu
== VAX_750
&& um
->um_tab
.b_active
== 0
&& udwtab
[um
->um_ctlr
].av_forw
== &udwtab
[um
->um_ctlr
]) {
printf("udintr: um_ubinfo == 0\n");
ubarelse(um
->um_ubanum
, &um
->um_ubinfo
);
dp
= &udutab
[ui
->ui_unit
];
dk_busy
&= ~(1<<ui
->ui_dk
);
if (st
== M_ST_OFFLN
|| st
== M_ST_AVLBL
) {
ui
->ui_flags
= 0; /* mark unit offline */
* Link the buffer onto the front of the drive queue
if ((bp
->av_forw
= dp
->b_actf
) == 0)
* Link the drive onto the controller queue
if (um
->um_tab
.b_actf
== NULL
)
um
->um_tab
.b_actl
->b_forw
= dp
;
if (cpu
== VAX750
&& um
->um_ubinfo
== 0)
uballoc(um
->um_ubanum
, (caddr_t
)0, 0,
printd("status %o\n", mp
->mscp_status
);
bp
->b_resid
= bp
->b_bcount
- mp
->mscp_bytecnt
;
case M_OP_GTUNT
|M_OP_END
:
printd("GTUNT end packet status = 0x%x media id 0x%x\n"
ra_info
[ui
->ui_unit
].rastatus
= st
;
ra_info
[ui
->ui_unit
].ratype
= mp
->mscp_mediaid
;
printf("uda: unknown packet\n");
uderror(um
, (struct mslg
*)mp
);
* Process an error log message
* For now, just log the error on the console.
* Only minimal decoding is done, only "useful"
* information is printed. Eventually should
* send message to an error logger.
register struct uba_ctlr
*um
;
register struct mslg
*mp
;
if(!(mp
->mslg_flags
& (M_LF_SUCC
| M_LF_CONT
)))
printf("uda%d: hard error\n");
mprintf("uda%d: %s error, ", um
->um_ctlr
,
mp
->mslg_flags
& ( M_LF_SUCC
| M_LF_CONT
) ? "soft" : "hard");
switch (mp
->mslg_format
) {
mprintf("controller error, event 0%o\n", mp
->mslg_event
);
mprintf("host memory access error, event 0%o, addr 0%o\n",
mp
->mslg_event
, mp
->mslg_busaddr
);
mprintf("disk transfer error, unit %d, grp 0x%x, hdr 0x%x, event 0%o\n",
mp
->mslg_unit
, mp
->mslg_group
, mp
->mslg_hdr
,
mprintf("SDI error, unit %d, event 0%o, hdr 0x%x\n",
mp
->mslg_unit
, mp
->mslg_event
, mp
->mslg_hdr
);
mprintf("\t0x%x",mp
->mslg_sdistat
[i
] & 0xff);
mprintf("small disk error, unit %d, event 0%o, cyl %d\n",
mp
->mslg_unit
, mp
->mslg_event
, mp
->mslg_sdecyl
);
mprintf("unknown error, unit %d, format 0%o, event 0%o\n",
mp
->mslg_unit
, mp
->mslg_format
, mp
->mslg_event
);
register long *p
= (long *)mp
;
for (i
= 0; i
< mp
->mslg_header
.uda_msglen
; i
+= sizeof(*p
))
* Find an unused command packet
register struct mscp
*mp
;
register struct udaca
*cp
;
register struct uda_softc
*sc
;
cp
= &uda
[um
->um_ctlr
].uda_ca
;
sc
= &uda_softc
[um
->um_ctlr
];
* If no credits, can't issue any commands
* until some outstanding commands complete.
if(((cp
->ca_cmddsc
[i
]&(UDA_OWN
|UDA_INT
))==UDA_INT
)&&
sc
->sc_credits
--; /* committed to issuing a command */
cp
->ca_cmddsc
[i
] &= ~UDA_INT
;
mp
= &uda
[um
->um_ctlr
].uda_cmd
[i
];
mp
->mscp_unit
= mp
->mscp_modifier
= 0;
mp
->mscp_opcode
= mp
->mscp_flags
= 0;
mp
->mscp_bytecnt
= mp
->mscp_buffer
= 0;
mp
->mscp_errlgfl
= mp
->mscp_copyspd
= 0;
sc
->sc_lastcmd
= (i
+ 1) % NCMD
;
register int unit
= udunit(dev
);
return (physio(udstrategy
, &rudbuf
[unit
], dev
, B_READ
, minphys
, uio
));
register int unit
= udunit(dev
);
return (physio(udstrategy
, &rudbuf
[unit
], dev
, B_WRITE
, minphys
, uio
));
register struct uba_ctlr
*um
;
register struct uba_device
*ui
;
register struct buf
*bp
, *dp
;
for (d
= 0; d
< NUDA
; d
++) {
if ((um
= udminfo
[d
]) == 0 || um
->um_ubanum
!= uban
||
um
->um_tab
.b_actf
= um
->um_tab
.b_actl
= 0;
uda_softc
[d
].sc_state
= S_IDLE
;
uda_softc
[d
].sc_mapped
= 0; /* Rich */
for (unit
= 0; unit
< NRA
; unit
++) {
if ((ui
= uddinfo
[unit
]) == 0)
if (ui
->ui_alive
== 0 || ui
->ui_mi
!= um
)
udutab
[unit
].b_active
= 0;
udutab
[unit
].b_qsize
= 0;
for (bp
= udwtab
[d
].av_forw
; bp
!= &udwtab
[d
]; bp
= nbp
) {
* Link the buffer onto the drive queue
dp
= &udutab
[udunit(bp
->b_dev
)];
dp
->b_actl
->av_forw
= bp
;
* Link the drive onto the controller queue
if (um
->um_tab
.b_actf
== NULL
)
um
->um_tab
.b_actl
->b_forw
= dp
;
#define ca_Rspdsc ca_rspdsc[0]
#define ca_Cmddsc ca_rspdsc[1]
#define uda_Rsp uda_rsp[0]
#define uda_Cmd uda_cmd[0]
struct udadevice
*udaddr
;
register struct uba_regs
*uba
;
register struct uba_device
*ui
;
register struct uda
*udp
;
#define phys(cast, addr) ((cast)((int)addr & 0x7fffffff))
ui
= phys(struct uba_device
*, uddinfo
[unit
]);
uba
= phys(struct uba_hd
*, ui
->ui_hd
)->uh_physuba
;
udaddr
= (struct udadevice
*)ui
->ui_physaddr
;
udp
= phys(struct uda
*, &udad
[ui
->ui_ctlr
]);
num
= btoc(sizeof(struct uda
)) + 1;
io
= &uba
->uba_map
[NUBMREG
-num
];
*(int *)io
++ = UBAMR_MRV
|(btop(udp
)+i
);
ud_ubaddr
= (struct uda
*)(((int)udp
& PGOFSET
)|((NUBMREG
-num
)<<9));
while ((udaddr
->udasa
& UDA_STEP1
) == 0)
if(udaddr
->udasa
& UDA_ERR
) return(EFAULT
);
while ((udaddr
->udasa
& UDA_STEP2
) == 0)
if(udaddr
->udasa
& UDA_ERR
) return(EFAULT
);
udaddr
->udasa
= (short)&ud_ubaddr
->uda_ca
.ca_ringbase
;
while ((udaddr
->udasa
& UDA_STEP3
) == 0)
if(udaddr
->udasa
& UDA_ERR
) return(EFAULT
);
udaddr
->udasa
= (short)(((int)&ud_ubaddr
->uda_ca
.ca_ringbase
) >> 16);
while ((udaddr
->udasa
& UDA_STEP4
) == 0)
if(udaddr
->udasa
& UDA_ERR
) return(EFAULT
);
udp
->uda_ca
.ca_Rspdsc
= (long)&ud_ubaddr
->uda_Rsp
.mscp_cmdref
;
udp
->uda_ca
.ca_Cmddsc
= (long)&ud_ubaddr
->uda_Cmd
.mscp_cmdref
;
udp
->uda_Cmd
.mscp_cntflgs
= 0;
udp
->uda_Cmd
.mscp_version
= 0;
if (udcmd(M_OP_STCON
, udp
, udaddr
) == 0) {
udp
->uda_Cmd
.mscp_unit
= ui
->ui_slave
;
if (udcmd(M_OP_ONLIN
, udp
, udaddr
) == 0) {
rasizes
= ra_info
[ui
->ui_unit
].ra_sizes
;
maxsz
= rasizes
[minor(dev
)&07].nblocks
;
blkoff
= rasizes
[minor(dev
)&07].blkoff
;
maxsz
= ra_info
[unit
].radsize
-blkoff
;
if (dumplo
+ num
>= maxsz
)
blk
= num
> DBSIZE
? DBSIZE
: num
;
for (i
= 0; i
< blk
; i
++)
*(int *)io
++ = (btop(start
)+i
) | UBAMR_MRV
;
udp
->uda_Cmd
.mscp_lbn
= btop(start
) + blkoff
;
udp
->uda_Cmd
.mscp_unit
= ui
->ui_slave
;
udp
->uda_Cmd
.mscp_bytecnt
= blk
*NBPG
;
udp
->uda_Cmd
.mscp_buffer
= 0;
if (udcmd(M_OP_WRITE
, udp
, udaddr
) == 0) {
register struct uda
*udp
;
struct udadevice
*udaddr
;
udp
->uda_Cmd
.mscp_opcode
= op
;
udp
->uda_Rsp
.mscp_header
.uda_msglen
= mscp_msglen
;
udp
->uda_Cmd
.mscp_header
.uda_msglen
= mscp_msglen
;
udp
->uda_ca
.ca_Rspdsc
|= UDA_OWN
|UDA_INT
;
udp
->uda_ca
.ca_Cmddsc
|= UDA_OWN
|UDA_INT
;
if (udaddr
->udasa
&UDA_ERR
)
printf("Udaerror udasa (%x)\n", udaddr
->udasa
&0xffff);
if (udp
->uda_ca
.ca_cmdint
)
udp
->uda_ca
.ca_cmdint
= 0;
if (udp
->uda_ca
.ca_rspint
)
udp
->uda_ca
.ca_rspint
= 0;
if (udp
->uda_Rsp
.mscp_opcode
!= (op
|M_OP_END
) ||
(udp
->uda_Rsp
.mscp_status
&M_ST_MASK
) != M_ST_SUCC
) {
printf("error: com %d opc 0x%x stat 0x%x\ndump ",
udp
->uda_Rsp
.mscp_opcode
,
udp
->uda_Rsp
.mscp_status
);
if (unit
>= NRA
|| (ui
= uddinfo
[unit
]) == 0 || ui
->ui_alive
== 0
rasizes
= ra_info
[ui
->ui_unit
].ra_sizes
;
return (rasizes
[minor(dev
) & 07].nblocks
);