root/sys/arch/vax/boot/boot/ra.c
/*      $NetBSD: ra.c,v 1.23 2025/07/14 12:39:34 hans Exp $ */
/*
 * Copyright (c) 1995 Ludd, University of Lule}, Sweden.
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
 */

 /* All bugs are subject to removal without further notice */

#define NRSP 1 /* Kludge */
#define NCMD 1 /* Kludge */

#include <sys/param.h>
#include <sys/disklabel.h>

#include <lib/libsa/stand.h>

#include <lib/libkern/libkern.h>

#include "../include/pte.h"
#include "../include/rpb.h"

#include <dev/mscp/mscp.h>
#include <dev/mscp/mscpreg.h>

#include <dev/bi/bireg.h>
#include <dev/bi/kdbreg.h>

#include "vaxstand.h"

static void command(int, int);

/*
 * These routines for RA disk standalone boot is wery simple,
 * assuming a lots of thing like that we only working at one ra disk
 * a time, no separate routines for uba driver etc..
 * This code is foolish and should need a cleanup.
 * But it works :)
 */

static volatile struct uda {
        struct  mscp_1ca uda_ca;  /* communications area */
        struct  mscp uda_rsp;     /* response packets */
        struct  mscp uda_cmd;     /* command packets */
} uda;

static struct disklabel ralabel;
static char io_buf[DEV_BSIZE];
static int dpart, dunit, is_tmscp, curblock;
static volatile u_short *ra_ip, *ra_sa, *ra_sw;

int
raopen(struct open_file *f, int adapt, int ctlr, int unit, int part)
{
        static volatile struct uda *ubauda;
        unsigned short johan, johan2;
        size_t i;
        int err;
        char *msg;

#ifdef DEV_DEBUG
        printf("raopen: adapter %d ctlr %d unit %d part %d\n",
            adapt, ctlr, unit, part);
        printf("raopen: csrbase %x nexaddr %x\n", csrbase, nexaddr);
#endif
        memset(&ralabel, 0, sizeof(struct disklabel));
        memset((void *)&uda, 0, sizeof(struct uda));
        if (bootrpb.devtyp == BDEV_TK)
                is_tmscp = 1;
        dunit = unit;
        dpart = part;
        if (ctlr < 0)
                ctlr = 0;
        curblock = 0;
        if (csrbase) { /* On a uda-alike adapter */
                if (askname == 0) {
                        csrbase = bootrpb.csrphy;
                        dunit = bootrpb.unit;
                        nexaddr = bootrpb.adpphy;
                } else
                        csrbase += (ctlr ? 000334 : 012150);
                ra_ip = (u_short *)csrbase;
                ra_sa = ra_sw = (u_short *)csrbase + 1;
                
                ubauda = (struct uda *)ubmap(494,
                    (int)&uda, sizeof(struct uda));
                johan = (((u_int)ubauda) & 0xffff) + 8;
                johan2 = (((u_int)ubauda) >> 16) & 077;
                *ra_ip = 0; /* Start init */
                bootrpb.csrphy = csrbase;
        } else {
                paddr_t kdaddr;
                volatile int *w;
                volatile int i = 10000;

                if (askname == 0) {
                        nexaddr = bootrpb.csrphy;
                        dunit = bootrpb.unit;
                } else {
                        nexaddr = (bootrpb.csrphy & ~(BI_NODESIZE - 1)) + KDB_IP;
                        bootrpb.csrphy = nexaddr;
                }

                kdaddr = nexaddr & ~(BI_NODESIZE - 1);
                ra_ip = (u_short *)(kdaddr + KDB_IP);
                ra_sa = (u_short *)(kdaddr + KDB_SA);
                ra_sw = (u_short *)(kdaddr + KDB_SW);
                johan = ((u_int)&uda.uda_ca.ca_rspdsc) & 0xffff;
                johan2 = (((u_int)&uda.uda_ca.ca_rspdsc) & 0xffff0000) >> 16;
                w = (int *)(kdaddr + BIREG_VAXBICSR);
                *w = *w | BICSR_NRST;
                while (i--) /* Need delay??? */
                        ;
                w = (int *)(kdaddr + BIREG_BER);
                *w = ~(BIBER_MBZ|BIBER_NMR|BIBER_UPEN);/* ??? */
                ubauda = &uda;
        }

#ifdef DEV_DEBUG
        printf("start init\n");
#endif
        /* Init of this uda */
        while ((*ra_sa & MP_STEP1) == 0)
                ;
#ifdef DEV_DEBUG
        printf("MP_STEP1...");
#endif
        *ra_sw = 0x8000;
        while ((*ra_sa & MP_STEP2) == 0)
                ;
#ifdef DEV_DEBUG
        printf("MP_STEP2...");
#endif

        *ra_sw = johan;
        while ((*ra_sa & MP_STEP3) == 0)
                ;
#ifdef DEV_DEBUG
        printf("MP_STEP3...");
#endif

        *ra_sw = johan2;
        while ((*ra_sa & MP_STEP4) == 0)
                ;
#ifdef DEV_DEBUG
        printf("MP_STEP4\n");
#endif

        *ra_sw = 0x0001;
        uda.uda_ca.ca_rspdsc = (int)&ubauda->uda_rsp.mscp_cmdref;
        uda.uda_ca.ca_cmddsc = (int)&ubauda->uda_cmd.mscp_cmdref;
        if (is_tmscp) {
                uda.uda_cmd.mscp_un.un_seq.seq_addr =
                    (long *)&uda.uda_ca.ca_cmddsc;
                uda.uda_rsp.mscp_un.un_seq.seq_addr =
                    (long *)&uda.uda_ca.ca_rspdsc;
                uda.uda_cmd.mscp_vcid = 1;
                uda.uda_cmd.mscp_un.un_sccc.sccc_ctlrflags = 0;
        }

        command(M_OP_SETCTLRC, 0);
        uda.uda_cmd.mscp_unit = dunit;
        command(M_OP_ONLINE, 0);

        if (is_tmscp) {
                if (part) {
#ifdef DEV_DEBUG
                        printf("Repos of tape...");
#endif
                        uda.uda_cmd.mscp_un.un_seq.seq_buffer = part;
                        command(M_OP_POS, 0);
                        uda.uda_cmd.mscp_un.un_seq.seq_buffer = 0;
#ifdef DEV_DEBUG
                        printf("Done!\n");
#endif
                }
                return 0;
        }
#ifdef DEV_DEBUG
        printf("reading disklabel\n");
#endif
        err = rastrategy(0, F_READ, LABELSECTOR, DEV_BSIZE, io_buf, &i);
        if(err){
                printf("reading disklabel: %s\n",strerror(err));
                return 0;
        }

#ifdef DEV_DEBUG
        printf("getting disklabel\n");
#endif
        msg = getdisklabel(io_buf+LABELOFFSET, &ralabel);
        if (msg)
                printf("getdisklabel: %s\n", msg);
        return(0);
}

static void
command(int cmd, int arg)
{
        volatile short hej;
        int to;

igen:   uda.uda_cmd.mscp_opcode = cmd;
        uda.uda_cmd.mscp_modifier = arg;

        uda.uda_cmd.mscp_msglen = MSCP_MSGLEN;
        uda.uda_rsp.mscp_msglen = MSCP_MSGLEN;
        uda.uda_ca.ca_rspdsc |= MSCP_OWN|MSCP_INT;
        uda.uda_ca.ca_cmddsc |= MSCP_OWN|MSCP_INT;
#ifdef DEV_DEBUG
        printf("sending cmd %x...", cmd);
#endif
        hej = *ra_ip;
        __USE(hej);
        to = 10000000;
        while (uda.uda_ca.ca_rspdsc < 0) {
//              if (uda.uda_ca.ca_cmdint)
//                      uda.uda_ca.ca_cmdint = 0;
                if (--to < 0) {
#ifdef DEV_DEBUG
                        printf("timing out, retry\n");
#endif
                        goto igen;
                }
        }
#ifdef DEV_DEBUG
        printf("sent.\n");
#endif
}

int
rastrategy(void *f, int func, daddr_t dblk,
    size_t size, void *buf, size_t *rsize)
{

#ifdef DEV_DEBUG
        printf("rastrategy: buf %p is_tmscp %d\n",
            buf, is_tmscp);
#endif

        uda.uda_cmd.mscp_seq.seq_buffer = ubmap(0, (int)buf, size);

        if (is_tmscp) {
                int i;

                /*
                 * First position tape. Remember where we are.
                 */
                if (dblk < curblock) {
                        uda.uda_cmd.mscp_seq.seq_bytecount = curblock - dblk;
                        command(M_OP_POS, 12); /* 12 == step block backward */
                } else {
                        uda.uda_cmd.mscp_seq.seq_bytecount = dblk - curblock;
                        command(M_OP_POS, 4); /* 4 == step block forward */
                }
                curblock = size/512 + dblk;

                /*
                 * Read in the number of blocks we need.
                 * Why doesn't read of multiple blocks work?????
                 */
                for (i = 0 ; i < size/512 ; i++) {
                        uda.uda_cmd.mscp_seq.seq_lbn = 1;
                        uda.uda_cmd.mscp_seq.seq_bytecount = 512;
                        uda.uda_cmd.mscp_seq.seq_buffer =
                            (((u_int)buf) & 0x1ff) + i * 512;
                        uda.uda_cmd.mscp_unit = dunit;
                        command(M_OP_READ, 0);
                }
        } else {

                uda.uda_cmd.mscp_seq.seq_lbn =
                    dblk + ralabel.d_partitions[dpart].p_offset;
                uda.uda_cmd.mscp_seq.seq_bytecount = size;
                uda.uda_cmd.mscp_unit = dunit;
#ifdef DEV_DEBUG
                printf("rastrategy: blk 0x%lx count %lx unit %x\n",
                    uda.uda_cmd.mscp_seq.seq_lbn, size, dunit);
#endif
#ifdef notdef
                if (func == F_WRITE)
                        command(M_OP_WRITE, 0);
                else
#endif
                        command(M_OP_READ, 0);
        }

        *rsize = size;
        return 0;
}

int
raclose(struct open_file *f)
{
        /* Reset controller by starting a soft initialization */
        *ra_ip = 0;

        return 0;
}