/*
 *				lun.c
 */

/*)LIBRARY
*/

#ifdef DOCUMENTATION

title	lun	LUN usage for RSX
index		Lun usage for RSX

description
	These routines where developed because of the need to access devices
	directly through QIO's under DECUS 'C. The problem at the time, was
	that we wished to access graphics terminals under 'C, without opening
	the device as a file [fopen()], because of the large DECUS 'C buffer
	overheads (I'ts a waste of memory to allocate buffers etc, when you're
	only accessing the device through a LUN). One solution is to select
	an arbitory LUN (using magic number generation program), and use this
	as a constant in the program. The problems with this are :
	a) Depending upon the program, the 'C run-time library may allocat that
	same lun to a file you open !! b) Many modules using the same allocation
	scheme used in the same program, could have conflicting LUNs, and might
	be hard to get working together, if lun schems don't line up.
	The obvious solution is to allocate the lun to use from the run-time
	library's table.
	Easy solution ? I thought so, so I started reading through code !!!
	Starting with fopen(), and then going through code for lots of
	associated modules, I eventually came accross the wanted table. While
	working out how this table worked ,I descoverd that the number of luns
	is hard-wired to 20 luns only (another symptom of RSTS). To get the full
	32 LUNs available to RSX, You would have to re-build the module
	[5,5]IOV.MAC, with $$lmax as the new lun table size. Also I found that
	the lun table for rsx starts at LUN 2, So that stderr is kept from harm
	to get at this, access it as lun 1. (C run-time librarys won't let you
	access it).

#endif
	

#include "lun.h"

/*			LUNOPN
 * Open and assign a device on a LUN, This by-passes the 'C bufferd IO system
 *  therfore not assigning any FILE type structures. The LUN is marked as
 *  used in the LUN table however, so as not to stir up the 'C environment
 *  Returns 0 on error or LUN number
 *  If an error occurs, the lun will be de-allocated
 */

int lunopn(device)
char *device;			/* device name to open xxn */
{
	int devnam;		/* 2 character device name */
	int devnum;		/* device unit number */
	int lun;		/* lun that we're allocated */

	/* Find a LUN to use */
	if(!(lun=alolun()))
		return(0);		/* return 0 if no luns left */

	/* split up the name into it's componant peices */
	if (isalpha(*device) && isalpha(*(device+1))) {
		devnam=amapiu(device);
		devnum=atoi(device+2);

		/* now assign the lun */
		if(alun(lun,devnam,devnum)==IS_SUC) {
			/* we may now need attach to the device */
			if(qiow(IO_ATT,lun,LUNEFN,0,0,0) == IS_SUC) {
				return(lun);
			}
		}
	}

	/* there's a problem, so de-allocate the lun */
	dealun(lun);

	/* return error code */
	return(0);
}


/*			LUNCLS
 * Close a device opened by lunopn()
 * returns 0 if successfull or -1 if problem encounted
 *
 */
luncls(lun)
int lun;		/* LUN to close */
{
	/* detach the lun */
	if (qiow(IO_DET,lun,LUNEFN,0,0,0)==IS_SUC) {

		/* de-allocate the lun */
		if(!dealun(lun)) {

			/* return success code */
			return(0);
		}
	}
	/* problem, so return error code */
	return(-1);
}


/*			ALOLUN
 * Find a free LUN in the lun table, and allocate it
 * Returns the LUN number or 0 on error
 */

alolun()
{
	int *ltp;	/* pointer to lun table */
	int lun;	/* lun we've got */
	int n;		/* lun's left to look at */

	ltp=$$luns;	/* point at lun table */
	n=$$nlun;	/* how many we're alowed to look at */

	/* find a free LUN */
	for(lun=2 ; ((n--)&&(ltp!=$$lune)&&(*(ltp))) ; lun++) {
		ltp++;
	}

	/* if there's a free LUN */
	if(!(*ltp)) {
		/* assign lun ... point to srderr for inquisitive people */
		*ltp=stderr;
		/* return the LUn to the caller */
		return(lun);
	} else {
		return(0);
	}
}

/*			DEALUN
 * De-allocate the specified lun, returning it to the LUN table
 *  Returns 0 on OK or -1 on error
 *
 */

dealun(lun)
int lun;	/* lun to de-allocate */
{
	/* if lun is valid, then de-allocate it and return 0 else return -1 */
	if (lun<=$$nlun) {
		*($$luns+(lun-2))=0;
		return(0);
	}
	return(-1);
}
