/*
 *  Machtype: determine machine type & display type
 *
 * RCS Info
 *	$Id: machtype_std.c,v 1.33 1996/06/02 07:38:50 ghudson Exp $
 *	$Locker:  $
 */

#include <stdio.h>
#include <string.h>
#if defined(_AIX) && defined(_BSD)
#undef _BSD
#endif
#include <nlist.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/file.h>
#ifndef _AIX
#include <machine/cpu.h>
#endif

#ifdef vax
#define  VAXSTAR
#include <machine/pte.h>
#include <machineio/ubareg.h> /* For VAX 3100 model */
#endif

#if defined(mips) && defined(ultrix)
#include <machine/hwconf.h>
#ifndef ULTRIX_40
#include <machine/pmreg.h>
#else
#include <sys/cpuconf.h>
#include <sys/sysinfo.h>
#include <sys/workstation.h>
#endif
#include <sys/ioctl.h>
#include <sys/devio.h>
#endif /* decmips */

#include <ctype.h>


#if defined(vax) || (defined(mips) && defined(ultrix))
#define DEC_SCSI
#ifdef vax
#include <sys/devio.h>
#endif
#endif
/* RT_SCSI NOT defined by default, as it is of questionable value */
#if defined(ibm032)
#include <machinecons/screen_conf.h>
#endif

/* Handle special nlist */
#if defined(i386) && defined(_AIX)
#include <sys/machinfo.h>
#define NL_NF(nl) ((nl).n_value == 0)
#else
#define NL_NF(nl) ((nl).n_type == 0)
#endif

#if !defined(_AIX)
#define KERNEL "/vmunix"
#else
#define KERNEL "/unix"
#endif
#define MEMORY "/dev/kmem"

int verbose = 0;

struct nlist nl[] = {
#if defined(vax)
#define X_cpu_subtype 0
	{ "_cpu_subtype" },
#define X_cpu 1
	{ "_cpu" },
#define X_qvinfo 2
	{ "_qvinfo" },
#define X_qdinfo 3
	{ "_qdinfo" },
#define X_vsdinfo 4
	{ "_vsdinfo" },
#define X_smdinfo 5
	{ "_smdinfo" },
#define X_ra_info 6
	{ "_ra_info" },
#define X_plxinfo 7
	{ "_plxinfo" },
#define X_udadinfo 8
	{ "_udadinfo"},
#define X_udatypes 9
	{ "_udatypes"},
#define X_maxmem 10
	{ "_maxmem" },
#define X_physmem 11
	{ "_physmem" },
#define X_scsi 12
	{ "_sz_softc" },
#define X_nscsi 13
	{ "_nNSCSI" },
#define X_sgdinfo 14
	{ "_sgdinfo" },
#define	X_nexus	15
	{ "_nexus" },
#else /* vax */
#if defined(ibm032)
#define X_cpu_model 0
	{ "_cpu_model" },
#define X_cpu 1
	{ "_cpu" },
#define X_screen_sw 2
	{ "_screen_sw" },
#define X_NSCREEN 3
	{ "_NSCREEN" },
#define X_maxmem 4
	{ "_maxmem" },
#define X_physmem 5
	{ "_physmem" },
#define X_hdtypes 6
	{ "_hdtypes" },
#define X_hdinfo 7
	{ "_hddinfo" },
#define X_hdst 8
	{ "_hdst" },
#if defined(RT_SCSI)
#define X_scsi 9
	{ "_scsidinfo" },
#define X_scst 10
	{ "_scsist" },
#define X_scsi_softc 11
	{ "_scsi_softc" },
#endif /* RT_SCSI */
#else /* ibm */
#if defined(mips) && defined(ultrix)
#define X_cpu 0
	{ "_cpu_systype" },
#define X_maxmem 1
	{ "_maxmem" },
#define X_physmem 2
	{ "_physmem" },
#ifdef ULTRIX_40
#define X_scsi 3
	{ "_sz_softc" },
#define X_screens 4
	{ "_screens" },
#define X_nscsi 5
	{ "_nNSCSIBUS" },
#define X_kn02ba_model 6
	{ "_kn02ba_model_number" },
#else /* ! ULTRIX_40 */
#define X_scsi 3
	{ "_siisc" },
#define X_pmDev 4
	{ "pmDev" },
#define X_nscsi 5
	{ "_nNSCSI" },
#endif /* ULTRIX_40 */
#endif /* mips */
#endif /* ibm */
#endif /* vax */
#if defined(_AIX) && defined(i386)
#define X_physmem 0
        { "physmem" },
#define X_maxmem  1
        { "maxmem" },
#define X_cpu     2
        { "mach_info" },
#endif
#if defined(sun)
#define X_cpu 0
	{ "_cpu" },
#define X_maxmem 1
	{ "_maxmem" },
#define X_physmem 2
	{ "_physmem" },
#define X_nscsi 3
	{ "_nscsi_devices" },
#endif
	{ "" },
};

main(argc, argv)
int	argc;
char	**argv;
{
    int i;
    int cpuflg = 0, dpyflg = 0, raflg = 0, memflg = 0;
    int doathenaV = 0;
    int dosyspV = 0;
    int dolocalV = 0;
    int dobosN = 0;
    int dobosV = 0;
    int dosysnam = 0;
    char *kernel = KERNEL,  *memory = MEMORY;
    FILE *f;

    for (i = 1; i < argc; i++) {
	if (argv[i][0] != '-')
	  usage(argv[0]);

	switch (argv[i][1]) {
	case 'c':
	    cpuflg++;
	    break;
	case 'd':
	    dpyflg++;
	    break;
	case 'r':
	    raflg++;
	    break;
	case 'M':
	    memflg++;
	    break;
	case 'k':
	    kernel = argv[i+1];
	    i++;
	    break;
	case 'm':
	    memory = argv[i+1];
	    i++;
	    break;
        case 'A':
	    doathenaV = 1;
	    break;
        case 'L':
	    dolocalV = 1;
	    break;
        case 'P':
	    dosyspV = 1;
	    break;
	case 'N':
	    dobosN = 1;
	    break;
	case 'E':
	    dobosV = 1;
	    break;
        case 'S':
	    dosysnam = 1;
            break;
	case 'v':
	    verbose++;
	    break;
	default:
	    usage(argv[0]);
	}
    }


    if ((argc == 1) || ((argc == 2) && verbose)) {
#if defined(vax)
      puts("vax");
#else
#if defined(ibm032)
      puts("rt");
#else
#if defined(ultrix) && defined(mips)
      puts("decmips");
#else
#if defined(i386) && defined(_AIX)
      puts("ps2");
#else /* ! ps2 */
#if defined(sun) && defined(sparc)
      puts("sun4");
#else /* ! sun sparc */
#if defined(sun) 
      puts("sun3");
#else
      puts("???");
#endif
#endif
#endif
#endif
#endif
#endif
      exit(0);
    }

	/* Print out version of Athena machtype compiled against */
    if (doathenaV) {
      if (verbose)
	printf("Machtype version: %s.%s\n",ATHMAJV,ATHMINV);
      else
	printf("%s.%s\n",ATHMAJV,ATHMINV);
    }

    /* Print out version of attached packs */
    if (dosyspV) {
      char buf[256],rvd_version[256], *p;
      if ((f = fopen("/srvd/.rvdinfo","r")) == NULL) {
	printf("Syspack information unavailable\n");
      } else {
	fgets(buf,256,f);
	fclose(f);
	
	/* If it is verbose, give the whole line, else just the vers # */
	if (verbose) {
	  printf(buf);
	} else {
	  p = index(buf,' '); /* skip "Athena" */
	  p = index(p+1,' '); /* skip "RVD" */
	  p = index(p+1,' '); /* Skip "RSAIX" */
	  p = index(p+1,' '); /* skip "version" */
	  strncpy(rvd_version,p+1,256);
	  p = index(rvd_version,' ');
	  *p = '\0';
	  printf("%s\n",rvd_version);
	}
      }
    }
	
    /* Print out local version from /etc/athena/version */
    if (dolocalV) {
      char buf[256],loc_version[256], *p;
      if ((f = fopen("/etc/athena/version","r")) == NULL) {
	printf("Local version information unavailable\n");
      } else {
	fseek(f,-100,2);
	while (fgets(buf,256,f) != NULL)
	  ;
	fclose(f);
	
	if (verbose) {
	  printf(buf);
	} else {
	  p = index(buf,' '); /* skip "Athena" */
	  p = index(p+1,' '); /* skip "Workstation/Server" */
	  p = index(p+1,' '); /* Skip "RSAIX" */
	  p = index(p+1,' '); /* skip "version" */
	  strncpy(loc_version,p+1,256);
	  p = index(loc_version,' ');
	  *p = '\0';
	  printf("%s\n",loc_version);
	}
      }
    }

    /* Print out vendor OS name */
    if (dobosN) {
      if (verbose) {
#if defined(vax) || defined(ibm032)
	printf("BSD 4.3\n");
#else
#if defined(ultrix)
	printf("Ultrix 4.2a\n");
#else
#if defined(sun)
     printf("SunOS 4.1.2\n");
#endif
#endif
#endif
      } else {
#if defined(vax) || defined(ibm032)
	printf("BSD\n");
#else
#if defined(ultrix)
	printf("Ultrix\n");
#else
#if defined(sun)
        printf("SunOS\n");
#endif
#endif
#endif
      }
    }

    /* Print out vendor OS version */
    if (dobosV) {
#if defined(vax) || defined(ibm032)
      printf("4.3\n");
#else
#if defined(ultrix)
	printf("4.2a\n");
#else
#if defined(sun)
        printf("4.1.2\n");
#endif
#endif
#endif
    }

    if (dosysnam) {
      printf("%s\n", ATHSYS);
    }

    if (cpuflg || dpyflg || raflg || memflg)
      {
        int memfd;

	if (nlist(kernel, nl) < 0) {
	  fprintf(stderr,"%s: can't get namelist\n", argv[0]);
	  exit(2);
	}
        if ((memfd = open (memory, O_RDONLY)) == -1) {
          perror ("machtype: can't open memory");
          exit(2);
	}
	if (cpuflg)
	  do_cpu(kernel, memfd);
	if (dpyflg)
	  do_dpy(kernel, memfd);
	if (raflg)
	  do_disk(kernel, memfd);
	if (memflg)
	  do_memory(kernel, memfd);
      }
    exit(0);
}



usage(name)
char *name;
{
    fprintf(stderr, "usage: %s [-v] [-c] [-d] [-r] [-E] [-N] [-M]\n",name);
    fprintf(stderr, "             [-k kernel] [-m memory] [-A] [-L] [-P] [-S]\n");
    exit(1);
}


do_cpu(kernel, mf)
char *kernel;
int mf;
{
#ifdef X_cpu 
#if defined(mips) && defined(ultrix)
    unsigned cpu;
#else
#if defined(i386) && defined(_AIX)
    struct mach_info cpu;
#else
    int cpu;
#if defined(sun)
    int cpu_type;
#define SUN3_ARCH       0x10            /* arch value for Sun 3 */
#define SUN3X_ARCH      0x40            /* arch value for Sun 3X */
#define SUN4_ARCH       0x20            /* arch value for Sun 4 */
#endif 
#endif    
#endif
    if (NL_NF(nl[X_cpu])) {
	fputs("cpu not found\n",stderr);
	exit(3);
    }
    lseek(mf, nl[X_cpu].n_value, L_SET);
    read(mf, &cpu, sizeof(cpu));
#if defined(vax)
    switch (cpu) {
    case VAX_780:
	puts("VAX780");
	break;
    case VAX_750:
	puts("VAX750");
	break;
    case VAX_730:
	puts("VAX730");
	break;
    case VAX_8600:
	puts("VAX8600");
	break;
    case VAX_8200:
	puts("VAX8200");
	break;
    case VAX_630:
	if (nl[X_cpu_subtype].n_type) {
	    int cpu_subtype;
	    lseek(mf, nl[X_cpu_subtype].n_value, L_SET);
	    read(mf, &cpu_subtype, sizeof(cpu_subtype));
	    if(cpu_subtype == 4) {
                puts(verbose ? "Microvax 2000" : "VAXSTAR");
		break;
	    } else if(cpu_subtype != 1) {
                puts(verbose ? "Unknown VAX 630" : "VAX???");
		break;
	    }
	}
        puts(verbose ? "Microvax II" : "MVAX-II");
	break;
#ifdef VAX_650
    case VAX_650:
        /* There are 3 subtypes of VAX 650, which this program
           does not distinguish. */
        puts(verbose ? "Microvax III" : "VAX650");
	break;
#endif
#ifdef VAX_420
    case VAX_420:
        if (verbose) {
          switch (ka420model()) {
          case -1:
            puts("VAX 3100");
            break;
          case 0:
          case 1:
            puts("VAX 3100 model 38/48");
            break;
          case 2:
            puts("VAX 3100 model 30/40");
            break;
          case 3:
            puts("VAX 3100 (100 ns CPU)");
            break;
          }
        } else {
          puts("CVAXSTAR");
        }
	break;
#endif /* VAX_420 */
    default:
        if(verbose)
                printf("Unknown VAX type %d\n", cpu);
        else
	        puts("VAX???");
    }
#else
#if defined(ibm032)
    lseek(mf, nl[X_cpu_model].n_value, L_SET);
    read(mf, &cpu_model, sizeof(cpu_model));
    switch (cpu) {
    case CPU_RTPC:
	switch(cpu_model) {
	case CPU_SGP:
	    puts("RTPC-SGP");
	    break;
	case CPU_ROMPC:
	    puts("RTPC-ROMPC");
	    break;
	case CPU_MOD135:
	    puts("RTPC-MOD135");
	    break;
	default:
	    puts("RTPC???");
	}
        break;
    case CPU_ATR:
	puts("IBM-ATR");
	break;
    default:
	puts("IBM???");
    }
#else
#if defined(mips) && defined(ultrix)
#ifdef ULTRIX_40
    if(GETCPUTYPE(cpu) == R2000a_CPU) {
      if(GETSYSTYPE(cpu) == ST_DS3100)
#else
    if(GETCPUTYPE(cpu) == R2000aCPU) {
      if(GETSYSTYPE(cpu) == PMAX)
#endif
	if(verbose)
	  printf("KN01 rev %d\n", GETHRDREV(cpu));
	else
	  puts("KN01");
#ifdef ULTRIX_40
      else if(GETSYSTYPE(cpu) == ST_DS5400)  
	if(verbose)
	  printf("KN210 rev %d\n", GETHRDREV(cpu));
	else
	  puts("KN210");
      else if(GETSYSTYPE(cpu) == ST_DS5000)  
	if(verbose)
	  printf("KN02 rev %d\n", GETHRDREV(cpu));
	else
	  puts("KN02");
      else if(GETSYSTYPE(cpu) == ST_DS5500)  
	if(verbose)
	  printf("KN220 rev %d\n", GETHRDREV(cpu));
	else
	  puts("KN220");
#ifdef DS_5000_100
      else if(GETSYSTYPE(cpu) == ST_DS5000_100)  
	if(verbose)
	  printf("KN02ba rev %d\n", GETHRDREV(cpu));
	else
	  puts("KN02ba");
#endif /* DS_5000_100 */
#ifdef DS_MAXINE
      else if(GETSYSTYPE(cpu) == ST_DSMAXINE)  
	if(verbose)
	  printf("KN02ca rev %d\n", GETHRDREV(cpu));
	else
	  puts("KN02ca");
#endif /* DS_MAXINE */
#endif	/* ULTRIX_40 */
      else
	if(verbose)
	  printf("KN??? type %02x.%02x\n",GETSYSTYPE(cpu),GETHRDREV(cpu));
	else
	  puts("KN???");
    } else {
#if defined(MIPSEL)
      if(verbose)
	printf("MIPSEL??? type %d\n", GETCPUTYPE(cpu));
      else
	puts("MIPSEL???");
#else
      puts("mips???");
#endif
    }
#else
#if defined(sun) 
      cpu_type = cpu & CPU_ARCH;

      if (cpu_type == SUN3_ARCH)
        puts(verbose ? "SUN 3" : "SUN3");
      if (cpu_type == SUN3X_ARCH)
        puts(verbose ? "SUN 3X" : "SUN3X");
      if (cpu_type == SUN4_ARCH)
        puts(verbose ? "SUN 4" : "SUN4");
      if (cpu_type == SUN4C_ARCH) {
        switch(cpu) {
          case CPU_SUN4C_60:
            puts(verbose ? "SPARCstation 1": "SPARC/1");
            break;
          case CPU_SUN4C_40:
            puts(verbose ? "SPARCstation IPC" : "SPARC/IPC");
            break;
          case CPU_SUN4C_65:
            puts(verbose ? "SPARCstation 1+" : "SPARC/1+");
            break;
          case CPU_SUN4C_20:
            puts(verbose ? "SPARCstation SLC" : "SPARC/SLC");
            break;
          case CPU_SUN4C_75:
            puts(verbose ? "SPARCstation 2" : "SPARC/2");
            break;
          case CPU_SUN4C_25:
            puts(verbose ? "SPARCstation ELC" : "SPARC/ELC");
            break;
          case CPU_SUN4C_50:
            puts(verbose ? "SPARCstation IPX" : "SPARC/IPX");
            break;

         default:
           if(verbose)
                printf("Unknown SUN type %d\n", cpu);
           else
	        puts("SUN???");
         }
       }
#else
#if defined(i386) && defined(_AIX)
      switch(cpu.mach_type) {
    case PS2_50:
      if(verbose)
        puts("PS/2 model 50");
      else
        puts("PS2-50");
      break;
    case PS2_55:
      if(verbose)
        puts("PS/2 model 55");
      else
        puts("PS2-55");
    case PS2_60:
      if(verbose)
        puts("PS/2 model 60");
      else
        puts("PS2-60");
      break;
    case PS2_70:
      if(verbose)
        puts("PS/2 model 70");
      else
        puts("PS2-70");
      break;
    case PS2_80:
      if(verbose)
        puts("PS/2 model 80");
      else
        puts("PS2-80");
      break;
    default:
      if(verbose)
        printf("PS/2 unknown type %d\n", cpu.mach_type);
      else
        puts("PS2-???\n");
    }
#if 0
    if(verbose)
      printf("CPU level %x, machine rev %x, serial %x\n", cpu.cpu_level,
             cpu.mach_level, cpu.mach_serial);
#endif
#endif
#endif
#endif
#endif
#endif
#else
    fprintf (stderr,
	     "Don't know how to determine CPU type for this machine.\n");
#endif
    return;
}

#ifdef vax
int ka420model()
{
    unsigned long cacr;
    int kUmf;
    if (nl[X_nexus].n_type == 0)
	return -1;
    kUmf = open("/dev/kUmem", O_RDONLY);
    if (kUmf == -1)
	return -1;
    lseek(kUmf, nl[X_nexus].n_value + (int)&((struct nb_regs *)0)->nb_cacr, L_SET);
    if(read(kUmf, &cacr, sizeof(cacr)) != sizeof(cacr))
	return -1;
    close (kUmf);
    return (cacr >> 6) & 3;
}
#endif /* vax */

do_dpy(kernel, mf)
char *kernel;
int mf;
{
#ifdef vax
    caddr_t value;
#else
#ifdef ibm032
    int i, ns;
    long pos;
    char buf[32];
    struct screen_sw sw;
#else
#if defined(ultrix) && defined(mips)
    int value;
#else
#if defined(_AIX) && defined(i386)
    hft_dpy();
    return;
#else
    fprintf (stderr,
	     "Don't know how to determine display type for this machine.\n");
    return;
#endif
#endif
#endif
#endif

#if defined(vax)
    if (nl[X_qvinfo].n_type != 0) {
	lseek(mf, nl[X_qvinfo].n_value, L_SET);
	read(mf, &value, sizeof(value));
	if (value)
	  puts("QVSS");
    }
    if (nl[X_qdinfo].n_type != 0) {
	lseek(mf, nl[X_qdinfo].n_value, L_SET);
	read(mf, &value, sizeof(value));
	if (value)
	  puts("QDSS");
    }
    if (nl[X_smdinfo].n_type != 0) {
	lseek(mf, nl[X_smdinfo].n_value, L_SET);
	read(mf, &value, sizeof(value));
	if (value)
	  puts("SM");
    }
    if (nl[X_sgdinfo].n_type != 0) {
	lseek(mf, nl[X_sgdinfo].n_value, 0);
	read(mf, &value, sizeof(value));
	if (value)
	  puts("SG");
    }
    if (nl[X_vsdinfo].n_type != 0) {
	lseek(mf, nl[X_vsdinfo].n_value, L_SET);
	read(mf, &value, sizeof(value));
	if (value)
	  puts("VS100");
    }
    if (nl[X_plxinfo].n_type != 0) {
	lseek(mf, nl[X_plxinfo].n_value, L_SET);
	read(mf, &value, sizeof(value));
	if (value)
	    if (verbose)
		puts("parallax");
	else
	    puts("PLX");
    }
#else
#if defined(ibm032)
    if (nl[X_screen_sw].n_type == 0) {
	fputs("can't find screen info\n",stderr);
	return;
    }
    lseek(mf, nl[X_NSCREEN].n_value, L_SET);
    read(mf, &ns, sizeof(ns));
    pos = nl[X_screen_sw].n_value;
    for (i = 0; i < ns; i++) {
	lseek(mf, pos, L_SET);
	pos += sizeof(sw);
	read(mf, &sw, sizeof(sw));
	if (sw.flags & 1) {
	    lseek(mf, sw.name, L_SET);
	    read(mf, buf, sizeof(buf));
	    if (index(buf, ' '))
	      *index(buf, ' ') = 0;
	    if (!strcmp(buf, "monochrome"))
	      continue;
	    puts(buf);
	}
    }
#else
#if defined(ultrix) && defined(mips) && !defined(ULTRIX_40)
    if (nl[X_pmDev].n_type == 0) {
	fprintf(stderr, "can't find console device id in kernel\n");
	return;
    }
    lseek(mf, nl[X_pmDev].n_value, L_SET);
    read(mf, &value, sizeof(value));
    if (value == GRAPHIC_DEV) {		/* there is a display */
	int fd;
	struct devget dev;

	fputs("PM-",stdout);
	/* XXX KLUDGE ALERT XXX */
	/* opening /dev/xcons will get the right device on a DEVIOCGET */
	fd = open("/dev/xcons", O_RDONLY, 0);
	if ((fd != -1) && (ioctl(fd, DEVIOCGET, &dev) == 0)) {
	    /* device here is probably either MONO or COLOR */
	    /* close before printing, else we may be printing to the
	       redirected console ! */
	    (void) close(fd);
#ifdef ULTRIX_40
	    /* The dev.device info is only valid on units 0,1 */
	    puts(dev.dev_name);
#else
	    puts(dev.device);
#endif
	} else {
	    if (fd != -1)
		(void) close(fd);
	    puts("???");
	}
    }
#else
#if defined(ultrix) && defined(mips) && defined(ULTRIX_40)
    if (getsysinfo(GSI_WSD_TYPE, &value, sizeof(&value)) <=0) {
	    fprintf(stderr, "Unable to determine display device.\n");
	    return;
    }
    switch(value) {
    case CONSOLE_DTYPE:
	    return;
    case GA_DTYPE:
	    printf("PA\n");
	    return;
    case PMM_DTYPE:
	    /* Obsolete... */
	    printf("PM-MONO\n");
	    return;
    case PMC_DTYPE:
	    /* Obsolete... */
	    printf("PM-COLOR\n");
    case WS_DTYPE: {
	    ws_monitor ws_mon;
	    ws_screen_descriptor sp;
	    /* Ok - here's the scoop, there is an array of "screens" whose
	       first element is a pointer to a ws_screen_descriptor */
	    if (nl[X_screens].n_type == 0) {
		    fprintf(stderr, "can't determine WS screen type\n");
		    return;
	    }
	    lseek(mf, nl[X_screens].n_value, L_SET);
	    read(mf, &value, sizeof(value));
	    if(value == 0) {
		    fprintf(stderr, "can't determine WS screen type\n");
		    return;
	    }
	    lseek(mf, value, L_SET);
	    read(mf, &sp, sizeof(sp));
	    printf("%s\n", sp.moduleID);


    	    return;
            }
    default:
	    /* Instead of a hardcoded table.. */
	    printf("%d\n",value);
    }

    return;

#else
    fprintf (stderr,
	     "Don't know how to determine display type for this machine.\n");
    return;
#endif
#endif
#endif
#endif
}


#ifdef vax

struct	ra_info {
	caddr_t		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 */
} ra_info[4];

do_disk(kernel, mf)
char *kernel;
int mf;
{
    int i, c;

    if (nl[X_ra_info].n_type == 0)
      return(do_torek(kernel,mf));
    lseek(mf, (long) nl[X_ra_info].n_value, L_SET);
    read(mf, ra_info, sizeof(ra_info));
    for (i = 0; i < 4; i++) {
#define F_to_C(x,i)     ( (x) >> (i*5+7) & 0x1f ? ( ( ((x) >>( i*5 + 7)) & 0x1f) + 'A' - 1): ' ')
	c = ra_info[i].ratype;
	printf("ra%d: %c%c%d\n", i, F_to_C(c,2), F_to_C(c,1), c & 0x7f);
    }
}

struct uba_device {
	char 	*ui_driver;  /* Not really, but is a pointer */
	short	ui_unit;	/* unit number on the system */
	short	ui_ctlr;	/* mass ctlr number; -1 if none */
	short	ui_ubanum;	/* the uba it is on */
	short	ui_slave;	/* slave on controller */
	int	(**ui_intr)();	/* interrupt handler(s) */
	caddr_t	ui_addr;	/* address of device in i/o space */
	short	ui_dk;		/* if init 1 set to number for iostat */
	int	ui_flags;	/* parameter from system specification */
	short	ui_alive;	/* device exists */
	short	ui_type;	/* driver specific type information */
	caddr_t	ui_physaddr;	/* phys addr, for standalone (dump) code */
/* this is the forward link in a list of devices on a controller */
	char *ui_forw;
/* if the device is connected to a controller, this is the controller */
	char *ui_mi;
	char *ui_hd;
} udadinfo;

struct udatypes {
	char	*ut_name;	/* drive type name */
	caddr_t *ut_sizes;	/* partition tables */
      } udatype;


do_torek(kernel,mf)
char *kernel;
int mf;
{
    int i;
    unsigned long ptr;
    char *c, disktype[32];

    if( nl[X_udadinfo].n_type == 0 && nl[X_udatypes].n_type == 0) 
      return
#if defined(DEC_SCSI)
	do_scsi_disk(kernel, mf)
#endif
	  ;

    for(i=0; i<4; i++) {
      lseek(mf, (long) nl[X_udadinfo].n_value + 4*i, L_SET);
      read(mf, &ptr, sizeof(ptr));
      if(ptr == 0) continue;
      lseek(mf, ptr, L_SET);
      read(mf, &udadinfo, sizeof(udadinfo));

      /* Now let's read the type from the kernel!!! */
      lseek(mf, (long) udadinfo.ui_type * sizeof(udatype) 
	    + nl[X_udatypes].n_value, L_SET);
      read(mf, &udatype, sizeof(udatype));
      lseek(mf, (long) udatype.ut_name, L_SET);
      read(mf, disktype, 32);
      printf("ra%d: ",i);
      c = disktype;
      while(*c && isalnum(*c)) {
	      putchar(islower(*c) ? toupper(*c) : *c);
	      c++;
      }
      putchar('\n');

    }
#if defined(DEC_SCSI)
    do_scsi_disk(kernel, mf);
#endif
    return;
  }
#else /* not vax */
#if defined(ibm032)
#include <sys/buf.h>
#include <machineio/ioccvar.h>
#include <machineio/scsireg.h>

do_disk(kernel, mf)
char *kernel;
int mf;
{
  int i, pos;
  char hdtypes[12][8];	/* size is arbitrary, just bigger than
			   the size in machineio/hd.c */
  struct hdst { long _0; 
		u_short ncpd, _1, nbps;
		u_char  nspt, ntpc;
		u_short nspc, _2 } hdst[12];
#if defined(RT_SCSI)
  struct scsist { long _0;
		  u_short ncpd, nbps;
		  u_char  nspt, ntpc;
		  u_short nspc;
		  u_char  type[8]; } scst[4];
  struct partab { struct part_entry { daddr_t nblocks;
				      int     cyloff;
				    } part[8];
		};
  struct scsi_softc { int scsi_flag;
		      int _0,_1;
		      struct partab sizes;
		      scsi_sense    sense;
		      char _2[32];
		      struct buf b;
		    } scsi_softc;
  int sscptr;
  int scsidinfoptr[14];
  struct iocc_device scsidinfo;
#endif
  if(verbose) {
    if((pos = nl[X_hdst].n_value) == 0) {
      fprintf(stderr, "can't find hdst\n");
      verbose = 0;
    } else {
      lseek(mf,pos,L_SET);
      if(read(mf,&hdst,sizeof(hdst)) == -1) {
	fprintf(stderr, "couldn't read hdst\n");
	verbose = 0;
      }
    }
  }
  if((pos = nl[X_hdtypes].n_value) == 0) {
      fprintf(stderr, "can't find hdtypes\n");
      exit(3);
  }
  lseek(mf,pos,L_SET);
  read(mf,&hdtypes,sizeof(hdtypes));
  if((pos = nl[X_hdinfo].n_value) == 0) {
      fprintf(stderr, "can't find hdinfo\n");
      exit(3);
  }
  for(i=0;i<3;i++) {
      int hdptr;
      struct iocc_device iod;

      lseek(mf,pos+4*i,L_SET);
      if(read(mf,&hdptr,sizeof(hdptr)) == -1) {
	  fprintf(stderr, "can't read hdinfo pointer\n");
	  exit(4);
      }
      lseek(mf, hdptr, L_SET);
      if(read(mf,&iod,sizeof(iod)) == -1) {
	  fprintf(stderr, "can't read hdinfo\n");
	  exit(5);
      }
      if(iod.iod_type > 0 && iod.iod_type < 12)
	{
	  int n = iod.iod_type;
	  if(verbose) 
	    printf("hd%d: %s (%d cyl, %d tracks, %d sectors = %dK)\n",i,
		   hdtypes[n],hdst[n].ncpd,hdst[n].ntpc,hdst[n].nspt,
		   hdst[n].ncpd*hdst[n].nspc/2);
	  else
	    printf("hd%d: %s\n",i,hdtypes[iod.iod_type]);
	}
    }
#if defined(RT_SCSI)
  if((pos = nl[X_scst].n_value) == 0)
    return;
  lseek(mf, pos, L_SET);
  if(read(mf, &scst, sizeof (scst)) == -1) {
      fprintf(stderr, "can't read scst\n");
      exit(6);
  }
  if((pos = nl[X_scsi].n_value) == 0 || (sscptr = nl[X_scsi_softc].n_value) == 0)
    return;
  lseek(mf, pos, L_SET);
  if(read(mf, &scsidinfoptr, sizeof (scsidinfoptr)) == -1) {
      fprintf(stderr, "can't read scsidinfo\n");
      exit(7);
  }
  for(i=0;i<14;i++) 
    {
      if(scsidinfoptr[i] == 0)
	continue;
      lseek(mf,scsidinfoptr[i], L_SET);
      if(read(mf, &scsidinfo, sizeof(scsidinfo)) == -1) {
	fprintf(stderr, "can't read scsidinfo for scsi %d\n", i);
	continue;
      }
      lseek(mf, sscptr + i * sizeof(scsi_softc), L_SET);
      if(read(mf, &scsi_softc, sizeof(scsi_softc)) == -1) {
	fprintf(stderr, "can't read scsi_softc for scsi %d\n", i);
	continue;
      }
      /* IBM :  << deleted >>.  They set alive == 1 for anything on
	 a configured controller, whether or not the drive is there.
	 The next best check is to see if any partitions are defined. */
      if(scsidinfo.iod_alive && (scsi_softc.sizes.part[2].nblocks ||
				 scsi_softc.sizes.part[0].nblocks ||
				 scsi_softc.sizes.part[1].nblocks ||
				 scsi_softc.sizes.part[3].nblocks ||
				 scsi_softc.sizes.part[4].nblocks ||
				 scsi_softc.sizes.part[5].nblocks ||
				 scsi_softc.sizes.part[6].nblocks ||
				 scsi_softc.sizes.part[7].nblocks))
	{ /* Alive AND has a C partition */
	  printf("sc%d: %s\n",i,scst[scsidinfo.iod_type].type);
	} else {
	  static int msg;
	  if(verbose)
	    if(!scsidinfo.iod_alive) {
	      printf("sc%d: dead\n",i);
	    } else {
	      printf("sc%d: invalid (null) partition table.  %s\n",i,
		     msg == 0 ? "There might be a drive here,\n\tand there might not be.  Check on the floor under the machine." : "");
	      msg = 1;
	    }
	}
    }
#endif /* RT_SCSI */
}

#else /* not rt */
#if defined(DEC_SCSI)
do_disk(kernel, mf)
char *kernel;
int mf;
{
  do_scsi_disk(kernel, mf);
}
#else 

do_disk (kernel, mf) char *kernel; int mf; {
    fprintf (stderr, "Don't know how to read disk types for this machine.\n");
    return;
}

#endif /* ultrix mips */
#endif /* RT */
#endif /* vax */

#ifdef DEC_SCSI
/* This function assumes there is only 1 scsi controller.  If there
   are more, then repeat.  For pmax, increment the first read address
   by 4 bytes.  For vax, increment the (only) read address by
   sizeof (struct sz_softc). */
#include <sys/time.h>
#ifndef ULTRIX_40
#include <machine/scsivar.h>
#if defined(vax) && !defined(ultrix) && !defined(FORMAT)
/* To fix size */
#define FORMAT 1
#endif
#include <machine/scsireg.h>
#else
#include <machine/io/scsi/scsivar.h>
#include <machine/io/scsi/scsireg.h>
#endif

do_scsi_disk(kernel, mf)
char *kernel;
int mf;
{
  int pos, base, nscsi, i, ctl;
  struct sz_softc sz;
  
  base = nl[X_scsi].n_value;
  nscsi = nl[X_nscsi].n_value;

  if(base == 0 || nscsi == 0)
    return;

  lseek(mf, nscsi, L_SET);
  if(read(mf, &nscsi, sizeof(nscsi)) < 0) {
	perror("read (kmem)");
	exit(2);
  }

#if defined(ULTRIX_40) || defined(vax)
  for(ctl=0;ctl< nscsi;ctl++)
#else
  for(ctl=0;ctl<=nscsi;ctl++)
#endif
    {
#if !defined(vax) && !defined(ULTRIX_40)	/* mips 3.1 indirects through a pointer */
      pos = base + 4 * ctl;
      lseek(mf, pos, L_SET);
      if(read(mf,&pos,sizeof(pos)) < 0) {
	perror("read (kmem)");
	exit(2);
      }
      if(pos == 0)
	return;
#else
      pos = base + ctl*sizeof(struct sz_softc);
#endif
      lseek(mf, pos, L_SET);
      if(read(mf,&sz,sizeof(sz)) < 0) {
	perror("read (kmem)");
	exit(2);
      }
      if(verbose)
	for(i=0; i<NDPS; i++)
	  {
	    if(sz.sc_devnam[i][0])
	      if(sz.sc_revlvl[i][0])
		printf("Drive %d: %.*s\t(rev lvl %.*s)\n", i + ctl*8,
		       SZ_DNSIZE, sz.sc_devnam[i], 
		       SZ_REV_LEN, sz.sc_revlvl[i]);
	      else
		printf("Drive %d: %.*s\n", i + ctl*8, SZ_DNSIZE, sz.sc_devnam[i]);
	    else
	        if(sz.sc_device[i][0]) printf("Drive %d: %.*s\n", i + ctl*8, SZ_DNSIZE, sz.sc_device[i]);
        }
      else
	for(i=0; i<NDPS; i++) 
	  if(sz.sc_device[i][0])
	    printf("rz%d: %.*s\n", i + ctl*8, DEV_SIZE, sz.sc_device[i]);
    }
}
#endif /* DEC_SCSI */

#define MEG (1024*1024)
do_memory (kernel, mf)
char *kernel;
int mf;
{
  int pos, mem;
  pos = nl[X_maxmem].n_value;
  if(pos == 0) {
      fprintf(stderr, "can't find maxmem\n");
      exit(3);
  }
  lseek(mf,pos,L_SET);	/* Error checking ? */
  if(read(mf,&mem,4) == -1) {
      perror("read (kmem)");
      exit(4);
  } else {
    if(verbose)
      printf("%#06x user, ",mem * NBPG);
  }
  pos = nl[X_physmem].n_value;
  if(pos == 0) {
      fprintf(stderr, "can't find physmem\n");
      exit(3);
  }
  lseek(mf,pos,L_SET);
  if(read(mf,&mem,4) == -1) {
      perror("read (kmem)");
      exit(4);
  } else {
    if(verbose)
      printf("%#06x (%d M) total\n",mem * NBPG,(mem * NBPG + MEG/2)/MEG);
    else
      printf("%d\n", mem * NBPG);
  }
  return; 
}

#if defined(i386) && defined(_AIX)
#include <sys/hft.h>

struct _hft_map { int id; char gen[8],dpy[8]; } hft_map[] = {
  {0x11, "VGA","8503",},
  {0x12, "VGA","8512",},
  {0x13, "VGA","8513",},
  {0x14, "VGA","8514",},
  {0x15, "VGA","8507",},
  {0x16, "VGA","8604",},
  {0x18, "8514a","8503"},
  {0x19, "8514a","8512"},
  {0x1A, "8514a","8513"},
  {0x1B, "8514a","8514"},
  {0x1C, "8514a","8507"},
  {0x1D, "8514a","8604"},
  {0,0,0}};

typedef struct hftdid  {
        char    hftDevID[4];
        char    hftDevClass[4];
} hftDeviceID;

int hft_dpy()
{
  int fd;
  struct _hft_map *h;
  hftDeviceID dev;
  struct {
    char    pad;
    char    hf_esc;
    char    hf_lbr;
    char    hf_ex;
    int     hf_len;
    char    hf_typehi;
    char    hf_typelo;
    char    hf_sublen;
    char    hf_subtype;
    short	hf_numdev;
    struct {
      short	hf_idhi,hf_idlo;
      short	hf_classhi,hf_classlo;
    } hf_devices[4];
  }  qDevIDResponse;
#define	HFWDCHARS(n)	(n)>>8&0xff, (n)&0xff
#define	FLWDCHARS(n)	(n)>>24&0xff,(n)>>16&0xff,(n)>>8&0xff,(n)&0xff
#define	VTD(n)	HFINTROESC, HFINTROLBR, HFINTROEX, FLWDCHARS(n)
  struct hfqdevidc qdevidcmd =
    { VTD(sizeof(struct hfqdevidc)-3), HFQDEVIDCH, HFQDEVIDCL };
  struct hfquery q = {qdevidcmd.hf_intro, sizeof(qdevidcmd),
			&qDevIDResponse, sizeof(qDevIDResponse) - 1};
  qDevIDResponse.hf_len= sizeof( qDevIDResponse ) - 4;
  fd = open("/dev/console", O_WRONLY);
  ioctl(fd, HFQUERY, &q);
  for(h = hft_map;h->id;h++)
    if(h->id == qDevIDResponse.hf_devices[0].hf_idhi && 0xff)
      if(verbose)
	printf("%s with %s adapter\n", h->dpy, h->gen);
      else
	puts(h->gen);
/*
  printf("Reponse %04x.%04x, %04x.%04x\n", qDevIDResponse.hf_devices[0].hf_idhi,
	 qDevIDResponse.hf_devices[0].hf_idlo, 
	 qDevIDResponse.hf_devices[0].hf_classhi,
	 qDevIDResponse.hf_devices[0].hf_classlo);
*/
}
#endif

