* Multi Protocol Communications Controller (MPCC).
* Asynchronous Terminal Protocol Support.
#include "../machine/pte.h"
#include "../machine/mtpr.h"
#include "../tahoevba/vbavar.h"
#include "../tahoevba/mpreg.h"
#define MPPORT(n) ((n) & 0xf)
#define MPUNIT(n) ((n) >> 4)
* Driver information for auto-configuration stuff.
int mpprobe(), mpattach(), mpintr();
struct vba_device
*mpinfo
[NMP
];
struct vba_driver mpdriver
=
{ mpprobe
, 0, mpattach
, 0, mpstd
, "mp", mpinfo
};
struct mpevent
*mpparam();
struct mpevent
*mp_getevent();
* The following structure is needed to deal with mpcc's convoluted
* method for locating it's mblok structures (hold your stomach).
* When an mpcc is reset at boot time it searches host memory
* looking for a string that says ``ThIs Is MpCc''. The mpcc
* then reads the structure to locate the pointer to it's mblok
* structure (you can wretch now).
char s
[12]; /* `ThIs Is MpCc'' */
struct mblok
*mbloks
[NMP
]; /* can support at most 16 mpcc's */
} mpbogus
= { 'T','h','I','s',' ','I','s',' ','M','p','C','c' };
* Software state per unit.
u_int ms_ivec
; /* interrupt vector */
u_int ms_softCAR
; /* software carrier for async */
struct mblok
*ms_mb
; /* mpcc status area */
struct vb_buf ms_buf
; /* vba resources for ms_mb */
struct hxmtl ms_hxl
[MPMAXPORT
];/* host transmit list */
struct asyncparam ms_async
[MPMAXPORT
][MPINSET
];/* async structs */
char ms_cbuf
[MPMAXPORT
][MPOUTSET
][CBSIZE
];/* input character buffers */
struct tty mp_tty
[NMP
*MPCHUNK
];
register struct mpsoftc
*ms
;
br
= 0; cvec
= br
; br
= cvec
;
ms
= &mp_softc
[vi
->ui_unit
];
* Allocate page tables and mblok
* structure (mblok in non-cached memory).
if (vbainit(&ms
->ms_buf
, sizeof (struct mblok
), VB_32BIT
) == 0) {
printf("mp%d: vbainit failed\n", vi
->ui_unit
);
ms
->ms_mb
= (struct mblok
*)ms
->ms_buf
.vb_rawbuf
;
ms
->ms_ivec
= MPINTRBASE
+ 2*vi
->ui_unit
; /* XXX */
br
= 0x14, cvec
= ms
->ms_ivec
; /* XXX */
register struct vba_device
*vi
;
register struct mpsoftc
*ms
= &mp_softc
[vi
->ui_unit
];
ms
->ms_softCAR
= vi
->ui_flags
;
* Setup pointer to mblok, initialize bogus
* status block used by mpcc to locate the pointer
* and then poke the mpcc to get it to search host
* memory to find mblok pointer.
mpbogus
.mbloks
[vi
->ui_unit
] = (struct mblok
*)ms
->ms_buf
.vb_physbuf
;
*(short *)vi
->ui_addr
= 0x100; /* magic */
register struct mpsoftc
*ms
;
int error
, s
, port
, unit
, mpu
;
if (mpu
>= NMP
|| (vi
= mpinfo
[mpu
]) == 0 || vi
->ui_alive
== 0)
if (tp
->t_state
& TS_XCLUDE
&& u
.u_uid
!= 0)
if (ms
->ms_mb
->mb_proto
[port
] != MPPROTO_ASYNC
||
ms
->ms_mb
->mb_status
!= MP_OPOPEN
)
mp
= &ms
->ms_mb
->mb_port
[port
]; /* host mpcc struct */
while (mp
->mp_flags
& MP_PROGRESS
)
sleep((caddr_t
)&tp
->t_canq
, TTIPRI
);
while (tp
->t_state
& TS_WOPEN
)
sleep((caddr_t
)&tp
->t_canq
, TTIPRI
);
if (tp
->t_state
& TS_ISOPEN
) {
tp
->t_addr
= (caddr_t
)ms
;
tp
->t_flags
|= ODDP
|EVENP
|ECHO
;
* Initialize port state: init MPCC interface
* structures for port and setup modem control.
mp
->mp_proto
= MPPROTO_ASYNC
; /* XXX */
error
= mpportinit(ms
, mp
, port
);
mpcmd(ev
, EVCMD_OPEN
, 0, ms
->ms_mb
, port
);
while ((tp
->t_state
& TS_CARR_ON
) == 0)
sleep((caddr_t
)&tp
->t_rawq
, TTIPRI
);
error
= mpmodem(unit
, MMOD_ON
);
while ((tp
->t_state
& TS_CARR_ON
) == 0)
sleep((caddr_t
)&tp
->t_rawq
, TTIPRI
);
error
= (*linesw
[tp
->t_line
].l_open
)(dev
,tp
);
/* wakeup anyone waiting for open to complete */
wakeup((caddr_t
)&tp
->t_canq
);
tp
->t_state
&= ~TS_WOPEN
;
register struct mpport
*mp
;
register struct mpevent
*ev
;
int s
, port
, unit
, error
;
mb
= mp_softc
[MPUNIT(unit
)].ms_mb
;
if (mp
->mp_flags
& MP_PROGRESS
) { /* close in progress */
if (mp
->mp_flags
& MP_REMBSY
) {
mp
->mp_flags
&= ~MP_REMBSY
;
while (mp
->mp_flags
& MP_PROGRESS
)
sleep((caddr_t
)&tp
->t_canq
,TTIPRI
);
mp
->mp_flags
|= MP_PROGRESS
;
(*linesw
[tp
->t_line
].l_close
)(tp
);
if (tp
->t_state
& TS_HUPCLS
|| (tp
->t_state
& TS_ISOPEN
) == 0)
if (error
= mpmodem(unit
, MMOD_OFF
)) {
mp
->mp_flags
&= ~MP_PROGRESS
;
while (tp
->t_state
& TS_FLUSH
) /* ??? */
sleep((caddr_t
)&tp
->t_state
, TTOPRI
); /* ??? */
ev
= mp_getevent(mp
, unit
);
mpcmd(ev
, EVCMD_CLOSE
, 0, mb
, port
);
if (mp
->mp_flags
& MP_REMBSY
)
* Read from an mpcc port.
tp
= &mp_tty
[minor(dev
)];
return ((*linesw
[tp
->t_line
].l_read
)(tp
, uio
));
tp
= &mp_tty
[minor(dev
)];
return ((*linesw
[tp
->t_line
].l_write
)(tp
, uio
));
mpioctl(dev
, cmd
, data
, flag
)
register struct mpsoftc
*ms
;
register struct mpevent
*ev
;
register struct mpport
*mp
;
int s
, port
, error
, unit
;
ms
= &mp_softc
[MPUNIT(unit
)];
error
= (*linesw
[tp
->t_line
].l_ioctl
)(tp
, cmd
, data
, flag
);
error
= ttioctl(tp
, cmd
, data
, flag
);
if (cmd
== TIOCSETP
|| cmd
== TIOCSETN
|| cmd
== TIOCLBIS
||
cmd
== TIOCLBIC
|| cmd
== TIOCLSET
) {
mpcmd(ev
, EVCMD_IOCTL
, A_CHGALL
, mb
,
case TIOCSBRK
: /* send break */
case TIOCCBRK
: /* clear break */
ev
= mp_getevent(mp
, unit
);
(cmd
== TIOCSBRK
? A_BRKON
: A_BRKOFF
),
case TIOCSDTR
: /* set dtr control line */
case TIOCCDTR
: /* clear dtr control line */
register struct mpevent
*ev
;
register struct mpport
*mp
;
register struct asyncparam
*asp
;
ms
= &mp_softc
[MPUNIT(unit
)];
ev
= mp_getevent(mp
, unit
); /* XXX */
asp
= &ms
->ms_async
[port
][mp
->mp_on
?mp
->mp_on
-1:MPINSET
-1];
asp
->ap_xon
= tp
->t_startc
;
asp
->ap_xoff
= tp
->t_stopc
;
asp
->ap_xena
= ((tp
->t_flags
& RAW
) ? MPA_DIS
: MPA_ENA
);
asp
->ap_xany
= ((tp
->t_flags
& DECCTQ
) ? MPA_DIS
: MPA_ENA
);
if (tp
->t_flags
& (RAW
|LITOUT
|PASS8
)) {
asp
->ap_parity
= MPPAR_NONE
;
if ((tp
->t_flags
& (EVENP
|ODDP
)) == ODDP
)
asp
->ap_parity
= MPPAR_ODD
;
asp
->ap_parity
= MPPAR_EVEN
;
if (tp
->t_ospeed
== B110
)
if (tp
->t_ospeed
== EXTA
|| tp
->t_ospeed
== EXTB
)
asp
->ap_baud
= tp
->t_ospeed
;
asp
->ap_loop
= MPA_DIS
; /* disable loopback */
asp
->ap_rtimer
= A_RCVTIM
; /* default receive timer */
if (ms
->ms_softCAR
& (1<<port
))
setm(&asp
->ap_modem
, A_DTR
, ASSERT
);
setm(&asp
->ap_modem
, A_DTR
, AUTO
);
seti(&asp
->ap_intena
, A_DCD
);
register struct mpevent
*ev
;
register struct mpport
*mp
;
int port
, unit
, xcnt
, n
, s
, i
;
ms
= &mp_softc
[MPUNIT(unit
)];
for (i
= 0; i
< MPXMIT
; i
++) {
if (tp
->t_state
& (TS_TIMEOUT
|TS_BUSY
|TS_TTSTOP
))
if (outq
.c_cc
<= TTLOWAT(tp
)) {
if (tp
->t_state
& TS_ASLEEP
) {
tp
->t_state
&= ~TS_ASLEEP
;
wakeup((caddr_t
)&tp
->t_outq
);
selwakeup(tp
->t_wsel
, tp
->t_state
& TS_WCOLL
);
tp
->t_state
&= ~TS_WCOLL
;
* If we're not currently busy outputting,
* and there is data to be output, set up
* port transmit structure to send to mpcc.
if (tp
->t_flags
& (RAW
|LITOUT
))
timeout(ttrstrt
, (caddr_t
)tp
, (n
&0177)+6);
tp
->t_state
|= TS_TIMEOUT
;
hxp
->dblock
[i
] = (caddr_t
)vtoph(0, (int)outq
.c_cf
);
xcnt
++; /* count of xmts to send */
* If data to send, poke mpcc.
ev
= mp_getevent(mp
, unit
);
tp
->t_state
&= ~(TS_BUSY
|TS_TIMEOUT
);
mpcmd(ev
, EVCMD_WRITE
, 0, mb
, MPPORT(unit
));
* Advance cc bytes from q but don't free memory.
register struct clist
*q
;
register struct cblock
*bp
;
while (cc
>0 && q
->c_cc
) {
bp
= (struct cblock
*)((int)q
->c_cf
& ~CROUND
);
if ((int)bp
== (((int)q
->c_cl
-1) & ~CROUND
)) {
end
= (char *)((int)bp
+ sizeof (struct cblock
));
q
->c_cf
= bp
->c_next
->c_info
;
q
->c_cf
= q
->c_cl
= NULL
;
* Stop output on a line, e.g. for ^S/^Q or output flush.
/* XXX: DISABLE TRANSMITTER */
if (tp
->t_state
& TS_BUSY
) {
if ((tp
->t_state
& TS_TTSTOP
) == 0)
* Initialize an async port's MPCC state.
register struct mpsoftc
*ms
;
register struct mpport
*mp
;
register struct mpevent
*ev
;
mp
->mp_on
= mp
->mp_off
= 0;
for (i
= 0; ev
< &mp
->mp_recvq
[MPINSET
]; ev
++, i
++) {
ev
->ev_status
= EVSTATUS_FREE
;
ev
->ev_un
.hxl
= (struct hxmtl
*) vtoph(0, &ms
->ms_hxl
[port
]);
ev
->ev_params
= (caddr_t
) vtoph(0, &ms
->ms_async
[port
][i
]);
for (i
= 0; ev
< &mp
->mp_sendq
[MPOUTSET
]; ev
++, i
++) {
/* init so that L2 can't send any events */
/* to host until open has completed */
ev
->ev_status
= EVSTATUS_FREE
;
ptr
= (caddr_t
) &ms
->ms_cbuf
[port
][i
][0];
ev
->ev_un
.rcvblk
= (u_char
*)vtoph(0, ptr
);
ev
->ev_params
= (caddr_t
) vtoph(0, ptr
);
* Send an event to an mpcc.
mpcmd(ev
, cmd
, flags
, mb
, port
)
register struct mpevent
*ev
;
/* move host values to inbound entry */
/* show event ready for mpcc */
ev
->ev_status
= EVSTATUS_GO
;
* Return the next available event entry for the indicated port.
register struct mpport
*mp
;
register struct mpevent
*ev
;
ev
= &mp
->mp_recvq
[mp
->mp_on
];
if (ev
->ev_status
!= EVSTATUS_FREE
)
* If not a close request, verify one extra
* event is available for closing the port.
if ((mp
->mp_flags
&& MP_PROGRESS
) == 0) {
if ((i
= mp
->mp_on
+ 1) >= MPINSET
)
if (mp
->mp_recvq
[i
].ev_status
!= EVSTATUS_FREE
)
/* init inbound fields marking this entry as busy */
ev
->ev_status
= EVSTATUS_BUSY
;
/* adjust pointer to next available inbound entry */
adjptr(mp
->mp_on
, MPINSET
);
log(LOG_ERR
, "mp%d: port%d, out of events", MPUNIT(unit
), MPPORT(unit
));
return ((struct mpevent
*)0);
struct mpsoftc
*ms
= &mp_softc
[MPUNIT(unit
)];
register struct mpport
*mp
;
register struct mpevent
*ev
;
register struct asyncparam
*asp
;
mp
= &ms
->ms_mb
->mb_port
[port
];
ev
= mp_getevent(mp
, unit
);
asp
= &ms
->ms_async
[port
][mp
->mp_on
?mp
->mp_on
-1:MPINSET
-1];
if (ms
->ms_softCAR
& (1 << port
))
setm(&asp
->ap_modem
, A_DTR
, ASSERT
);
setm(&asp
->ap_modem
, A_DTR
, AUTO
);
seti(&asp
->ap_intena
, A_DCD
);
setm(&asp
->ap_modem
, 0, DROP
);
seti(&asp
->ap_intena
, 0);
mpcmd(ev
, EVCMD_IOCTL
, A_MDMCHG
, ms
->ms_mb
, port
);
* Set up the modem control structure according to mask.
* Each set bit in the mask means assert the corresponding
* modem control line, otherwise, it will be dropped.
* RTS is special since it can either be asserted, dropped
* or put in auto mode for auto modem control.
register struct mdmctl
*mc
;
mc
->mc_rngdsr
= (mask
& A_RNGDSR
) ? ASSERT
: DROP
;
mc
->mc_rate
= (mask
& A_RATE
) ? ASSERT
: DROP
;
mc
->mc_dcd
= (mask
& A_DCD
) ? ASSERT
: DROP
;
mc
->mc_sectx
= (mask
& A_SECTX
) ? ASSERT
: DROP
;
mc
->mc_cts
= (mask
& A_CTS
) ? ASSERT
: DROP
;
mc
->mc_secrx
= (mask
& A_SECRX
) ? ASSERT
: DROP
;
mc
->mc_dtr
= (mask
& A_DTR
) ? ASSERT
: DROP
;
* Set up the status change enable field from mask.
* When a signal is enabled in this structure and
* and a change in state on a corresponding modem
* control line occurs, a status change event will
* be delivered to the host.
register struct mdmctl
*mc
;
mc
->mc_rngdsr
= (mask
& A_RNGDSR
) ? MDM_ON
: MDM_OFF
;
mc
->mc_rate
= (mask
& A_RATE
) ? MDM_ON
: MDM_OFF
;
mc
->mc_dcd
= (mask
& A_DCD
) ? MDM_ON
: MDM_OFF
;
mc
->mc_sectx
= (mask
& A_SECTX
) ? MDM_ON
: MDM_OFF
;
mc
->mc_cts
= (mask
& A_CTS
) ? MDM_ON
: MDM_OFF
;
mc
->mc_secrx
= (mask
& A_SECRX
) ? MDM_ON
: MDM_OFF
;
mc
->mc_dtr
= (mask
& A_DTR
) ? MDM_ON
: MDM_OFF
;
mc
->mc_rts
= (mask
& A_RTS
) ? MDM_ON
: MDM_OFF
;
register struct mpport
*mp
;
if (mp
->mp_proto
== MPPROTO_ASYNC
) {
mp
->mp_flags
= MP_REMBSY
;
/* flush I/O queues and send hangup signals */
tp
= &mp_tty
[mb
->mb_unit
*MPCHUNK
+port
];
tp
->t_state
&= ~TS_CARR_ON
;
ttyflush(tp
, FREAD
|FWRITE
);
gsignal(tp
->t_pgrp
, SIGHUP
);
gsignal(tp
->t_pgrp
, SIGKILL
);
register struct mblok
*mb
;
register struct mpport
*mp
;
register struct mpevent
*ev
;
for (i
= mp
->mp_off
; i
!= mp
->mp_on
; i
= (i
+1 % MPINSET
)) {
ev
->ev_status
= EVSTATUS_DONE
;
list
[0] = port
, list
[1] = MPPORT_EOL
;
/* Clear async for port */
mp
->mp_proto
= MPPROTO_UNUSED
;
mp_tty
[unit
*MPCHUNK
+ port
].t_state
= 0;
for (ev
= &mp
->mp_sendq
[0]; ev
< &mp
->mp_sendq
[MPOUTSET
]; ev
++) {
ev
->ev_status
= EVSTATUS_FREE
;
for (ev
= &mp
->mp_recvq
[0]; ev
< &mp
->mp_recvq
[MPINSET
]; ev
++) {
ev
->ev_status
= EVSTATUS_FREE
;
* MPCC interrupt handler.
register struct mblok
*mb
;
register struct his
*his
;
mb
= mp_softc
[mpcc
].ms_mb
;
printf("mp%d: stray interrupt\n", mpcc
);
his
->semaphore
&= ~MPSEMA_AVAILABLE
;
* Check for events to be processed.
if (his
->proto
[MPPROTO_ASYNC
].outbdone
[0] != MPPORT_EOL
)
mprintr(mpcc
, his
->proto
[MPPROTO_ASYNC
].outbdone
);
if (his
->proto
[MPPROTO_ASYNC
].inbdone
[0] != MPPORT_EOL
)
mpxintr(mpcc
, his
->proto
[MPPROTO_ASYNC
].inbdone
);
if (mb
->mb_harderr
|| mb
->mb_softerr
)
his
->semaphore
|= MPSEMA_AVAILABLE
;
* Handler for processing completion of transmitted events.
register struct mpport
*mp
;
register struct mpevent
*ev
;
register struct mblok
*mb
;
register struct asyncparam
*ap
;
mb
= mp_softc
[unit
].ms_mb
;
for (j
= 0; j
< MPMAXPORT
&& ((port
= *list
++) != MPPORT_EOL
); j
++) {
* Process each completed entry in the inbound queue.
tp
= &mp_tty
[unit
*MPCHUNK
+ port
];
#define nextevent(mp) &mp->mp_recvq[mp->mp_off]
for(; ev
->ev_status
& EVSTATUS_DONE
; ev
= nextevent(mp
)) {
ap
= &ms
->ms_async
[port
][mp
->mp_off
];
mppurge(ap
, sizeof (*ap
));
* Open completion, start all reads and
* assert modem status information.
for (i
= 0; i
< MPOUTSET
; i
++)
mp
->mp_sendq
[i
].ev_status
= EVSTATUS_GO
;
(*linesw
[tp
->t_line
].l_modem
)
(tp
, ap
->ap_modem
.mc_dcd
== ASSERT
);
* Close completion, flush all pending
* transmissions, free resources, and
* cleanup mpcc port state.
for (i
= 0; i
< MPOUTSET
; i
++) {
mp
->mp_sendq
[i
].ev_status
=
mp
->mp_sendq
[i
].ev_un
.rcvblk
= 0;
mp
->mp_sendq
[i
].ev_params
= 0;
tp
->t_state
&= ~TS_CARR_ON
;
mp
->mp_on
= mp
->mp_off
= mp
->mp_nextrcv
= 0;
mp
->mp_flags
&= ~MP_PROGRESS
;
mp
->mp_proto
= MPPROTO_UNUSED
;
wakeup((caddr_t
)&tp
->t_canq
); /* ??? */
* Nothing to do, just pitch.
* Transmission completed, update tty
* state and restart output.
if (tp
->t_state
& TS_FLUSH
) {
tp
->t_state
&= ~TS_FLUSH
;
wakeup((caddr_t
)&tp
->t_state
);
for(i
= 0; i
< ev
->ev_count
; i
++)
ndflush(&tp
->t_outq
, cc
);
case A_SIZERR
: /*# error in xmt data size */
mplog(unit
, port
, A_XSIZE
, 0);
case A_NXBERR
: /*# no more xmt evt buffers */
mplog(unit
, port
, A_NOXBUF
, 0);
mplog(unit
, port
, A_INVCMD
, ev
->ev_cmd
);
/* re-init all values in this entry */
/* show this entry is available for use */
ev
->ev_status
= EVSTATUS_FREE
;
adjptr(mp
->mp_off
, MPINSET
);
* Handler for processing received events.
register struct mpport
*mp
;
register struct mpevent
*ev
;
mb
= mp_softc
[unit
].ms_mb
;
for (i
= 0; i
< MPMAXPORT
&& (port
= *list
++) != MPPORT_EOL
; i
++) {
tp
= &mp_tty
[unit
*MPCHUNK
+ port
];
ev
= &mp
->mp_sendq
[mp
->mp_nextrcv
];
while (ev
->ev_status
& EVSTATUS_DONE
) {
if (ev
->ev_cmd
!= EVCMD_READ
&&
ev
->ev_cmd
!= EVCMD_STATUS
) {
mplog(unit
, port
, "unexpected command",
if (ev
->ev_cmd
== EVCMD_STATUS
) {
* Status change, look for carrier changes.
if (ev
->ev_opts
== DCDASRT
||
(*linesw
[tp
->t_line
].l_modem
)
(tp
, ev
->ev_opts
== DCDASRT
);
"unexpect status command",
if ((tp
->t_state
& (TS_ISOPEN
|TS_WOPEN
)) == 0)
cp
= ms
->ms_cbuf
[port
][mp
->mp_nextrcv
];
* A null character is inserted, potentially
* when a break or framing error occurs. If
* we're not in raw mode, substitute the
(ev
->ev_error
== BRKASRT
||
ev
->ev_error
== FRAMERR
))
if ((tp
->t_flags
&RAW
) == 0)
(*linesw
[tp
->t_line
].l_rint
)(*cp
++, tp
);
/* setup for next read */
ptr
= (caddr_t
)&mp_softc
[unit
].ms_cbuf
[port
][mp
->mp_nextrcv
][0];
ev
->ev_un
.rcvblk
= (u_char
*)vtoph(0, ptr
);
ev
->ev_params
= (caddr_t
) vtoph(0, ptr
);
case RCVDTA
: /* Normal (good) rcv data */
/* do not report the following */
/* they are "normal" errors */
case FRAMERR
: /* frame error */
case BRKASRT
: /* Break condition */
case PARERR
: /* parity error */
case OVRNERR
: /* Overrun error */
rcverr
= "overrun error";
case OVFERR
: /* Overflow error */
rcverr
= "overflow error";
rcverr
= "undefined rcv error";
mplog(unit
, port
, rcverr
, ev
->ev_error
);
ev
->ev_status
= EVSTATUS_GO
; /* start next read */
adjptr(mp
->mp_nextrcv
, MPOUTSET
);
ev
= &mp
->mp_sendq
[mp
->mp_nextrcv
];
* Log an mpcc diagnostic.
mplog(unit
, port
, cp
, flags
)
log(LOG_ERR
, "mp%d: port%d, %s (%d)\n",
log(LOG_ERR
, "mp%d: port%d, %s\n", unit
, port
, cp
);
register struct mblok
*mb
;
mb
->mb_mpintclk
= (caddr_t
)0;
*(u_short
*)mpinfo
[mb
->mb_unit
]->ui_addr
= 2;
register struct mblok
*mb
;
mb
->mb_intr
[port
] |= MPSEMA_WORK
;
if (++mb
->mb_mpintcnt
== MPHOSTINT
) {
*(u_short
*)mpinfo
[mb
->mb_unit
]->ui_addr
= 2;
untimeout(mptimeint
, mb
);
if (mb
->mb_mpintclk
== 0) {
timeout(mptimeint
, mb
, 4);
mb
->mb_mpintclk
= (caddr_t
)1;
static char *mpherrmsg
[] = {
"Bus error", /* MPBUSERR */
"Address error", /* ADDRERR */
"Undefined ecc interrupt", /* UNDECC */
"Undefined interrupt", /* UNDINT */
"Power failure occurred", /* PWRFL */
"Stray transmit done interrupt", /* NOXENTRY */
"Two fast timers on one port", /* TWOFTMRS */
"Interrupt queue full", /* INTQFULL */
"Interrupt queue ack error", /* INTQERR */
"Uncorrectable dma parity error", /* CBPERR */
"32 port ACAP failed power up", /* ACPDEAD */
#define NHERRS (sizeof (mpherrmsg) / sizeof (mpherrmsg[0]))
register struct mblok
*mb
;
switch (mb
->mb_softerr
) {
case DMAPERR
: /* dma parity error */
cp
= "local memory ecc error";
log(LOG_ERR
, "mp%d: soft error, %s", unit
, cp
);
if (mb
->mb_harderr
< NHERRS
)
cp
= mpherrmsg
[mb
->mb_harderr
];
log(LOG_ERR
, "mp%d: hard error, %s", unit
, cp
);
if (mb
->mb_status
== MP_OPOPEN
) {
for (i
= 0; i
< MPMAXPORT
; i
++) {
mb
->mb_proto
[i
] = MPPROTO_UNUSED
;
for (; cc
>= 0; addr
+= NBPG
, cc
-= NBPG
)
* MPCC Download Pseudo-device.
char mpdlbuf
[MPDLBUFSIZE
];
int mpdlbusy
; /* interlock on download buffer */
if (mpu
>= NMP
|| (vi
= mpinfo
[mpu
]) == 0 || vi
->ui_alive
== 0)
register struct mpsoftc
*ms
= &mp_softc
[MPUNIT(minor(dev
))];
register struct mpdl
*dl
;
if (ms
->ms_mb
== 0 || ms
->ms_mb
->mb_status
!= MP_DLOPEN
)
dl
->mpdl_count
= uio
->uio_iov
->iov_len
;
dl
->mpdl_data
= (caddr_t
) vtoph((struct proc
*)0, mpdlbuf
);
if (error
= uiomove(mpdlbuf
, dl
->mpdl_count
, UIO_WRITE
, uio
))
uio
->uio_resid
-= dl
->mpdl_count
; /* set up return from write */
dl
->mpdl_cmd
= MPDLCMD_NORMAL
;
register struct mblok
*mb
= mp_softc
[MPUNIT(minor(dev
))].ms_mb
;
if (mb
== 0 || mb
->mb_status
!= MP_DLDONE
) {
if (mpbogus
.mb
== mpbogus
.mbloks
[MPUNIT(minor(dev
))])
mb
->mb_status
= MP_OPOPEN
;
/* set to dead, for board handshake */
mb
->mb_hostint
.imok
= MPIMOK_DEAD
;
mpdlioctl(dev
, cmd
, data
, flag
)
register struct mblok
*mb
;
register struct mpdl
*dl
;
int unit
, error
, s
, i
, j
;
mb
= mp_softc
[unit
=MPUNIT(minor(dev
))].ms_mb
;
bcopy(data
, (caddr_t
)mb
->mb_proto
, sizeof (mb
->mb_proto
));
bcopy(data
, (caddr_t
)&mb
->mb_hiport
, 2*(sizeof(mb
->mb_hiport
)));
dl
->mpdl_cmd
= MPIOENDDL
&IOCPARM_MASK
;
mb
->mb_status
= MP_DLDONE
;
dl
->mpdl_cmd
= MPIOENDCODE
&IOCPARM_MASK
;
bcopy(data
, mpdlbuf
, sizeof (struct abdcf
));
dl
->mpdl_data
= (caddr_t
) vtoph((struct proc
*)0, mpdlbuf
);
dl
->mpdl_count
= sizeof (struct abdcf
);
dl
->mpdl_cmd
= MPIOASYNCNF
&IOCPARM_MASK
;
sleep((caddr_t
)&mpdlbusy
, PZERO
+1);
/* initialize the downloading interface */
mpbogus
.mb
= mpbogus
.mbloks
[unit
];
dl
->mpdl_status
= EVSTATUS_FREE
;
dl
->mpdl_data
= (char *) 0;
mb
->mb_ivec
= mp_softc
[unit
].ms_ivec
+1; /* download vector */
mb
->mb_status
= MP_DLPEND
;
mb
->mb_diagswitch
[0] = 'A';
mb
->mb_diagswitch
[1] = 'P';
*(u_short
*)mpinfo
[unit
]->ui_addr
= 2;
timeout(mpdltimeout
, mb
, 30*hz
); /* approx 15 seconds */
sleep((caddr_t
)&mb
->mb_status
, PZERO
+1);
if (mb
->mb_status
== MP_DLOPEN
) {
untimeout(mpdltimeout
, mb
);
} else if (mb
->mb_status
== MP_DLTIME
) {
log(LOG_ERR
, "mp%d: start download: unknown status %x",
bzero(mb
->mb_port
, sizeof (mb
->mb_port
));
*(u_short
*)mpinfo
[unit
]->ui_addr
= 0x100;
if (mb
->mb_status
== MP_DLOPEN
|| mb
->mb_status
== MP_DLDONE
) {
dl
->mpdl_status
= EVSTATUS_FREE
;
wakeup((caddr_t
)&dl
->mpdl_status
);
for (i
= 0; i
< MPMAXPORT
; i
++) {
if (mb
->mb_harderr
|| mb
->mb_softerr
)
mb
->mb_proto
[i
] = MPPROTO_UNUSED
;
register struct mblok
*mb
= mp_softc
[unit
].ms_mb
;
register struct his
*his
;
mb
->mb_status
= MP_DLDONE
;
mb
->mb_ivec
= mp_softc
[unit
].ms_ivec
;
/* Init host interface structure */
his
->semaphore
= MPSEMA_AVAILABLE
;
for (i
= 0; i
< NMPPROTO
; i
++)
for (j
= 0; j
< MPMAXPORT
; j
++) {
his
->proto
[i
].inbdone
[j
] = MPPORT_EOL
;
his
->proto
[i
].outbdone
[j
] = MPPORT_EOL
;
register struct mblok
*mb
;
register struct mpdl
*dl
;
mb
= mp_softc
[mpcc
].ms_mb
;
printf("mp%d: stray download interrupt\n", mpcc
);
if (dl
->mpdl_status
!= EVSTATUS_DONE
)
dl
->mpdl_status
= EVSTATUS_FREE
;
wakeup((caddr_t
)&dl
->mpdl_status
);
mb
->mb_status
= MP_DLOPEN
;
mb
->mb_nointcnt
= 0; /* reset no interrupt count */
mb
->mb_hostint
.imok
= MPIMOK_DEAD
;
mb
->mb_imokclk
= (caddr_t
)1;
log(LOG_ERR
, "mp%d: mpdlintr, status %x\n",
mp
->mb_status
= MP_DLTIME
;
wakeup((caddr_t
)&mp
->mb_status
);
* Wait for a transfer to complete or a timeout to occur.
register struct mpdl
*dl
;
dl
->mpdl_status
= EVSTATUS_GO
;
while (dl
->mpdl_status
!= EVSTATUS_FREE
) {
sleep((caddr_t
)&dl
->mpdl_status
, PZERO
+1);
if (mpdlerr
== MP_DLERROR
)