mirror of
https://github.com/PDP-10/klh10.git
synced 2026-02-25 16:30:44 +00:00
by the late MRC, Mark Crispin. Source: probably the former http://panda.com/tops-20/ . panda-dist.tar.gz dated Mar 30 2007.
1080 lines
28 KiB
C
1080 lines
28 KiB
C
/* VDISK.C - Virtual Disk support routines
|
||
*/
|
||
/* $Id: vdisk.c,v 2.5 2002/05/21 09:47:06 klh Exp $
|
||
*/
|
||
/* Copyright © 1993, 2001 Kenneth L. Harrenstien
|
||
** All Rights Reserved
|
||
**
|
||
** This file is part of the KLH10 Distribution. Use, modification, and
|
||
** re-distribution is permitted subject to the terms in the file
|
||
** named "LICENSE", which contains the full text of the legal notices
|
||
** and should always accompany this Distribution.
|
||
**
|
||
** This software is provided "AS IS" with NO WARRANTY OF ANY KIND.
|
||
**
|
||
** This notice (including the copyright and warranty disclaimer)
|
||
** must be included in all copies or derivations of this software.
|
||
*/
|
||
/*
|
||
* $Log: vdisk.c,v $
|
||
* Revision 2.5 2002/05/21 09:47:06 klh
|
||
* Second pass at LFS: make sure internal computations are big enough
|
||
*
|
||
* Revision 2.4 2002/03/28 16:52:52 klh
|
||
* First pass at using LFS (Large File Support)
|
||
*
|
||
* Revision 2.3 2001/11/10 21:28:59 klh
|
||
* Final 2.0 distribution checkin
|
||
*
|
||
*/
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h> /* For malloc */
|
||
#include <stdarg.h>
|
||
#include <string.h>
|
||
|
||
#include "rcsid.h"
|
||
#include "cenv.h"
|
||
#include "word10.h"
|
||
#include "osdsup.h"
|
||
#include "vdisk.h"
|
||
|
||
#ifdef RCSID
|
||
RCSID(vdisk_c,"$Id: vdisk.c,v 2.5 2002/05/21 09:47:06 klh Exp $")
|
||
#endif
|
||
|
||
/* Define stuff for format conversions */
|
||
|
||
# define vdk_fmt(i,n,c,s,fr,to) \
|
||
fr(w10_t *, int, unsigned char *), \
|
||
to(unsigned char *, w10_t *, int)
|
||
|
||
static void VDK_FORMATS; /* Automate function predecls */
|
||
# undef vdk_fmt
|
||
|
||
static struct {
|
||
char *fmt_name; /* Short name of format */
|
||
int fmt_siz; /* # bytes in a double-word */
|
||
void (*fmt_fr)( /* Conversion routine FROM format to words */
|
||
w10_t *, int, unsigned char *);
|
||
void (*fmt_to)( /* Conversion routine TO format from words */
|
||
unsigned char *, w10_t *, int);
|
||
} vdkfmttab[] = {
|
||
# define vdk_fmt(i,n,c,s,f,t) { n, s, f, t }
|
||
VDK_FORMATS
|
||
# undef vdk_fmt
|
||
};
|
||
|
||
/* Error reporting for all VDISK code.
|
||
** Currently uses a fixed-size error string buffer. This is dumb but
|
||
** simple; all calling routines must make some effort to keep length
|
||
** within bounds.
|
||
** Specifically, never use plain "%s" -- always limit it.
|
||
*/
|
||
static void
|
||
vdkerror(register struct vdk_unit *d, char *fmt, ...)
|
||
{
|
||
char ebuf[512];
|
||
char *devnam = &d->dk_devname[0];
|
||
|
||
if (*devnam == 0)
|
||
devnam = "<\?\?\?>";
|
||
{
|
||
va_list ap;
|
||
va_start(ap, fmt);
|
||
vsprintf(ebuf, fmt, ap);
|
||
va_end(ap);
|
||
}
|
||
|
||
if (d->dk_errhan == NULL)
|
||
fprintf(stderr, "%s: %s\n", devnam, ebuf);
|
||
else
|
||
(*(d->dk_errhan))(d, ebuf);
|
||
}
|
||
|
||
|
||
int
|
||
vdk_init(register struct vdk_unit *d,
|
||
void (*errhdlr)(struct vdk_unit *, char *),
|
||
char *arg)
|
||
{
|
||
memset((char *)d, 0, sizeof(*d)); /* For now */
|
||
d->dk_errhan = errhdlr;
|
||
d->dk_errarg = arg;
|
||
return TRUE;
|
||
}
|
||
|
||
int
|
||
vdk_mount(register struct vdk_unit *d,
|
||
char *path,
|
||
int wrtf)
|
||
{
|
||
size_t cvtsiz;
|
||
|
||
if (!d->dk_devname[0]) {
|
||
d->dk_err = EINVAL; /* Invalid arg */
|
||
return FALSE; /* Not initialized */
|
||
}
|
||
|
||
/* Prepare some things that depend on format.
|
||
** If doing conversion, the buffer pointed to by dk_buf needs to be big
|
||
** enough to contain at least one sector of the largest possible format.
|
||
** For now I'll default it to 1024 words as that's the largest OS page
|
||
** unit (ITS) and should contain enough bytes to support even a bizarro
|
||
** future sector format.
|
||
*/
|
||
|
||
if ((0 <= d->dk_format) && (d->dk_format < VDK_FMT_N)) {
|
||
cvtsiz = 1024 * sizeof(w10_t); /* Default bufsiz */
|
||
d->dk_bytesec = (VDK_NWDS(d) * vdkfmttab[d->dk_format].fmt_siz) / 2;
|
||
|
||
if ((d->dk_fmt2wds = vdkfmttab[d->dk_format].fmt_fr) == cvtfr_raw)
|
||
d->dk_fmt2wds = NULL;
|
||
if ((d->dk_wds2fmt = vdkfmttab[d->dk_format].fmt_to) == cvtto_raw)
|
||
d->dk_wds2fmt = NULL;
|
||
|
||
} else {
|
||
vdkerror(d, "vdk_mount: Unknown disk format %d", d->dk_format);
|
||
d->dk_err = EINVAL;
|
||
return FALSE;
|
||
}
|
||
|
||
/* If doing any kind of conversions, will need buffer */
|
||
if (d->dk_fmt2wds || d->dk_wds2fmt) {
|
||
if (!d->dk_buf || (d->dk_bufsiz < cvtsiz)) {
|
||
if (d->dk_buf) {
|
||
free(d->dk_buf);
|
||
d->dk_buf = NULL;
|
||
}
|
||
if (!(d->dk_buf = (unsigned char *)malloc(cvtsiz))) {
|
||
vdkerror(d, "vdk_mount: Cannot alloc cvt buffer of size %ld",
|
||
(long)cvtsiz);
|
||
d->dk_err = errno;
|
||
return FALSE;
|
||
}
|
||
d->dk_bufsiz = cvtsiz;
|
||
}
|
||
d->dk_bufsecs = d->dk_bufsiz / d->dk_bytesec; /* # sectors in buff */
|
||
}
|
||
|
||
|
||
#if VDK_DISKMAP
|
||
if (d->dk_ismap) {
|
||
memset((char *)d->dk_dfh, 0, sizeof(struct vdk_header));
|
||
d->dk_blkalign = -1; /* Round down, ignore extra sectors */
|
||
d->dk_secblk = 1; /* Blocking factor: # sectors per block */
|
||
|
||
d->dk_wdsblk = d->dk_secblk * d->dk_nwds; /* # words per block */
|
||
d->dk_byteblk = d->dk_secblk * d->dk_bytesec; /* # bytes per block */
|
||
d->dk_blkcyl = (uint32)d->dk_nsecs * d->dk_ntrks;
|
||
|
||
/* Temporarily blkcyl is # sectors per cylinder */
|
||
if (d->dk_blkalign < 0) {
|
||
d->dk_blkcyl /= d->dk_secblk; /* Round down */
|
||
d->dk_nblks = d->dk_blkcyl * d->dk_ncyls;
|
||
} else if (d->dk_blkalign > 0) { /* Round up */
|
||
d->dk_blkcyl = (d->dk_blkcyl + d->dk_secblk - 1) / d->dk_secblk;
|
||
d->dk_nblks = d->dk_blkcyl * d->dk_ncyls;
|
||
} else { /* Don't round */
|
||
d->dk_nblks = (d->dk_blkcyl * d->dk_ncyls) / d->dk_secblk;
|
||
d->dk_blkcyl = 0; /* Shouldn't need this any more */
|
||
}
|
||
|
||
d->dk_map = NULL;
|
||
d->dk_freep = 0;
|
||
}
|
||
#endif /* VDK_DISKMAP */
|
||
|
||
|
||
/* Actually open the real device! */
|
||
d->dk_iswrite = wrtf; /* See if writing */
|
||
if (!os_fdopen(&d->dk_fd, path, (wrtf ? "+b" : "rb"))) {
|
||
/* Diskfile doesn't appear to exist, try to create it */
|
||
fprintf(stderr, "[Creating %s disk file \"%s\"]\r\n",
|
||
d->dk_devname, path);
|
||
if (!wrtf || !os_fdopen(&d->dk_fd, path, "+bc")) {
|
||
vdkerror(d, "vdk_mount: Cannot create %s disk file \"%s\"",
|
||
d->dk_devname, path);
|
||
d->dk_err = errno;
|
||
return FALSE;
|
||
}
|
||
#if VDK_DISKMAP
|
||
if (d->dk_ismap && !vdk_mapcreate(d)) {
|
||
vdkerror(d, "vdk_mount: Cannot create disk map");
|
||
/* mapcreate should set dkerr */
|
||
return FALSE;
|
||
}
|
||
#endif
|
||
}
|
||
#if VDK_DISKMAP
|
||
else if (d->dk_ismap) {
|
||
if (!vdk_mapload(d)) {
|
||
vdkerror(d, "vdk_mount: Cannot load disk map");
|
||
/* mapload should set dkerr */
|
||
return FALSE;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
/* Success, remember the filename */
|
||
if (!(d->dk_filename = (char *)malloc(strlen(path)+1))) {
|
||
vdkerror(d, "vdk_mount: Cannot malloc pathname \"%s\"", path);
|
||
d->dk_err = errno;
|
||
os_fdclose(d->dk_fd);
|
||
return FALSE;
|
||
}
|
||
strcpy(d->dk_filename, path);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
int
|
||
vdk_unmount(register struct vdk_unit *d)
|
||
{
|
||
if (d->dk_filename) {
|
||
#if VDK_DISKMAP
|
||
if (d->dk_ismap) {
|
||
if (!vdk_unmap(d))
|
||
return 0;
|
||
}
|
||
#endif
|
||
if (!os_fdclose(d->dk_fd))
|
||
return 0;
|
||
free(d->dk_filename);
|
||
d->dk_filename = NULL;
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
/* Read from disk.
|
||
** Return # sectors read.
|
||
**
|
||
** Raw (no-conversion) case reads directly to word buffer.
|
||
** Conversion cases will use intermediate buffer.
|
||
** Too dangerous to do conversion-in-place as CPU and disk are
|
||
** now independent threads/processes and CPU shouldn't ever see
|
||
** the intermediate forms!
|
||
*/
|
||
int
|
||
vdk_read(register struct vdk_unit *d,
|
||
w10_t *wp, /* Word buffer to read data */
|
||
uint32 secaddr, /* Sector addr on disk */
|
||
int nsec) /* # sectors - Never more than 16 bits */
|
||
{
|
||
#if VDK_DISKMAP
|
||
register osdaddr_t dwaddr;
|
||
|
||
if (d->dk_format != VDK_FMT_RAW) {
|
||
vdkerror(d, "vdk_read: Can't map format %d", d->dk_format);
|
||
return 0;
|
||
}
|
||
dwaddr = ((osdaddr_t)secaddr) * VDK_NWDS(d);
|
||
if (dwaddr % d->dk_wdsblk) {
|
||
vdkerror(d, "vdk_read: Non-sector disk address %" OSDADDR_FMT "d",
|
||
dwaddr);
|
||
return 0; /* Later do something better */
|
||
}
|
||
return vdk_mapio(d, 0, dwaddr, wp, (int)(nsec * VDK_NWDS(d)))
|
||
|
||
#else
|
||
register osdaddr_t daddr;
|
||
register size_t bcnt;
|
||
size_t ndone = 0;
|
||
int secleft;
|
||
|
||
d->dk_err = 0;
|
||
|
||
if (d->dk_fmt2wds == NULL) { /* RAW input? (No conversion) */
|
||
|
||
daddr = ((osdaddr_t)secaddr) * VDK_NWDS(d) * sizeof(w10_t);
|
||
bcnt = nsec * VDK_NWDS(d) * sizeof(w10_t);
|
||
|
||
if (!os_fdseek(d->dk_fd, daddr)) {
|
||
d->dk_err = errno; /* OS DEP!! */
|
||
vdkerror(d, "vdk_read: seek failed for %"
|
||
OSDADDR_FMT "d, errno = %d", daddr, errno);
|
||
return 0; /* Later do something better? */
|
||
}
|
||
|
||
if (!os_fdread(d->dk_fd, (char *)wp, bcnt, &ndone)) {
|
||
d->dk_err = errno; /* OS DEP!! */
|
||
vdkerror(d, "vdk_read: failed: cnt %ld, ret %ld, errno = %d",
|
||
(long)bcnt, (long)ndone, errno);
|
||
return ndone / (VDK_NWDS(d) * sizeof(w10_t));
|
||
}
|
||
|
||
if (ndone < bcnt) { /* If incomplete read, sector may not exist */
|
||
/* SPECIAL HACK FOR SPARSE NORMAL FILES
|
||
** Fill out unread words with zeros, assuming sectors haven't yet
|
||
** been created on disk and we ran into EOF.
|
||
*/
|
||
memset(((char *)wp)+ndone, 0, bcnt - ndone);
|
||
}
|
||
return nsec;
|
||
}
|
||
|
||
/* Any other kind of format comes here -- requires using another buffer.
|
||
** Speed is not of the essence for the following cases.
|
||
** An inner loop is used because the buffer may not be large enough to
|
||
** hold the entire transfer requested. It will always, however, be large
|
||
** enough to hold at least one sector at a time.
|
||
*/
|
||
|
||
/* Set up for OS I/O */
|
||
daddr = ((osdaddr_t)secaddr) * d->dk_bytesec; /* Disk addr in bytes */
|
||
if (!os_fdseek(d->dk_fd, daddr)) {
|
||
d->dk_err = errno; /* OS DEP!! */
|
||
vdkerror(d, "vdk_read: seek failed for %" OSDADDR_FMT "d, errno = %d",
|
||
daddr, errno);
|
||
return 0;
|
||
}
|
||
|
||
secleft = nsec;
|
||
while (secleft > 0) {
|
||
int err;
|
||
int secwant, secdone;
|
||
|
||
secwant = (secleft <= d->dk_bufsecs) ? secleft : d->dk_bufsecs;
|
||
bcnt = secwant * d->dk_bytesec; /* # bytes to read */
|
||
|
||
err = !os_fdread(d->dk_fd, (char *) d->dk_buf, bcnt, &ndone);
|
||
|
||
/* Find # sectors read in (ie need conversion) */
|
||
secdone = (ndone == bcnt) ? secwant : (ndone / d->dk_bytesec);
|
||
if (secdone) {
|
||
(*d->dk_fmt2wds)(wp, (int)(secdone * VDK_NWDS(d)), d->dk_buf);
|
||
secleft -= secdone;
|
||
wp += secdone * VDK_NWDS(d);
|
||
}
|
||
|
||
if (err) {
|
||
d->dk_err = errno; /* OS DEP!! */
|
||
vdkerror(d, "vdk_read: failed, cnt %ld, ret %ld, errno = %d",
|
||
(long)bcnt, (long)ndone, errno);
|
||
break;
|
||
}
|
||
|
||
if (secdone < secwant) {
|
||
/* SPECIAL HACK FOR SPARSE NORMAL FILES
|
||
** Fill out unread words with zeros, assuming sectors haven't yet
|
||
** been created on disk and we ran into EOF.
|
||
*/
|
||
memset((char *)wp, 0, secleft * VDK_NWDS(d) * sizeof(w10_t));
|
||
/* wp += secleft * VDK_NWDS(d); */
|
||
secleft = 0;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return nsec - secleft;
|
||
#endif /* !VDK_DISKMAP */
|
||
}
|
||
|
||
/* Write to disk.
|
||
** Return # sectors written.
|
||
**
|
||
** Raw (no-conversion) case writes directly from word buffer.
|
||
** Conversion cases use intermediate buffer.
|
||
*/
|
||
int
|
||
vdk_write(register struct vdk_unit *d,
|
||
w10_t *wp, /* Word buffer to read data */
|
||
uint32 secaddr, /* Sector addr on disk */
|
||
int nsec) /* # sectors - Never more than 16 bits */
|
||
{
|
||
#if VDK_DISKMAP
|
||
register osdaddr_t dwaddr;
|
||
|
||
if (d->dk_format != VDK_FMT_RAW) {
|
||
vdkerror(d, "vdk_write: Can't map format %d", d->dk_format);
|
||
return 0;
|
||
}
|
||
dwaddr = ((osdaddr_t)secaddr) * VDK_NWDS(d);
|
||
if (dwaddr % d->dk_wdsblk) {
|
||
vdkerror(d, "vdk_write: Non-sector disk address %" OSDADDR_FMT "d",
|
||
dwaddr);
|
||
return 0; /* Later do something better */
|
||
}
|
||
return vdk_mapio(d, TRUE, dwaddr, wp, (int)(nsec * VDK_NWDS(d)))
|
||
|
||
#else
|
||
register osdaddr_t daddr;
|
||
register size_t bcnt;
|
||
size_t ndone = 0;
|
||
int secleft;
|
||
|
||
d->dk_err = 0;
|
||
|
||
if (d->dk_wds2fmt == NULL) { /* RAW output? (No conversion) */
|
||
|
||
daddr = ((osdaddr_t)secaddr) * VDK_NWDS(d) * sizeof(w10_t);
|
||
bcnt = nsec * VDK_NWDS(d) * sizeof(w10_t);
|
||
|
||
if (!os_fdseek(d->dk_fd, daddr)) {
|
||
vdkerror(d, "vdk_write: seek failed for %" OSDADDR_FMT
|
||
"d, errno = %d", daddr, errno);
|
||
d->dk_err = errno; /* OS DEP!! */
|
||
return 0; /* Later do something better? */
|
||
}
|
||
|
||
if (!os_fdwrite(d->dk_fd, (char *)wp, bcnt, &ndone)) {
|
||
vdkerror(d, "vdk_write: failed: cnt %ld, ret %ld, errno = %d",
|
||
(long)bcnt, (long)ndone, errno);
|
||
d->dk_err = errno; /* OS DEP!! */
|
||
return ndone / (VDK_NWDS(d) * sizeof(w10_t));
|
||
}
|
||
return nsec;
|
||
}
|
||
|
||
/* Any other kind of format comes here -- may require using another buffer.
|
||
** Speed is not of the essence for the following cases.
|
||
** An inner loop is used because the buffer may not be large enough to
|
||
** hold the entire transfer requested. It will always, however, be large
|
||
** enough to hold at least one sector at a time.
|
||
*/
|
||
|
||
/* Set up for OS I/O */
|
||
daddr = ((osdaddr_t)secaddr) * d->dk_bytesec; /* Disk addr in bytes */
|
||
if (!os_fdseek(d->dk_fd, daddr)) {
|
||
vdkerror(d, "vdk_read: seek failed for %" OSDADDR_FMT "d, errno = %d",
|
||
daddr, errno);
|
||
d->dk_err = errno; /* OS DEP!! */
|
||
return 0;
|
||
}
|
||
|
||
secleft = nsec;
|
||
while (secleft > 0) {
|
||
int err;
|
||
int secwant, secdone;
|
||
|
||
secwant = (secleft <= d->dk_bufsecs) ? secleft : d->dk_bufsecs;
|
||
|
||
/* Convert words into buffer */
|
||
(*d->dk_wds2fmt)(d->dk_buf, wp, (int)(secwant * VDK_NWDS(d)));
|
||
|
||
bcnt = secwant * d->dk_bytesec; /* # bytes to write */
|
||
|
||
err = !os_fdwrite(d->dk_fd, (char *) d->dk_buf, bcnt, &ndone);
|
||
|
||
/* Find # sectors written */
|
||
secdone = (ndone == bcnt) ? secwant : (ndone / d->dk_bytesec);
|
||
if (secdone) {
|
||
secleft -= secdone;
|
||
wp += secdone * VDK_NWDS(d);
|
||
}
|
||
|
||
if (err || (secdone != secwant)) {
|
||
d->dk_err = errno; /* OS DEP!!! */
|
||
vdkerror(d, "vdk_write: failed, cnt %ld, ret %ld, errno = %d",
|
||
(long)bcnt, (long)ndone, errno);
|
||
break;
|
||
}
|
||
}
|
||
|
||
return nsec - secleft;
|
||
#endif /* !VDK_DISKMAP */
|
||
}
|
||
|
||
/* Format conversion routines */
|
||
|
||
/*
|
||
dbd9: Disk_BigEnd_Double (9/2) - Same as H36 (Tape_Hidens)
|
||
B0 1 2 3 4 5 6 7
|
||
8 9 10 11 12 13 14 15 [Word 0]
|
||
16 17 18 19 20 21 22 23
|
||
24 25 26 27 28 29 30 31
|
||
32 33 34 35 B0 1 2 3
|
||
4 5 6 7 8 9 10 11 [Word 1]
|
||
12 13 14 15 16 17 18 19
|
||
20 21 22 23 24 25 26 27
|
||
28 29 30 31 32 33 34 35
|
||
|
||
*/
|
||
static void
|
||
cvtfr_dbd9(register w10_t *wp,
|
||
register int wcnt,
|
||
register unsigned char *ucp)
|
||
{
|
||
register w10_t w;
|
||
register int dwcnt = wcnt >> 1;
|
||
|
||
for (; --dwcnt >= 0; ucp += 9) {
|
||
LRHSET(w,
|
||
(((ucp[0]&0377)<<10) | ((ucp[1]&0377)<<2) | ((ucp[2]>>6)&03)),
|
||
(((ucp[2]&077)<<12) | ((ucp[3]&0377)<<4) | ((ucp[4]>>4)&017)));
|
||
*wp++ = w;
|
||
LRHSET(w,
|
||
(((ucp[4]&017)<<14) | ((ucp[5]&0377)<<6) | ((ucp[6]>>2)&077)),
|
||
(((ucp[6]&03)<<16) | ((ucp[7]&0377)<<8) | (ucp[8]&0377)));
|
||
*wp++ = w;
|
||
}
|
||
|
||
/* Ugh, allow gobbling an odd word for generality */
|
||
if (wcnt & 01) {
|
||
LRHSET(w,
|
||
(((ucp[0]&0377)<<10) | ((ucp[1]&0377)<<2) | ((ucp[2]>>6)&03)),
|
||
(((ucp[2]&077)<<12) | ((ucp[3]&0377)<<4) | ((ucp[4]>>4)&017)));
|
||
*wp++ = w;
|
||
}
|
||
}
|
||
|
||
static void
|
||
cvtto_dbd9(register unsigned char *ucp,
|
||
register w10_t *wp,
|
||
register int wcnt)
|
||
{
|
||
register w10_t w, w2;
|
||
register int dwcnt = wcnt >> 1;
|
||
|
||
for (; --dwcnt >= 0; ) {
|
||
w = *wp++;
|
||
w2 = *wp++;
|
||
*ucp++ = (LHGET(w) >> 10) & 0377;
|
||
*ucp++ = (LHGET(w) >> 2) & 0377;
|
||
*ucp++ = ((LHGET(w)&03)<<6) | ((RHGET(w) >> 12) & 077);
|
||
*ucp++ = (RHGET(w) >> 4) & 0377;
|
||
*ucp++ = ((RHGET(w)&017)<<4) | ((LHGET(w2) >> 14) & 017);
|
||
*ucp++ = (LHGET(w2) >> 6) & 0377;
|
||
*ucp++ = ((LHGET(w2)&077)<<2) | ((RHGET(w2) >> 16) & 03);
|
||
*ucp++ = (RHGET(w2) >> 8) & 0377;
|
||
*ucp++ = RHGET(w2) & 0377;
|
||
}
|
||
|
||
/* Ugh, allow writing an odd word for generality */
|
||
if (wcnt & 01) {
|
||
w = *wp++;
|
||
*ucp++ = (LHGET(w) >> 10) & 0377;
|
||
*ucp++ = (LHGET(w) >> 2) & 0377;
|
||
*ucp++ = ((LHGET(w)&03)<<6) | ((RHGET(w) >> 12) & 077);
|
||
*ucp++ = (RHGET(w) >> 4) & 0377;
|
||
*ucp++ = ((RHGET(w)&017)<<4);
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
dld9: Disk_LittleEnd_Double (9/2)
|
||
28 29 30 31 32 33 34 35
|
||
20 21 22 23 24 25 26 27
|
||
12 13 14 15 16 17 18 19
|
||
4 5 6 7 8 9 10 11 [Word 0]
|
||
32 33 34 35 B0 1 2 3
|
||
24 25 26 27 28 29 30 31
|
||
16 17 18 19 20 21 22 23
|
||
8 9 10 11 12 13 14 15 [Word 1]
|
||
B0 1 2 3 4 5 6 7
|
||
*/
|
||
static void
|
||
cvtfr_dld9(register w10_t *wp,
|
||
register int wcnt,
|
||
register unsigned char *ucp)
|
||
{
|
||
register w10_t w;
|
||
register int dwcnt = wcnt >> 1;
|
||
|
||
for (; --dwcnt >= 0; ucp += 9) {
|
||
LRHSET(w,
|
||
(((ucp[4]&017)<<14) | ((ucp[3]&0377)<<6) | ((ucp[2]>>2)&077)),
|
||
(((ucp[2]&03)<<16) | ((ucp[1]&0377)<<8) | (ucp[0]&0377)));
|
||
*wp++ = w;
|
||
LRHSET(w,
|
||
(((ucp[8]&0377)<<10) | ((ucp[7]&0377)<<2) | ((ucp[6]>>6)&03)),
|
||
(((ucp[6]&077)<<12) | ((ucp[5]&0377)<<4) | ((ucp[4]>>4)&017)));
|
||
*wp++ = w;
|
||
}
|
||
|
||
/* Ugh, allow gobbling an odd word for generality */
|
||
if (wcnt & 01) {
|
||
LRHSET(w,
|
||
(((ucp[4]&017)<<14) | ((ucp[3]&0377)<<6) | ((ucp[2]>>2)&077)),
|
||
(((ucp[2]&03)<<16) | ((ucp[1]&0377)<<8) | (ucp[0]&0377)));
|
||
*wp++ = w;
|
||
}
|
||
}
|
||
|
||
static void
|
||
cvtto_dld9(register unsigned char *ucp,
|
||
register w10_t *wp,
|
||
register int wcnt)
|
||
{
|
||
register w10_t w, w2;
|
||
register int dwcnt = wcnt >> 1;
|
||
|
||
for (; --dwcnt >= 0; ) {
|
||
w = *wp++;
|
||
w2 = *wp++;
|
||
*ucp++ = RHGET(w) & 0377;
|
||
*ucp++ = (RHGET(w) >> 8) & 0377;
|
||
*ucp++ = ((LHGET(w)&077)<<2) | ((RHGET(w) >> 16) & 03);
|
||
*ucp++ = (LHGET(w) >> 6) & 0377;
|
||
*ucp++ = ((RHGET(w2)&017)<<4) | ((LHGET(w) >> 14) & 017);
|
||
*ucp++ = (RHGET(w2) >> 4) & 0377;
|
||
*ucp++ = ((LHGET(w2)&03)<<6) | ((RHGET(w2) >> 12) & 077);
|
||
*ucp++ = (LHGET(w2) >> 2) & 0377;
|
||
*ucp++ = (LHGET(w2) >> 10) & 0377;
|
||
}
|
||
|
||
/* Ugh, allow writing an odd word for generality */
|
||
if (wcnt & 01) {
|
||
w = *wp++;
|
||
*ucp++ = RHGET(w) & 0377;
|
||
*ucp++ = (RHGET(w) >> 8) & 0377;
|
||
*ucp++ = ((LHGET(w)&077)<<2) | ((RHGET(w) >> 16) & 03);
|
||
*ucp++ = (LHGET(w) >> 6) & 0377;
|
||
*ucp++ = (LHGET(w) >> 14) & 017;
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
dbw8: Disk_BigEnd_Word (8)
|
||
0 0 0 0 0 0 0 0
|
||
0 0 0 0 0 0 0 0
|
||
0 0 0 0 0 0 0 0
|
||
0 0 0 0 B0 1 2 3
|
||
4 5 6 7 8 9 10 11
|
||
12 13 14 15 16 17 18 19
|
||
20 21 22 23 24 25 26 27
|
||
28 29 30 31 32 33 34 35
|
||
*/
|
||
static void
|
||
cvtfr_dbw8(register w10_t *wp,
|
||
register int wcnt,
|
||
register unsigned char *ucp)
|
||
{
|
||
register w10_t w;
|
||
|
||
for (; --wcnt >= 0; ucp += 8) {
|
||
LRHSET(w,
|
||
(((ucp[3]&017)<<14) | ((ucp[4]&0377)<<6) | ((ucp[5]>>2)&077)),
|
||
(((ucp[5]&03)<<16) | ((ucp[6]&0377)<<8) | (ucp[7]&0377)));
|
||
*wp++ = w;
|
||
}
|
||
}
|
||
|
||
static void
|
||
cvtto_dbw8(register unsigned char *ucp,
|
||
register w10_t *wp,
|
||
register int wcnt)
|
||
{
|
||
register w10_t w;
|
||
|
||
for (; --wcnt >= 0; ) {
|
||
w = *wp++;
|
||
*ucp++ = 0;
|
||
*ucp++ = 0;
|
||
*ucp++ = 0;
|
||
*ucp++ = (LHGET(w) >> 14) & 017;
|
||
*ucp++ = (LHGET(w) >> 6) & 0377;
|
||
*ucp++ = ((LHGET(w)&077)<<2) | ((RHGET(w) >> 16) & 03);
|
||
*ucp++ = (RHGET(w) >> 8) & 0377;
|
||
*ucp++ = RHGET(w) & 0377;
|
||
}
|
||
}
|
||
|
||
/*
|
||
dlw8: Disk_LittleEnd_Word (8)
|
||
28 29 30 31 32 33 34 35
|
||
20 21 22 23 24 25 26 27
|
||
12 13 14 15 16 17 18 19
|
||
4 5 6 7 8 9 10 11
|
||
0 0 0 0 B0 1 2 3
|
||
0 0 0 0 0 0 0 0
|
||
0 0 0 0 0 0 0 0
|
||
0 0 0 0 0 0 0 0
|
||
*/
|
||
static void
|
||
cvtfr_dlw8(register w10_t *wp,
|
||
register int wcnt,
|
||
register unsigned char *ucp)
|
||
{
|
||
register w10_t w;
|
||
|
||
for (; --wcnt >= 0; ucp += 8) {
|
||
LRHSET(w,
|
||
(((ucp[4]&017)<<14) | ((ucp[3]&0377)<<6) | ((ucp[2]>>2)&077)),
|
||
(((ucp[2]&03)<<16) | ((ucp[1]&0377)<<8) | (ucp[0]&0377)));
|
||
*wp++ = w;
|
||
}
|
||
}
|
||
|
||
static void
|
||
cvtto_dlw8(register unsigned char *ucp,
|
||
register w10_t *wp,
|
||
register int wcnt)
|
||
{
|
||
register w10_t w;
|
||
|
||
for (; --wcnt >= 0; ) {
|
||
w = *wp++;
|
||
*ucp++ = RHGET(w) & 0377;
|
||
*ucp++ = (RHGET(w) >> 8) & 0377;
|
||
*ucp++ = ((LHGET(w)&077)<<2) | ((RHGET(w) >> 16) & 03);
|
||
*ucp++ = (LHGET(w) >> 6) & 0377;
|
||
*ucp++ = (LHGET(w) >> 14) & 017;
|
||
*ucp++ = 0;
|
||
*ucp++ = 0;
|
||
*ucp++ = 0;
|
||
}
|
||
}
|
||
|
||
/*
|
||
dbh4: Disk_BigEnd_Halfword (8)
|
||
0 0 0 0 0 0 0 0
|
||
0 0 0 0 0 0 B0 1
|
||
2 3 4 5 6 7 8 9
|
||
10 11 12 13 14 15 16 17
|
||
0 0 0 0 0 0 0 0
|
||
0 0 0 0 0 0 18 19
|
||
20 21 22 23 24 25 26 27
|
||
28 29 30 31 32 33 34 35
|
||
*/
|
||
static void
|
||
cvtfr_dbh4(register w10_t *wp,
|
||
register int wcnt,
|
||
register unsigned char *ucp)
|
||
{
|
||
register w10_t w;
|
||
|
||
for (; --wcnt >= 0; ucp += 8) {
|
||
LRHSET(w, (((ucp[1]&03)<<16) | ((ucp[2]&0377)<<8) | (ucp[3]&0377)),
|
||
(((ucp[5]&03)<<16) | ((ucp[6]&0377)<<8) | (ucp[7]&0377)));
|
||
*wp++ = w;
|
||
}
|
||
}
|
||
|
||
static void
|
||
cvtto_dbh4(register unsigned char *ucp,
|
||
register w10_t *wp,
|
||
register int wcnt)
|
||
{
|
||
register w10_t w;
|
||
|
||
for (; --wcnt >= 0; ) {
|
||
w = *wp++;
|
||
*ucp++ = 0;
|
||
*ucp++ = (LHGET(w) >> 16) & 03;
|
||
*ucp++ = (LHGET(w) >> 8) & 0377;
|
||
*ucp++ = LHGET(w) & 0377;
|
||
*ucp++ = 0;
|
||
*ucp++ = (RHGET(w) >> 16) & 03;
|
||
*ucp++ = (RHGET(w) >> 8) & 0377;
|
||
*ucp++ = RHGET(w) & 0377;
|
||
}
|
||
}
|
||
|
||
/*
|
||
dlh4: Disk_LittleEnd_Halfword (8)
|
||
28 29 30 31 32 33 34 35
|
||
20 21 22 23 24 25 26 27
|
||
0 0 0 0 0 0 18 19
|
||
0 0 0 0 0 0 0 0
|
||
10 11 12 13 14 15 16 17
|
||
2 3 4 5 6 7 8 9
|
||
0 0 0 0 0 0 B0 1
|
||
0 0 0 0 0 0 0 0
|
||
|
||
*/
|
||
static void
|
||
cvtfr_dlh4(register w10_t *wp,
|
||
register int wcnt,
|
||
register unsigned char *ucp)
|
||
{
|
||
register w10_t w;
|
||
|
||
for (; --wcnt >= 0; ucp += 8) {
|
||
LRHSET(w, (((ucp[6]&03)<<16) | ((ucp[5]&0377)<<8) | (ucp[4]&0377)),
|
||
(((ucp[2]&03)<<16) | ((ucp[1]&0377)<<8) | (ucp[0]&0377)));
|
||
*wp++ = w;
|
||
}
|
||
}
|
||
|
||
static void
|
||
cvtto_dlh4(register unsigned char *ucp,
|
||
register w10_t *wp,
|
||
register int wcnt)
|
||
{
|
||
register w10_t w;
|
||
|
||
for (; --wcnt >= 0; ) {
|
||
w = *wp++;
|
||
*ucp++ = RHGET(w) & 0377;
|
||
*ucp++ = (RHGET(w) >> 8) & 0377;
|
||
*ucp++ = (RHGET(w) >> 16) & 03;
|
||
*ucp++ = 0;
|
||
*ucp++ = LHGET(w) & 0377;
|
||
*ucp++ = (LHGET(w) >> 8) & 0377;
|
||
*ucp++ = (LHGET(w) >> 16) & 03;
|
||
*ucp++ = 0;
|
||
}
|
||
}
|
||
|
||
|
||
/* "Rare" semi-raw conversions - no byte shuffling, but data is masked.
|
||
*/
|
||
static void
|
||
cvtfr_rare(register w10_t *wp,
|
||
register int wcnt,
|
||
register unsigned char *ucp)
|
||
{
|
||
register w10_t w, *frwp = (w10_t *)ucp;
|
||
|
||
while (--wcnt >= 0) {
|
||
XWDSET(w, LHPGET(frwp)&H10MASK, RHPGET(frwp)&H10MASK);
|
||
++frwp;
|
||
*wp++ = w;
|
||
}
|
||
}
|
||
|
||
static void
|
||
cvtto_rare(register unsigned char *ucp,
|
||
register w10_t *wp,
|
||
register int wcnt)
|
||
{
|
||
register w10_t w, *towp = (w10_t *)ucp;
|
||
|
||
while (--wcnt >= 0) {
|
||
XWDSET(w, LHPGET(wp)&H10MASK, RHPGET(wp)&H10MASK);
|
||
++wp;
|
||
*towp++ = w;
|
||
}
|
||
}
|
||
|
||
|
||
/* Raw no-op conversions.
|
||
** Mainly here so conversion table can be filled out with meaningful
|
||
** vectors for no-conversion cases. Shouldn't actually be called.
|
||
*/
|
||
static void
|
||
cvtfr_raw(register w10_t *wp,
|
||
register int wcnt,
|
||
register unsigned char *ucp)
|
||
{
|
||
memcpy((char *)wp, (char *)ucp, wcnt * sizeof(w10_t));
|
||
}
|
||
|
||
static void
|
||
cvtto_raw(register unsigned char *ucp,
|
||
register w10_t *wp,
|
||
register int wcnt)
|
||
{
|
||
memcpy((char *)ucp, (char *)wp, wcnt * sizeof(w10_t));
|
||
}
|
||
|
||
/* Disk-map specific support */
|
||
|
||
#if VDK_DISKMAP
|
||
|
||
static int
|
||
vdk_mapcreate(register struct vdk_unit *d)
|
||
{
|
||
register osdaddr_t da;
|
||
register size_t mapsiz;
|
||
size_t err;
|
||
|
||
/* Derive map config params from blocking factor */
|
||
#define MAPINIT \
|
||
d->dk_byteblk = (uint32) d->dk_secblk * d->dk_bytesec; /* bytes/blk */\
|
||
d->dk_nblks = (((uint32) d->dk_nsecs ) * d-<dk_ntrks) \
|
||
/* Later, may subtract leftover sectors here? (- SKIPSECS) */ \
|
||
* d->dk_ncyls; \
|
||
d->dk_nblks /= d->dk_secblk; /* Find # blocks this disk */
|
||
|
||
mapsiz = d->dk_nblks * sizeof(osdaddr_t);
|
||
d->dk_map = (osdaddr_t *)calloc((size_t)d->dk_nblks, sizeof(osdaddr_t));
|
||
if (!d->dk_map) {
|
||
vdkerror(d, "vdk_mapcreate: Malloc failed for map of %ld entries",
|
||
(long) d->dk_nblks);
|
||
return 0;
|
||
}
|
||
|
||
/* Compute first free disk addr after header and map written.
|
||
** Round up to first block.
|
||
*/
|
||
da = sizeof(struct vdk_header) + mapsiz;
|
||
da = ((da + d->dk_byteblk-1) / d->dk_byteblk) * d->dk_byteblk;
|
||
|
||
/* Fill out initial disk header */
|
||
d->dk_dfh.dh_freep = da; /* First free realdisk address */
|
||
|
||
/* Now initialize the diskfile. Assume just created, so at start. */
|
||
if (!os_fdwrite(d->dk_fd, (char *) &(d->dk_dfh), sizeof(struct vdk_header), &err)
|
||
|| err != sizeof(struct vdk_header)) {
|
||
vdkerror(d, "vdk_mapcreate: write failed for cnt %ld, errno = %d",
|
||
(long)sizeof(struct vdk_header), errno);
|
||
return 0;
|
||
}
|
||
if (!os_fdwrite(d->dk_fd, (char *) d->dk_map, mapsiz, &err)
|
||
|| err != mapsiz) {
|
||
vdkerror(d, "vdk_mapcreate: write failed for cnt %ld, errno = %d",
|
||
(long)mapsiz, errno);
|
||
return 0;
|
||
}
|
||
return 1; /* Won! */
|
||
}
|
||
|
||
static int
|
||
vdk_mapload(register struct vdk_unit *d)
|
||
{
|
||
register osdaddr_t da, *dp;
|
||
register size_t mapsiz;
|
||
size_t err;
|
||
|
||
if (d->dk_map) {
|
||
vdkerror(d, "vdk_mapload: Disk already mapped");
|
||
return 0;
|
||
}
|
||
|
||
/* Read in diskfile header */
|
||
if (!os_fdseek(d->dk_fd, (osdaddr_t)0)) {
|
||
vdkerror(d, "vdk_mapload: seek failed for BOF");
|
||
return 0;
|
||
}
|
||
if (!os_fdread(d->dk_fd, (char *) &(d->dk_dfh), sizeof(struct vdk_header), &err)
|
||
|| err != sizeof(struct vdk_header)) {
|
||
vdkerror(d, "vdk_mapload: read failed for cnt %ld, errno = %d",
|
||
(long)sizeof(struct vdk_header), errno);
|
||
return 0;
|
||
}
|
||
|
||
/* Now should check veracity of header and set up remaining stuff
|
||
** based on the config info it contains.
|
||
*/
|
||
#if 0
|
||
/* Nothing for now */
|
||
#endif
|
||
MAPINIT /* Do same config setup as mapcreate for now */
|
||
|
||
mapsiz = d->dk_nblks * sizeof(osdaddr_t);
|
||
d->dk_map = (osdaddr_t *)malloc(mapsiz);
|
||
if (!d->dk_map) {
|
||
vdkerror(d, "vdk_mapload: Malloc failed for map of %ld entries",
|
||
(long) d->dk_nblks);
|
||
return 0;
|
||
}
|
||
|
||
if (!os_fdread(d->dk_fd, (char *) d->dk_map, mapsiz, &err)
|
||
|| err != mapsiz) {
|
||
vdkerror(d, "vdk_mapload: read failed for cnt %ld, errno = %d",
|
||
(long)mapsiz, errno);
|
||
return 0;
|
||
}
|
||
|
||
/* Now scan the map to determine the largest known block address,
|
||
** hence the first free one.
|
||
** Slogging through this at startup lets us avoid updating a
|
||
** disk-resident variable at every write.
|
||
*/
|
||
da = 0;
|
||
dp = d->dk_map;
|
||
for (mapsiz = d->dk_nblks; mapsiz > 0; --mapsiz, ++dp) {
|
||
if (*dp > da)
|
||
da = *dp;
|
||
}
|
||
d->dk_freep = da + d->dk_byteblk; /* Point one block past highest */
|
||
|
||
return 1; /* Won! */
|
||
}
|
||
|
||
|
||
static int
|
||
vdk_mapio(struct vdk_unit *d,
|
||
int wrtf,
|
||
osdaddr_t dwaddr,
|
||
w10_t *wp,
|
||
int wcnt)
|
||
{
|
||
register uint32 blkno;
|
||
register osdaddr_t da;
|
||
register int bcnt;
|
||
register size_t bytes;
|
||
size_t err;
|
||
|
||
blkno = dwaddr / d->dk_wdsblk;
|
||
|
||
if (wcnt) for (;;) {
|
||
if ((bcnt = wcnt) > d->dk_wdsblk)
|
||
bcnt = d->dk_wdsblk;
|
||
bytes = bcnt * sizeof(w10_t);
|
||
if (blkno >= d->dk_nblks) {
|
||
vdkerror(d, "vdk_mapread: Non-ex block %ld", (long)blkno);
|
||
return 0;
|
||
}
|
||
d->dk_mupdate = FALSE;
|
||
if (!(da = d->dk_map[blkno])) { /* Block exists in map? */
|
||
if (!wrtf) {
|
||
/* Nope, just pretend we read a bunch of zeros */
|
||
memset((char *)vp, 0, bytes);
|
||
goto rdone;
|
||
} else {
|
||
d->dk_mupdate = TRUE;
|
||
da = d->dk_freep;
|
||
}
|
||
}
|
||
if (!os_fdseek(d->dk_fd, da)) {
|
||
vdkerror(d, "vdk_mapread: seek failed for %" OSDADDR_FMT
|
||
"d, errno = %d", (long)da, errno);
|
||
return 0; /* Later do something better */
|
||
}
|
||
if (!(wrtf
|
||
? os_fdwrite(d->dk_fd, (char *)vp, bytes, &err)
|
||
? os_fdread(d->dk_fd, (char *)vp, bytes, &err))) {
|
||
vdkerror(d, "vdk_mapio: %s failed for cnt %ld, ret %ld, errno = %d",
|
||
wrtf ? "write" : "read",
|
||
(long)(bytes), (long)err, errno);
|
||
return 0; /* Later do something better */
|
||
}
|
||
if (err != bytes) {
|
||
#if 0
|
||
if (!wrtf && err == 0) { /* Check for read of non-ex data */
|
||
memset((char *)vp, 0, bytes);
|
||
goto rdone;
|
||
}
|
||
#endif
|
||
vdkerror(d, "vdk_mapio: r/w failed for cnt %ld, ret %ld, errno = %d",
|
||
(long)bytes, (long)err, errno);
|
||
return 0; /* Later do something better */
|
||
}
|
||
if (d->dk_mupdate) {
|
||
/* Successful write, update the map */
|
||
if (bcnt < d->dk_wdsblk) {
|
||
/* Fill out all of incompletely written block */
|
||
bytes = sizeof(w10_t)*(d->dk_wdsblk - bcnt);
|
||
memset(d->dk_blkbuf, 0, bytes);
|
||
if (!os_fdwrite(d->dk_fd, d->dk_blkbuf, bytes, &err)) {
|
||
vdkerror(d, "vdk_mapio: w failed for cnt %ld, ret %ld, errno = %d",
|
||
(long)bytes, (long)err, errno);
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
da = sizeof(struct vdk_header) + (blkno * sizeof(osdaddr_t));
|
||
if (!os_fdseek(d->dk_fd, da)) {
|
||
vdkerror(d, "vdk_mapio: seek failed, map update at %"
|
||
OSDADDR_FMT "d, errno = %d", da, errno);
|
||
return 0;
|
||
}
|
||
if (!os_fdwrite(d->dk_fd, (char *)&(d->dk_freep),
|
||
sizeof(osdaddr_t), &err)) {
|
||
vdkerror(d, "vdk_mapio: w failed for cnt %ld, ret %ld, errno = %d",
|
||
(long)sizeof(osdaddr_t), (long)err, errno);
|
||
return 0;
|
||
}
|
||
|
||
/* Update on disk won, so now update mem */
|
||
d->dk_map[blkno] = d->dk_freep;
|
||
d->dk_freep = d->dk_byteblk;
|
||
}
|
||
|
||
rdone:
|
||
if (wcnt <= bcnt)
|
||
break; /* Done, leave now */
|
||
wcnt -= bcnt;
|
||
vp += bcnt;
|
||
blkno++;
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
#endif /* VDK_DISKMAP */
|