/* mba.c 4.26 82/04/11 */
* Massbus driver, arbitrates a massbus among attached devices.
char mbsr_bits
[] = MBSR_BITS
;
* Start activity on a massbus device.
* We are given the device's mba_device structure and activate
* the device via the unit start routine. The unit start
* routine may indicate that it is finished (e.g. if the operation
* was a ``sense'' on a tape drive), that the (multi-ported) unit
* is busy (we will get an interrupt later), that it started the
* unit (e.g. for a non-data transfer operation), or that it has
* set up a data transfer operation and we should start the massbus adaptor.
register struct mba_device
*mi
;
register struct buf
*bp
; /* i/o operation at head of queue */
register struct mba_hd
*mhp
; /* header for mba device is on */
* Get the first thing to do off device queue.
* Make sure the drive is still there before starting it up.
if ((mi
->mi_drv
->mbd_dt
& MBDT_TYPE
) == 0) {
printf("%s%d: nonexistent\n", mi
->mi_driver
->md_dname
,
mi
->mi_tab
.b_actf
= bp
->av_forw
;
* Let the drivers unit start routine have at it
* and then process the request further, per its instructions.
switch ((*mi
->mi_driver
->md_ustart
)(mi
)) {
case MBU_NEXT
: /* request is complete (e.g. ``sense'') */
mi
->mi_tab
.b_actf
= bp
->av_forw
;
case MBU_DODATA
: /* all ready to do data transfer */
* Queue the device mba_device structure on the massbus
* mba_hd structure for processing as soon as the
* data path is available.
if (mhp
->mh_actf
== NULL
)
mhp
->mh_actl
->mi_forw
= mi
;
* If data path is idle, start transfer now.
* In any case the device is ``active'' waiting for the
case MBU_STARTED
: /* driver started a non-data transfer */
* Mark device busy during non-data transfer
* and count this as a ``seek'' on the device.
dk_busy
|= (1 << mi
->mi_dk
);
case MBU_BUSY
: /* dual port drive busy */
* We mark the device structure so that when an
* interrupt occurs we will know to restart the unit.
mi
->mi_tab
.b_flags
|= B_BUSY
;
* Start an i/o operation on the massbus specified by the argument.
* We peel the first operation off its queue and insure that the drive
* is present and on-line. We then use the drivers start routine
* (if any) to prepare the drive, setup the massbus map for the transfer
* and start the transfer.
register struct mba_hd
*mhp
;
register struct mba_device
*mi
;
register struct mba_regs
*mbp
;
* Look for an operation at the front of the queue.
if ((mi
= mhp
->mh_actf
) == NULL
) {
if ((bp
= mi
->mi_tab
.b_actf
) == NULL
) {
mhp
->mh_actf
= mi
->mi_forw
;
* If this device isn't present and on-line, then
* we screwed up, and can't really do the operation.
* Only check for non-tapes because tape drivers check
* ONLINE themselves and because TU78 registers are
if (((com
= mi
->mi_drv
->mbd_dt
) & MBDT_TAP
) == 0)
if ((mi
->mi_drv
->mbd_ds
& MBDS_DREADY
) != MBDS_DREADY
) {
if ((com
& MBDT_TYPE
) == 0) {
printf("%s%d: nonexistent\n", mi
->mi_driver
->md_dname
,
printf("%s%d: not ready\n", mi
->mi_driver
->md_dname
,
mi
->mi_tab
.b_actf
= bp
->av_forw
;
* We can do the operation; mark the massbus active
* and let the device start routine setup any necessary
* device state for the transfer (e.g. desired cylinder, etc
if (mi
->mi_driver
->md_start
) {
if ((com
= (*mi
->mi_driver
->md_start
)(mi
)) == 0)
com
= (bp
->b_flags
& B_READ
) ?
MB_RCOM
|MB_GO
: MB_WCOM
|MB_GO
;
com
= (bp
->b_flags
& B_READ
) ? MB_RCOM
|MB_GO
: MB_WCOM
|MB_GO
;
* Setup the massbus control and map registers and start
mbp
->mba_sr
= -1; /* conservative */
mbp
->mba_var
= mbasetup(mi
);
mbp
->mba_bcr
= -bp
->b_bcount
;
mi
->mi_drv
->mbd_cs1
= com
;
dk_busy
|= 1 << mi
->mi_dk
;
dk_wds
[mi
->mi_dk
] += bp
->b_bcount
>> 6;
* Take an interrupt off of massbus mbanum,
* and dispatch to drivers as appropriate.
register struct mba_hd
*mhp
= &mba_hd
[mbanum
];
register struct mba_regs
*mbp
= mhp
->mh_mba
;
register struct mba_device
*mi
;
extern struct mba_device
*mbaconfig();
* Read out the massbus status register
* and attention status register and clear
* the bits in same by writing them back.
printf("mba%d: control bus hung\n", mbanum
);
/* note: the mbd_as register is shared between drives */
as
= mbp
->mba_drv
[0].mbd_as
& 0xff;
mbp
->mba_drv
[0].mbd_as
= as
;
* If the mba was active, process the data transfer
* complete interrupt; otherwise just process units which
* Clear attention status for drive whose data
* transfer related operation completed,
* and give the dtint driver
* routine a chance to say what is next.
as
&= ~(1 << mi
->mi_drive
);
dk_busy
&= ~(1 << mi
->mi_dk
);
switch ((*mi
->mi_driver
->md_dtint
)(mi
, mbasr
)) {
case MBD_DONE
: /* all done, for better or worse */
* Flush request from drive queue.
mi
->mi_tab
.b_actf
= bp
->av_forw
;
case MBD_RETRY
: /* attempt the operation again */
* Dequeue data transfer from massbus queue;
* if there is still a i/o request on the device
* queue then start the next operation on the device.
* (Common code for DONE and RETRY).
mhp
->mh_actf
= mi
->mi_forw
;
case MBD_RESTARTED
: /* driver restarted op (ecc, e.g.)
* Note that mhp->mh_active is still on.
* Service drives which require attention
* after non-data-transfer operations.
while (drive
= ffs(as
)) {
drive
--; /* was 1 origin */
mi
= mhp
->mh_mbip
[drive
];
if (mi
== NULL
|| mi
->mi_alive
== 0) {
struct mba_drv
*mbd
= &mhp
->mh_mba
->mba_drv
[drive
];
int dt
= mbd
->mbd_dt
& 0xffff;
if (dt
== 0 || dt
== MBDT_MOH
)
fnd
.mi_mba
= mhp
->mh_mba
;
if ((mi
= mbaconfig(&fnd
, dt
)) == NULL
)
for (ms
= mbsinit
; ms
->ms_driver
; ms
++)
if (ms
->ms_driver
== mi
->mi_driver
&&
(ms
->ms_ctlr
== mi
->mi_unit
||
if ((*ms
->ms_driver
->md_slave
)(mi
, ms
)) {
printf("%s%d at %s%d slave %d\n",
ms
->ms_ctlr
= mi
->mi_unit
;
* If driver has a handler for non-data transfer
* interrupts, give it a chance to tell us what to do.
if (mi
->mi_driver
->md_ndint
) {
switch ((*mi
->mi_driver
->md_ndint
)(mi
)) {
case MBN_DONE
: /* operation completed */
mi
->mi_tab
.b_actf
= bp
->av_forw
;
/* fall into common code */
case MBN_RETRY
: /* operation continues */
case MBN_SKIP
: /* ignore unsol. interrupt */
* If there is no non-data transfer interrupt
* routine, then we should just
* restart the unit, leading to a mbstart() soon.
* If there is an operation available and
* the massbus isn't active, get it going.
if (mhp
->mh_actf
&& !mhp
->mh_active
)
/* THHHHATS all folks... */
* Setup the mapping registers for a transfer.
register struct mba_device
*mi
;
register struct mba_regs
*mbap
= mi
->mi_mba
;
struct buf
*bp
= mi
->mi_tab
.b_actf
;
register struct pte
*pte
, *io
;
v
= btop(bp
->b_un
.b_addr
);
o
= (int)bp
->b_un
.b_addr
& PGOFSET
;
npf
= btoc(bp
->b_bcount
+ o
);
rp
= bp
->b_flags
&B_DIRTY
? &proc
[2] : bp
->b_proc
;
if ((bp
->b_flags
& B_PHYS
) == 0)
pte
= &Sysmap
[btop(((int)bp
->b_un
.b_addr
)&0x7fffffff)];
else if (bp
->b_flags
& B_UAREA
)
else if (bp
->b_flags
& B_PAGET
)
pte
= &Usrptmap
[btokmx((struct pte
*)bp
->b_un
.b_addr
)];
panic("mba, zero entry");
*(int *)io
++ = pte
++->pg_pfnum
| PG_V
;
* Init and interrupt enable a massbus adapter.