/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:osifile.c 12.2$ */
/* $ACIS:osifile.c 12.2$ */
/* $Source: /ibm/acis/usr/sys/afs/RCS/osifile.c,v $ */

#ifndef lint
static char *rcsid = "$Header:osifile.c 12.2$";
#endif

#include "../h/types.h"
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/time.h"
#include "../h/kernel.h"
#include "../h/cmap.h"
#include "../h/socket.h"
#include "../h/socketvar.h"
#include "../h/protosw.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/uio.h"
#include "../h/buf.h"
#include "../h/vfs.h"
#include "../h/vnode.h"
#include "../ufs/inode.h"
#include "../netinet/in.h"
#include "../h/mbuf.h"
#include "../h/proc.h"
#include "../afs/osi.h"
#include "../afs/lock.h"

#if defined(vax) || defined(ibm032)
#include "../h/vm.h"
#include "../h/map.h"
#include "../machine/pte.h"
#endif vax || ibm032
#ifdef ibm032
#include "../machine/mmu.h"
#endif ibm032

static init=0;
struct ucred osi_cred;
struct vattr tvattr;
struct lock afs_xosi;	/* lock is for tvattr */

osi_file_cleanup() {
    init=0;
    bzero(&osi_cred, sizeof(osi_cred));
    bzero(&tvattr, sizeof(tvattr));
    bzero(&afs_xosi, sizeof(afs_xosi));
}

struct osi_file *osi_UFSOpen(adev, ainode)
    register struct osi_dev *adev;
    long ainode; {
    register struct inode *ip;
    register struct osi_file *afile;
    if (!init) {
	bzero(&osi_cred, sizeof(struct ucred));
	Lock_Init(&afs_xosi);
	crhold(&osi_cred);	/* don't let it evaporate, since it is static */
	init = 1;
    }
    afile = (struct osi_file *) osi_Alloc(sizeof(struct osi_file));
    u.u_error = 0;
    ip = (struct inode *) igetinode((dev_t) adev->dev, (ino_t)ainode);
    if (u.u_error)
	    return (struct osi_file *) 0;
    iunlock(ip);
    afile->vnode = ITOV(ip);
    afile->offset = 0;
    afile->proc = (int (*)()) 0;
    return afile;
}

osi_Stat(afile, astat)
    register struct osi_file *afile;
    register struct osi_stat *astat; {
    register long code;

    ObtainWriteLock(&afs_xosi);
    code = VOP_GETATTR(afile->vnode, &tvattr, &osi_cred);
    if (code == 0) {
	astat->size = tvattr.va_size;
	astat->blksize = tvattr.va_blocksize;
	astat->mtime = tvattr.va_mtime.tv_sec;
	astat->atime = tvattr.va_atime.tv_sec;
    }
    ReleaseWriteLock(&afs_xosi);
    return code;
}

osi_Close(afile)
    register struct osi_file *afile; {
    VN_RELE(afile->vnode);
    osi_Free(afile, sizeof(struct osi_file));
    return 0;
}

osi_Truncate(afile, asize)
    register struct osi_file *afile;
    long asize; {
    struct ucred *oldCred;
    register long code;

    ObtainWriteLock(&afs_xosi);
    vattr_null(&tvattr);
    tvattr.va_size = asize;
    /* note that this credential swapping crap is only necessary because
	of ufs's references directly to u.u_cred instead of to
	credentials parameter.  Probably should fix ufs some day. */
    oldCred = u.u_cred;	    /* remember old credentials pointer  */
    u.u_cred = &osi_cred;   /* temporarily use superuser credentials */
    code = VOP_SETATTR(afile->vnode, &tvattr, &osi_cred);
    u.u_cred = oldCred;	    /* restore */
    ReleaseWriteLock(&afs_xosi);
    return code;
}

/* Generic read interface */
osi_Read(afile, aptr, asize)
    register struct osi_file *afile;
    char *aptr;
    long asize; {
    unsigned int resid;
    register long code;

    code = gop_rdwr(UIO_READ, afile->vnode, (caddr_t) aptr, asize, afile->offset,
		  AFS_UIOSYS, IO_UNIT, &resid);
    if (code == 0) {
	code = asize - resid;
	afile->offset += code;
    }
    else {
	u.u_error = code;
	code = -1;
    }
    return code;
}

/* Generic write interface */
osi_Write(afile, aptr, asize)
    register struct osi_file *afile;
    char *aptr;
    long asize; {
    unsigned int resid;
    register long code;

    code = gop_rdwr(UIO_WRITE, afile->vnode, (caddr_t) aptr, asize, afile->offset,
		  AFS_UIOSYS, IO_UNIT, &resid);
    if (code == 0) {
	code = asize - resid;
	afile->offset += code;
    }
    else {
	u.u_error = code;
	code = -1;
    }
    if (afile->proc) {
	(*afile->proc)(afile, code);
    }
    return code;
}


/* BARF CITY: this work should be handled by physstrat in ca/machdep.c.
    This routine written from the RT NFS port strategy routine.
    It has been generalized a bit, but should still be pretty clear. */
int osi_MapStrategy(aproc, bp)
	int (*aproc)();
	register struct buf *bp;
{
	long returnCode;

#if defined(vax) || defined(ibm032)
	if (bp->b_flags & B_PHYS) {
		register int npte;
		register int n;
		register long a;
		register struct pte *pte, *kpte;
		caddr_t va;
		int o;
		caddr_t saddr;
#ifdef ibm032
		struct hatipt_entry *ipte;
		u_int vp;
		long saddrtag;	/* puke */
#endif ibm032

		/*
		 * Buffer's data is in userland, or in some other
		 * currently inaccessable place. We get a hunk of
		 * kernel address space and map it in.
		 */
		o = (int)bp->b_un.b_addr & PGOFSET;
		npte = btoc(bp->b_bcount + o);
		while ((a = rmalloc(kernelmap, (long)clrnd(npte))) == NULL) {
			kmapwnt++;
			sleep((caddr_t)kernelmap, PSWP+4);
		}
		kpte = &Usrptmap[a];
		pte = vtopte(bp->b_proc, btop(bp->b_un.b_addr));
#ifdef vax
		for (n = npte; n--; kpte++, pte++)
			*(int *)kpte = PG_NOACC | (*(int *)pte & PG_PFNUM);
		va = (caddr_t)kmxtob(a);
		vmaccess(&Usrptmap[a], va, npte);
#endif vax
#ifdef ibm032
		va = (caddr_t)kmxtob(a);
		vp = btop(va);
		for (n = npte; n; kpte++, pte++, vp++, n--) {
			*(int *)kpte = *(int *)pte & PG_PFNUM;
			ipte = &MMU_HATIPT[*(int *)kpte];
			if (n == npte)
				saddrtag = ipte->key_addrtag;
			else if (saddrtag != ipte->key_addrtag)
				printf("AFS temp map confusion\n");
			ipte->key_addrtag = MMU_SID_SYSTEM << MMU_VPAGE_BITS;
			mapin(kpte, vp, (u_int)(PG_V|PG_KW | *(int *)kpte), 1);
		}
#endif ibm032
		saddr = bp->b_un.b_addr;
		bp->b_un.b_addr = va + o;
		/*
		 * do the io
		 */
		returnCode = (*aproc)(bp);
		/*
		 * Release kernel maps
		 */
		bp->b_un.b_addr = saddr;
		kpte = &Usrptmap[a];
#ifdef vax
		for (n = npte; n-- ; kpte++)
			*(int *)kpte = PG_NOACC;
#endif vax
#ifdef ibm032
		for (n = npte; n--; kpte++, vp++) {
			ipte = &MMU_HATIPT[*(int *)kpte & PG_PFNUM];
			mapout(kpte, 1);
			*(int *)kpte = PG_NOACC; /* who cares? */
			ipte->key_addrtag = saddrtag;
		}
#endif ibm032
		rmfree(kernelmap, (long)clrnd(npte), a);
	} else
#endif vax || ibm032
	    returnCode = (*aproc) (bp);

	return returnCode;
}
