/* $NetBSD: ra.c,v 1.22 2018/03/21 18:27:27 ragge 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;
}