int RIOAssignRta(struct rio_info *p, struct Map *MapP) { int host; struct Map *HostMapP; char *sptr; int link; ; if ((MapP->ID != (u16) - 1) && ((int) MapP->ID < (int) 1 || (int) MapP->ID > MAX_RUP)) { ; p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE; return -EINVAL; } if (MapP->RtaUniqueNum == 0) { ; p->RIOError.Error = RTA_UNIQUE_NUMBER_ZERO; return -EINVAL; } if ((MapP->SysPort != NO_PORT) && (MapP->SysPort % PORTS_PER_RTA)) { ; p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE; return -EINVAL; } if ((MapP->SysPort != NO_PORT) && (MapP->SysPort >= RIO_PORTS)) { ; 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 > '~') { ; 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 entry does not already have one. */ if (MapP->ID == (u16) - 1) { int nNewID; ; /* ** 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 = (u16) nNewID + 1; ; 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; ; } } HostMapP = &p->RIOHosts[host].Mapping[MapP->ID - 1]; if (HostMapP->Flags & SLOT_IN_USE) { ; 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) memcpy(HostMapP->Name, MapP->Name, MAX_NAME_LEN); HostMapP->Flags = SLOT_IN_USE | RTA_BOOTED; #ifdef 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) ; else ; return 0; } } p->RIOError.Error = UNKNOWN_HOST_NUMBER; ; return -ENXIO; }
/* ** 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. */ 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 ) cprintf("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 TRUE; } /* ** Send the ID (entry) to this RTA. The ID number is implicit as ** the offset into the table. It is worth noting at this stage ** that offset zero in the table contains the entries for the ** RTA with ID 1!!!! */ PktReplyP->Command = ROUTE_ALLOCATE; PktReplyP->IDNum = ThisUnit+1; if (RtaType == TYPE_RTA16) { if (HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE) /* ** Adjust the phb and tx pkt dest_units for 2nd block of 8 ** only if the RTA has ports associated (SLOT_IN_USE) */ RIOFixPhbs(p, HostP, ThisUnit2); PktReplyP->IDNum2 = ThisUnit2+1; rio_dprintk (RIO_DEBUG_ROUTE, "RTA '%s' has been allocated IDs %d+%d\n", HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum, PktReplyP->IDNum2); } else { PktReplyP->IDNum2 = ROUTE_NO_ID; rio_dprintk (RIO_DEBUG_ROUTE, "RTA '%s' has been allocated ID %d\n", HostP->Mapping[ThisUnit].Name,PktReplyP->IDNum); } HostP->Copy("RT_ALLOCAT",PktReplyP->CommandText,10); RIOQueueCmdBlk( HostP, Rup, CmdBlkP); /* ** If this is a freshly booted RTA, then we need to re-open ** the ports, if any where open, so that data may once more ** flow around the system! */ if ( (HostP->Mapping[ThisUnit].Flags & RTA_NEWBOOT) && (HostP->Mapping[ThisUnit].SysPort != NO_PORT) ) { /* ** look at the ports associated with this beast and ** see if any where open. If they was, then re-open ** them, using the info from the tty flags. */ for ( port=0; port<PORTS_PER_RTA; port++ ) { PortP = p->RIOPortp[port+HostP->Mapping[ThisUnit].SysPort]; if ( PortP->State & (RIO_MOPEN|RIO_LOPEN) ) { rio_dprintk (RIO_DEBUG_ROUTE, "Re-opened this port\n"); rio_spin_lock_irqsave(&PortP->portSem, flags); PortP->MagicFlags |= MAGIC_REBOOT; rio_spin_unlock_irqrestore(&PortP->portSem, flags); } } if (RtaType == TYPE_RTA16) { for ( port=0; port<PORTS_PER_RTA; port++ ) { PortP = p->RIOPortp[port+HostP->Mapping[ThisUnit2].SysPort]; if ( PortP->State & (RIO_MOPEN|RIO_LOPEN) ) { rio_dprintk (RIO_DEBUG_ROUTE, "Re-opened this port\n"); rio_spin_lock_irqsave(&PortP->portSem, flags); PortP->MagicFlags |= MAGIC_REBOOT; rio_spin_unlock_irqrestore(&PortP->portSem, flags); } } } } /* ** keep a copy of the module types! */ HostP->UnixRups[ThisUnit].ModTypes = Mod; if (RtaType == TYPE_RTA16) HostP->UnixRups[ThisUnit2].ModTypes = Mod; /* ** If either of the modules on this unit is read-only or write-only ** or none-xprint, then we need to transfer that info over to the ** relevant ports. */ if ( HostP->Mapping[ThisUnit].SysPort != NO_PORT ) { for ( port=0; port<PORTS_PER_MODULE; port++ ) { p->RIOPortp[port+HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK; p->RIOPortp[port+HostP->Mapping[ThisUnit].SysPort]->Config |= p->RIOModuleTypes[Mod1].Flags[port]; p->RIOPortp[port+PORTS_PER_MODULE+HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK; p->RIOPortp[port+PORTS_PER_MODULE+HostP->Mapping[ThisUnit].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port]; } if (RtaType == TYPE_RTA16) { for ( port=0; port<PORTS_PER_MODULE; port++ ) { p->RIOPortp[port+HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK; p->RIOPortp[port+HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod1].Flags[port]; p->RIOPortp[port+PORTS_PER_MODULE+HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK; p->RIOPortp[port+PORTS_PER_MODULE+HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port]; } } } /* ** Job done, get on with the interrupts! */ return TRUE; } } /* ** There is no table entry for this RTA at all. ** ** Lets check to see if we actually booted this unit - if not, ** then we reset it and it will go round the loop of being booted ** we can then worry about trying to fit it into the table. */ for ( ThisUnit=0; ThisUnit<HostP->NumExtraBooted; ThisUnit++ ) if ( HostP->ExtraUnits[ThisUnit] == RtaUniq ) break; if ( ThisUnit == HostP->NumExtraBooted && ThisUnit != MAX_EXTRA_UNITS ) { /* ** if the unit wasn't in the table, and the table wasn't full, then ** we reset the unit, because we didn't boot it. ** However, if the table is full, it could be that we did boot ** this unit, and so we won't reboot it, because it isn't really ** all that disasterous to keep the old bins in most cases. This ** is a rather tacky feature, but we are on the edge of reallity ** here, because the implication is that someone has connected ** 16+MAX_EXTRA_UNITS onto one host. */ static int UnknownMesgDone = 0; if ( !UnknownMesgDone ) { if (! p->RIONoMessage) cprintf("One or more unknown RTAs are being updated.\n"); UnknownMesgDone = 1; } PktReplyP->Command = ROUTE_FOAD; HostP->Copy("RT_FOAD",PktReplyP->CommandText,7); } else { /* ** we did boot it (as an extra), and there may now be a table ** slot free (because of a delete), so we will try to make ** a tentative entry for it, so that the configurator can see it ** and fill in the details for us. */ if (RtaType == TYPE_RTA16) { if (RIOFindFreeID(p, HostP, &ThisUnit, &ThisUnit2) == 0) { RIODefaultName(p, HostP, ThisUnit); FillSlot(ThisUnit, ThisUnit2, RtaUniq, HostP); } } else { if (RIOFindFreeID(p, HostP, &ThisUnit, NULL) == 0) { RIODefaultName(p, HostP, ThisUnit); FillSlot(ThisUnit, 0, RtaUniq, HostP); } } PktReplyP->Command = ROUTE_USED; HostP->Copy("RT_USED",PktReplyP->CommandText,7); } RIOQueueCmdBlk( HostP, Rup, CmdBlkP); return TRUE; }
int RIORouteRup(struct rio_info *p, unsigned int Rup, struct Host *HostP, struct PKT __iomem * PacketP) { struct PktCmd __iomem *PktCmdP = (struct PktCmd __iomem *) 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; unsigned int OldUnit, NewUnit, OldLink, NewLink; char *MyType, *MyName; int Lies; unsigned long flags; if (readb(&PktCmdP->Command) == ROUTE_TOPOLOGY) { MapP = HostP->Mapping; 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 = 0; for (ThisLink = ThisLinkMin + 1; ThisLink <= ThisLinkMax; ThisLink++) { 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; } for (ThisLink = ThisLinkMin; ThisLink <= ThisLinkMax; ThisLink++) { OldUnit = TopP[ThisLink].Unit; OldLink = TopP[ThisLink].Link; NewUnit = readb(&PktCmdP->RouteTopology[ThisLink].Unit); NewLink = readb(&PktCmdP->RouteTopology[ThisLink].Link); if (OldUnit != NewUnit || OldLink != NewLink) { 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 { TopP[ThisLink].Unit = NewUnit; TopP[ThisLink].Link = NewLink; RIOSetChange(p); if (OldUnit <= MAX_RUP) { 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); } 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; } 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); 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) { 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 (!(CmdBlkP = RIOGetCmdBlk())) { rio_dprintk(RIO_DEBUG_ROUTE, "No command blocks to route RTA! come back later.\n"); return 0; } 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; memcpy(PktReplyP->CommandText, "RT_FOAD", 7); RIOQueueCmdBlk(HostP, Rup, CmdBlkP); return 1; } 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); 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 ((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; memcpy(PktReplyP->CommandText, "RT_FOAD", 7); RIOQueueCmdBlk(HostP, Rup, CmdBlkP); return 1; } PktReplyP->Command = ROUTE_ALLOCATE; PktReplyP->IDNum = ThisUnit + 1; if (RtaType == TYPE_RTA16) { if (HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE) RIOFixPhbs(p, HostP, ThisUnit2); PktReplyP->IDNum2 = ThisUnit2 + 1; rio_dprintk(RIO_DEBUG_ROUTE, "RTA '%s' has been allocated IDs %d+%d\n", HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum, PktReplyP->IDNum2); } else { PktReplyP->IDNum2 = ROUTE_NO_ID; rio_dprintk(RIO_DEBUG_ROUTE, "RTA '%s' has been allocated ID %d\n", HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum); } memcpy(PktReplyP->CommandText, "RT_ALLOCAT", 10); RIOQueueCmdBlk(HostP, Rup, CmdBlkP); if ((HostP->Mapping[ThisUnit].Flags & RTA_NEWBOOT) && (HostP->Mapping[ThisUnit].SysPort != NO_PORT)) { for (port = 0; port < PORTS_PER_RTA; port++) { PortP = p->RIOPortp[port + HostP->Mapping[ThisUnit].SysPort]; if (PortP->State & (RIO_MOPEN | RIO_LOPEN)) { rio_dprintk(RIO_DEBUG_ROUTE, "Re-opened this port\n"); rio_spin_lock_irqsave(&PortP->portSem, flags); PortP->MagicFlags |= MAGIC_REBOOT; rio_spin_unlock_irqrestore(&PortP->portSem, flags); } } if (RtaType == TYPE_RTA16) { for (port = 0; port < PORTS_PER_RTA; port++) { PortP = p->RIOPortp[port + HostP->Mapping[ThisUnit2].SysPort]; if (PortP->State & (RIO_MOPEN | RIO_LOPEN)) { rio_dprintk(RIO_DEBUG_ROUTE, "Re-opened this port\n"); rio_spin_lock_irqsave(&PortP->portSem, flags); PortP->MagicFlags |= MAGIC_REBOOT; rio_spin_unlock_irqrestore(&PortP->portSem, flags); } } } } HostP->UnixRups[ThisUnit].ModTypes = Mod; if (RtaType == TYPE_RTA16) HostP->UnixRups[ThisUnit2].ModTypes = Mod; if (HostP->Mapping[ThisUnit].SysPort != NO_PORT) { for (port = 0; port < PORTS_PER_MODULE; port++) { p->RIOPortp[port + HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK; p->RIOPortp[port + HostP->Mapping[ThisUnit].SysPort]->Config |= p->RIOModuleTypes[Mod1].Flags[port]; p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK; p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port]; } if (RtaType == TYPE_RTA16) { for (port = 0; port < PORTS_PER_MODULE; port++) { p->RIOPortp[port + HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK; p->RIOPortp[port + HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod1].Flags[port]; p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK; p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port]; } } } return 1; } } for (ThisUnit = 0; ThisUnit < HostP->NumExtraBooted; ThisUnit++) if (HostP->ExtraUnits[ThisUnit] == RtaUniq) break; if (ThisUnit == HostP->NumExtraBooted && ThisUnit != MAX_EXTRA_UNITS) { static int UnknownMesgDone = 0; if (!UnknownMesgDone) { if (!p->RIONoMessage) printk(KERN_DEBUG "rio: One or more unknown RTAs are being updated.\n"); UnknownMesgDone = 1; } PktReplyP->Command = ROUTE_FOAD; memcpy(PktReplyP->CommandText, "RT_FOAD", 7); } else { if (RtaType == TYPE_RTA16) { if (RIOFindFreeID(p, HostP, &ThisUnit, &ThisUnit2) == 0) { RIODefaultName(p, HostP, ThisUnit); rio_fill_host_slot(ThisUnit, ThisUnit2, RtaUniq, HostP); } } else { if (RIOFindFreeID(p, HostP, &ThisUnit, NULL) == 0) { RIODefaultName(p, HostP, ThisUnit); rio_fill_host_slot(ThisUnit, 0, RtaUniq, HostP); } } PktReplyP->Command = ROUTE_USED; memcpy(PktReplyP->CommandText, "RT_USED", 7); } RIOQueueCmdBlk(HostP, Rup, CmdBlkP); return 1; }