patch-2.2.15 linux/drivers/char/rio/riotable.c

Next file: linux/drivers/char/rio/riotime.h
Previous file: linux/drivers/char/rio/riospace.h
Back to the patch index
Back to the overall index

diff -u --new-file --recursive --exclude-from ../../exclude v2.2.14/drivers/char/rio/riotable.c linux/drivers/char/rio/riotable.c
@@ -0,0 +1,1058 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**	Module		: riotable.c
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 10:33:47
+**	Retrieved	: 11/6/98 10:33:50
+**
+**  ident @(#)riotable.c	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+#ifdef SCCS_LABELS
+static char *_riotable_c_sccs_ = "@(#)riotable.c	1.2";
+#endif
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/compatmac.h>
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "typdef.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "top.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "riotypes.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "error.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "control.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+#include "list.h"
+#include "sam.h"
+#include "protsts.h"
+
+/*
+** A configuration table has been loaded. It is now up to us
+** to sort it out and use the information contained therein.
+*/
+int
+RIONewTable(p)
+struct rio_info *	p;
+{
+	int Host, Host1, Host2, NameIsUnique, Entry, SubEnt;
+	struct Map *MapP;
+	struct Map *HostMapP;
+	struct Host *HostP;
+
+	char *cptr;
+
+	/*
+	** We have been sent a new table to install. We need to break
+	** it down into little bits and spread it around a bit to see
+	** what we have got.
+	*/
+	/*
+	** Things to check:
+	** (things marked 'xx' aren't checked any more!)
+	** (1)	That there are no booted Hosts/RTAs out there.
+	** (2)	That the names are properly formed
+	** (3)	That blank entries really are.
+	** xx (4)	That hosts mentioned in the table actually exist. xx
+	** (5)	That the IDs are unique (per host).
+	** (6)	That host IDs are zero
+	** (7)	That port numbers are valid
+	** (8)	That port numbers aren't duplicated
+	** (9)	That names aren't duplicated
+	** xx (10) That hosts that actually exist are mentioned in the table. xx
+	*/
+	rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(1)\n")); 
+	if ( p->RIOSystemUp ) {		/* (1) */
+		p->RIOError.Error = HOST_HAS_ALREADY_BEEN_BOOTED;
+		return EBUSY;
+	}
+
+	p->RIOError.Error = NOTHING_WRONG_AT_ALL;
+	p->RIOError.Entry = -1;
+	p->RIOError.Other = -1;
+
+	for ( Entry=0; Entry<TOTAL_MAP_ENTRIES; Entry++ ) {
+		MapP = &p->RIOConnectTable[Entry];
+		if ((MapP->Flags & RTA16_SECOND_SLOT) == 0) {
+			rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(2)\n"));
+			cptr = MapP->Name;		/* (2) */
+			cptr[MAX_NAME_LEN-1]='\0';
+			if ( cptr[0]=='\0' ) {
+				bcopy(MapP->RtaUniqueNum?"RTA	NN":"HOST NN",MapP->Name,8);
+				MapP->Name[5] = '0'+Entry/10;
+				MapP->Name[6] = '0'+Entry%10;
+			}
+			while ( *cptr ) {
+				if ( *cptr<' ' || *cptr>'~' ) {
+					p->RIOError.Error = BAD_CHARACTER_IN_NAME;
+					p->RIOError.Entry = Entry;
+					return ENXIO;
+				}
+				cptr++;
+			}
+		}
+
+		/*
+		** If the entry saved was a tentative entry then just forget
+		** about it.
+		*/
+		if ( MapP->Flags & SLOT_TENTATIVE ) {
+			MapP->HostUniqueNum = 0;
+			MapP->RtaUniqueNum = 0;
+			continue;
+		}
+
+		rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(3)\n"));
+		if ( !MapP->RtaUniqueNum && !MapP->HostUniqueNum ) { /* (3) */
+			if ( MapP->ID || MapP->SysPort || MapP->Flags ) {
+				rio_dprint(RIO_DEBUG_TABLE, ("%s pretending to be empty but isn't\n",MapP->Name));
+				p->RIOError.Error = TABLE_ENTRY_ISNT_PROPERLY_NULL;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+			rio_dprint(RIO_DEBUG_TABLE, ("!RIO: Daemon: test (3) passes\n"));
+			continue;
+		}
+
+		rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(4)\n"));
+		for ( Host=0; Host<p->RIONumHosts; Host++ ) { /* (4) */
+			if ( p->RIOHosts[Host].UniqueNum==MapP->HostUniqueNum ) {
+				HostP = &p->RIOHosts[Host];
+				/*
+				** having done the lookup, we don't really want to do
+				** it again, so hang the host number in a safe place
+				*/
+				MapP->Topology[0].Unit = Host;
+				break;
+			}
+		}
+
+		if ( Host >= p->RIONumHosts ) {
+			rio_dprint(RIO_DEBUG_TABLE, ("RTA %s has unknown host unique number 0x%x\n",
+									MapP->Name,MapP->HostUniqueNum));
+			MapP->HostUniqueNum = 0;
+			/* MapP->RtaUniqueNum	= 0; */
+			/* MapP->ID			= 0; */
+			/* MapP->Flags		 = 0; */
+			/* MapP->SysPort		 = 0; */
+			/* MapP->Name[0]		 = 0; */
+			continue;
+		}
+
+		rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(5)\n")); 
+		if ( MapP->RtaUniqueNum ) { /* (5) */
+			if ( !MapP->ID ) {
+				rio_dprint(RIO_DEBUG_TABLE, ("RIO: RTA %s has been allocated an ID of zero!\n",
+							MapP->Name));
+				p->RIOError.Error		 = ZERO_RTA_ID;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+			if ( MapP->ID > MAX_RUP ) {
+				rio_dprint(RIO_DEBUG_TABLE, ("RIO: RTA %s has been allocated an illegal ID %d\n",
+							MapP->Name, MapP->ID));
+				p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+			for ( SubEnt=0; SubEnt<Entry; SubEnt++ ) {
+				if ( MapP->HostUniqueNum == 
+						p->RIOConnectTable[SubEnt].HostUniqueNum && 
+						MapP->ID == p->RIOConnectTable[SubEnt].ID ) {
+					rio_dprint(RIO_DEBUG_TABLE, ("Dupl. ID number allocated to RTA %s and RTA %s\n",
+							MapP->Name,p->RIOConnectTable[SubEnt].Name));
+					p->RIOError.Error = DUPLICATED_RTA_ID;
+					p->RIOError.Entry = Entry;
+					p->RIOError.Other = SubEnt;
+					return ENXIO;
+				}
+				/*
+				** If the RtaUniqueNum is the same, it may be looking at both
+				** entries for a 16 port RTA, so check the ids
+				*/
+				if ((MapP->RtaUniqueNum == 
+						p->RIOConnectTable[SubEnt].RtaUniqueNum)
+				 		&& (MapP->ID2 != p->RIOConnectTable[SubEnt].ID)) {
+					rio_dprint(RIO_DEBUG_TABLE, ("RTA %s has duplicate unique number\n",MapP->Name));
+					rio_dprint(RIO_DEBUG_TABLE, ("RTA %s has duplicate unique number\n",
+										p->RIOConnectTable[SubEnt].Name));
+					p->RIOError.Error = DUPLICATE_UNIQUE_NUMBER;
+					p->RIOError.Entry = Entry;
+					p->RIOError.Other = SubEnt;
+					return ENXIO;
+				}
+			}
+			rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(7a)\n")); 
+			/* (7a) */
+			if ((MapP->SysPort != NO_PORT)&&(MapP->SysPort % PORTS_PER_RTA)) {
+				rio_dprint(RIO_DEBUG_TABLE, ("TTY Port number %d-RTA %s is not a multiple of %d!\n",
+					(int)MapP->SysPort,MapP->Name,PORTS_PER_RTA));
+				p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+			rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(7b)\n")); 
+			/* (7b) */
+			if ((MapP->SysPort != NO_PORT)&&(MapP->SysPort >= RIO_PORTS)) {
+				rio_dprint(RIO_DEBUG_TABLE, ("TTY Port number %d for RTA %s is too big\n",
+							(int)MapP->SysPort,MapP->Name));
+				p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+			for ( SubEnt=0; SubEnt<Entry; SubEnt++ ) {
+				if ( p->RIOConnectTable[SubEnt].Flags & RTA16_SECOND_SLOT )
+						continue;
+				if ( p->RIOConnectTable[SubEnt].RtaUniqueNum ) {
+					rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(8)\n")); 
+					/* (8) */
+					if ( (MapP->SysPort != NO_PORT) && (MapP->SysPort == 
+									p->RIOConnectTable[SubEnt].SysPort) ) {
+						rio_dprint(RIO_DEBUG_TABLE, ("RTA %s:same TTY port # as RTA %s (%d)\n",
+							MapP->Name, p->RIOConnectTable[SubEnt].Name,
+							(int)MapP->SysPort));
+						p->RIOError.Error = TTY_NUMBER_IN_USE;
+						p->RIOError.Entry = Entry;
+						p->RIOError.Other = SubEnt;
+						return ENXIO;
+					}
+					rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(9)\n")); 
+					if (RIOStrCmp(MapP->Name,
+							p->RIOConnectTable[SubEnt].Name)==0 && !(MapP->Flags & RTA16_SECOND_SLOT)) { /* (9) */
+						rio_dprint(RIO_DEBUG_TABLE, ("RTA name %s used twice\n",MapP->Name));
+						p->RIOError.Error = NAME_USED_TWICE;
+						p->RIOError.Entry = Entry;
+						p->RIOError.Other = SubEnt;
+						return ENXIO;
+					}
+				}
+			}
+		}
+		else { /* (6) */
+			rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: entering(6)\n")); 
+			if ( MapP->ID ) {
+				rio_dprint(RIO_DEBUG_TABLE, ("RIO:HOST %s has been allocated ID that isn't zero!\n",
+					MapP->Name));
+				p->RIOError.Error = HOST_ID_NOT_ZERO;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+			if ( MapP->SysPort != NO_PORT ) {
+				rio_dprint(RIO_DEBUG_TABLE, ("RIO: HOST %s has been allocated port numbers!\n",
+					MapP->Name));
+				p->RIOError.Error = HOST_SYSPORT_BAD;
+				p->RIOError.Entry = Entry;
+				return ENXIO;
+			}
+		}
+	}
+
+	/*
+	** wow! if we get here then its a goody!
+	*/
+
+	/*
+	** Zero the (old) entries for each host...
+	*/
+	for ( Host=0; Host<RIO_HOSTS; Host++ ) {
+		for ( Entry=0; Entry<MAX_RUP; Entry++ ) {
+			bzero((caddr_t)&p->RIOHosts[Host].Mapping[Entry], 
+											sizeof(struct Map));
+		}
+		bzero((caddr_t)&p->RIOHosts[Host].Name[0],
+								sizeof(p->RIOHosts[Host].Name) );
+	}
+
+	/*
+	** Copy in the new table entries
+	*/
+	for ( Entry=0; Entry< TOTAL_MAP_ENTRIES; Entry++ ) {
+		rio_dprint(RIO_DEBUG_TABLE, ("RIONewTable: Copy table for Host entry %d\n", Entry));
+		MapP = &p->RIOConnectTable[Entry];
+
+		/*
+		** Now, if it is an empty slot ignore it!
+		*/
+		if ( MapP->HostUniqueNum==0 )
+			continue;
+
+		/*
+		** we saved the host number earlier, so grab it back
+		*/
+		HostP = &p->RIOHosts[MapP->Topology[0].Unit];
+
+		/*
+		** If it is a host, then we only need to fill in the name field.
+		*/
+		if ( MapP->ID==0 ) {
+			rio_dprint(RIO_DEBUG_TABLE, ("Host entry found. Name %s\n",MapP->Name));
+			bcopy(MapP->Name,HostP->Name,MAX_NAME_LEN);
+			continue;
+		}
+
+		/*
+		** Its an RTA entry, so fill in the host mapping entries for it
+		** and the port mapping entries. Notice that entry zero is for
+		** ID one.
+		*/
+		HostMapP = &HostP->Mapping[MapP->ID-1];
+
+		if (MapP->Flags & SLOT_IN_USE) {
+			rio_dprint(RIO_DEBUG_TABLE, ("Rta entry found. Name %s\n",MapP->Name));
+			/*
+			** structure assign, then sort out the bits we shouldn't have done
+			*/
+			*HostMapP = *MapP;
+
+			HostMapP->Flags = SLOT_IN_USE;
+			if (MapP->Flags & RTA16_SECOND_SLOT)
+				HostMapP->Flags |= RTA16_SECOND_SLOT;
+
+			RIOReMapPorts(p, HostP, HostMapP );
+		}
+		else {
+			rio_dprint(RIO_DEBUG_TABLE, ("TENTATIVE Rta entry found. Name %s\n",MapP->Name));
+		}
+	}
+
+	for ( Entry=0; Entry< TOTAL_MAP_ENTRIES; Entry++ ) {
+		p->RIOSavedTable[Entry] = p->RIOConnectTable[Entry];
+	}
+
+	for ( Host=0; Host<p->RIONumHosts; Host++ ) {
+		for ( SubEnt=0; SubEnt<LINKS_PER_UNIT; SubEnt++ ) {
+			p->RIOHosts[Host].Topology[SubEnt].Unit = ROUTE_DISCONNECT;
+			p->RIOHosts[Host].Topology[SubEnt].Link = NO_LINK;
+		}
+		for ( Entry=0; Entry<MAX_RUP; Entry++ ) {
+			for ( SubEnt=0; SubEnt<LINKS_PER_UNIT; SubEnt++ ) {
+				p->RIOHosts[Host].Mapping[Entry].Topology[SubEnt].Unit = 
+								ROUTE_DISCONNECT;
+				p->RIOHosts[Host].Mapping[Entry].Topology[SubEnt].Link = 
+								NO_LINK;
+			}
+		}
+		if ( !p->RIOHosts[Host].Name[0] ) {
+			bcopy("HOST 1",p->RIOHosts[Host].Name,7);
+			p->RIOHosts[Host].Name[5] += Host;
+		}
+		/*
+		** Check that default name assigned is unique.
+		*/
+		Host1 = Host;
+		NameIsUnique = 0;
+		while (!NameIsUnique) {
+			NameIsUnique = 1;
+			for ( Host2=0; Host2<p->RIONumHosts; Host2++ ) {
+				if (Host2 == Host)
+					continue;
+				if (RIOStrCmp(p->RIOHosts[Host].Name, p->RIOHosts[Host2].Name)
+									 == 0) {
+					NameIsUnique = 0;
+					Host1++;
+					if (Host1 >= p->RIONumHosts)
+						Host1 = 0;
+					p->RIOHosts[Host].Name[5] = '1' + Host1;
+				}
+			}
+		}
+		/*
+		** Rename host if name already used.
+		*/
+		if (Host1 != Host)
+		{
+			rio_dprint(RIO_DEBUG_TABLE, ("Default name %s already used\n", p->RIOHosts[Host].Name));
+			bcopy("HOST 1",p->RIOHosts[Host].Name,7);
+			p->RIOHosts[Host].Name[5] += Host1;
+		}
+		rio_dprint(RIO_DEBUG_TABLE, ("Assigning default name %s\n", p->RIOHosts[Host].Name));
+	}
+	return 0;
+}
+
+/*
+** User process needs the config table - build it from first
+** principles.
+*/
+int
+RIOApel(p)
+struct rio_info *	p;
+{
+	int Host;
+	int link;
+	int Rup;
+	int Next = 0;
+	struct Map *MapP;
+	struct Host *HostP;
+	int oldspl;
+
+	disable(oldspl);		/* strange but true! */
+ 
+	rio_dprint(RIO_DEBUG_TABLE, ("Generating a table to return to config.rio\n"));
+
+	bzero((caddr_t)&p->RIOConnectTable[0], 
+					sizeof(struct Map) * TOTAL_MAP_ENTRIES );
+
+	for ( Host=0; Host<RIO_HOSTS; Host++ ) {
+		rio_dprint(RIO_DEBUG_TABLE, ("Processing host %d\n", Host));
+		HostP = &p->RIOHosts[Host];
+		MapP = &p->RIOConnectTable[Next++];
+		MapP->HostUniqueNum = HostP->UniqueNum;
+		if ( (HostP->Flags & RUN_STATE) != RC_RUNNING )
+			continue;
+		MapP->RtaUniqueNum = 0;
+		MapP->ID = 0;
+		MapP->Flags = SLOT_IN_USE;
+		MapP->SysPort = NO_PORT;
+		for ( link=0; link<LINKS_PER_UNIT; link++ )
+			MapP->Topology[link] = HostP->Topology[link];
+		bcopy(HostP->Name,MapP->Name,MAX_NAME_LEN);
+		for ( Rup=0; Rup<MAX_RUP; Rup++ ) {
+			if ( HostP->Mapping[Rup].Flags & (SLOT_IN_USE|SLOT_TENTATIVE) ) {
+				p->RIOConnectTable[Next] = HostP->Mapping[Rup];
+				if ( HostP->Mapping[Rup].Flags & SLOT_IN_USE)
+					p->RIOConnectTable[Next].Flags |= SLOT_IN_USE;
+				if ( HostP->Mapping[Rup].Flags & SLOT_TENTATIVE)
+					p->RIOConnectTable[Next].Flags |= SLOT_TENTATIVE;
+				if ( HostP->Mapping[Rup].Flags & RTA16_SECOND_SLOT )
+					p->RIOConnectTable[Next].Flags |= RTA16_SECOND_SLOT;
+				Next++;
+			}
+		}
+	}
+	restore(oldspl);
+	return 0;
+}
+
+/*
+** config.rio has taken a dislike to one of the gross maps entries.
+** if the entry is suitably inactive, then we can gob on it and remove
+** it from the table.
+*/
+int
+RIODeleteRta(p, MapP)
+struct rio_info *p;
+struct Map *MapP;
+{
+	int host, entry, port, link;
+	int SysPort;
+	struct Host *HostP;
+	struct Map *HostMapP;
+	struct Port *PortP;
+	int work_done = 0;
+	unsigned long flags;
+
+	rio_dprint(RIO_DEBUG_TABLE, ("Delete entry on host %x, rta %x\n",
+								MapP->HostUniqueNum,MapP->RtaUniqueNum));
+
+	for ( host=0; host < p->RIONumHosts; host++ ) {
+		HostP = &p->RIOHosts[host];
+
+		rio_spin_lock_irqsave( &HostP->HostLock, flags );
+
+		if ( (HostP->Flags & RUN_STATE) != RC_RUNNING ) {
+			rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+			continue;
+		}
+
+		for ( entry=0; entry<MAX_RUP; entry++ ) {
+			if ( MapP->RtaUniqueNum == HostP->Mapping[entry].RtaUniqueNum ) {
+				HostMapP = &HostP->Mapping[entry];
+				rio_dprint(RIO_DEBUG_TABLE, ("Found entry offset %d on host %s\n", 
+						entry,HostP->Name));
+
+				/*
+				** Check all four links of the unit are disconnected
+				*/
+				for ( link=0; link< LINKS_PER_UNIT; link++ ) {
+					if ( HostMapP->Topology[link].Unit != ROUTE_DISCONNECT ) {
+						rio_dprint(RIO_DEBUG_TABLE, ("Entry is in use and cannot be deleted!\n"));
+						p->RIOError.Error = UNIT_IS_IN_USE;
+						rio_spin_unlock_irqrestore( &HostP->HostLock, flags);
+						return EBUSY;
+					}
+				}
+				/*
+				** Slot has been allocated, BUT not booted/routed/
+				** connected/selected or anything else-ed
+				*/
+				SysPort = HostMapP->SysPort;
+
+				if ( SysPort != NO_PORT ) {
+					for (port=SysPort; port < SysPort+PORTS_PER_RTA; port++) {
+						PortP = p->RIOPortp[port];
+						rio_dprint(RIO_DEBUG_TABLE, ("Unmap port\n"));
+
+						rio_spin_lock_irqsave( &PortP->portSem, flags );
+
+						PortP->Mapped = 0;
+
+						if ( PortP->State & (RIO_MOPEN|RIO_LOPEN) ) {
+
+							rio_dprint(RIO_DEBUG_TABLE, ("Gob on port\n"));
+							PortP->TxBufferIn = PortP->TxBufferOut = 0;
+							/* What should I do 
+							wakeup( &PortP->TxBufferIn );
+							wakeup( &PortP->TxBufferOut);
+							*/
+							PortP->InUse = NOT_INUSE;
+							/* What should I do 
+							wakeup( &PortP->InUse );
+							signal(PortP->TtyP->t_pgrp,SIGKILL);
+							ttyflush(PortP->TtyP,(FREAD|FWRITE));
+							*/
+							PortP->State |= RIO_CLOSING | RIO_DELETED;
+						}
+
+						/*
+						** For the second slot of a 16 port RTA, the
+						** driver needs to reset the changes made to
+						** the phb to port mappings in RIORouteRup.
+						*/
+						if (PortP->SecondBlock) {
+							ushort dest_unit = HostMapP->ID;
+							ushort dest_port = port - SysPort;
+							WORD	 *TxPktP;
+							PKT	*Pkt;
+
+							for (TxPktP = PortP->TxStart;
+								TxPktP <= PortP->TxEnd; TxPktP++) {
+								/*
+								** *TxPktP is the pointer to the
+								** transmit packet on the host card.
+								** This needs to be translated into
+								** a 32 bit pointer so it can be
+								** accessed from the driver.
+								*/
+								Pkt = (PKT *) RIO_PTR(HostP->Caddr,
+								 	RWORD(*TxPktP));
+								rio_dprint(RIO_DEBUG_TABLE, (
+						"Tx packet (%x) destination: Old %x:%x New %x:%x\n",
+								 *TxPktP, Pkt->dest_unit,
+								 Pkt->dest_port, dest_unit, dest_port));
+								WWORD(Pkt->dest_unit, dest_unit);
+								WWORD(Pkt->dest_port, dest_port);
+							}
+							rio_dprint(RIO_DEBUG_TABLE, (
+						"Port %d phb destination: Old %x:%x New %x:%x\n",
+							 port, PortP->PhbP->destination & 0xff,
+							 (PortP->PhbP->destination >> 8) & 0xff,
+							 dest_unit, dest_port));
+							WWORD(PortP->PhbP->destination,
+							 dest_unit + (dest_port << 8));
+						}
+						rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+					}
+				}
+				rio_dprint(RIO_DEBUG_TABLE, ("Entry nulled.\n"));
+				bzero((char *)HostMapP,sizeof(struct Map));
+				work_done++;
+			}
+		}
+		rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+	}
+
+	/* XXXXX lock me up */
+	for ( entry=0; entry< TOTAL_MAP_ENTRIES; entry++ ) {
+		if ( p->RIOSavedTable[entry].RtaUniqueNum == MapP->RtaUniqueNum ) {
+			bzero((char *)&p->RIOSavedTable[entry],sizeof(struct Map));
+			work_done++;
+		}
+		if ( p->RIOConnectTable[entry].RtaUniqueNum == MapP->RtaUniqueNum ) {
+			bzero((char *)&p->RIOConnectTable[entry],sizeof(struct Map));
+			work_done++;
+		}
+	}
+	if ( work_done )
+		return 0;
+
+	rio_dprint(RIO_DEBUG_TABLE, ("Couldn't find entry to be deleted\n"));
+	p->RIOError.Error = COULDNT_FIND_ENTRY;
+	return ENXIO;
+}
+
+int RIOAssignRta( struct rio_info *p, struct Map *MapP )
+{
+    int host;
+    struct Map *HostMapP;
+    char *sptr;
+    int	link;
+
+
+    rio_dprint(RIO_DEBUG_TABLE, ("Assign entry on host %x, rta %x, ID %d, Sysport %d\n",
+				MapP->HostUniqueNum,MapP->RtaUniqueNum,
+				MapP->ID, (int)MapP->SysPort ));
+
+    if ((MapP->ID != (ushort)-1) &&
+	((int)MapP->ID < (int)1 || (int)MapP->ID > MAX_RUP ))
+    {
+	rio_dprint(RIO_DEBUG_TABLE, ("Bad ID in map entry!\n"));
+	p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE;
+	return EINVAL;
+    }
+    if (MapP->RtaUniqueNum == 0)
+    {
+	rio_dprint(RIO_DEBUG_TABLE, ("Rta Unique number zero!\n"));
+	p->RIOError.Error = RTA_UNIQUE_NUMBER_ZERO;
+	return EINVAL;
+    }
+    if ( (MapP->SysPort != NO_PORT) && (MapP->SysPort % PORTS_PER_RTA) )
+    {
+	rio_dprint(RIO_DEBUG_TABLE, ("Port %d not multiple of %d!\n",(int)MapP->SysPort,PORTS_PER_RTA));
+	p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+	return EINVAL;
+    }
+    if ( (MapP->SysPort != NO_PORT) && (MapP->SysPort >= RIO_PORTS) )
+    {
+	rio_dprint(RIO_DEBUG_TABLE, ("Port %d not valid!\n",(int)MapP->SysPort));
+	p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+	return EINVAL;
+    }
+
+    /*
+    ** Copy the name across to the map entry.
+    */
+    MapP->Name[MAX_NAME_LEN-1] = '\0';
+    sptr = MapP->Name;
+    while ( *sptr )
+    {
+    if ( *sptr<' ' || *sptr>'~' )
+    {
+	rio_dprint(RIO_DEBUG_TABLE, ("Name entry contains non-printing characters!\n"));
+	p->RIOError.Error = BAD_CHARACTER_IN_NAME;
+	return EINVAL;
+    }
+    sptr++;
+    }
+
+    for ( host=0; host < p->RIONumHosts; host++ )
+    {
+	if ( MapP->HostUniqueNum == p->RIOHosts[host].UniqueNum )
+	{
+	    if ( (p->RIOHosts[host].Flags & RUN_STATE) != RC_RUNNING )
+	    {
+		p->RIOError.Error = HOST_NOT_RUNNING;
+		return ENXIO;
+	    }
+
+	    /*
+	    ** Now we have a host we need to allocate an ID
+	    ** if the the entry does not already have one.
+	    */
+	    if (MapP->ID == (ushort)-1)
+	    {
+		int nNewID;
+
+		rio_dprint(RIO_DEBUG_TABLE, ("Attempting to get a new ID for rta \"%s\"\n",
+		      MapP->Name));
+		/*
+		** The idea here is to allow RTA's to be assigned
+		** before they actually appear on the network.
+		** This allows the addition of RTA's without having
+		** to plug them in.
+		** What we do is:
+		**  - Find a free ID and allocate it to the RTA.
+		**  - If this map entry is the second half of a
+		**    16 port entry then find the other half and
+		**    make sure the 2 cross reference each other.
+		*/
+		if (RIOFindFreeID(p, &p->RIOHosts[host], &nNewID, NULL) != 0)
+		{
+		    p->RIOError.Error = COULDNT_FIND_ENTRY;
+		    return EBUSY;
+		}
+		MapP->ID = (ushort)nNewID + 1;
+		rio_dprint(RIO_DEBUG_TABLE, ("Allocated ID %d for this new RTA.\n",MapP->ID));
+		HostMapP = &p->RIOHosts[host].Mapping[nNewID];
+		HostMapP->RtaUniqueNum = MapP->RtaUniqueNum;
+		HostMapP->HostUniqueNum = MapP->HostUniqueNum;
+		HostMapP->ID = MapP->ID;
+		for (link = 0; link < LINKS_PER_UNIT; link++)
+		{
+		    HostMapP->Topology[link].Unit = ROUTE_DISCONNECT;
+		    HostMapP->Topology[link].Link = NO_LINK;
+		}
+		if (MapP->Flags & RTA16_SECOND_SLOT)
+		{
+		    int unit;
+
+		    for (unit = 0; unit < MAX_RUP; unit++)
+			if (p->RIOHosts[host].Mapping[unit].RtaUniqueNum ==
+			    MapP->RtaUniqueNum)
+			    break;
+		    if (unit == MAX_RUP)
+		    {
+			p->RIOError.Error = COULDNT_FIND_ENTRY;
+			return EBUSY;
+		    }
+		    HostMapP->Flags |= RTA16_SECOND_SLOT;
+		    HostMapP->ID2 = MapP->ID2 = p->RIOHosts[host].Mapping[unit].ID;
+		    p->RIOHosts[host].Mapping[unit].ID2 = MapP->ID;
+		    rio_dprint(RIO_DEBUG_TABLE, ("Cross referenced id %d to ID %d.\n",
+			  MapP->ID,
+			  p->RIOHosts[host].Mapping[unit].ID));
+		}
+	    }
+
+	    HostMapP = &p->RIOHosts[host].Mapping[MapP->ID-1];
+
+	    if ( HostMapP->Flags & SLOT_IN_USE )
+	    {
+		rio_dprint(RIO_DEBUG_TABLE, ("Map table slot for ID %d is already in use.\n",MapP->ID));
+		p->RIOError.Error = ID_ALREADY_IN_USE;
+		return EBUSY;
+	    }
+
+	    /*
+	    ** Assign the sys ports and the name, and mark the slot as
+	    ** being in use.
+	    */
+	    HostMapP->SysPort = MapP->SysPort;
+	    if ((MapP->Flags & RTA16_SECOND_SLOT) == 0)
+	      CCOPY( MapP->Name, HostMapP->Name, MAX_NAME_LEN );
+	    HostMapP->Flags = SLOT_IN_USE | RTA_BOOTED;
+#if NEED_TO_FIX
+	    RIO_SV_BROADCAST(p->RIOHosts[host].svFlags[MapP->ID-1]);
+#endif
+	    if (MapP->Flags & RTA16_SECOND_SLOT)
+		HostMapP->Flags |= RTA16_SECOND_SLOT;
+
+	    RIOReMapPorts( p, &p->RIOHosts[host], HostMapP );
+	    /*
+	    ** Adjust 2nd block of 8 phbs
+	    */
+	    if (MapP->Flags & RTA16_SECOND_SLOT)
+		RIOFixPhbs(p, &p->RIOHosts[host], HostMapP->ID - 1);
+
+	    if ( HostMapP->SysPort != NO_PORT )
+	    {
+		if ( HostMapP->SysPort < p->RIOFirstPortsBooted )
+		    p->RIOFirstPortsBooted = HostMapP->SysPort;
+		if ( HostMapP->SysPort > p->RIOLastPortsBooted )
+		    p->RIOLastPortsBooted = HostMapP->SysPort;
+	    }
+	    if (MapP->Flags & RTA16_SECOND_SLOT)
+	        rio_dprint(RIO_DEBUG_TABLE, ("Second map of RTA %s added to configuration\n",
+		 p->RIOHosts[host].Mapping[MapP->ID2 - 1].Name));
+	    else
+	        rio_dprint(RIO_DEBUG_TABLE, ("RTA %s added to configuration\n",MapP->Name));
+	    return 0;
+	}
+    }
+    p->RIOError.Error = UNKNOWN_HOST_NUMBER;
+    rio_dprint(RIO_DEBUG_TABLE, ("Unknown host %x\n",MapP->HostUniqueNum));
+    return ENXIO;
+}
+
+
+int
+RIOReMapPorts(p, HostP, HostMapP)
+struct rio_info *	p;
+struct Host *HostP;
+struct Map *HostMapP; 
+{
+	register struct Port *PortP;
+	uint SubEnt;
+	uint HostPort;
+	uint SysPort;
+	ushort RtaType;
+	unsigned long flags;
+
+#ifdef CHECK
+	CheckHostP( HostP );
+	CheckHostMapP( HostMapP );
+#endif
+
+	rio_dprint(RIO_DEBUG_TABLE, ("Mapping sysport %d to id %d\n",(int)HostMapP->SysPort, HostMapP->ID));
+
+	/*
+	** We need to tell the UnixRups which sysport the rup corresponds to
+	*/
+	HostP->UnixRups[HostMapP->ID-1].BaseSysPort = HostMapP->SysPort;
+
+	if ( HostMapP->SysPort == NO_PORT )
+		return(0);
+
+	RtaType = GetUnitType(HostMapP->RtaUniqueNum);
+	rio_dprint(RIO_DEBUG_TABLE, ("Mapping sysport %d-%d\n",
+				(int)HostMapP->SysPort,(int)HostMapP->SysPort+PORTS_PER_RTA-1));
+
+	/*
+	** now map each of its eight ports
+	*/
+	for ( SubEnt=0; SubEnt<PORTS_PER_RTA; SubEnt++) {
+	  rio_dprint  (RIO_DEBUG_TABLE, ("subent = %d, HostMapP->SysPort = %d\n", 
+		  SubEnt, (int) HostMapP->SysPort));
+		SysPort = HostMapP->SysPort+SubEnt;		/* portnumber within system */
+					/* portnumber on host */
+		
+		HostPort = (HostMapP->ID-1)*PORTS_PER_RTA+SubEnt; 
+
+		rio_dprint (RIO_DEBUG_TABLE, ("c1 p = %p, p->rioPortp = %p\n", p, p->RIOPortp));
+		PortP = p->RIOPortp[SysPort];
+#if 0
+		PortP->TtyP	= &p->channel[SysPort];
+#endif
+		rio_dprint(RIO_DEBUG_TABLE, ("Map port\n"));
+
+		/*
+		** Point at all the real neat data structures
+		*/
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+		PortP->HostP = HostP;
+		PortP->Caddr = HostP->Caddr;
+
+		/*
+		** The PhbP cannot be filled in yet
+		** unless the host has been booted
+		*/
+		if ((HostP->Flags & RUN_STATE) == RC_RUNNING) {
+			struct PHB *PhbP = PortP->PhbP = &HostP->PhbP[HostPort];
+			PortP->TxAdd =(WORD *)RIO_PTR(HostP->Caddr,RWORD(PhbP->tx_add));
+			PortP->TxStart =(WORD *)RIO_PTR(HostP->Caddr,RWORD(PhbP->tx_start));
+			PortP->TxEnd =(WORD *)RIO_PTR(HostP->Caddr,RWORD(PhbP->tx_end));
+			PortP->RxRemove=(WORD *)RIO_PTR(HostP->Caddr,
+									RWORD(PhbP->rx_remove));
+			PortP->RxStart =(WORD *)RIO_PTR(HostP->Caddr,RWORD(PhbP->rx_start));
+			PortP->RxEnd =(WORD *)RIO_PTR(HostP->Caddr,RWORD(PhbP->rx_end));
+		}
+		else
+			PortP->PhbP = NULL;
+
+		/*
+		** port related flags
+		*/
+		PortP->HostPort	= HostPort;
+		/*
+		** For each part of a 16 port RTA, RupNum is ID - 1.
+		*/
+		PortP->RupNum = HostMapP->ID - 1;
+		if (HostMapP->Flags & RTA16_SECOND_SLOT) {
+			PortP->ID2			 = HostMapP->ID2 - 1;
+			PortP->SecondBlock	 = TRUE;
+		}
+		else {
+			PortP->ID2			 = 0;
+			PortP->SecondBlock	 = FALSE;
+		}
+		PortP->RtaUniqueNum	= HostMapP->RtaUniqueNum;
+
+		/*
+		** If the port was already mapped then thats all we need to do.
+		*/
+		if (PortP->Mapped) {
+			rio_spin_unlock_irqrestore( &PortP->portSem, flags);
+			continue;
+		}
+		else HostMapP->Flags &= ~RTA_NEWBOOT;
+
+		PortP->State		 = 0;
+		PortP->Config		= 0;
+		/*
+		** Check out the module type - if it is special (read only etc.)
+		** then we need to set flags in the PortP->Config.
+		** Note: For 16 port RTA, all ports are of the same type.
+		*/
+		if (RtaType == TYPE_RTA16) {
+			PortP->Config |= p->RIOModuleTypes[HostP->UnixRups
+				[HostMapP->ID-1].ModTypes].Flags[SubEnt % PORTS_PER_MODULE];
+		} else {
+			if ( SubEnt < PORTS_PER_MODULE )
+				PortP->Config |= p->RIOModuleTypes[LONYBLE(HostP->UnixRups
+				[HostMapP->ID-1].ModTypes)].Flags[SubEnt % PORTS_PER_MODULE];
+			else
+				PortP->Config |= p->RIOModuleTypes[HINYBLE(HostP->UnixRups
+				[HostMapP->ID-1].ModTypes)].Flags[SubEnt % PORTS_PER_MODULE];
+		}
+
+		/*
+		** more port related flags
+		*/
+		PortP->PortState	= 0;
+		PortP->ModemLines	= 0;
+		PortP->ModemState	= 0;
+		PortP->CookMode		= COOK_WELL;
+		PortP->ParamSem		= 0;
+		PortP->FlushCmdBodge= 0;
+		PortP->WflushFlag	= 0;
+		PortP->MagicFlags	= 0;
+		PortP->Lock			= 0;
+		PortP->Store		= 0;
+		PortP->FirstOpen	= 1;
+
+		/*
+		** handle the xprint issues
+		*/
+#ifdef XPRINT_SUPPORT
+		PortP->Xprint.XpActive	= 0;
+		PortP->Xprint.XttyP = &riox_tty[SysPort];
+		/*				TO				FROM			MAXLEN */
+		RIOStrNCpy( PortP->Xprint.XpOn,	RIOConf.XpOn,	MAX_XP_CTRL_LEN );
+		RIOStrNCpy( PortP->Xprint.XpOff, RIOConf.XpOff, MAX_XP_CTRL_LEN );
+		PortP->Xprint.XpCps = RIOConf.XpCps;
+		PortP->Xprint.XpLen = RIOStrlen(PortP->Xprint.XpOn)+
+									RIOStrlen(PortP->Xprint.XpOff);
+#endif
+
+		/*
+		** Buffers 'n things
+		*/
+		PortP->RxDataStart	= 0;
+		PortP->Cor2Copy	 = 0;
+		PortP->Name		 = &HostMapP->Name[0];
+#ifdef STATS
+		bzero( (caddr_t)&PortP->Stat, sizeof(struct RIOStats) );
+#endif
+		PortP->statsGather = 0;
+		PortP->txchars = 0;
+		PortP->rxchars = 0;
+		PortP->opens = 0;
+		PortP->closes = 0;
+		PortP->ioctls = 0;
+		if ( PortP->TxRingBuffer )
+			bzero( PortP->TxRingBuffer, p->RIOBufferSize );
+		else if ( p->RIOBufferSize ) {
+			PortP->TxRingBuffer = sysbrk(p->RIOBufferSize);
+			bzero( PortP->TxRingBuffer, p->RIOBufferSize );
+		}
+		PortP->TxBufferOut	= 0;
+		PortP->TxBufferIn	 = 0;
+		PortP->Debug		= 0;
+		/*
+		** LastRxTgl stores the state of the rx toggle bit for this
+		** port, to be compared with the state of the next pkt received.
+		** If the same, we have received the same rx pkt from the RTA
+		** twice. Initialise to a value not equal to PHB_RX_TGL or 0.
+		*/
+		PortP->LastRxTgl	= ~(uchar)PHB_RX_TGL;
+
+		/*
+		** and mark the port as usable
+		*/
+		PortP->Mapped = 1;
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	}
+	if ( HostMapP->SysPort < p->RIOFirstPortsMapped )
+		p->RIOFirstPortsMapped = HostMapP->SysPort;
+	if ( HostMapP->SysPort > p->RIOLastPortsMapped )
+		p->RIOLastPortsMapped = HostMapP->SysPort;
+
+	return 0;
+}
+
+int
+RIOChangeName(p, MapP)
+struct rio_info *p;
+struct Map* MapP; 
+{
+	int host;
+	struct Map *HostMapP;
+	char *sptr;
+
+	rio_dprint(RIO_DEBUG_TABLE, ("Change name entry on host %x, rta %x, ID %d, Sysport %d\n",
+								MapP->HostUniqueNum,MapP->RtaUniqueNum,
+								MapP->ID, (int)MapP->SysPort ));
+
+	if ( MapP->ID > MAX_RUP ) {
+		rio_dprint(RIO_DEBUG_TABLE, ("Bad ID in map entry!\n"));
+		p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE;
+		return EINVAL;
+	}
+
+	MapP->Name[MAX_NAME_LEN-1] = '\0';
+	sptr = MapP->Name;
+
+	while ( *sptr ) {
+		if ( *sptr<' ' || *sptr>'~' ) {
+			rio_dprint(RIO_DEBUG_TABLE, ("Name entry contains non-printing characters!\n"));
+			p->RIOError.Error = BAD_CHARACTER_IN_NAME;
+			return EINVAL;
+		}
+		sptr++;
+	}
+
+	for ( host=0; host < p->RIONumHosts; host++ ) {
+		if ( MapP->HostUniqueNum == p->RIOHosts[host].UniqueNum ) {
+			if ( (p->RIOHosts[host].Flags & RUN_STATE) != RC_RUNNING ) {
+				p->RIOError.Error = HOST_NOT_RUNNING;
+				return ENXIO;
+			}
+			if ( MapP->ID==0 ) {
+				CCOPY( MapP->Name, p->RIOHosts[host].Name, MAX_NAME_LEN );
+				return 0;
+			}
+
+			HostMapP = &p->RIOHosts[host].Mapping[MapP->ID-1];
+
+			if ( HostMapP->RtaUniqueNum != MapP->RtaUniqueNum ) {
+				p->RIOError.Error = RTA_NUMBER_WRONG;
+				return ENXIO;
+			}
+			CCOPY( MapP->Name, HostMapP->Name, MAX_NAME_LEN );
+			return 0;
+		}
+	}
+	p->RIOError.Error = UNKNOWN_HOST_NUMBER;
+	rio_dprint(RIO_DEBUG_TABLE, ("Unknown host %x\n",MapP->HostUniqueNum));
+	return ENXIO;
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)