code:
/* $OpenBSD: dec_6600.c,v 1.14 2014/05/08 20:46:49 miod Exp $ */
/* $NetBSD: dec_6600.c,v 1.7 2000/06/20 03:48:54 matt Exp $ */

/*
 * Copyright (c) 2009 Miodrag Vallat.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
/*
 * Copyright (c) 1995, 1996, 1997 Carnegie-Mellon University.
 * All rights reserved.
 *
 * Author: Chris G. Demetriou
 *
 * Permission to use, copy, modify and distribute this software and
 * its documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/termios.h>
#include <dev/cons.h>

#include <machine/rpb.h>
#include <machine/autoconf.h>
#include <machine/cpuconf.h>
#include <machine/bus.h>
#include <machine/logout.h>

#include <dev/ic/comreg.h>
#include <dev/ic/comvar.h>

#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include <dev/ic/i8042reg.h>
#include <dev/ic/pckbcvar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>

#include <alpha/pci/tsreg.h>
#include <alpha/pci/tsvar.h>

#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
#include <dev/ata/atavar.h>

#include "pckbd.h"

#ifndef CONSPEED
#define CONSPEED TTYDEF_SPEED
#endif

#define	DR_VERBOSE(f) while (0)

static int comcnrate __attribute__((unused)) = CONSPEED;

void dec_6600_init(void);
static void dec_6600_cons_init(void);
static void dec_6600_device_register(struct device *, void *);
static void dec_6600_mcheck_handler(unsigned long, struct trapframe *,
	    unsigned long, unsigned long);
#ifndef SMALL_KERNEL
static void dec_6600_environmental_mcheck(unsigned long, struct trapframe *,
	    unsigned long, unsigned long);
static void dec_6600_mcheck(unsigned long, struct trapframe *, unsigned long,
	    unsigned long);
static void dec_6600_print_syndrome(int, unsigned long);
#endif

void
dec_6600_init()
{

	platform.family = "6600";

	if ((platform.model = alpha_dsr_sysname()) == NULL) {
		/* XXX Don't know the system variations, yet. */
		platform.model = alpha_unknown_sysname();
	}

	platform.iobus = "tsc";
	platform.cons_init = dec_6600_cons_init;
	platform.device_register = dec_6600_device_register;
	platform.mcheck_handler = dec_6600_mcheck_handler;
	STQP(TS_C_DIM0) = 0UL;
	STQP(TS_C_DIM1) = 0UL;
}

static void
dec_6600_cons_init()
{
	struct ctb *ctb;
	u_int64_t ctbslot;
	struct tsp_config *tsp;

	ctb = (struct ctb *)(((caddr_t)hwrpb) + hwrpb->rpb_ctb_off);
	ctbslot = ctb->ctb_turboslot;

	/* Console hose defaults to hose 0. */
	tsp_console_hose = 0;

	tsp = tsp_init(0, tsp_console_hose);

	switch (ctb->ctb_term_type) {
	case CTB_PRINTERPORT:
		/* serial console ... */
		/* XXX */
		{
			/*
			 * Delay to allow PROM putchars to complete.
			 * FIFO depth * character time,
			 * character time = (1000000 / (defaultrate / 10))
			 */
			DELAY(160000000 / comcnrate);

			if(comcnattach(&tsp->pc_iot, 0x3f8, comcnrate,
			    COM_FREQ,
			    (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8))
				panic("can't init serial console");

			break;
		}

	case CTB_GRAPHICS:
#if NPCKBD > 0
		/* display console ... */
		/* XXX */
		(void) pckbc_cnattach(&tsp->pc_iot, IO_KBD, KBCMDP, 0);

		if (CTB_TURBOSLOT_TYPE(ctbslot) ==
		    CTB_TURBOSLOT_TYPE_ISA)
			isa_display_console(&tsp->pc_iot, &tsp->pc_memt);
		else {
			/* The display PCI might be different */
			tsp_console_hose = CTB_TURBOSLOT_HOSE(ctbslot);
			tsp = tsp_init(0, tsp_console_hose);
			pci_display_console(&tsp->pc_iot, &tsp->pc_memt,
			    &tsp->pc_pc, CTB_TURBOSLOT_BUS(ctbslot),
			    CTB_TURBOSLOT_SLOT(ctbslot), 0);
		}
#else
		panic("not configured to use display && keyboard console");
#endif
		break;

	default:
		printf("ctb_term_type = 0x%lx ctb_turboslot = 0x%lx"
		    " hose = %ld\n",
		    (unsigned long)ctb->ctb_term_type,
		    (unsigned long)ctbslot,
		    (unsigned long)CTB_TURBOSLOT_HOSE(ctbslot));

		panic("consinit: unknown console type %lu",
		    (unsigned long)ctb->ctb_term_type);
	}
}

static void
dec_6600_device_register(dev, aux)
	struct device *dev;
	void *aux;
{
	static int found, initted, diskboot, netboot;
	static struct device *primarydev, *pcidev, *ctrlrdev;
	struct bootdev_data *b = bootdev_data;
	struct device *parent = dev->dv_parent;
	struct cfdata *cf = dev->dv_cfdata;
	struct cfdriver *cd = cf->cf_driver;

	if (found)
		return;

	if (!initted) {
		diskboot = (strncasecmp(b->protocol, "SCSI", 4) == 0) ||
		    (strncasecmp(b->protocol, "IDE", 3) == 0);
		netboot = (strncasecmp(b->protocol, "BOOTP", 5) == 0) ||
		    (strncasecmp(b->protocol, "MOP", 3) == 0);
		DR_VERBOSE(printf("diskboot = %d, netboot = %d\n", diskboot,
		    netboot));
		initted = 1;
	}

	if (primarydev == NULL) {
		if (strcmp(cd->cd_name, "tsp"))
			return;
		else {
			struct tsp_attach_args *tsp = aux;

			if (b->bus != tsp->tsp_slot)
				return;
			primarydev = dev;
			DR_VERBOSE(printf("\nprimarydev = %s\n",
			    dev->dv_xname));
			return;
		}
	}

	if (pcidev == NULL) {
		if (strcmp(cd->cd_name, "pci"))
			return;
		/*
		 * Try to find primarydev anywhere in the ancestry.  This is
		 * necessary if the PCI bus is hidden behind a bridge.
		 */
		while (parent) {
			if (parent == primarydev)
				break;
			parent = parent->dv_parent;
		}
		if (!parent)
			return;
		else {
			struct pcibus_attach_args *pba = aux;

			if ((b->slot / 1000) != pba->pba_bus)
				return;

			pcidev = dev;
			DR_VERBOSE(printf("\npcidev = %s\n", dev->dv_xname));
			return;
		}
	}

	if (ctrlrdev == NULL) {
		if (parent != pcidev)
			return;
		else {
			struct pci_attach_args *pa = aux;
			int slot;

			slot = pa->pa_bus * 1000 + pa->pa_function * 100 +
			    pa->pa_device;
			if (b->slot != slot)
				return;

			if (netboot) {
				booted_device = dev;
				DR_VERBOSE(printf("\nbooted_device = %s\n",
				    dev->dv_xname));
				found = 1;
			} else {
				ctrlrdev = dev;
				DR_VERBOSE(printf("\nctrlrdev = %s\n",
				    dev->dv_xname));
			}
			return;
		}
	}

	if (!diskboot)
		return;

	if (!strcmp(cd->cd_name, "sd") || !strcmp(cd->cd_name, "st") ||
	    !strcmp(cd->cd_name, "cd")) {
		struct scsi_attach_args *sa = aux;
		struct scsi_link *periph = sa->sa_sc_link;
		int unit;

		if (parent->dv_parent != ctrlrdev)
			return;

		unit = periph->target * 100 + periph->lun;
		if (b->unit != unit)
                        return;

		/* we've found it! */
		booted_device = dev;
		DR_VERBOSE(printf("\nbooted_device = %s\n", dev->dv_xname));
		found = 1;
	}

	/*
	 * Support to boot from IDE drives.
	 */
	if (!strcmp(cd->cd_name, "wd")) {
		struct ata_atapi_attach *aa_link = aux;

		if ((strcmp("pciide", parent->dv_cfdata->cf_driver->cd_name) != 0))
			return;
		if (parent != ctrlrdev)
			return;

		DR_VERBOSE(printf("\nAtapi info: drive: %d, channel %d\n",
		    aa_link->aa_drv_data->drive, aa_link->aa_channel));
		DR_VERBOSE(printf("Bootdev info: unit: %d, channel: %d\n",
		    b->unit, b->channel));
		if (b->unit != aa_link->aa_drv_data->drive ||
		    b->channel != aa_link->aa_channel)
			return;

		/* we've found it! */
		booted_device = dev;
		DR_VERBOSE(printf("booted_device = %s\n", dev->dv_xname));
		found = 1;
	}
}

#ifndef SMALL_KERNEL
static void
dec_6600_environmental_mcheck(unsigned long mces, struct trapframe *framep,
    unsigned long vector, unsigned long logout)
{
	mc_hdr_ev6 *hdr = (mc_hdr_ev6 *)logout;
	mc_env_ev6 *env = (mc_env_ev6 *)(logout + hdr->la_system_offset);
	int silent = 0;
	int itemno;

	/*
	 * Note that we do not check for an expected machine check,
	 * since software is not supposed to trigger an environmental
	 * machine check, and there might be an environmental change
	 * just before our expected machine check occurs.
	 */

	/*
	 * Most environmental changes are handled at the RMC level,
	 * and we are either not notified (e.g. PCI door open) or
	 * drastic action is taken (e.g. the RMC will power down the
	 * system immediately if the CPU door is open).
	 *
	 * The only events we seem to be notified of are power supply
	 * failures.
	 */

	/* display CPU failures */
	for (itemno = 0; itemno < 4; itemno++) {
		if ((env->cpuir & EV6_ENV_CPUIR_CPU_ENABLE(itemno)) != 0 &&
		    (env->cpuir & EV6_ENV_CPUIR_CPU_FAIL(itemno)) != 0) {
			printf("CPU%d FAILURE\n", itemno);
			silent = 1;
		}
	}

	/* display PSU failures */
	if (env->smir & EV6_ENV_SMIR_PSU_FAILURE) {
		for (itemno = 0; itemno < 3; itemno++) {
			if ((env->psir & EV6_ENV_PSIR_PSU_FAIL(itemno)) != 0) {
				if ((env->psir &
				    EV6_ENV_PSIR_PSU_ENABLE(itemno)) != 0)
					printf("PSU%d FAILURE\n", itemno);
				else
					printf("PSU%d DISABLED\n", itemno);
			} else {
				if ((env->psir &
				    EV6_ENV_PSIR_PSU_ENABLE(itemno)) != 0)
					printf("PSU%d ENABLED\n", itemno);
			}
		}
		silent = 1;
	}

	/* if we could not print a summary, display everything */
	if (silent == 0) {
		printf("      Processor Environmental Machine Check, "
		    "Code 0x%x\n", hdr->mcheck_code);

		printf("Flags\t%016lx\n", (unsigned long)env->flags);
		printf("DIR\t%016lx\n", (unsigned long)env->c_dir);
		printf("SMIR\t%016lx\n", (unsigned long)env->smir);
		printf("CPUIR\t%016lx\n", (unsigned long)env->cpuir);
		printf("PSIR\t%016lx\n", (unsigned long)env->psir);
		printf("LM78_ISR\t%016lx\n", (unsigned long)env->lm78_isr);
		printf("Doors\t%016lx\n", (unsigned long)env->doors);
		printf("Temp Warning\t%016lx\n",
		    (unsigned long)env->temp_warning);
		printf("Fan Control\t%016lx\n",
		    (unsigned long)env->fan_control);
		printf("Fatal Power Down\t%016lx\n",
		    (unsigned long)env->fatal_power_down);
	}

	/*
	 * Apparently, these checks occur with MCES == 0, which
	 * is supposed to be an uncorrectable machine check.
	 *
	 * Until I know of a better way to tell recoverable and
	 * unrecoverable environmental checks apart, I'll use
	 * the fatal power down code to discriminate.
	 */
	if (mces == 0 && env->fatal_power_down == 0)
		return;
	else
		machine_check(mces, framep, vector, logout);
}

/*
 * Expected syndrome values per faulting bit
 */
static const uint8_t ev6_syndrome[64 + 8] = {
	0xce, 0xcb, 0xd3, 0xd5, 0xd6, 0xd9, 0xda, 0xdc,
	0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x31, 0x34,
	0x0e, 0x0b, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c,
	0xe3, 0xe5, 0xe6, 0xe9, 0xea, 0xec, 0xf1, 0xf4,
	0x4f, 0x4a, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d,
	0xa2, 0xa4, 0xa7, 0xa8, 0xab, 0xad, 0xb0, 0xb5,
	0x8f, 0x8a, 0x92, 0x94, 0x97, 0x98, 0x9b, 0x9d,
	0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x70, 0x75,
	0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
};

static void
dec_6600_print_syndrome(int sno, unsigned long syndrome)
{
	unsigned int bitno;

	syndrome &= 0xff;
	printf("Syndrome bits %d\t%02lx ", sno, syndrome);
	for (bitno = 0; bitno < nitems(ev6_syndrome); bitno++)
		if (syndrome == ev6_syndrome[bitno])
			break;

	if (bitno < 64)
		printf("(%d)\n", bitno);
	else if (bitno < nitems(ev6_syndrome))
		printf("(CB%d)\n", bitno - 64);
	else
		printf("(unknown)\n");
}

static void
dec_6600_mcheck(unsigned long mces, struct trapframe *framep,
    unsigned long vector, unsigned long logout)
{
	mc_hdr_ev6 *hdr = (mc_hdr_ev6 *)logout;
	struct mchkinfo *mcp;

	/*
	 * If we expected a machine check, don't decode it.
	 */
	mcp = &curcpu()->ci_mcinfo;
	if (mcp->mc_expected) {
		machine_check(mces, framep, vector, logout);
		return;
	}

	printf("      Processor Machine Check (%lx), Code 0x%x\n",
	    vector, hdr->mcheck_code);

	if (vector == ALPHA_SYS_MCHECK) {
#ifdef notyet
		mc_sys_ev6 *sys = (mc_sys_ev6 *)(logout + hdr->la_system_offset);
#endif
		/* XXX Decode and report P-Chip errors */
	} else /* ALPHA_PROC_MCHECK */ {
		mc_cpu_ev6 *cpu = (mc_cpu_ev6 *)(logout + hdr->la_cpu_offset);
		size_t cpu_size = hdr->la_system_offset - hdr->la_cpu_offset;

		printf("Dcache status\t0x%05lx\n",
		    (unsigned long)cpu->dc_stat & EV6_DC_STAT_MASK);
		dec_6600_print_syndrome(0, cpu->c_syndrome_0);
		dec_6600_print_syndrome(1, cpu->c_syndrome_1);
		/* C_STAT */
		printf("C_STAT\t");
		switch (cpu->c_stat & EV6_C_STAT_MASK) {
		case EV6_C_STAT_DBL_ISTREAM_BC_ECC_ERR:
			printf("Bcache instruction stream double ECC error\n");
			break;
		case EV6_C_STAT_DBL_ISTREAM_MEM_ECC_ERR:
			printf("Memory instruction stream double ECC error\n");
			break;
		case EV6_C_STAT_DBL_DSTREAM_BC_ECC_ERR:
			printf("Bcache data stream double ECC error\n");
			break;
		case EV6_C_STAT_DBL_DSTREAM_MEM_ECC_ERR:
			printf("Memory data stream double ECC error\n");
			break;
		case EV6_C_STAT_SNGL_ISTREAM_BC_ECC_ERR:
			printf("Bcache instruction stream single ECC error\n");
			break;
		case EV6_C_STAT_SNGL_ISTREAM_MEM_ECC_ERR:
			printf("Memory instruction stream single ECC error\n");
			break;
		case EV6_C_STAT_SNGL_BC_PROBE_HIT_ERR:
		case EV6_C_STAT_SNGL_BC_PROBE_HIT_ERR2:
			printf("Bcache probe hit error\n");
			break;
		case EV6_C_STAT_SNGL_DSTREAM_DC_ECC_ERR:
			printf("Dcache data stream single ECC error\n");
			break;
		case EV6_C_STAT_SNGL_DSTREAM_BC_ECC_ERR:
			printf("Bcache data stream single ECC error\n");
			break;
		case EV6_C_STAT_SNGL_DSTREAM_MEM_ECC_ERR:
			printf("Memory data stream single ECC error\n");
			break;
		case EV6_C_STAT_SNGL_DC_DUPLICATE_TAG_PERR:
			printf("Dcache duplicate tag error\n");
			break;
		case EV6_C_STAT_SNGL_BC_TAG_PERR:
			printf("Bcache tag error\n");
			break;
		case EV6_C_STAT_NO_ERROR:
			if (cpu->dc_stat & EV6_DC_STAT_STORE_DATA_ECC_ERROR) {
				printf("Bcache/Dcache victim read ECC error\n");
				break;
			}
			/* FALLTHROUGH */
		default:
			printf("%02lx\n", (unsigned long)cpu->c_stat);
			break;
		}
		/* C_ADDR */
		printf("Error address\t");
		if ((cpu->c_stat & EV6_C_STAT_MASK) ==
		    EV6_C_STAT_SNGL_DSTREAM_DC_ECC_ERR)
			printf("0xXXXXXXXXXXX%05lx\n",
			    (unsigned long)cpu->c_addr & 0xfffc0);
		else
			printf("0x%016lx\n",
			    (unsigned long)cpu->c_addr & 0xffffffffffffffc0);

		if (cpu_size > offsetof(mc_cpu_ev6, exc_addr)) {
			printf("Exception address\t0x%016lx%s\n",
			    (unsigned long)cpu->exc_addr & 0xfffffffffffffffc,
			    cpu->exc_addr & 1 ? " in PAL mode" : "");
			/* other fields are not really informative */
		}
	}

	machine_check(mces, framep, vector, logout);
}
#endif

static void
dec_6600_mcheck_handler(unsigned long mces, struct trapframe *framep,
    unsigned long vector, unsigned long param)
{
#ifdef SMALL_KERNEL
	/*
	 * Even though we can not afford the machine check
	 * analysis code, we need to ignore environmental
	 * changes.
	 */
	if (vector == ALPHA_ENV_MCHECK)
		return;

	machine_check(mces, framep, vector, param);
#else
	switch (vector) {
	case ALPHA_ENV_MCHECK:
		dec_6600_environmental_mcheck(mces, framep, vector, param);
		break;
	case ALPHA_PROC_MCHECK:
	case ALPHA_SYS_MCHECK:
		dec_6600_mcheck(mces, framep, vector, param);
		break;
	default:
		machine_check(mces, framep, vector, param);
		break;
	}
#endif
}


code:
/* $NetBSD: dec_alphabook1.c,v 1.27 2012/10/13 17:58:54 jdc Exp $ */

/*
 * Copyright (c) 1995, 1996, 1997 Carnegie-Mellon University.
 * All rights reserved.
 *
 * Author: Chris G. Demetriou
 *
 * Permission to use, copy, modify and distribute this software and
 * its documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */
/*
 * Additional Copyright (c) 1997 by Matthew Jacob for NASA/Ames Research Center
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/termios.h>
#include <sys/conf.h>
#include <dev/cons.h>

#include <machine/rpb.h>
#include <machine/autoconf.h>
#include <machine/cpuconf.h>

#include <dev/ic/comreg.h>
#include <dev/ic/comvar.h>

#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include <dev/ic/i8042reg.h>
#include <dev/ic/pckbcvar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>

#include <alpha/pci/lcareg.h>
#include <alpha/pci/lcavar.h>

#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>

#include "pckbd.h"

#ifndef CONSPEED
#define CONSPEED TTYDEF_SPEED
#endif
static int comcnrate = CONSPEED;

void dec_alphabook1_init(void);
static void dec_alphabook1_cons_init(void);
static void dec_alphabook1_device_register(struct device *, void *);

const struct alpha_variation_table dec_alphabook1_variations[] = {
	{ 0, "AlphaBook" },
	{ 0, NULL },
};

void
dec_alphabook1_init(void)
{
	uint64_t variation;

	platform.family = "AlphaBook";

	if ((platform.model = alpha_dsr_sysname()) == NULL) {
		variation = hwrpb->rpb_variation & SV_ST_MASK;
		if ((platform.model = alpha_variation_name(variation,
		    dec_alphabook1_variations)) == NULL)
			platform.model = alpha_unknown_sysname();
	}

	platform.iobus = "lca";
	platform.cons_init = dec_alphabook1_cons_init;
	platform.device_register = dec_alphabook1_device_register;
}

static void
dec_alphabook1_cons_init(void)
{
	struct ctb *ctb;
	struct lca_config *lcp;
	extern struct lca_config lca_configuration;

	lcp = &lca_configuration;
	lca_init(lcp, 0);

	ctb = (struct ctb *)(((char *)hwrpb) + hwrpb->rpb_ctb_off);

	switch (ctb->ctb_term_type) {
	case CTB_PRINTERPORT:
		/* serial console ... */
		/* XXX */
		{
			/*
			 * Delay to allow PROM putchars to complete.
			 * FIFO depth * character time,
			 * character time = (1000000 / (defaultrate / 10))
			 */
			DELAY(160000000 / comcnrate);

			if(comcnattach(&lcp->lc_iot, 0x3f8, comcnrate,
			    COM_FREQ,
			    (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8))
				panic("can't init serial console");

			break;
		}

	case CTB_GRAPHICS:
#if NPCKBD > 0
		/* display console ... */
		/* XXX */
		(void) pckbc_cnattach(&lcp->lc_iot, IO_KBD, KBCMDP, 0);

		if (CTB_TURBOSLOT_TYPE(ctb->ctb_turboslot) ==
		    CTB_TURBOSLOT_TYPE_ISA)
			isa_display_console(&lcp->lc_iot, &lcp->lc_memt);
		else
			pci_display_console(&lcp->lc_iot, &lcp->lc_memt,
			    &lcp->lc_pc, CTB_TURBOSLOT_BUS(ctb->ctb_turboslot),
			    CTB_TURBOSLOT_SLOT(ctb->ctb_turboslot), 0);
#else
		panic("not configured to use display && keyboard console");
#endif
		break;

	default:
		printf("ctb->ctb_term_type = 0x%lx\n",
		    (unsigned long)ctb->ctb_term_type);
		printf("ctb->ctb_turboslot = 0x%lx\n",
		    (unsigned long)ctb->ctb_turboslot);

		panic("consinit: unknown console type %lu",
		    (unsigned long)ctb->ctb_term_type);
	}
}

static void
dec_alphabook1_device_register(struct device *dev, void *aux)
{
	static int found, initted, diskboot, netboot;
	static struct device *pcidev, *ctrlrdev;
	struct bootdev_data *b = bootdev_data;
	struct device *parent = dev->dv_parent;
	struct cfdata *cf = dev->dv_cfdata;
	struct cfdriver *cd = cf->cf_driver;

	if (found)
		return;

	if (!initted) {
		diskboot = (strncasecmp(b->protocol, "SCSI", 4) == 0);
		netboot = (strncasecmp(b->protocol, "BOOTP", 5) == 0) ||
		    (strncasecmp(b->protocol, "MOP", 3) == 0);
#if 0
		printf("diskboot = %d, netboot = %d\n", diskboot, netboot);
#endif
		initted =1;
	}

	if (pcidev == NULL) {
		if (strcmp(cd->cd_name, "pci"))
			return;
		else {
			struct pcibus_attach_args *pba = aux;

			if ((b->slot / 1000) != pba->pba_bus)
				return;

			pcidev = dev;
#if 0
			printf("\npcidev = %s\n", device_xname(dev));
#endif
			return;
		}
	}

	if (ctrlrdev == NULL) {
		if (parent != pcidev)
			return;
		else {
			struct pci_attach_args *pa = aux;
			int slot;

			slot = pa->pa_bus * 1000 + pa->pa_function * 100 +
			    pa->pa_device;
			if (b->slot != slot)
				return;

			if (netboot) {
				booted_device = dev;
#if 0
				printf("\nbooted_device = %s\n", device_xname(dev));
#endif
				found = 1;
			} else {
				ctrlrdev = dev;
#if 0
				printf("\nctrlrdev = %s\n", device_xname(dev));
#endif
			}
			return;
		}
	}

	if (!diskboot)
		return;

	if (!strcmp(cd->cd_name, "sd") || !strcmp(cd->cd_name, "st") ||
	    !strcmp(cd->cd_name, "cd")) {
		struct scsi_attach_args *sa = aux;
		struct scsi_link *periph = sa->sa_sc_link;
		int unit;

		if (parent->dv_parent != ctrlrdev)
			return;

		unit = periph->target * 100 + periph->lun;
		if (b->unit != unit)
			return;

		/* we've found it! */
		booted_device = dev;
#if 0
		printf("\nbooted_device = %s\n", device_xname(dev));
#endif
		found = 1;
	}
}

license: unknown


code:
/* $OpenBSD: dec_axppci_33.c,v 1.23 2014/05/08 20:46:49 miod Exp $ */
/* $NetBSD: dec_axppci_33.c,v 1.44 2000/05/22 20:13:32 thorpej Exp $ */

/*
 * Copyright (c) 1995, 1996, 1997 Carnegie-Mellon University.
 * All rights reserved.
 *
 * Author: Chris G. Demetriou
 *
 * Permission to use, copy, modify and distribute this software and
 * its documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */
/*
 * Additional Copyright (c) 1997 by Matthew Jacob for NASA/Ames Research Center
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/termios.h>
#include <dev/cons.h>
#include <sys/conf.h>

#include <machine/rpb.h>
#include <machine/autoconf.h>
#include <machine/cpuconf.h>

#include <dev/ic/comreg.h>
#include <dev/ic/comvar.h>

#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include <dev/ic/i8042reg.h>
#include <dev/ic/pckbcvar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>

#include <alpha/pci/lcareg.h>
#include <alpha/pci/lcavar.h>

#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>

#include "pckbd.h"

#ifndef CONSPEED
#define CONSPEED TTYDEF_SPEED
#endif
static int comcnrate = CONSPEED;

void dec_axppci_33_init(void);
static void dec_axppci_33_cons_init(void);
static void dec_axppci_33_device_register(struct device *, void *);

const struct alpha_variation_table dec_axppci_33_variations[] = {
	{ 0, "Alpha PC AXPpci33 (\"NoName\")" },
	{ 0, NULL },
};

static struct lca_config *lca_preinit(void);

static struct lca_config *
lca_preinit()
{
	extern struct lca_config lca_configuration;

	lca_init(&lca_configuration, 0);
	return &lca_configuration;
}

#define	NSIO_PORT  0x26e	/* Hardware enabled option: 0x398 */
#define	NSIO_BASE  0
#define	NSIO_INDEX NSIO_BASE
#define	NSIO_DATA  1
#define	NSIO_SIZE  2
#define	NSIO_CFG0  0
#define	NSIO_CFG1  1
#define	NSIO_CFG2  2
#define	NSIO_IDE_ENABLE 0x40

void
dec_axppci_33_init()
{
	int cfg0val;
	u_int64_t variation;
	bus_space_tag_t iot;
	struct lca_config *lcp;
	bus_space_handle_t nsio;
#define	A33_NSIOBARRIER(type) bus_space_barrier(iot, nsio,\
				NSIO_BASE, NSIO_SIZE, (type))

	platform.family = "DEC AXPpci";

	if ((platform.model = alpha_dsr_sysname()) == NULL) {
		variation = hwrpb->rpb_variation & SV_ST_MASK;
		if ((platform.model = alpha_variation_name(variation,
		    dec_axppci_33_variations)) == NULL)
			platform.model = alpha_unknown_sysname();
	}

	platform.iobus = "lca";
	platform.cons_init = dec_axppci_33_cons_init;
	platform.device_register = dec_axppci_33_device_register;

	lcp = lca_preinit();
	iot = &lcp->lc_iot;
	if (bus_space_map(iot, NSIO_PORT, NSIO_SIZE, 0, &nsio))
		return;

	bus_space_write_1(iot, nsio, NSIO_INDEX, NSIO_CFG0);
	A33_NSIOBARRIER(BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
	cfg0val = bus_space_read_1(iot, nsio, NSIO_DATA);

	cfg0val |= NSIO_IDE_ENABLE;

	bus_space_write_1(iot, nsio, NSIO_INDEX, NSIO_CFG0);
	A33_NSIOBARRIER(BUS_SPACE_BARRIER_WRITE);
	bus_space_write_1(iot, nsio, NSIO_DATA, cfg0val);
	A33_NSIOBARRIER(BUS_SPACE_BARRIER_WRITE);
	bus_space_write_1(iot, nsio, NSIO_DATA, cfg0val);

	/* Leave nsio mapped to catch any accidental port space collisions  */
}

static void
dec_axppci_33_cons_init()
{
	struct ctb *ctb;
	struct lca_config *lcp;

	lcp = lca_preinit();

	ctb = (struct ctb *)(((caddr_t)hwrpb) + hwrpb->rpb_ctb_off);

	switch (ctb->ctb_term_type) {
	case CTB_PRINTERPORT:
		/* serial console ... */
		/* XXX */
		{
			/*
			 * Delay to allow PROM putchars to complete.
			 * FIFO depth * character time,
			 * character time = (1000000 / (defaultrate / 10))
			 */
			DELAY(160000000 / comcnrate);

			if(comcnattach(&lcp->lc_iot, 0x3f8, comcnrate,
			    COM_FREQ,
			    (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8))
				panic("can't init serial console");

			break;
		}

	case CTB_GRAPHICS:
#if NPCKBD > 0
		/* display console ... */
		/* XXX */
		(void) pckbc_cnattach(&lcp->lc_iot, IO_KBD, KBCMDP, 0);

		if (CTB_TURBOSLOT_TYPE(ctb->ctb_turboslot) ==
		    CTB_TURBOSLOT_TYPE_ISA)
			isa_display_console(&lcp->lc_iot, &lcp->lc_memt);
		else
			pci_display_console(&lcp->lc_iot, &lcp->lc_memt,
			    &lcp->lc_pc, CTB_TURBOSLOT_BUS(ctb->ctb_turboslot),
			    CTB_TURBOSLOT_SLOT(ctb->ctb_turboslot), 0);
#else
		panic("not configured to use display && keyboard console");
#endif
		break;

	default:
		printf("ctb->ctb_term_type = 0x%lx\n",
		    (unsigned long)ctb->ctb_term_type);
		printf("ctb->ctb_turboslot = 0x%lx\n",
		    (unsigned long)ctb->ctb_turboslot);

		panic("consinit: unknown console type %lu",
		    (unsigned long)ctb->ctb_term_type);
	}
}

static void
dec_axppci_33_device_register(dev, aux)
	struct device *dev;
	void *aux;
{
	static int found, initted, diskboot, netboot;
	static struct device *pcidev, *ctrlrdev;
	struct bootdev_data *b = bootdev_data;
	struct device *parent = dev->dv_parent;
	struct cfdata *cf = dev->dv_cfdata;
	struct cfdriver *cd = cf->cf_driver;

	if (found)
		return;

	if (!initted) {
		diskboot = (strncasecmp(b->protocol, "SCSI", 4) == 0);
		netboot = (strncasecmp(b->protocol, "BOOTP", 5) == 0) ||
		    (strncasecmp(b->protocol, "MOP", 3) == 0);
#if 0
		printf("diskboot = %d, netboot = %d\n", diskboot, netboot);
#endif
		initted =1;
	}

	if (pcidev == NULL) {
		if (strcmp(cd->cd_name, "pci"))
			return;
		else {
			struct pcibus_attach_args *pba = aux;

			if ((b->slot / 1000) != pba->pba_bus)
				return;

			pcidev = dev;
#if 0
			printf("\npcidev = %s\n", dev->dv_xname);
#endif
			return;
		}
	}

	if (ctrlrdev == NULL) {
		if (parent != pcidev)
			return;
		else {
			struct pci_attach_args *pa = aux;
			int slot;

			slot = pa->pa_bus * 1000 + pa->pa_function * 100 +
			    pa->pa_device;
			if (b->slot != slot)
				return;

			if (netboot) {
				booted_device = dev;
#if 0
				printf("\nbooted_device = %s\n", dev->dv_xname);
#endif
				found = 1;
			} else {
				ctrlrdev = dev;
#if 0
				printf("\nctrlrdev = %s\n", dev->dv_xname);
#endif
			}
			return;
		}
	}

	if (!diskboot)
		return;

	if (!strcmp(cd->cd_name, "sd") || !strcmp(cd->cd_name, "st") ||
	    !strcmp(cd->cd_name, "cd")) {
		struct scsi_attach_args *sa = aux;
		struct scsi_link *periph = sa->sa_sc_link;
		int unit;

		if (parent->dv_parent != ctrlrdev)
			return;

		unit = periph->target * 100 + periph->lun;
		if (b->unit != unit)
			return;

		/* we've found it! */
		booted_device = dev;
#if 0
		printf("\nbooted_device = %s\n", dev->dv_xname);
#endif
		found = 1;
	}
}


code:
/* $OpenBSD: dec_eb164.c,v 1.19 2014/05/08 20:46:49 miod Exp $ */
/* $NetBSD: dec_eb164.c,v 1.33 2000/05/22 20:13:32 thorpej Exp $ */

/*
 * Copyright (c) 1995, 1996, 1997 Carnegie-Mellon University.
 * All rights reserved.
 *
 * Author: Chris G. Demetriou
 *
 * Permission to use, copy, modify and distribute this software and
 * its documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */
/*
 * Additional Copyright (c) 1997 by Matthew Jacob for NASA/Ames Research Center
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/termios.h>
#include <dev/cons.h>
#include <sys/conf.h>

#include <machine/rpb.h>
#include <machine/autoconf.h>
#include <machine/cpuconf.h>
#include <machine/bus.h>

#include <dev/ic/comreg.h>
#include <dev/ic/comvar.h>

#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include <dev/ic/i8042reg.h>
#include <dev/ic/pckbcvar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>

#include <alpha/pci/ciareg.h>
#include <alpha/pci/ciavar.h>

#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
#include <dev/ata/atavar.h>

#include "pckbd.h"

#ifndef CONSPEED
#define CONSPEED TTYDEF_SPEED
#endif
static int comcnrate = CONSPEED;

#define	DR_VERBOSE(f) while (0)

void dec_eb164_init(void);
static void dec_eb164_cons_init(void);
static void dec_eb164_device_register(struct device *, void *);

void
dec_eb164_init()
{

	platform.family = "EB164";

	if ((platform.model = alpha_dsr_sysname()) == NULL) {
		/* XXX Don't know the system variations, yet. */
		platform.model = alpha_unknown_sysname();
	}

	platform.iobus = "cia";
	platform.cons_init = dec_eb164_cons_init;
	platform.device_register = dec_eb164_device_register;
}

static void
dec_eb164_cons_init()
{
	struct ctb *ctb;
	struct cia_config *ccp;
	extern struct cia_config cia_configuration;

	ccp = &cia_configuration;
	cia_init(ccp, 0);

	ctb = (struct ctb *)(((caddr_t)hwrpb) + hwrpb->rpb_ctb_off);

	switch (ctb->ctb_term_type) {
	case CTB_PRINTERPORT:
		/* serial console ... */
		/* XXX */
		{
			/*
			 * Delay to allow PROM putchars to complete.
			 * FIFO depth * character time,
			 * character time = (1000000 / (defaultrate / 10))
			 */
			DELAY(160000000 / comcnrate);

			if(comcnattach(&ccp->cc_iot, 0x3f8, comcnrate,
			    COM_FREQ,
			    (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8))
				panic("can't init serial console");

			break;
		}

	case CTB_GRAPHICS:
#if NPCKBD > 0
		/* display console ... */
		/* XXX */
		(void) pckbc_cnattach(&ccp->cc_iot, IO_KBD, KBCMDP, 0);

		/*
		 * On at least LX164, SRM reports an isa video board
		 * as a pci slot with 0xff as the bus and slot numbers.
		 * Since these values are not plausible from a pci point
		 * of view, it is safe to check for them.
		 */
		if (CTB_TURBOSLOT_TYPE(ctb->ctb_turboslot) ==
		    CTB_TURBOSLOT_TYPE_ISA ||
		    (CTB_TURBOSLOT_BUS(ctb->ctb_turboslot) == 0xff &&
		     CTB_TURBOSLOT_SLOT(ctb->ctb_turboslot) == 0xff))
			isa_display_console(&ccp->cc_iot, &ccp->cc_memt);
		else
			pci_display_console(&ccp->cc_iot, &ccp->cc_memt,
			    &ccp->cc_pc, CTB_TURBOSLOT_BUS(ctb->ctb_turboslot),
			    CTB_TURBOSLOT_SLOT(ctb->ctb_turboslot), 0);
#else
		panic("not configured to use display && keyboard console");
#endif
		break;

	default:
		printf("ctb->ctb_term_type = 0x%lx\n",
		    (unsigned long)ctb->ctb_term_type);
		printf("ctb->ctb_turboslot = 0x%lx\n",
		    (unsigned long)ctb->ctb_turboslot);

		panic("consinit: unknown console type %lu",
		    (unsigned long)ctb->ctb_term_type);
	}
}

static void
dec_eb164_device_register(dev, aux)
	struct device *dev;
	void *aux;
{
	static int found, initted, diskboot, netboot;
	static struct device *pcidev, *ctrlrdev;
	struct bootdev_data *b = bootdev_data;
	struct device *parent = dev->dv_parent;
	struct cfdata *cf = dev->dv_cfdata;
	struct cfdriver *cd = cf->cf_driver;

	if (found)
		return;

	if (!initted) {
		diskboot = (strncasecmp(b->protocol, "SCSI", 4) == 0) ||
		    (strncasecmp(b->protocol, "IDE", 3) == 0);
		netboot = (strncasecmp(b->protocol, "BOOTP", 5) == 0) ||
		    (strncasecmp(b->protocol, "MOP", 3) == 0);
		DR_VERBOSE(printf("diskboot = %d, netboot = %d\n", diskboot,
		    netboot));
		initted = 1;
	}

	if (pcidev == NULL) {
		if (strcmp(cd->cd_name, "pci"))
			return;
		else {
			struct pcibus_attach_args *pba = aux;

			if ((b->slot / 1000) != pba->pba_bus)
				return;

			pcidev = dev;
			DR_VERBOSE(printf("\npcidev = %s\n", dev->dv_xname));
			return;
		}
	}

	if (ctrlrdev == NULL) {
		if (parent != pcidev)
			return;
		else {
			struct pci_attach_args *pa = aux;
			int slot;

			slot = pa->pa_bus * 1000 + pa->pa_function * 100 +
			    pa->pa_device;
			if (b->slot != slot)
				return;

			if (netboot) {
				booted_device = dev;
				DR_VERBOSE(printf("\nbooted_device = %s\n",
				    dev->dv_xname));
				found = 1;
			} else {
				ctrlrdev = dev;
				DR_VERBOSE(printf("\nctrlrdev = %s\n",
				    dev->dv_xname));
			}
			return;
		}
	}

	if (!diskboot)
		return;

	if (!strcmp(cd->cd_name, "sd") || !strcmp(cd->cd_name, "st") ||
	    !strcmp(cd->cd_name, "cd")) {
		struct scsi_attach_args *sa = aux;
		struct scsi_link *periph = sa->sa_sc_link;
		int unit;

		if (parent->dv_parent != ctrlrdev)
			return;

		unit = periph->target * 100 + periph->lun;
		if (b->unit != unit)
			return;

		/* we've found it! */
		booted_device = dev;
		DR_VERBOSE(printf("\nbooted_device = %s\n", dev->dv_xname));
		found = 1;
	}

	/*
	 * Support to boot from IDE drives.
	 */
	if (!strcmp(cd->cd_name, "wd")) {
		struct ata_atapi_attach *aa_link = aux;
		int variation = hwrpb->rpb_variation & SV_ST_MASK;

		if ((strcmp("pciide", parent->dv_cfdata->cf_driver->cd_name) != 0))
			return;
		if (parent != ctrlrdev)
			return;

		DR_VERBOSE(printf("\nAtapi info: drive: %d, channel %d\n",
		    aa_link->aa_drv_data->drive, aa_link->aa_channel));
		DR_VERBOSE(printf("Bootdev info: unit: %d, channel: %d\n",
		    b->unit, b->channel));
		if (b->unit != aa_link->aa_drv_data->drive)
			return;

		/*
		 * On 164SX, the built-in IDE controller appears as
		 * two distinct pciide devices, both with a single
		 * channel.  However SRM will nevertheless pretend
		 * the second channel is channel #1 of the second
		 * device, while it is really channel #0, so just
		 * ignore the channel number in this case.
		 */
		if (variation >= SV_ST_ALPHAPC164SX_400 &&
		   variation <= SV_ST_ALPHAPC164SX_600 &&
		    b->slot == 0 * 1000 + 2 * 100 + 8) {
			/* nothing */
		} else {
			if (b->channel != aa_link->aa_channel)
				return;
		}

		/* we've found it! */
		booted_device = dev;
		DR_VERBOSE(printf("booted_device = %s\n", dev->dv_xname));
		found = 1;
	}
}


code:
/* $OpenBSD: dec_eb64plus.c,v 1.9 2014/05/08 20:46:49 miod Exp $ */
/* $NetBSD: dec_eb64plus.c,v 1.25 2001/06/05 04:53:11 thorpej Exp $ */

/*
 * Copyright (c) 1995, 1996, 1997 Carnegie-Mellon University.
 * All rights reserved.
 *
 * Author: Chris G. Demetriou
 *
 * Permission to use, copy, modify and distribute this software and
 * its documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */
/*
 * Additional Copyright (c) 1997 by Matthew Jacob for NASA/Ames Research Center
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/termios.h>
#include <dev/cons.h>

#include <machine/rpb.h>
#include <machine/autoconf.h>
#include <machine/cpuconf.h>
#include <machine/conf.h>

#include <dev/ic/comreg.h>
#include <dev/ic/comvar.h>

#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include <dev/ic/i8042reg.h>
#include <dev/ic/pckbcvar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>

#include <alpha/pci/apecsreg.h>
#include <alpha/pci/apecsvar.h>

#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
#include <dev/ata/atavar.h>

#include "pckbd.h"

#ifndef CONSPEED
#define CONSPEED TTYDEF_SPEED
#endif
static int comcnrate = CONSPEED;

void dec_eb64plus_init(void);
static void dec_eb64plus_cons_init(void);
static void dec_eb64plus_device_register(struct device *, void *);

const struct alpha_variation_table dec_eb64plus_variations[] = {
	{ 0, "DEC EB64+" },
	{ 0, NULL },
};

void
dec_eb64plus_init()
{
	u_int64_t variation;

	platform.family = "EB64+";

	if ((platform.model = alpha_dsr_sysname()) == NULL) {
		variation = hwrpb->rpb_variation & SV_ST_MASK;
		if ((platform.model = alpha_variation_name(variation,
		    dec_eb64plus_variations)) == NULL)
			platform.model = alpha_unknown_sysname();
	}

	platform.iobus = "apecs";
	platform.cons_init = dec_eb64plus_cons_init;
	platform.device_register = dec_eb64plus_device_register;
}

static void
dec_eb64plus_cons_init()
{
	struct ctb *ctb;
	struct apecs_config *acp;
	extern struct apecs_config apecs_configuration;

	acp = &apecs_configuration;
	apecs_init(acp, 0);

	ctb = (struct ctb *)(((caddr_t)hwrpb) + hwrpb->rpb_ctb_off);

	switch (ctb->ctb_term_type) {
	case CTB_PRINTERPORT:
		/* serial console ... */
		/* XXX */
		{
			/*
			 * Delay to allow PROM putchars to complete.
			 * FIFO depth * character time,
			 * character time = (1000000 / (defaultrate / 10))
			 */
			DELAY(160000000 / comcnrate);

			if(comcnattach(&acp->ac_iot, 0x3f8, comcnrate,
			    COM_FREQ,
			    (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8))
				panic("can't init serial console");

			break;
		}

	case CTB_GRAPHICS:
#if NPCKBD > 0
		/* display console ... */
		/* XXX */
		(void) pckbc_cnattach(&acp->ac_iot, IO_KBD, KBCMDP, 0);

		if (CTB_TURBOSLOT_TYPE(ctb->ctb_turboslot) ==
		    CTB_TURBOSLOT_TYPE_ISA)
			isa_display_console(&acp->ac_iot, &acp->ac_memt);
		else
			pci_display_console(&acp->ac_iot, &acp->ac_memt,
			    &acp->ac_pc, CTB_TURBOSLOT_BUS(ctb->ctb_turboslot),
			    CTB_TURBOSLOT_SLOT(ctb->ctb_turboslot), 0);
#else
		panic("not configured to use display && keyboard console");
#endif
		break;

	default:
		printf("ctb->ctb_term_type = 0x%lx\n",
		    (unsigned long)ctb->ctb_term_type);
		printf("ctb->ctb_turboslot = 0x%lx\n",
		    (unsigned long)ctb->ctb_turboslot);

		panic("consinit: unknown console type %lu",
		    (unsigned long)ctb->ctb_term_type);
	}
}

static void
dec_eb64plus_device_register(dev, aux)
	struct device *dev;
	void *aux;
{
	static int found, initted, diskboot, netboot;
	static struct device *pcidev, *ctrlrdev;
	struct bootdev_data *b = bootdev_data;
	struct device *parent = dev->dv_parent;
	struct cfdata *cf = dev->dv_cfdata;
	struct cfdriver *cd = cf->cf_driver;

	if (found)
		return;

	if (!initted) {
		diskboot = (strncasecmp(b->protocol, "SCSI", 4) == 0);
		netboot = (strncasecmp(b->protocol, "BOOTP", 5) == 0) ||
		    (strncasecmp(b->protocol, "MOP", 3) == 0);
#if 0
		printf("diskboot = %d, netboot = %d\n", diskboot, netboot);
#endif
		initted =1;
	}

	if (pcidev == NULL) {
		if (strcmp(cd->cd_name, "pci"))
			return;
		else {
			struct pcibus_attach_args *pba = aux;

			if ((b->slot / 1000) != pba->pba_bus)
				return;

			pcidev = dev;
#if 0
			printf("\npcidev = %s\n", dev->dv_xname);
#endif
			return;
		}
	}

	if (ctrlrdev == NULL) {
		if (parent != pcidev)
			return;
		else {
			struct pci_attach_args *pa = aux;
			int slot;

			slot = pa->pa_bus * 1000 + pa->pa_function * 100 +
			    pa->pa_device;
			if (b->slot != slot)
				return;

			if (netboot) {
				booted_device = dev;
#if 0
				printf("\nbooted_device = %s\n", dev->dv_xname);
#endif
				found = 1;
			} else {
				ctrlrdev = dev;
#if 0
				printf("\nctrlrdev = %s\n", dev->dv_xname);
#endif
			}
			return;
		}
	}

	if (!diskboot)
		return;

	if (!strcmp(cd->cd_name, "sd") || !strcmp(cd->cd_name, "st") ||
	    !strcmp(cd->cd_name, "cd")) {
		struct scsi_attach_args *sa = aux;
		struct scsi_link *periph = sa->sa_sc_link;
		int unit;

		if (parent->dv_parent != ctrlrdev)
			return;

		unit = periph->target * 100 + periph->lun;
		if (b->unit != unit)
			return;

		/* we've found it! */
		booted_device = dev;
#if 0
		printf("\nbooted_device = %s\n", dev->dv_xname);
#endif
		found = 1;
	}
}


code:
/* $OpenBSD: dec_kn20aa.c,v 1.20 2014/05/08 20:46:49 miod Exp $ */
/* $NetBSD: dec_kn20aa.c,v 1.42 2000/05/22 20:13:32 thorpej Exp $ */

/*
 * Copyright (c) 1995, 1996, 1997 Carnegie-Mellon University.
 * All rights reserved.
 *
 * Author: Chris G. Demetriou
 *
 * Permission to use, copy, modify and distribute this software and
 * its documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */
/*
 * Additional Copyright (c) 1997 by Matthew Jacob for NASA/Ames Research Center
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/termios.h>
#include <dev/cons.h>
#include <sys/conf.h>

#include <machine/rpb.h>
#include <machine/autoconf.h>
#include <machine/cpuconf.h>
#include <machine/bus.h>

#include <dev/ic/comreg.h>
#include <dev/ic/comvar.h>

#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include <dev/ic/i8042reg.h>
#include <dev/ic/pckbcvar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>

#include <alpha/pci/ciareg.h>
#include <alpha/pci/ciavar.h>

#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>

#include "pckbd.h"

#ifndef CONSPEED
#define CONSPEED TTYDEF_SPEED
#endif
static int comcnrate = CONSPEED;

void dec_kn20aa_init(void);
static void dec_kn20aa_cons_init(void);
static void dec_kn20aa_device_register(struct device *, void *);

const struct alpha_variation_table dec_kn20aa_variations[] = {
	{ 0, "AlphaStation 500 or 600 (KN20AA)" },
	{ 0, NULL },
};

void
dec_kn20aa_init()
{
	u_int64_t variation;

	platform.family = "AlphaStation 500 or 600 (KN20AA)";

	if ((platform.model = alpha_dsr_sysname()) == NULL) {
		variation = hwrpb->rpb_variation & SV_ST_MASK;
		if ((platform.model = alpha_variation_name(variation,
		    dec_kn20aa_variations)) == NULL)
			platform.model = alpha_unknown_sysname();
	}

	platform.iobus = "cia";
	platform.cons_init = dec_kn20aa_cons_init;
	platform.device_register = dec_kn20aa_device_register;
}

static void
dec_kn20aa_cons_init()
{
	struct ctb *ctb;
	struct cia_config *ccp;
	extern struct cia_config cia_configuration;

	ccp = &cia_configuration;
	cia_init(ccp, 0);

	ctb = (struct ctb *)(((caddr_t)hwrpb) + hwrpb->rpb_ctb_off);

	switch (ctb->ctb_term_type) {
	case CTB_PRINTERPORT:
		/* serial console ... */
		/* XXX */
		{
			/*
			 * Delay to allow PROM putchars to complete.
			 * FIFO depth * character time,
			 * character time = (1000000 / (defaultrate / 10))
			 */
			DELAY(160000000 / comcnrate);

			if(comcnattach(&ccp->cc_iot, 0x3f8, comcnrate,
			    COM_FREQ,
			    (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8))
				panic("can't init serial console");

			break;
		}

	case CTB_GRAPHICS:
#if NPCKBD > 0
		/* display console ... */
		/* XXX */
		(void) pckbc_cnattach(&ccp->cc_iot, IO_KBD, KBCMDP, 0);

		if (CTB_TURBOSLOT_TYPE(ctb->ctb_turboslot) ==
		    CTB_TURBOSLOT_TYPE_ISA)
			isa_display_console(&ccp->cc_iot, &ccp->cc_memt);
		else
			pci_display_console(&ccp->cc_iot, &ccp->cc_memt,
			    &ccp->cc_pc, CTB_TURBOSLOT_BUS(ctb->ctb_turboslot),
			    CTB_TURBOSLOT_SLOT(ctb->ctb_turboslot), 0);
#else
		panic("not configured to use display && keyboard console");
#endif
		break;

	default:
		printf("ctb->ctb_term_type = 0x%lx\n",
		    (unsigned long)ctb->ctb_term_type);
		printf("ctb->ctb_turboslot = 0x%lx\n",
		    (unsigned long)ctb->ctb_turboslot);

		panic("consinit: unknown console type %lu",
		    (unsigned long)ctb->ctb_term_type);
	}
}

static void
dec_kn20aa_device_register(dev, aux)
	struct device *dev;
	void *aux;
{
	static int found, initted, diskboot, netboot;
	static struct device *pcidev, *ctrlrdev;
	struct bootdev_data *b = bootdev_data;
	struct device *parent = dev->dv_parent;
	struct cfdata *cf = dev->dv_cfdata;
	struct cfdriver *cd = cf->cf_driver;

	if (found)
		return;

	if (!initted) {
		diskboot = (strncasecmp(b->protocol, "SCSI", 4) == 0);
		netboot = (strncasecmp(b->protocol, "BOOTP", 5) == 0) ||
		    (strncasecmp(b->protocol, "MOP", 3) == 0);
#if 0
		printf("diskboot = %d, netboot = %d\n", diskboot, netboot);
#endif
		initted =1;
	}

	if (pcidev == NULL) {
		if (strcmp(cd->cd_name, "pci"))
			return;
		else {
			struct pcibus_attach_args *pba = aux;

			if ((b->slot / 1000) != pba->pba_bus)
				return;

			pcidev = dev;
#if 0
			printf("\npcidev = %s\n", dev->dv_xname);
#endif
			return;
		}
	}

	if (ctrlrdev == NULL) {
		if (parent != pcidev)
			return;
		else {
			struct pci_attach_args *pa = aux;
			int slot;

			slot = pa->pa_bus * 1000 + pa->pa_function * 100 +
			    pa->pa_device;
			if (b->slot != slot)
				return;

			if (netboot) {
				booted_device = dev;
#if 0
				printf("\nbooted_device = %s\n", dev->dv_xname);
#endif
				found = 1;
			} else {
				ctrlrdev = dev;
#if 0
				printf("\nctrlrdev = %s\n", dev->dv_xname);
#endif
			}
			return;
		}
	}

	if (!diskboot)
		return;

	if (!strcmp(cd->cd_name, "sd") || !strcmp(cd->cd_name, "st") ||
	    !strcmp(cd->cd_name, "cd")) {
		struct scsi_attach_args *sa = aux;
		struct scsi_link *periph = sa->sa_sc_link;
		int unit;

		if (parent->dv_parent != ctrlrdev)
			return;

		unit = periph->target * 100 + periph->lun;
		if (b->unit != unit)
			return;

		/* we've found it! */
		booted_device = dev;
#if 0
		printf("\nbooted_device = %s\n", dev->dv_xname);
#endif
		found = 1;
	}
}


code:
/* $OpenBSD: dec_kn300.c,v 1.8 2014/05/08 20:46:49 miod Exp $ */
/* $NetBSD: dec_kn300.c,v 1.34 2007/03/04 15:18:10 yamt Exp $ */

/*
 * Copyright (c) 1998 by Matthew Jacob
 * NASA AMES Research Center.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice immediately at the beginning of the file, without modification,
 *    this list of conditions, and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/termios.h>
#include <sys/conf.h>
#include <dev/cons.h>

#include <machine/rpb.h>
#include <machine/autoconf.h>
#include <machine/frame.h>
#include <machine/cpuconf.h>

#include <dev/ic/comreg.h>
#include <dev/ic/comvar.h>

#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include <dev/ic/i8042reg.h>
#include <dev/ic/pckbcvar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>

#include <alpha/mcbus/mcbusreg.h>
#include <alpha/mcbus/mcbusvar.h>
#include <alpha/pci/mcpciareg.h>
#include <alpha/pci/mcpciavar.h>
#include <alpha/pci/pci_kn300.h>

#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>

#include "pckbd.h"

#ifndef	CONSPEED
#define	CONSPEED	TTYDEF_SPEED
#endif
static int comcnrate = CONSPEED;

#ifdef DEBUG
int bootdev_debug;
#define DPRINTF(x)	do { if (bootdev_debug) printf x; } while (0)
#else
#define DPRINTF(x)	do { } while (0)
#endif

void dec_kn300_init (void);
void dec_kn300_cons_init (void);
static void dec_kn300_device_register (struct device *, void *);

#ifdef KGDB
#include <machine/db_machdep.h>

static const char *kgdb_devlist[] = {
	"com",
	NULL,
};
#endif /* KGDB */

#define	ALPHASERVER_4100	"AlphaServer 4100"

const struct alpha_variation_table dec_kn300_variations[] = {
	{ 0, ALPHASERVER_4100 },
	{ 0, NULL },
};

void
dec_kn300_init()
{
	u_int64_t variation;
	int cachesize;

	platform.family = ALPHASERVER_4100;

	if ((platform.model = alpha_dsr_sysname()) == NULL) {
		variation = hwrpb->rpb_variation & SV_ST_MASK;
		if ((platform.model = alpha_variation_name(variation,
		    dec_kn300_variations)) == NULL)
			platform.model = alpha_unknown_sysname();
	}

	platform.iobus = "mcbus";
	platform.cons_init = dec_kn300_cons_init;
	platform.device_register = dec_kn300_device_register;

	/*
	 * Determine B-cache size by looking at the primary (console)
	 * MCPCIA's WHOAMI register.
	 */
	mcpcia_init();

	if (mcbus_primary.mcbus_valid) {
		switch (mcbus_primary.mcbus_bcache) {
		default:
		case CPU_BCache_0MB:
			/* No B-cache or invalid; default to 1MB. */
			/* FALLTHROUGH */

		case CPU_BCache_1MB:
			cachesize = (1 * 1024 * 1024);
			break;

		case CPU_BCache_2MB:
			cachesize = (2 * 1024 * 1024);
			break;

		case CPU_BCache_4MB:
			cachesize = (4 * 1024 * 1024);
			break;
		}
	} else {
		/* Default to 1MB. */
		cachesize = (1 * 1024 * 1024);
	}
}

void
dec_kn300_cons_init()
{
	struct ctb *ctb;
	struct mcpcia_config *ccp;
	extern struct mcpcia_config mcpcia_console_configuration;

	ccp = &mcpcia_console_configuration;
	/* It's already initialized. */

	ctb = (struct ctb *)(((char *)hwrpb) + hwrpb->rpb_ctb_off);

	switch (ctb->ctb_term_type) {
	case CTB_PRINTERPORT:
		/* serial console ... */
		/*
		 * Delay to allow PROM putchars to complete.
		 * FIFO depth * character time,
		 * character time = (1000000 / (defaultrate / 10))
		 */
		DELAY(160000000 / comcnrate);
		if (comcnattach(&ccp->cc_iot, 0x3f8, comcnrate,
		    COM_FREQ,
		    (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8)) {
			panic("can't init serial console");

		}
		break;

	case CTB_GRAPHICS:
#if NPCKBD > 0
		/* display console ... */
		/* XXX */
		(void) pckbc_cnattach(&ccp->cc_iot, IO_KBD, KBCMDP, 0);

		if (CTB_TURBOSLOT_TYPE(ctb->ctb_turboslot) ==
		    CTB_TURBOSLOT_TYPE_ISA)
			isa_display_console(&ccp->cc_iot, &ccp->cc_memt);
		else
			pci_display_console(&ccp->cc_iot, &ccp->cc_memt,
			    &ccp->cc_pc, CTB_TURBOSLOT_BUS(ctb->ctb_turboslot),
			    CTB_TURBOSLOT_SLOT(ctb->ctb_turboslot), 0);
#else
		panic("not configured to use display && keyboard console");
#endif
		break;

	default:
		printf("ctb->ctb_term_type = 0x%lx\n",
		    (unsigned long)ctb->ctb_term_type);
		printf("ctb->ctb_turboslot = 0x%lx\n",
		    (unsigned long)ctb->ctb_turboslot);

		panic("consinit: unknown console type %lu",
		    (unsigned long)ctb->ctb_term_type);
	}
#ifdef KGDB
	/* Attach the KGDB device. */
	alpha_kgdb_init(kgdb_devlist, &ccp->cc_iot);
#endif /* KGDB */
}

static void
dec_kn300_device_register(dev, aux)
	struct device *dev;
	void *aux;
{
	static int found, initted, diskboot, netboot;
	static struct device *primarydev, *pcidev, *ctrlrdev;
	struct bootdev_data *b = bootdev_data;
	struct device *parent = dev->dv_parent;
	struct cfdata *cf = dev->dv_cfdata;
	struct cfdriver *cd = cf->cf_driver;

	if (found)
		return;

	if (!initted) {
		diskboot = (strncasecmp(b->protocol, "SCSI", 4) == 0);
		netboot = (strncasecmp(b->protocol, "BOOTP", 5) == 0) ||
		    (strncasecmp(b->protocol, "MOP", 3) == 0);

		DPRINTF(("proto:%s bus:%d slot:%d chan:%d", b->protocol,
		    b->bus, b->slot, b->channel));
		if (b->remote_address)
			DPRINTF((" remote_addr:%s", b->remote_address));
		DPRINTF((" un:%d bdt:%d", b->unit, b->boot_dev_type));
		if (b->ctrl_dev_type)
			DPRINTF((" cdt:%s\n", b->ctrl_dev_type));
		else
			DPRINTF(("\n"));
		DPRINTF(("diskboot = %d, netboot = %d\n", diskboot, netboot));
		initted = 1;
	}

	if (primarydev == NULL) {
		if (strcmp(cd->cd_name, "mcpcia"))
			return;
		else {
			struct mcbus_dev_attach_args *ma = aux;

			if (b->bus != ma->ma_mid - 4)
				return;
			primarydev = dev;
			DPRINTF(("\nprimarydev = %s\n", dev->dv_xname));
			return;
		}
	}

	if (pcidev == NULL) {
		if (strcmp(cd->cd_name, "pci"))
			return;
		/*
		 * Try to find primarydev anywhere in the ancestry.  This is
		 * necessary if the PCI bus is hidden behind a bridge.
		 */
		else {
			struct pcibus_attach_args *pba = aux;

			if ((b->slot / 1000) != pba->pba_bus)
				return;

			pcidev = dev;
			DPRINTF(("\npcidev = %s\n", dev->dv_xname));
			return;
		}
	}

	if (ctrlrdev == NULL) {
		if (parent != pcidev)
			return;
		else {
			struct pci_attach_args *pa = aux;
			int slot;

			slot = pa->pa_bus * 1000 + pa->pa_function * 100 +
			    pa->pa_device;
			if (b->slot != slot)
				return;

			if (netboot) {
				booted_device = dev;
				DPRINTF(("\nbooted_device = %s\n", dev->dv_xname));
				found = 1;
			} else {
				ctrlrdev = dev;
				DPRINTF(("\nctrlrdev = %s\n", dev->dv_xname));
			}
			return;
		}
	}

	if (!diskboot)
		return;

	if (strcmp(cd->cd_name, "sd") ||
	    strcmp(cd->cd_name, "st") ||
	    strcmp(cd->cd_name, "cd")) {
		struct scsi_attach_args *sa = aux;
		struct scsi_link *periph = sa->sa_sc_link;
		int unit;

		if (parent->dv_parent != ctrlrdev)
			return;

		unit = periph->target * 100 + periph->lun;
		if (b->unit != unit)
			return;

		/* we've found it! */
		booted_device = dev;
		DPRINTF(("\nbooted_device = %s\n", dev->dv_xname));
		found = 1;
	}
}


code:
/*	$OpenBSD: disksubr.c,v 1.98 2011/04/16 03:21:15 krw Exp $	*/
/*	$NetBSD: disksubr.c,v 1.21 1996/05/03 19:42:03 christos Exp $	*/

/*
 * Copyright (c) 1997 Niklas Hallqvist
 * Copyright (c) 1996 Theo de Raadt
 * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/disklabel.h>
#include <sys/disk.h>

/*
 * Attempt to read a disk label from a device
 * using the indicated strategy routine.
 * The label must be partly set up before this:
 * secpercyl, secsize and anything required for a block i/o read
 * operation in the driver's strategy/start routines
 * must be filled in before calling us.
 */
int
readdisklabel(dev_t dev, void (*strat)(struct buf *),
    struct disklabel *lp, int spoofonly)
{
	struct buf *bp = NULL;
	int error;

	if ((error = initdisklabel(lp)))
		goto done;

	/* get a buffer and initialize it */
	bp = geteblk((int)lp->d_secsize);
	bp->b_dev = dev;

	if (spoofonly)
		goto doslabel;

	bp->b_blkno = LABELSECTOR;
	bp->b_bcount = lp->d_secsize;
	CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
	SET(bp->b_flags, B_BUSY | B_READ | B_RAW);
	(*strat)(bp);
	if (biowait(bp)) {
		error = bp->b_error;
		goto done;
	}

	error = checkdisklabel(bp->b_data + LABELOFFSET, lp, 0,
	    DL_GETDSIZE(lp));
	if (error == 0)
		goto done;

doslabel:
	error = readdoslabel(bp, strat, lp, NULL, spoofonly);
	if (error == 0)
		goto done;

#if defined(CD9660)
	error = iso_disklabelspoof(dev, strat, lp);
	if (error == 0)
		goto done;
#endif
#if defined(UDF)
	error = udf_disklabelspoof(dev, strat, lp);
	if (error == 0)
		goto done;
#endif

done:
	if (bp) {
		bp->b_flags |= B_INVAL;
		brelse(bp);
	}
	disk_change = 1;
	return (error);
}

/*
 * Write disk label back to device after modification.
 */
int
writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp)
{
	u_int64_t csum = 0, *p;
	struct disklabel *dlp;
	struct buf *bp = NULL;
	int error, i;

	/* get a buffer and initialize it */
	bp = geteblk((int)lp->d_secsize);
	bp->b_dev = dev;

	bp->b_blkno = LABELSECTOR;
	bp->b_bcount = lp->d_secsize;
	CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
	SET(bp->b_flags, B_BUSY | B_READ | B_RAW);
	(*strat)(bp);
	if ((error = biowait(bp)) != 0)
		goto done;

	/* Write it in the regular place. */
	dlp = (struct disklabel *)(bp->b_data + LABELOFFSET);
	*dlp = *lp;

	/* Alpha bootblocks require a checksum over the sector */
	for (i = 0, p = (u_int64_t *)bp->b_data; i < 63; i++)
		csum += *p++;
	*p = csum;

	CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
	SET(bp->b_flags, B_BUSY | B_WRITE | B_RAW);
	(*strat)(bp);
	error = biowait(bp);

done:
	if (bp) {
		bp->b_flags |= B_INVAL;
		brelse(bp);
	}
	disk_change = 1;
	return (error);
}


code:
/*	$OpenBSD: fp_complete.c,v 1.11 2014/11/18 20:51:00 krw Exp $	*/
/*	$NetBSD: fp_complete.c,v 1.5 2002/01/18 22:15:56 ross Exp $	*/

/*-
 * Copyright (c) 2001 Ross Harvey
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the NetBSD
 *	Foundation, Inc. and its contributors.
 * 4. Neither the name of The NetBSD Foundation nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>

#include <machine/cpu.h>
#include <machine/fpu.h>
#include <machine/reg.h>
#include <alpha/alpha/db_instruction.h>

#include <lib/libkern/softfloat.h>

#define	TSWINSIZE 4	/* size of trap shadow window in u_int32_t units */

/*	Set Name		Opcodes			AARM C.* Symbols  */

#define	CPUREG_CLASS		(0xfUL << 0x10)		/* INT[ALSM]	  */
#define	FPUREG_CLASS		(0xfUL << 0x14)		/* ITFP, FLT[ILV] */
#define	CHECKFUNCTIONCODE	(1UL << 0x18)		/* MISC		  */
#define	TRAPSHADOWBOUNDARY	(1UL << 0x00 |		/* PAL		  */\
				 1UL << 0x19 |		/* \PAL\	  */\
				 1UL << 0x1a |		/* JSR		  */\
				 1UL << 0x1b |		/* \PAL\	  */\
				 1UL << 0x1d |		/* \PAL\	  */\
				 1UL << 0x1e |		/* \PAL\	  */\
				 1UL << 0x1f |		/* \PAL\	  */\
				 0xffffUL << 0x30 | 	/* branch ops	  */\
				 CHECKFUNCTIONCODE)

#define	MAKE_FLOATXX(width, expwidth, sign, exp, msb, rest_of_frac) \
	(u_int ## width ## _t)(sign) << ((width) - 1)			|\
	(u_int ## width ## _t)(exp)  << ((width) - 1 - (expwidth))	|\
	(u_int ## width ## _t)(msb)  << ((width) - 1 - (expwidth) - 1)	|\
	(u_int ## width ## _t)(rest_of_frac)

#define	FLOAT32QNAN MAKE_FLOATXX(32, 8, 0, 0xff, 1, 0)
#define	FLOAT64QNAN MAKE_FLOATXX(64, 11, 0, 0x7ff, 1, 0)

#define IS_SUBNORMAL(v)	((v)->exp == 0 && (v)->frac != 0)

#define	PREFILTER_SUBNORMAL(p,v) if ((p)->p_md.md_flags & IEEE_MAP_DMZ	\
				     && IS_SUBNORMAL(v))		\
					 (v)->frac = 0; else

#define	POSTFILTER_SUBNORMAL(p,v) if ((p)->p_md.md_flags & IEEE_MAP_UMZ	\
				      && IS_SUBNORMAL(v))		\
					  (v)->frac = 0; else

	/* Alpha returns 2.0 for true, all zeroes for false. */

#define CMP_RESULT(flag) ((flag) ? 4UL << 60 : 0L)

	/* Move bits from sw fp_c to hw fpcr. */

#define	CRBLIT(sw, hw, m, offs) (((sw) & ~(m)) | ((hw) >> (offs) & (m)))

/*
 * Temporary trap shadow instrumentation. The [un]resolved counters
 * could be kept permanently, as they provide information on whether
 * user code has met AARM trap shadow generation requirements.
 */

struct alpha_shadow {
	u_int64_t resolved;	/* cases trigger pc found */
	u_int64_t unresolved;	/* cases it wasn't, code problems? */
	u_int64_t scans;		/* trap shadow scans */
	u_int64_t len;		/* number of instructions examined */
	u_int64_t uop;		/* bit mask of unexpected opcodes */
	u_int64_t sqrts;	/* ev6+ square root single count */
	u_int64_t sqrtt;	/* ev6+ square root double count */
	u_int32_t ufunc;	/* bit mask of unexpected functions */
	u_int32_t max;		/* max trap shadow scan */
	u_int32_t nilswop;	/* unexpected op codes */
	u_int32_t nilswfunc;	/* unexpected function codes */
	u_int32_t nilanyop;	/* this "cannot happen" */
	u_int32_t vax;		/* sigs from vax fp opcodes */
} alpha_shadow, alpha_shadow_zero;

static float64 float64_unk(float64, float64);
static float64 compare_un(float64, float64);
static float64 compare_eq(float64, float64);
static float64 compare_lt(float64, float64);
static float64 compare_le(float64, float64);
static void cvt_qs_ts_st_gf_qf(u_int32_t, struct proc *);
static void cvt_gd(u_int32_t, struct proc *);
static void cvt_qt_dg_qg(u_int32_t, struct proc *);
static void cvt_tq_gq(u_int32_t, struct proc *);

static float32 (*swfp_s[])(float32, float32) = {
	float32_add, float32_sub, float32_mul, float32_div,
};

static float64 (*swfp_t[])(float64, float64) = {
	float64_add, float64_sub, float64_mul, float64_div,
	compare_un,    compare_eq,    compare_lt,    compare_le,
	float64_unk, float64_unk, float64_unk, float64_unk
};

static void (*swfp_cvt[])(u_int32_t, struct proc *) = {
	cvt_qs_ts_st_gf_qf, cvt_gd, cvt_qt_dg_qg, cvt_tq_gq
};

static void
this_cannot_happen(int what_cannot_happen, int64_t bits)
{
	static int total;
	alpha_instruction inst;
	static u_int64_t reported;

	inst.bits = bits;
	++alpha_shadow.nilswfunc;
	if (bits != -1)
		alpha_shadow.uop |= 1UL << inst.generic_format.opcode;
	if (1UL << what_cannot_happen & reported)
		return;
	reported |= 1UL << what_cannot_happen;
	if (total >= 1000)
		return;	/* right now, this return "cannot happen" */
	++total;
	if (bits)
		printf("FP instruction %x\n", (unsigned int)bits);
	printf("FP event %d/%lx/%lx\n", what_cannot_happen,
	    (unsigned long)reported, (unsigned long)alpha_shadow.uop);
}

static __inline void
sts(unsigned int rn, s_float *v, struct proc *p)
{
	alpha_sts(rn, v);
	PREFILTER_SUBNORMAL(p, v);
}

static __inline void
stt(unsigned int rn, t_float *v, struct proc *p)
{
	alpha_stt(rn, v);
	PREFILTER_SUBNORMAL(p, v);
}

static __inline void
lds(unsigned int rn, s_float *v, struct proc *p)
{
	POSTFILTER_SUBNORMAL(p, v);
	alpha_lds(rn, v);
}

static __inline void
ldt(unsigned int rn, t_float *v, struct proc *p)
{
	POSTFILTER_SUBNORMAL(p, v);
	alpha_ldt(rn, v);
}

static float64
compare_lt(float64 a, float64 b)
{
	return CMP_RESULT(float64_lt(a, b));
}

static float64
compare_le(float64 a, float64 b)
{
	return CMP_RESULT(float64_le(a, b));
}

static float64
compare_un(float64 a, float64 b)
{
	if (float64_is_nan(a) | float64_is_nan(b)) {
		if (float64_is_signaling_nan(a) | float64_is_signaling_nan(b))
			float_set_invalid();
		return CMP_RESULT(1);
	}
	return CMP_RESULT(0);
}

static float64
compare_eq(float64 a, float64 b)
{
	return CMP_RESULT(float64_eq(a, b));
}
/*
 * A note regarding the VAX FP ops.
 *
 * The AARM gives us complete leeway to set or not set status flags on VAX
 * ops, but we do any subnorm, NaN and dirty zero fixups anyway, and we set
 * flags by IEEE rules.  Many ops are common to d/f/g and s/t source types.
 * For the purely vax ones, it's hard to imagine ever running them.
 * (Generated VAX fp ops with completion flags? Hmm.)  We are careful never
 * to panic, assert, or print unlimited output based on a path through the
 * decoder, so weird cases don't become security issues.
 */
static void
cvt_qs_ts_st_gf_qf(u_int32_t inst_bits, struct proc *p)
{
	t_float tfb, tfc;
	s_float sfb, sfc;
	alpha_instruction inst;

	inst.bits = inst_bits;
	/*
	 * cvtst and cvtts have the same opcode, function, and source.  The
	 * distinction for cvtst is hidden in the illegal modifier combinations.
	 * We decode even the non-/s modifier, so that the fix-up-always mode
	 * works on ev6 and later. The rounding bits are unused and fixed for
	 * cvtst, so we check those too.
	 */
	switch(inst.float_format.function) {
	case op_cvtst:
	case op_cvtst_u:
		sts(inst.float_detail.fb, &sfb, p);
		tfc.i = float32_to_float64(sfb.i);
		ldt(inst.float_detail.fc, &tfc, p);
		return;
	}
	if(inst.float_detail.src == 2) {
		stt(inst.float_detail.fb, &tfb, p);
		sfc.i = float64_to_float32(tfb.i);
		lds(inst.float_detail.fc, &sfc, p);
		return;
	}
	/* 0: S/F */
	/* 1:  /D */
	/* 3: Q/Q */
	this_cannot_happen(5, inst.generic_format.opcode);
	tfc.i = FLOAT64QNAN;
	ldt(inst.float_detail.fc, &tfc, p);
	return;
}

static void
cvt_gd(u_int32_t inst_bits, struct proc *p)
{
	t_float tfb, tfc;
	alpha_instruction inst;

	inst.bits = inst_bits;
	stt(inst.float_detail.fb, &tfb, p);
	(void) float64_to_float32(tfb.i);
	p->p_md.md_flags &= ~OPENBSD_FLAG_TO_FP_C(FP_X_IMP);
	tfc.i = float64_add(tfb.i, (float64)0);
	ldt(inst.float_detail.fc, &tfc, p);
}

static void
cvt_qt_dg_qg(u_int32_t inst_bits, struct proc *p)
{
	t_float tfb, tfc;
	alpha_instruction inst;

	inst.bits = inst_bits;
	switch(inst.float_detail.src) {
	case 0:	/* S/F */
		this_cannot_happen(3, inst.bits);
		/* fall thru */
	case 1: /* D */
		/* VAX dirty 0's and reserved ops => UNPREDICTABLE */
		/* We've done what's important by just not trapping */
		tfc.i = 0;
		break;
	case 2: /* T/G */
		this_cannot_happen(4, inst.bits);
		tfc.i = 0;
		break;
	case 3:	/* Q/Q */
		stt(inst.float_detail.fb, &tfb, p);
		tfc.i = int64_to_float64(tfb.i);
		break;
	}
	alpha_ldt(inst.float_detail.fc, &tfc);
}
/*
 * XXX: AARM and 754 seem to disagree here, also, beware of softfloat's
 *      unfortunate habit of always returning the nontrapping result.
 * XXX: there are several apparent AARM/AAH disagreements, as well as
 *      the issue of trap handler pc and trapping results.
 * XXX: this function will work for signed and unsigned 64-bit integers.
 *      rounding will happen per IEEE 754.  invalid exception will be
 *      raised if argument is infinity, not-a-number or if it
 *      overflows/underflows.  zero will be returned, in this case.
 */
static void
cvt_tq_gq(u_int32_t inst_bits, struct proc *p)
{
	t_float tfb, tfc;
	alpha_instruction inst;

	inst.bits = inst_bits;
	stt(inst.float_detail.fb, &tfb, p);
	tfc.i = float64_to_int64_no_overflow(tfb.i);
	alpha_ldt(inst.float_detail.fc, &tfc);	/* yes, ldt */
}

static u_int64_t
fp_c_to_fpcr_1(u_int64_t fpcr, u_int64_t fp_c)
{
	u_int64_t disables;

	/*
	 * It's hard to arrange for conforming bit fields, because the FP_C
	 * and the FPCR are both architected, with specified (and relatively
	 * scrambled) bit numbers. Defining an internal unscrambled FP_C
	 * wouldn't help much, because every user exception requires the
	 * architected bit order in the sigcontext.
	 *
	 * Programs that fiddle with the fpcr exception bits (instead of fp_c)
	 * will lose, because those bits can be and usually are subsetted;
	 * the official home is in the fp_c. Furthermore, the kernel puts
	 * phony enables (it lies :-) in the fpcr in order to get control when
	 * it is necessary to initially set a sticky bit.
	 */

	fpcr &= FPCR_DYN(3);

	/*
	 * enable traps = case where flag bit is clear OR program wants a trap
	 * enables = ~flags | mask
	 * disables = ~(~flags | mask)
	 * disables = flags & ~mask. Thank you, Augustus De Morgan (1806-1871)
	 */
	disables = FP_C_TO_OPENBSD_FLAG(fp_c) & ~FP_C_TO_OPENBSD_MASK(fp_c);

	fpcr |= (disables & (FP_X_IMP | FP_X_UFL)) << (61 - 3);
	fpcr |= (disables & (FP_X_OFL | FP_X_DZ | FP_X_INV)) << (49 - 0);

#	if !(FP_X_INV == 1 && FP_X_DZ == 2 && FP_X_OFL == 4 &&		\
	    FP_X_UFL == 8 && FP_X_IMP == 16 && FP_X_IOV == 32 &&	\
	    FP_X_UFL << (61 - 3) == FPCR_UNFD &&			\
	    FP_X_IMP << (61 - 3) == FPCR_INED &&			\
	    FP_X_OFL << (49 - 0) == FPCR_OVFD)
#		error "Assertion failed"
	/*
	 * We don't care about the other built-in bit numbers because they
	 * have been architecturally specified.
	 */
#	endif

	fpcr |= fp_c & FP_C_MIRRORED << (FPCR_MIR_START - FP_C_MIR_START);
	fpcr |= (fp_c & IEEE_MAP_DMZ) << 36;
	if (fp_c & FP_C_MIRRORED)
		fpcr |= FPCR_SUM;
	if (fp_c & IEEE_MAP_UMZ)
		fpcr |= FPCR_UNDZ | FPCR_UNFD;
	fpcr |= (~fp_c & IEEE_TRAP_ENABLE_DNO) << 41;
	return fpcr;
}

static void
fp_c_to_fpcr(struct proc *p)
{
	alpha_write_fpcr(fp_c_to_fpcr_1(alpha_read_fpcr(), p->p_md.md_flags));
}

void
alpha_write_fp_c(struct proc *p, u_int64_t fp_c)
{
	u_int64_t md_flags;

	fp_c &= MDP_FP_C;
	md_flags = p->p_md.md_flags;
	if ((md_flags & MDP_FP_C) == fp_c)
		return;
	p->p_md.md_flags = (md_flags & ~MDP_FP_C) | fp_c;
	alpha_enable_fp(p, 1);
	alpha_pal_wrfen(1);
	fp_c_to_fpcr(p);
	alpha_pal_wrfen(0);
}

u_int64_t
alpha_read_fp_c(struct proc *p)
{
	/*
	 * A possibly desirable EV6-specific optimization would deviate from
	 * the Alpha Architecture spec and keep some FP_C bits in the FPCR,
	 * but in a transparent way. Some of the code for that would need to
	 * go right here.
	 */
	return p->p_md.md_flags & MDP_FP_C;
}

static float64
float64_unk(float64 a, float64 b)
{
	return 0;
}

/*
 * The real function field encodings for IEEE and VAX FP instructions.
 *
 * Since there is only one operand type field, the cvtXX instructions
 * require a variety of special cases, and these have to be analyzed as
 * they don't always fit into the field descriptions in AARM section I.
 *
 * Lots of staring at bits in the appendix shows what's really going on.
 *
 *	   |	       |
 * 15 14 13|12 11 10 09|08 07 06 05
 * --------======------============
 *  TRAP   : RND : SRC : FUNCTION  :
 *  0  0  0:. . .:. . . . . . . . . . . . Imprecise
 *  0  0  1|. . .:. . . . . . . . . . . ./U underflow enable (if FP output)
 *	   |				 /V overfloat enable (if int output)
 *  0  1  0:. . .:. . . . . . . . . . . ."Unsupported", but used for CVTST
 *  0  1  1|. . .:. . . . . . . . . . . . Unsupported
 *  1  0  0:. . .:. . . . . . . . . . . ./S software completion (VAX only)
 *  1  0  1|. . .:. . . . . . . . . . . ./SU
 *	   |				 /SV
 *  1  1  0:. . .:. . . . . . . . . . . ."Unsupported", but used for CVTST/S
 *  1  1  1|. . .:. . . . . . . . . . . ./SUI (if FP output)	(IEEE only)
 *	   |				 /SVI (if int output)   (IEEE only)
 *  S  I  UV: In other words: bits 15:13 are S:I:UV, except that _usually_
 *	   |  not all combinations are valid.
 *	   |	       |
 * 15 14 13|12 11 10 09|08 07 06 05
 * --------======------============
 *  TRAP   : RND : SRC : FUNCTION  :
 *	   | 0	0 . . . . . . . . . . . ./C Chopped
 *	   : 0	1 . . . . . . . . . . . ./M Minus Infinity
 *	   | 1	0 . . . . . . . . . . . .   Normal
 *	   : 1	1 . . . . . . . . . . . ./D Dynamic (in FPCR: Plus Infinity)
 *	   |	       |
 * 15 14 13|12 11 10 09|08 07 06 05
 * --------======------============
 *  TRAP   : RND : SRC : FUNCTION  :
 *		   0 0. . . . . . . . . . S/F
 *		   0 1. . . . . . . . . . -/D
 *		   1 0. . . . . . . . . . T/G
 *		   1 1. . . . . . . . . . Q/Q
 *	   |	       |
 * 15 14 13|12 11 10 09|08 07 06 05
 * --------======------============
 *  TRAP   : RND : SRC : FUNCTION  :
 *			 0  0  0  0 . . . addX
 *			 0  0  0  1 . . . subX
 *			 0  0  1  0 . . . mulX
 *			 0  0  1  1 . . . divX
 *			 0  1  0  0 . . . cmpXun
 *			 0  1  0  1 . . . cmpXeq
 *			 0  1  1  0 . . . cmpXlt
 *			 0  1  1  1 . . . cmpXle
 *			 1  0  0  0 . . . reserved
 *			 1  0  0  1 . . . reserved
 *			 1  0  1  0 . . . sqrt[fg] (op_fix, not exactly "vax")
 *			 1  0  1  1 . . . sqrt[st] (op_fix, not exactly "ieee")
 *			 1  1  0  0 . . . cvtXs/f (cvt[qt]s, cvtst(!), cvt[gq]f)
 *			 1  1  0  1 . . . cvtXd   (vax only)
 *			 1  1  1  0 . . . cvtXt/g (cvtqt, cvt[dq]g only)
 *			 1  1  1  1 . . . cvtXq/q (cvttq, cvtgq)
 *	   |	       |
 * 15 14 13|12 11 10 09|08 07 06 05	  the twilight zone
 * --------======------============
 *  TRAP   : RND : SRC : FUNCTION  :
 * /s /i /u  x  x  1  0  1  1  0  0 . . . cvtts, /siu only 0, 1, 5, 7
 *  0  1  0  1  0  1  0  1  1  0  0 . . . cvtst   (src == T (!)) 2ac NOT /S
 *  1  1  0  1  0  1  0  1  1  0  0 . . . cvtst/s (src == T (!)) 6ac
 *  x  0  x  x  x  x  0	 1  1  1  1 . . . cvttq/_ (src == T)
 */

static void
alpha_fp_interpret(alpha_instruction *pc, struct proc *p, u_int64_t bits)
{
	s_float sfa, sfb, sfc;
	t_float tfa, tfb, tfc;
	alpha_instruction inst;

	inst.bits = bits;
	switch(inst.generic_format.opcode) {
	default:
		/* this "cannot happen" */
		this_cannot_happen(2, inst.bits);
		return;
	case op_any_float:
		if (inst.float_format.function == op_cvtql_sv ||
		    inst.float_format.function == op_cvtql_v) {
			alpha_stt(inst.float_detail.fb, &tfb);
			sfc.i = (int64_t)tfb.i >= 0L ? INT_MAX : INT_MIN;
			alpha_lds(inst.float_detail.fc, &sfc);
			float_raise(FP_X_INV);
		} else {
			++alpha_shadow.nilanyop;
			this_cannot_happen(3, inst.bits);
		}
		break;
	case op_vax_float:
		++alpha_shadow.vax;	/* fall thru */
	case op_ieee_float:
	case op_fix_float:
		switch(inst.float_detail.src) {
		case op_src_sf:
			sts(inst.float_detail.fb, &sfb, p);
			if (inst.float_detail.opclass == 10)
				sfc.i = float32_sqrt(sfb.i);
			else if (inst.float_detail.opclass & ~3) {
				this_cannot_happen(1, inst.bits);
				sfc.i = FLOAT32QNAN;
			} else {
				sts(inst.float_detail.fa, &sfa, p);
				sfc.i = (*swfp_s[inst.float_detail.opclass])(
				    sfa.i, sfb.i);
			}
			lds(inst.float_detail.fc, &sfc, p);
			break;
		case op_src_xd:
		case op_src_tg:
			if (inst.float_detail.opclass >= 12)
				(*swfp_cvt[inst.float_detail.opclass - 12])(
				    inst.bits, p);
			else {
				stt(inst.float_detail.fb, &tfb, p);
				if (inst.float_detail.opclass == 10)
					tfc.i = float64_sqrt(tfb.i);
				else {
					stt(inst.float_detail.fa, &tfa, p);
					tfc.i = (*swfp_t[inst.float_detail
					    .opclass])(tfa.i, tfb.i);
				}
				ldt(inst.float_detail.fc, &tfc, p);
			}
			break;
		case op_src_qq:
			float_raise(FP_X_IMP);
			break;
		}
	}
}

static int
alpha_fp_complete_at(alpha_instruction *trigger_pc, struct proc *p,
    u_int64_t *ucode)
{
	int needsig;
	alpha_instruction inst;
	u_int64_t rm, fpcr, orig_fpcr;
	u_int64_t orig_flags, new_flags, changed_flags, md_flags;

	if (__predict_false(copyin(trigger_pc, &inst, sizeof inst))) {
		this_cannot_happen(6, -1);
		return SIGSEGV;
	}
	alpha_enable_fp(p, 1);
	alpha_pal_wrfen(1);
	/*
	 * If necessary, lie about the dynamic rounding mode so emulation
	 * software need go to only one place for it, and so we don't have to
	 * lock any memory locations or pass a third parameter to every
	 * SoftFloat entry point.
	 */
	orig_fpcr = fpcr = alpha_read_fpcr();
	rm = inst.float_detail.rnd;
	if (__predict_false(rm != 3 /* dynamic */ && rm != (fpcr >> 58 & 3))) {
		fpcr = (fpcr & ~FPCR_DYN(3)) | FPCR_DYN(rm);
		alpha_write_fpcr(fpcr);
	}
	orig_flags = FP_C_TO_OPENBSD_FLAG(p->p_md.md_flags);

	alpha_fp_interpret(trigger_pc, p, inst.bits);

	md_flags = p->p_md.md_flags;

	new_flags = FP_C_TO_OPENBSD_FLAG(md_flags);
	changed_flags = orig_flags ^ new_flags;
	KASSERT((orig_flags | changed_flags) == new_flags); /* panic on 1->0 */
	alpha_write_fpcr(fp_c_to_fpcr_1(orig_fpcr, md_flags));
	needsig = changed_flags & FP_C_TO_OPENBSD_MASK(md_flags);
	alpha_pal_wrfen(0);
	if (__predict_false(needsig)) {
		*ucode = needsig;
		return SIGFPE;
	}
	return 0;
}

int
alpha_fp_complete(u_long a0, u_long a1, struct proc *p, u_int64_t *ucode)
{
	int t;
	int sig;
	u_int64_t op_class;
	alpha_instruction inst;
	/* "trigger_pc" is Compaq's term for the earliest faulting op */
	alpha_instruction *trigger_pc, *usertrap_pc;
	alpha_instruction *pc, *win_begin, tsw[TSWINSIZE];

	sig = SIGFPE;
	pc = (alpha_instruction *)p->p_md.md_tf->tf_regs[FRAME_PC];
	trigger_pc = pc - 1;	/* for ALPHA_AMASK_PAT case */
	if (cpu_amask & ALPHA_AMASK_PAT) {
		if (a0 & 1 || alpha_fp_sync_complete) {
			sig = alpha_fp_complete_at(trigger_pc, p, ucode);
			goto done;
		}
	}
	*ucode = a0;
	if (!(a0 & 1))
		return sig;
/*
 * At this point we are somewhere in the trap shadow of one or more instruc-
 * tions that have trapped with software completion specified.  We have a mask
 * of the registers written by trapping instructions.
 *
 * Now step backwards through the trap shadow, clearing bits in the
 * destination write mask until the trigger instruction is found, and
 * interpret this one instruction in SW. If a SIGFPE is not required, back up
 * the PC until just after this instruction and restart. This will execute all
 * trap shadow instructions between the trigger pc and the trap pc twice.
 *
 * If a SIGFPE is generated from the OSF1 emulation,  back up one more
 * instruction to the trigger pc itself. Native binaries don't because it
 * is non-portable and completely defeats the intended purpose of IEEE
 * traps -- for example, to count the number of exponent wraps for a later
 * correction.
 */
	trigger_pc = 0;
	win_begin = pc;
	++alpha_shadow.scans;
	t = alpha_shadow.len;
	for (--pc; a1; --pc) {
		++alpha_shadow.len;
		if (pc < win_begin) {
			win_begin = pc - TSWINSIZE + 1;
			if (copyin(win_begin, tsw, sizeof tsw)) {
				/* sigh, try to get just one */
				win_begin = pc;
				if (copyin(win_begin, tsw, 4))
					return SIGSEGV;
			}
		}
		inst = tsw[pc - win_begin];
		op_class = 1UL << inst.generic_format.opcode;
		if (op_class & FPUREG_CLASS) {
			a1 &= ~(1UL << (inst.operate_generic_format.rc + 32));
			trigger_pc = pc;
		} else if (op_class & CPUREG_CLASS) {
			a1 &= ~(1UL << inst.operate_generic_format.rc);
			trigger_pc = pc;
		} else if (op_class & TRAPSHADOWBOUNDARY) {
			if (op_class & CHECKFUNCTIONCODE) {
				if (inst.mem_format.displacement == op_trapb ||
				    inst.mem_format.displacement == op_excb)
					break;	/* code breaks AARM rules */
			} else
				break; /* code breaks AARM rules */
		}
		/* Some shadow-safe op, probably load, store, or FPTI class */
	}
	t = alpha_shadow.len - t;
	if (t > alpha_shadow.max)
		alpha_shadow.max = t;
	if (__predict_true(trigger_pc != 0 && a1 == 0)) {
		++alpha_shadow.resolved;
		sig = alpha_fp_complete_at(trigger_pc, p, ucode);
	} else {
		++alpha_shadow.unresolved;
		return sig;
	}
done:
	if (sig) {
		usertrap_pc = trigger_pc + 1;
		p->p_md.md_tf->tf_regs[FRAME_PC] = (unsigned long)usertrap_pc;
		return sig;
	}
	return 0;
}


code:
#	$OpenBSD: genassym.cf,v 1.12 2012/11/01 21:09:17 miod Exp $

# Copyright (c) 1994, 1995 Gordon W. Ross
# Copyright (c) 1993 Adam Glass
# Copyright (c) 1982, 1990, 1993
#	The Regents of the University of California.  All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. Neither the name of the University nor the names of its contributors
#    may be used to endorse or promote products derived from this software
#    without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.

include <sys/param.h>
include <sys/buf.h>
include <sys/proc.h>
include <sys/mbuf.h>
include <sys/msgbuf.h>
include <sys/syscall.h>
include <sys/user.h>

include <machine/cpu.h>
include <machine/reg.h>
include <machine/frame.h>
include <machine/rpb.h>
include <machine/vmparam.h>

include <uvm/uvm_extern.h>

# general constants
export	VM_MAX_ADDRESS

# Register offsets, for stack frames.
export	FRAME_V0
export	FRAME_T0
export	FRAME_T1
export	FRAME_T2
export	FRAME_T3
export	FRAME_T4
export	FRAME_T5
export	FRAME_T6
export	FRAME_T7
export	FRAME_S0
export	FRAME_S1
export	FRAME_S2
export	FRAME_S3
export	FRAME_S4
export	FRAME_S5
export	FRAME_S6
export	FRAME_A3
export	FRAME_A4
export	FRAME_A5
export	FRAME_T8
export	FRAME_T9
export	FRAME_T10
export	FRAME_T11
export	FRAME_RA
export	FRAME_T12
export	FRAME_AT
export	FRAME_SP

export	FRAME_SW_SIZE

export	FRAME_PS
export	FRAME_PC
export	FRAME_GP
export	FRAME_A0
export	FRAME_A1
export	FRAME_A2

export	FRAME_SIZE

# bits of the PS register
export	ALPHA_PSL_USERMODE
export	ALPHA_PSL_IPL_MASK
export	ALPHA_PSL_IPL_0
export	ALPHA_PSL_IPL_SOFT
export	ALPHA_PSL_IPL_HIGH

# pte bits
export	ALPHA_PTE_VALID
export	ALPHA_PTE_ASM
export	ALPHA_PTE_KR
export	ALPHA_PTE_KW

# Important offsets into the proc struct & associated constants
struct	proc
member	p_addr
member	p_vmspace
member	p_stat
member	P_MD_ASTPENDING	p_md.md_astpending
member	P_MD_PCBPADDR	p_md.md_pcbpaddr
member	p_cpu

export	SONPROC

# offsets needed by cpu_switch() to switch mappings.
define	VM_MAP_PMAP		offsetof(struct vmspace, vm_map.pmap)

# Important offsets into the user struct & associated constants
export	UPAGES
struct	user
member	u_pcb
member	U_PCB_HWPCB		u_pcb.pcb_hw
member	U_PCB_HWPCB_KSP		u_pcb.pcb_hw.apcb_ksp
member	U_PCB_CONTEXT		u_pcb.pcb_context[0]
member	U_PCB_ONFAULT		u_pcb.pcb_onfault

# Offsets into struct fpstate, for save, restore
struct	fpreg		FPREG_
member	FPR_REGS	fpr_regs[0]
member	fpr_cr

# Important other addresses
export	HWRPB_ADDR
export	VPTBASE

# Offsets into the HWRPB.
define	RPB_PRIMARY_CPU_ID	offsetof(struct rpb, rpb_primary_cpu_id)

# Kernel entries
export	ALPHA_KENTRY_ARITH
export	ALPHA_KENTRY_MM
export	ALPHA_KENTRY_IF
export	ALPHA_KENTRY_UNA

# errno values
export	ENAMETOOLONG
export	EFAULT

# Syscalls called from sigreturn.
export	SYS_sigreturn
export	SYS_exit

# CPU info
struct	cpu_info	CPU_INFO_
member	CURPROC		ci_curproc
member	FPCURPROC	ci_fpcurproc
member	CURPCB		ci_curpcb
member	IDLE_PCB_PADDR	ci_idle_pcb_paddr
member	WANT_RESCHED	ci_want_resched


code:
/*	$OpenBSD: in_cksum.c,v 1.9 2014/08/21 14:24:08 mpi Exp $	*/
/*	$NetBSD: in_cksum.c,v 1.4 1996/11/13 21:13:06 cgd Exp $	*/

/*
 * Copyright (c) 1988, 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 * Copyright (c) 1996
 *	Matt Thomas <matt@3am-software.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)in_cksum.c	8.1 (Berkeley) 6/10/93
 */

#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/systm.h>
#include <sys/socketvar.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>

/*
 * Checksum routine for Internet Protocol family headers
 *    (Portable Alpha version).
 *
 * This routine is very heavily used in the network
 * code and should be modified for each CPU to be as fast as possible.
 */

#define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
#define REDUCE32							  \
    {									  \
	q_util.q = sum;							  \
	sum = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3];	  \
    }
#define REDUCE16							  \
    {									  \
	q_util.q = sum;							  \
	l_util.l = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
	sum = l_util.s[0] + l_util.s[1];				  \
	ADDCARRY(sum);							  \
    }

static const u_int32_t in_masks[] = {
	/*0 bytes*/ /*1 byte*/	/*2 bytes*/ /*3 bytes*/
	0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF,	/* offset 0 */
	0x00000000, 0x0000FF00, 0x00FFFF00, 0xFFFFFF00,	/* offset 1 */
	0x00000000, 0x00FF0000, 0xFFFF0000, 0xFFFF0000,	/* offset 2 */
	0x00000000, 0xFF000000, 0xFF000000, 0xFF000000,	/* offset 3 */
};

union l_util {
	u_int16_t s[2];
	u_int32_t l;
};
union q_util {
	u_int16_t s[4];
	u_int32_t l[2];
	u_int64_t q;
};

static u_int64_t
in_cksumdata(caddr_t buf, int len)
{
	const u_int32_t *lw = (u_int32_t *) buf;
	u_int64_t sum = 0;
	u_int64_t prefilled;
	int offset;
	union q_util q_util;

	if ((3 & (long) lw) == 0 && len == 20) {
	     sum = (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3] + lw[4];
	     REDUCE32;
	     return sum;
	}

	if ((offset = 3 & (long) lw) != 0) {
		const u_int32_t *masks = in_masks + (offset << 2);
		lw = (u_int32_t *) (((long) lw) - offset);
		sum = *lw++ & masks[len >= 3 ? 3 : len];
		len -= 4 - offset;
		if (len <= 0) {
			REDUCE32;
			return sum;
		}
	}
#if 0
	/*
	 * Force to cache line boundary.
	 */
	offset = 32 - (0x1f & (long) lw);
	if (offset < 32 && len > offset) {
		len -= offset;
		if (4 & offset) {
			sum += (u_int64_t) lw[0];
			lw += 1;
		}
		if (8 & offset) {
			sum += (u_int64_t) lw[0] + lw[1];
			lw += 2;
		}
		if (16 & offset) {
			sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3];
			lw += 4;
		}
	}
#endif
	/*
	 * access prefilling to start load of next cache line.
	 * then add current cache line
	 * save result of prefilling for loop iteration.
	 */
	prefilled = lw[0];
	while ((len -= 32) >= 4) {
		u_int64_t prefilling = lw[8];
		sum += prefilled + lw[1] + lw[2] + lw[3]
			+ lw[4] + lw[5] + lw[6] + lw[7];
		lw += 8;
		prefilled = prefilling;
	}
	if (len >= 0) {
		sum += prefilled + lw[1] + lw[2] + lw[3]
			+ lw[4] + lw[5] + lw[6] + lw[7];
		lw += 8;
	} else {
		len += 32;
	}
	while ((len -= 16) >= 0) {
		sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3];
		lw += 4;
	}
	len += 16;
	while ((len -= 4) >= 0) {
		sum += (u_int64_t) *lw++;
	}
	len += 4;
	if (len > 0)
		sum += (u_int64_t) (in_masks[len] & *lw);
	REDUCE32;
	return sum;
}

int
in_cksum(struct mbuf *m, int len)
{
	u_int64_t sum = 0;
	int mlen = 0;
	int clen = 0;
	caddr_t addr;
	union l_util l_util;
	union q_util q_util;

	for (; m && len; m = m->m_next) {
		if (m->m_len == 0)
			continue;
		mlen = m->m_len;
		if (len < mlen)
			mlen = len;
		addr = mtod(m, caddr_t);
		if ((clen ^ (long) addr) & 1)
		    sum += in_cksumdata(addr, mlen) << 8;
		else
		    sum += in_cksumdata(addr, mlen);

		clen += mlen;
		len -= mlen;
	}
	REDUCE16;
	return (~sum & 0xffff);
}

int
in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len)
{
	u_int64_t sum = 0;
	int mlen = 0;
	int clen = 0;
	caddr_t addr;
	union q_util q_util;
	union l_util l_util;
	struct ipovly ipov;

	if (nxt != 0) {
#ifdef DEBUG
		/* pseudo header */
		if (off < sizeof(struct ipovly))
			panic("in4_cksum: offset too short");
		if (m->m_len < sizeof(struct ip))
			panic("in4_cksum: bad mbuf chain");
#endif

		memset(&ipov, 0, sizeof(ipov));

		ipov.ih_len = htons(len);
		ipov.ih_pr = nxt;
		ipov.ih_src = mtod(m, struct ip *)->ip_src;
		ipov.ih_dst = mtod(m, struct ip *)->ip_dst;

		sum += in_cksumdata((caddr_t) &ipov, sizeof(ipov));
	}

	/* skip over unnecessary part */
	while (m != NULL && off > 0) {
		if (m->m_len > off)
			break;
		off -= m->m_len;
		m = m->m_next;
	}

	for (; m && len; m = m->m_next, off = 0) {
		if (m->m_len == 0)
			continue;
		mlen = m->m_len - off;
		if (len < mlen)
			mlen = len;
		addr = mtod(m, caddr_t) + off;
		if ((clen ^ (long) addr) & 1)
			sum += in_cksumdata(addr, mlen) << 8;
 		else
			sum += in_cksumdata(addr, mlen);

 		clen += mlen;
 		len -= mlen;
	}
	REDUCE16;
	return (~sum & 0xffff);
}