📄 rioroute.c
字号:
/*** -----------------------------------------------------------------------------**** 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 : rioroute.c** SID : 1.3** Last Modified : 11/6/98 10:33:46** Retrieved : 11/6/98 10:33:50**** ident @(#)rioroute.c 1.3**** -----------------------------------------------------------------------------*/#ifdef SCCS_LABELSstatic char *_rioroute_c_sccs_ = "@(#)rioroute.c 1.3";#endif#include <linux/module.h>#include <linux/slab.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/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"static int RIOCheckIsolated(struct rio_info *, struct Host *, uint);static int RIOIsolate(struct rio_info *, struct Host *, uint);static int RIOCheck(struct Host *, uint);static void RIOConCon(struct rio_info *, struct Host *, uint, uint, uint, uint, int);/*** Incoming on the ROUTE_RUP** I wrote this while I was tired. Forgive me.*/int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP ){ struct PktCmd *PktCmdP = (struct PktCmd *)PacketP->data; struct PktCmd_M *PktReplyP; struct CmdBlk *CmdBlkP; struct Port *PortP; struct Map *MapP; struct Top *TopP; int ThisLink, ThisLinkMin, ThisLinkMax; int port; int Mod, Mod1, Mod2; ushort RtaType; uint RtaUniq; uint ThisUnit, ThisUnit2; /* 2 ids to accommodate 16 port RTA */ uint OldUnit, NewUnit, OldLink, NewLink; char *MyType, *MyName; int Lies; unsigned long flags;#ifdef STACK RIOStackCheck("RIORouteRup");#endif#ifdef CHECK CheckPacketP(PacketP); CheckHostP(HostP); CheckRup(Rup); CheckHost(Host);#endif /* ** Is this unit telling us it's current link topology? */ if ( RBYTE(PktCmdP->Command) == ROUTE_TOPOLOGY ) { MapP = HostP->Mapping; /* ** The packet can be sent either by the host or by an RTA. ** If it comes from the host, then we need to fill in the ** Topology array in the host structure. If it came in ** from an RTA then we need to fill in the Mapping structure's ** Topology array for the unit. */ if ( Rup >= (ushort)MAX_RUP ) { ThisUnit = HOST_ID; TopP = HostP->Topology; MyType = "Host"; MyName = HostP->Name; ThisLinkMin = ThisLinkMax = Rup - MAX_RUP; } else { ThisUnit = Rup+1; TopP = HostP->Mapping[Rup].Topology; MyType = "RTA"; MyName = HostP->Mapping[Rup].Name; ThisLinkMin = 0; ThisLinkMax = LINKS_PER_UNIT - 1; } /* ** Lies will not be tolerated. ** If any pair of links claim to be connected to the same ** place, then ignore this packet completely. */ Lies = 0; for ( ThisLink=ThisLinkMin + 1; ThisLink <= ThisLinkMax; ThisLink++) { /* ** it won't lie about network interconnect, total disconnects ** and no-IDs. (or at least, it doesn't *matter* if it does) */ if ( RBYTE(PktCmdP->RouteTopology[ThisLink].Unit) > (ushort)MAX_RUP ) continue; for ( NewLink=ThisLinkMin; NewLink < ThisLink; NewLink++ ) { if ( (RBYTE(PktCmdP->RouteTopology[ThisLink].Unit) == RBYTE(PktCmdP->RouteTopology[NewLink].Unit)) && (RBYTE(PktCmdP->RouteTopology[ThisLink].Link) == RBYTE(PktCmdP->RouteTopology[NewLink].Link)) ) { Lies++; } } } if ( Lies ) { rio_dprintk (RIO_DEBUG_ROUTE, "LIES! DAMN LIES! %d LIES!\n",Lies); rio_dprintk (RIO_DEBUG_ROUTE, "%d:%c %d:%c %d:%c %d:%c\n", RBYTE(PktCmdP->RouteTopology[0].Unit), 'A'+RBYTE(PktCmdP->RouteTopology[0].Link), RBYTE(PktCmdP->RouteTopology[1].Unit), 'A'+RBYTE(PktCmdP->RouteTopology[1].Link), RBYTE(PktCmdP->RouteTopology[2].Unit), 'A'+RBYTE(PktCmdP->RouteTopology[2].Link), RBYTE(PktCmdP->RouteTopology[3].Unit), 'A'+RBYTE(PktCmdP->RouteTopology[3].Link)); return TRUE; } /* ** now, process each link. */ for ( ThisLink=ThisLinkMin; ThisLink <= ThisLinkMax; ThisLink++) { /* ** this is what it was connected to */ OldUnit = TopP[ThisLink].Unit; OldLink = TopP[ThisLink].Link; /* ** this is what it is now connected to */ NewUnit = RBYTE(PktCmdP->RouteTopology[ThisLink].Unit); NewLink = RBYTE(PktCmdP->RouteTopology[ThisLink].Link); if ( OldUnit != NewUnit || OldLink != NewLink ) { /* ** something has changed! */ if ( NewUnit > MAX_RUP && NewUnit != ROUTE_DISCONNECT && NewUnit != ROUTE_NO_ID && NewUnit != ROUTE_INTERCONNECT ) { rio_dprintk (RIO_DEBUG_ROUTE, "I have a link from %s %s to unit %d:%d - I don't like it.\n", MyType, MyName, NewUnit, NewLink); } else { /* ** put the new values in */ TopP[ThisLink].Unit = NewUnit; TopP[ThisLink].Link = NewLink; RIOSetChange(p); if ( OldUnit <= MAX_RUP ) { /* ** If something has become bust, then re-enable them messages */ if (! p->RIONoMessage) RIOConCon(p,HostP,ThisUnit,ThisLink,OldUnit,OldLink,DISCONNECT); } if ( ( NewUnit <= MAX_RUP ) && !p->RIONoMessage ) RIOConCon(p,HostP,ThisUnit,ThisLink,NewUnit,NewLink,CONNECT); if ( NewUnit == ROUTE_NO_ID ) rio_dprintk (RIO_DEBUG_ROUTE, "%s %s (%c) is connected to an unconfigured unit.\n", MyType,MyName,'A'+ThisLink); if ( NewUnit == ROUTE_INTERCONNECT ) { if (! p->RIONoMessage) cprintf("%s '%s' (%c) is connected to another network.\n", MyType,MyName,'A'+ThisLink); } /* ** perform an update for 'the other end', so that these messages ** only appears once. Only disconnect the other end if it is pointing ** at us! */ if ( OldUnit == HOST_ID ) { if ( HostP->Topology[OldLink].Unit == ThisUnit && HostP->Topology[OldLink].Link == ThisLink ) { rio_dprintk (RIO_DEBUG_ROUTE, "SETTING HOST (%c) TO DISCONNECTED!\n", OldLink+'A'); HostP->Topology[OldLink].Unit = ROUTE_DISCONNECT; HostP->Topology[OldLink].Link = NO_LINK; } else { rio_dprintk (RIO_DEBUG_ROUTE, "HOST(%c) WAS NOT CONNECTED TO %s (%c)!\n", OldLink+'A',HostP->Mapping[ThisUnit-1].Name,ThisLink+'A'); } } else if ( OldUnit <= MAX_RUP ) { if ( HostP->Mapping[OldUnit-1].Topology[OldLink].Unit == ThisUnit && HostP->Mapping[OldUnit-1].Topology[OldLink].Link == ThisLink ) { rio_dprintk (RIO_DEBUG_ROUTE, "SETTING RTA %s (%c) TO DISCONNECTED!\n", HostP->Mapping[OldUnit-1].Name,OldLink+'A'); HostP->Mapping[OldUnit-1].Topology[OldLink].Unit=ROUTE_DISCONNECT; HostP->Mapping[OldUnit-1].Topology[OldLink].Link=NO_LINK; } else { rio_dprintk (RIO_DEBUG_ROUTE, "RTA %s (%c) WAS NOT CONNECTED TO %s (%c)\n", HostP->Mapping[OldUnit-1].Name,OldLink+'A', HostP->Mapping[ThisUnit-1].Name,ThisLink+'A'); } } if ( NewUnit == HOST_ID ) { rio_dprintk (RIO_DEBUG_ROUTE, "MARKING HOST (%c) CONNECTED TO %s (%c)\n", NewLink+'A',MyName,ThisLink+'A'); HostP->Topology[NewLink].Unit = ThisUnit; HostP->Topology[NewLink].Link = ThisLink; } else if ( NewUnit <= MAX_RUP ) { rio_dprintk (RIO_DEBUG_ROUTE, "MARKING RTA %s (%c) CONNECTED TO %s (%c)\n", HostP->Mapping[NewUnit-1].Name,NewLink+'A',MyName,ThisLink+'A'); HostP->Mapping[NewUnit-1].Topology[NewLink].Unit=ThisUnit; HostP->Mapping[NewUnit-1].Topology[NewLink].Link=ThisLink; } } RIOSetChange(p); RIOCheckIsolated(p, HostP, OldUnit ); } } return TRUE; } /* ** The only other command we recognise is a route_request command */ if ( RBYTE(PktCmdP->Command) != ROUTE_REQUEST ) { rio_dprintk (RIO_DEBUG_ROUTE, "Unknown command %d received on rup %d host %d ROUTE_RUP\n", RBYTE(PktCmdP->Command),Rup,(int)HostP); return TRUE; } RtaUniq = (RBYTE(PktCmdP->UniqNum[0])) + (RBYTE(PktCmdP->UniqNum[1]) << 8) + (RBYTE(PktCmdP->UniqNum[2]) << 16) + (RBYTE(PktCmdP->UniqNum[3]) << 24); /* ** Determine if 8 or 16 port RTA */ RtaType = GetUnitType(RtaUniq); rio_dprintk (RIO_DEBUG_ROUTE, "Received a request for an ID for serial number %x\n", RtaUniq); Mod = RBYTE(PktCmdP->ModuleTypes); Mod1 = LONYBLE(Mod); if (RtaType == TYPE_RTA16) { /* ** Only one ident is set for a 16 port RTA. To make compatible ** with 8 port, set 2nd ident in Mod2 to the same as Mod1. */ Mod2 = Mod1; rio_dprintk (RIO_DEBUG_ROUTE, "Backplane type is %s (all ports)\n", p->RIOModuleTypes[Mod1].Name); } else { Mod2 = HINYBLE(Mod); rio_dprintk (RIO_DEBUG_ROUTE, "Module types are %s (ports 0-3) and %s (ports 4-7)\n", p->RIOModuleTypes[Mod1].Name, p->RIOModuleTypes[Mod2].Name); } if ( RtaUniq == 0xffffffff ) { ShowPacket( DBG_SPECIAL, PacketP ); } /* ** try to unhook a command block from the command free list. */ if ( !(CmdBlkP = RIOGetCmdBlk()) ) { rio_dprintk (RIO_DEBUG_ROUTE, "No command blocks to route RTA! come back later.\n"); return 0; } /* ** Fill in the default info on the command block */ CmdBlkP->Packet.dest_unit = Rup; CmdBlkP->Packet.dest_port = ROUTE_RUP; CmdBlkP->Packet.src_unit = HOST_ID; CmdBlkP->Packet.src_port = ROUTE_RUP; CmdBlkP->Packet.len = PKT_CMD_BIT | 1; CmdBlkP->PreFuncP = CmdBlkP->PostFuncP = NULL; PktReplyP = (struct PktCmd_M *)CmdBlkP->Packet.data; if (! RIOBootOk(p, HostP, RtaUniq)) { rio_dprintk (RIO_DEBUG_ROUTE, "RTA %x tried to get an ID, but does not belong - FOAD it!\n", RtaUniq); PktReplyP->Command = ROUTE_FOAD; HostP->Copy("RT_FOAD", PktReplyP->CommandText, 7); RIOQueueCmdBlk(HostP, Rup, CmdBlkP); return TRUE; } /* ** Check to see if the RTA is configured for this host */ for ( ThisUnit=0; ThisUnit<MAX_RUP; ThisUnit++ ) { rio_dprintk (RIO_DEBUG_ROUTE, "Entry %d Flags=%s %s UniqueNum=0x%x\n", ThisUnit, HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE ? "Slot-In-Use":"Not In Use", HostP->Mapping[ThisUnit].Flags & SLOT_TENTATIVE ? "Slot-Tentative":"Not Tentative", HostP->Mapping[ThisUnit].RtaUniqueNum); /* ** We have an entry for it.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -