mirror of
https://github.com/simh/simh.git
synced 2026-03-26 02:05:36 +00:00
279 lines
8.0 KiB
C
279 lines
8.0 KiB
C
|
|
#include <ctype> /* Character type classification macros/routines */
|
|
#include <descrip> /* For VMS descriptor manipulation */
|
|
#include <iodef> /* I/O function code definitions */
|
|
#include <ssdef> /* System service return status code definitions */
|
|
#include <starlet> /* System library routine prototypes */
|
|
#include <stdio> /* ANSI C Standard Input/Output */
|
|
#include <stdlib> /* General utilities */
|
|
#include <string> /* String handling */
|
|
#include <stsdef> /* VMS status code definitions */
|
|
#include "nmadef.h" /* NMA stuff */
|
|
|
|
#define $SUCCESS(status) (((status) & STS$M_SUCCESS) == SS$_NORMAL)
|
|
#define $FAIL(status) (((status) & STS$M_SUCCESS) != SS$_NORMAL)
|
|
|
|
#pragma nomember_alignment
|
|
|
|
struct parm_802e
|
|
{
|
|
short pcli_fmt; /* Format - 802E */
|
|
int fmt_value;
|
|
short pcli_bfn;
|
|
int bnf_value;
|
|
// short pcli_acc;
|
|
// int acc_value;
|
|
short pcli_prm;
|
|
int prm_value;
|
|
short pcli_pid; /* Protocol ID - 08-00-2B-90-00 */
|
|
short pid_length;
|
|
unsigned char pid_value[5];
|
|
} setparm_802e = {
|
|
NMA$C_PCLI_FMT,
|
|
NMA$C_LINFM_802E,
|
|
NMA$C_PCLI_BFN,
|
|
255,
|
|
// NMA$C_PCLI_ACC,
|
|
// NMA$C_ACC_SHR,
|
|
NMA$C_PCLI_PRM,
|
|
NMA$C_STATE_ON,
|
|
NMA$C_PCLI_PID, 5, 8,0,0x2b,0x80,0x00
|
|
};
|
|
|
|
typedef struct _hdr {
|
|
unsigned char dsap;
|
|
unsigned char ssap;
|
|
unsigned char ctl;
|
|
unsigned char pid[5];
|
|
unsigned char da[6];
|
|
unsigned char sa[6];
|
|
unsigned char pty[2];
|
|
} hdr, *hdrPtr;
|
|
|
|
struct setparmdsc
|
|
{
|
|
int parm_len;
|
|
void *parm_buffer;
|
|
};
|
|
|
|
struct setparmdsc setparmdsc_loop = {sizeof(setparm_802e),&setparm_802e};
|
|
|
|
struct p5_param /* P5 Receive header buffer */
|
|
{
|
|
unsigned char da[6];
|
|
unsigned char sa[6];
|
|
char misc[20];
|
|
};
|
|
|
|
struct iosb /* IOSB structure */
|
|
{
|
|
short w_err; /* Completion Status */
|
|
short w_xfer_size; /* Transfer Size */
|
|
short w_addl; /* Additional status */
|
|
short w_misc; /* Miscellaneous */
|
|
};
|
|
|
|
struct ascid /* Device descriptor for assign */
|
|
{
|
|
short w_len;
|
|
short w_info;
|
|
char *a_string;
|
|
} devdsc = {4,0,"EWA0"};
|
|
|
|
struct iosb qio_iosb; /* IOSB structure */
|
|
struct p5_param rcv_param; /* Receive header structure */
|
|
struct p5_param xmt_param={ /* Transmit header structure */
|
|
0xCF,0,0,0,0,0}; /* Loopback Assistant Multicast Address */
|
|
char rcv_buffer[2048]; /* Receive buffer */
|
|
char xmt_buffer[20]={ /* Transmit buffer */
|
|
0,0, /* Skip count */
|
|
2,0, /* Forward request */
|
|
0,0,0,0,0,0, /* Forward address */
|
|
1,0, /* Reply request */
|
|
0,0};
|
|
|
|
char sense_buffer[512]; /* Sensemode buffer */
|
|
|
|
struct setparmdsc sensedsc_loop = {sizeof(sense_buffer),&sense_buffer};
|
|
|
|
/*
|
|
** Helper routines
|
|
*/
|
|
char *add_int_value(char *buf, short code, int value)
|
|
{
|
|
char *tmpptr = buf;
|
|
|
|
*tmpptr = code;
|
|
*tmpptr += 2;
|
|
*tmpptr = value;
|
|
*tmpptr += 4;
|
|
return tmpptr;
|
|
}
|
|
|
|
char *add_counted_value(char *buf, short code, short len, char *value)
|
|
{
|
|
char *tmpptr = buf;
|
|
|
|
*tmpptr = code;
|
|
*tmpptr += 2;
|
|
*tmpptr = len;
|
|
*tmpptr += 2;
|
|
memcpy(tmpptr,value,len);
|
|
return tmpptr;
|
|
}
|
|
|
|
int find_value(int buflen, char *buf, short code, char *retbuf)
|
|
{
|
|
int i = 0;
|
|
int item;
|
|
char *tmpbuf = buf;
|
|
int value;
|
|
int status = 0;
|
|
|
|
while (i < buflen) {
|
|
item = (tmpbuf[i] + (tmpbuf[i+1]<<8));
|
|
if (0x1000 & item) {
|
|
if ((item & 0xFFF) == code) {
|
|
memcpy(retbuf, &tmpbuf[i+4],6);
|
|
status = 1;
|
|
break;
|
|
}
|
|
i += (tmpbuf[i+2] + (tmpbuf[i+3]<<8)) + 4;
|
|
} else {
|
|
// A value, ours?
|
|
if ((item & 0xFFF) == code) {
|
|
// Yep, return it
|
|
memcpy(retbuf, &tmpbuf[i+2], 4);
|
|
status = 1;
|
|
break;
|
|
}
|
|
i += 6;
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* MAIN
|
|
*/
|
|
|
|
main(int argc, char *argv[])
|
|
{
|
|
int i, j; /* Scratch */
|
|
int chan; /* Channel assigned */
|
|
int status; /* Return status */
|
|
char phyaddr[6];
|
|
int val;
|
|
hdrPtr r_head;
|
|
|
|
/*
|
|
* Start a channel.
|
|
*/
|
|
|
|
status = sys$assign(&devdsc,&chan,0,0);
|
|
if ($FAIL(status)) exit(status);
|
|
|
|
status = sys$qiow(0,chan,IO$_SETMODE|IO$M_CTRL|IO$M_STARTUP,&qio_iosb,0,0,0,
|
|
&setparmdsc_loop,0,0,0,0);
|
|
if ($SUCCESS(status)) status = qio_iosb.w_err;
|
|
if ($FAIL(status))
|
|
{
|
|
printf("IOSB addl status = %04X %04X (on startup)\n",qio_iosb.w_addl,qio_iosb.w_misc);
|
|
exit(status);
|
|
}
|
|
|
|
/*
|
|
* Issue the SENSEMODE QIO to get our physical address for the loopback message.
|
|
*/
|
|
|
|
status = sys$qiow(0,chan,IO$_SENSEMODE|IO$M_CTRL,&qio_iosb,0,0,0,
|
|
&sensedsc_loop,0,0,0,0);
|
|
if ($SUCCESS(status)) status = qio_iosb.w_err;
|
|
if ($FAIL(status))
|
|
{
|
|
printf("IOSB addl status = %04X %04X (on sensemode)\n",
|
|
qio_iosb.w_addl,qio_iosb.w_misc);
|
|
exit(status);
|
|
}
|
|
|
|
status = find_value(qio_iosb.w_xfer_size, sense_buffer,
|
|
NMA$C_PCLI_PHA, phyaddr);
|
|
/*
|
|
* Locate the PHA parameter in the SENSEMODE buffer and copy it into the
|
|
* LOOPBACK transmit message. The PHA parameter is a string parameter.
|
|
*/
|
|
|
|
j = 0;
|
|
while (j < sizeof(sense_buffer))
|
|
{
|
|
i = (sense_buffer[j] + (sense_buffer[j+1]<<8));
|
|
if (0x1000 & i)
|
|
{
|
|
if ((i & 0xFFF) == NMA$C_PCLI_PHA)
|
|
{
|
|
memcpy(&xmt_buffer[4],&sense_buffer[j+4],6);
|
|
break;
|
|
}
|
|
j += (sense_buffer[j+2] + (sense_buffer[j+3]<<8)) + 4;
|
|
}
|
|
else
|
|
{
|
|
j += 6; /* Skip over longword parameter */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Transmit the loopback message.
|
|
*/
|
|
|
|
status = sys$qiow(0,chan,IO$_WRITEVBLK,&qio_iosb,0,0,&xmt_buffer[0],
|
|
sizeof(xmt_buffer),0,0,&xmt_param,0);
|
|
if ($SUCCESS(status)) status = qio_iosb.w_err;
|
|
if ($FAIL(status))
|
|
{
|
|
printf("IOSB addl status = %04X %04X (on transmit)\n",
|
|
qio_iosb.w_addl,qio_iosb.w_misc);
|
|
exit(status);
|
|
}
|
|
|
|
/*
|
|
* Look for a response. We use the NOW function modifier on the READ so that
|
|
* we don't hang here waiting forever if there is no response. If there is no
|
|
* response in 1000 receive attempts, we declare no response status.
|
|
*/
|
|
|
|
for (i=0;i<1000;i++)
|
|
{
|
|
// status = sys$qiow(0,chan,IO$_READVBLK|IO$M_NOW,&qio_iosb,0,0,&rcv_buffer[0],
|
|
status = sys$qiow(0,chan,IO$_READVBLK,&qio_iosb,0,0,&rcv_buffer[0],
|
|
sizeof(rcv_buffer),0,0,&rcv_param,0);
|
|
if ($SUCCESS(status)) status = qio_iosb.w_err;
|
|
if ($SUCCESS(status)) {
|
|
|
|
printf("da %02x%02x%02x%02x%02x%02x, sa %02x%02x%02x%02x%02x%02x\n",
|
|
rcv_param.da[0],
|
|
rcv_param.da[1],
|
|
rcv_param.da[2],
|
|
rcv_param.da[3],
|
|
rcv_param.da[4],
|
|
rcv_param.da[5],
|
|
rcv_param.sa[0],
|
|
rcv_param.sa[1],
|
|
rcv_param.sa[2],
|
|
rcv_param.sa[3],
|
|
rcv_param.sa[4],
|
|
rcv_param.sa[5]);
|
|
} else {
|
|
printf("Error\n");
|
|
exit(status);
|
|
break;
|
|
}
|
|
}
|
|
if ($SUCCESS(status))
|
|
printf("Successful test\n");
|
|
else
|
|
printf("No response\n");
|
|
|
|
}
|
|
|