rioroute.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,045 行 · 第 1/3 页
C
1,045 行
/*** -----------------------------------------------------------------------------**** 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 "pkt.h"#include "daemon.h"#include "rio.h"#include "riospace.h"#include "cmdpkt.h"#include "map.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 "phb.h"#include "link.h"#include "cmdblk.h"#include "route.h"#include "cirrus.h"#include "rioioctl.h"#include "param.h"static int RIOCheckIsolated(struct rio_info *, struct Host *, unsigned int);static int RIOIsolate(struct rio_info *, struct Host *, unsigned int);static int RIOCheck(struct Host *, unsigned int);static void RIOConCon(struct rio_info *, struct Host *, unsigned int, unsigned int, unsigned int, unsigned int, int);/*** Incoming on the ROUTE_RUP** I wrote this while I was tired. Forgive me.*/int RIORouteRup(struct rio_info *p, unsigned int Rup, struct Host *HostP, struct 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; unsigned short RtaType; unsigned int RtaUniq; unsigned int ThisUnit, ThisUnit2; /* 2 ids to accommodate 16 port RTA */ unsigned int OldUnit, NewUnit, OldLink, NewLink; char *MyType, *MyName; int Lies; unsigned long flags; /* ** Is this unit telling us it's current link topology? */ if (readb(&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 >= (unsigned short) 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 (readb(&PktCmdP->RouteTopology[ThisLink].Unit) > (unsigned short) MAX_RUP) continue; for (NewLink = ThisLinkMin; NewLink < ThisLink; NewLink++) { if ((readb(&PktCmdP->RouteTopology[ThisLink].Unit) == readb(&PktCmdP->RouteTopology[NewLink].Unit)) && (readb(&PktCmdP->RouteTopology[ThisLink].Link) == readb(&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", readb(&PktCmdP->RouteTopology[0].Unit), 'A' + readb(&PktCmdP->RouteTopology[0].Link), readb(&PktCmdP->RouteTopology[1].Unit), 'A' + readb(&PktCmdP->RouteTopology[1].Link), readb(&PktCmdP->RouteTopology[2].Unit), 'A' + readb(&PktCmdP->RouteTopology[2].Link), readb(&PktCmdP->RouteTopology[3].Unit), 'A' + readb(&PktCmdP->RouteTopology[3].Link)); return 1; } /* ** 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 = readb(&PktCmdP->RouteTopology[ThisLink].Unit); NewLink = readb(&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) printk(KERN_DEBUG "rio: %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 1; } /* ** The only other command we recognise is a route_request command */ if (readb(&PktCmdP->Command) != ROUTE_REQUEST) { rio_dprintk(RIO_DEBUG_ROUTE, "Unknown command %d received on rup %d host %p ROUTE_RUP\n", readb(&PktCmdP->Command), Rup, HostP); return 1; } RtaUniq = (readb(&PktCmdP->UniqNum[0])) + (readb(&PktCmdP->UniqNum[1]) << 8) + (readb(&PktCmdP->UniqNum[2]) << 16) + (readb(&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 = readb(&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); } /* ** 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 1; } /* ** 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. */ if ((HostP->Mapping[ThisUnit].Flags & (SLOT_IN_USE | SLOT_TENTATIVE)) && (HostP->Mapping[ThisUnit].RtaUniqueNum == RtaUniq)) { if (RtaType == TYPE_RTA16) { ThisUnit2 = HostP->Mapping[ThisUnit].ID2 - 1; rio_dprintk(RIO_DEBUG_ROUTE, "Found unit 0x%x at slots %d+%d\n", RtaUniq, ThisUnit, ThisUnit2); } else rio_dprintk(RIO_DEBUG_ROUTE, "Found unit 0x%x at slot %d\n", RtaUniq, ThisUnit); /* ** If we have no knowledge of booting it, then the host has ** been re-booted, and so we must kill the RTA, so that it ** will be booted again (potentially with new bins) ** and it will then re-ask for an ID, which we will service. */ if ((HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE) && !(HostP->Mapping[ThisUnit].Flags & RTA_BOOTED)) { if (!(HostP->Mapping[ThisUnit].Flags & MSG_DONE)) { if (!p->RIONoMessage) printk(KERN_DEBUG "rio: RTA '%s' is being updated.\n", HostP->Mapping[ThisUnit].Name); HostP->Mapping[ThisUnit].Flags |= MSG_DONE; } PktReplyP->Command = ROUTE_FOAD; HostP->Copy("RT_FOAD", PktReplyP->CommandText, 7); RIOQueueCmdBlk(HostP, Rup, CmdBlkP); return 1; } /*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?