Showing error 1789

User: Jiri Slaby
Error type: Invalid Pointer Dereference
Error type description: A pointer which is invalid is being dereferenced
File location: drivers/char/rio/rioroute.c
Line in file: 930
Project: Linux Kernel
Project version: 2.6.28
Tools: Smatch (1.59)
Entered: 2013-09-11 08:47:26 UTC


Source:

   1/*
   2** -----------------------------------------------------------------------------
   3**
   4**  Perle Specialix driver for Linux
   5**  Ported from existing RIO Driver for SCO sources.
   6 *
   7 *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
   8 *
   9 *      This program is free software; you can redistribute it and/or modify
  10 *      it under the terms of the GNU General Public License as published by
  11 *      the Free Software Foundation; either version 2 of the License, or
  12 *      (at your option) any later version.
  13 *
  14 *      This program is distributed in the hope that it will be useful,
  15 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 *      GNU General Public License for more details.
  18 *
  19 *      You should have received a copy of the GNU General Public License
  20 *      along with this program; if not, write to the Free Software
  21 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22**
  23**        Module                : rioroute.c
  24**        SID                : 1.3
  25**        Last Modified        : 11/6/98 10:33:46
  26**        Retrieved        : 11/6/98 10:33:50
  27**
  28**  ident @(#)rioroute.c        1.3
  29**
  30** -----------------------------------------------------------------------------
  31*/
  32
  33#include <linux/module.h>
  34#include <linux/slab.h>
  35#include <linux/errno.h>
  36#include <asm/io.h>
  37#include <asm/system.h>
  38#include <asm/string.h>
  39#include <asm/uaccess.h>
  40
  41#include <linux/termios.h>
  42#include <linux/serial.h>
  43
  44#include <linux/generic_serial.h>
  45
  46
  47#include "linux_compat.h"
  48#include "rio_linux.h"
  49#include "pkt.h"
  50#include "daemon.h"
  51#include "rio.h"
  52#include "riospace.h"
  53#include "cmdpkt.h"
  54#include "map.h"
  55#include "rup.h"
  56#include "port.h"
  57#include "riodrvr.h"
  58#include "rioinfo.h"
  59#include "func.h"
  60#include "errors.h"
  61#include "pci.h"
  62
  63#include "parmmap.h"
  64#include "unixrup.h"
  65#include "board.h"
  66#include "host.h"
  67#include "phb.h"
  68#include "link.h"
  69#include "cmdblk.h"
  70#include "route.h"
  71#include "cirrus.h"
  72#include "rioioctl.h"
  73#include "param.h"
  74
  75static int RIOCheckIsolated(struct rio_info *, struct Host *, unsigned int);
  76static int RIOIsolate(struct rio_info *, struct Host *, unsigned int);
  77static int RIOCheck(struct Host *, unsigned int);
  78static void RIOConCon(struct rio_info *, struct Host *, unsigned int, unsigned int, unsigned int, unsigned int, int);
  79
  80
  81/*
  82** Incoming on the ROUTE_RUP
  83** I wrote this while I was tired. Forgive me.
  84*/
  85int RIORouteRup(struct rio_info *p, unsigned int Rup, struct Host *HostP, struct PKT __iomem * PacketP)
  86{
  87        struct PktCmd __iomem *PktCmdP = (struct PktCmd __iomem *) PacketP->data;
  88        struct PktCmd_M *PktReplyP;
  89        struct CmdBlk *CmdBlkP;
  90        struct Port *PortP;
  91        struct Map *MapP;
  92        struct Top *TopP;
  93        int ThisLink, ThisLinkMin, ThisLinkMax;
  94        int port;
  95        int Mod, Mod1, Mod2;
  96        unsigned short RtaType;
  97        unsigned int RtaUniq;
  98        unsigned int ThisUnit, ThisUnit2;        /* 2 ids to accommodate 16 port RTA */
  99        unsigned int OldUnit, NewUnit, OldLink, NewLink;
 100        char *MyType, *MyName;
 101        int Lies;
 102        unsigned long flags;
 103
 104        /*
 105         ** Is this unit telling us it's current link topology?
 106         */
 107        if (readb(&PktCmdP->Command) == ROUTE_TOPOLOGY) {
 108                MapP = HostP->Mapping;
 109
 110                /*
 111                 ** The packet can be sent either by the host or by an RTA.
 112                 ** If it comes from the host, then we need to fill in the
 113                 ** Topology array in the host structure. If it came in
 114                 ** from an RTA then we need to fill in the Mapping structure's
 115                 ** Topology array for the unit.
 116                 */
 117                if (Rup >= (unsigned short) MAX_RUP) {
 118                        ThisUnit = HOST_ID;
 119                        TopP = HostP->Topology;
 120                        MyType = "Host";
 121                        MyName = HostP->Name;
 122                        ThisLinkMin = ThisLinkMax = Rup - MAX_RUP;
 123                } else {
 124                        ThisUnit = Rup + 1;
 125                        TopP = HostP->Mapping[Rup].Topology;
 126                        MyType = "RTA";
 127                        MyName = HostP->Mapping[Rup].Name;
 128                        ThisLinkMin = 0;
 129                        ThisLinkMax = LINKS_PER_UNIT - 1;
 130                }
 131
 132                /*
 133                 ** Lies will not be tolerated.
 134                 ** If any pair of links claim to be connected to the same
 135                 ** place, then ignore this packet completely.
 136                 */
 137                Lies = 0;
 138                for (ThisLink = ThisLinkMin + 1; ThisLink <= ThisLinkMax; ThisLink++) {
 139                        /*
 140                         ** it won't lie about network interconnect, total disconnects
 141                         ** and no-IDs. (or at least, it doesn't *matter* if it does)
 142                         */
 143                        if (readb(&PktCmdP->RouteTopology[ThisLink].Unit) > (unsigned short) MAX_RUP)
 144                                continue;
 145
 146                        for (NewLink = ThisLinkMin; NewLink < ThisLink; NewLink++) {
 147                                if ((readb(&PktCmdP->RouteTopology[ThisLink].Unit) == readb(&PktCmdP->RouteTopology[NewLink].Unit)) && (readb(&PktCmdP->RouteTopology[ThisLink].Link) == readb(&PktCmdP->RouteTopology[NewLink].Link))) {
 148                                        Lies++;
 149                                }
 150                        }
 151                }
 152
 153                if (Lies) {
 154                        rio_dprintk(RIO_DEBUG_ROUTE, "LIES! DAMN LIES! %d LIES!\n", Lies);
 155                        rio_dprintk(RIO_DEBUG_ROUTE, "%d:%c %d:%c %d:%c %d:%c\n",
 156                                    readb(&PktCmdP->RouteTopology[0].Unit),
 157                                    'A' + readb(&PktCmdP->RouteTopology[0].Link),
 158                                    readb(&PktCmdP->RouteTopology[1].Unit),
 159                                    '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));
 160                        return 1;
 161                }
 162
 163                /*
 164                 ** now, process each link.
 165                 */
 166                for (ThisLink = ThisLinkMin; ThisLink <= ThisLinkMax; ThisLink++) {
 167                        /*
 168                         ** this is what it was connected to
 169                         */
 170                        OldUnit = TopP[ThisLink].Unit;
 171                        OldLink = TopP[ThisLink].Link;
 172
 173                        /*
 174                         ** this is what it is now connected to
 175                         */
 176                        NewUnit = readb(&PktCmdP->RouteTopology[ThisLink].Unit);
 177                        NewLink = readb(&PktCmdP->RouteTopology[ThisLink].Link);
 178
 179                        if (OldUnit != NewUnit || OldLink != NewLink) {
 180                                /*
 181                                 ** something has changed!
 182                                 */
 183
 184                                if (NewUnit > MAX_RUP && NewUnit != ROUTE_DISCONNECT && NewUnit != ROUTE_NO_ID && NewUnit != ROUTE_INTERCONNECT) {
 185                                        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);
 186                                } else {
 187                                        /*
 188                                         ** put the new values in
 189                                         */
 190                                        TopP[ThisLink].Unit = NewUnit;
 191                                        TopP[ThisLink].Link = NewLink;
 192
 193                                        RIOSetChange(p);
 194
 195                                        if (OldUnit <= MAX_RUP) {
 196                                                /*
 197                                                 ** If something has become bust, then re-enable them messages
 198                                                 */
 199                                                if (!p->RIONoMessage)
 200                                                        RIOConCon(p, HostP, ThisUnit, ThisLink, OldUnit, OldLink, DISCONNECT);
 201                                        }
 202
 203                                        if ((NewUnit <= MAX_RUP) && !p->RIONoMessage)
 204                                                RIOConCon(p, HostP, ThisUnit, ThisLink, NewUnit, NewLink, CONNECT);
 205
 206                                        if (NewUnit == ROUTE_NO_ID)
 207                                                rio_dprintk(RIO_DEBUG_ROUTE, "%s %s (%c) is connected to an unconfigured unit.\n", MyType, MyName, 'A' + ThisLink);
 208
 209                                        if (NewUnit == ROUTE_INTERCONNECT) {
 210                                                if (!p->RIONoMessage)
 211                                                        printk(KERN_DEBUG "rio: %s '%s' (%c) is connected to another network.\n", MyType, MyName, 'A' + ThisLink);
 212                                        }
 213
 214                                        /*
 215                                         ** perform an update for 'the other end', so that these messages
 216                                         ** only appears once. Only disconnect the other end if it is pointing
 217                                         ** at us!
 218                                         */
 219                                        if (OldUnit == HOST_ID) {
 220                                                if (HostP->Topology[OldLink].Unit == ThisUnit && HostP->Topology[OldLink].Link == ThisLink) {
 221                                                        rio_dprintk(RIO_DEBUG_ROUTE, "SETTING HOST (%c) TO DISCONNECTED!\n", OldLink + 'A');
 222                                                        HostP->Topology[OldLink].Unit = ROUTE_DISCONNECT;
 223                                                        HostP->Topology[OldLink].Link = NO_LINK;
 224                                                } else {
 225                                                        rio_dprintk(RIO_DEBUG_ROUTE, "HOST(%c) WAS NOT CONNECTED TO %s (%c)!\n", OldLink + 'A', HostP->Mapping[ThisUnit - 1].Name, ThisLink + 'A');
 226                                                }
 227                                        } else if (OldUnit <= MAX_RUP) {
 228                                                if (HostP->Mapping[OldUnit - 1].Topology[OldLink].Unit == ThisUnit && HostP->Mapping[OldUnit - 1].Topology[OldLink].Link == ThisLink) {
 229                                                        rio_dprintk(RIO_DEBUG_ROUTE, "SETTING RTA %s (%c) TO DISCONNECTED!\n", HostP->Mapping[OldUnit - 1].Name, OldLink + 'A');
 230                                                        HostP->Mapping[OldUnit - 1].Topology[OldLink].Unit = ROUTE_DISCONNECT;
 231                                                        HostP->Mapping[OldUnit - 1].Topology[OldLink].Link = NO_LINK;
 232                                                } else {
 233                                                        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');
 234                                                }
 235                                        }
 236                                        if (NewUnit == HOST_ID) {
 237                                                rio_dprintk(RIO_DEBUG_ROUTE, "MARKING HOST (%c) CONNECTED TO %s (%c)\n", NewLink + 'A', MyName, ThisLink + 'A');
 238                                                HostP->Topology[NewLink].Unit = ThisUnit;
 239                                                HostP->Topology[NewLink].Link = ThisLink;
 240                                        } else if (NewUnit <= MAX_RUP) {
 241                                                rio_dprintk(RIO_DEBUG_ROUTE, "MARKING RTA %s (%c) CONNECTED TO %s (%c)\n", HostP->Mapping[NewUnit - 1].Name, NewLink + 'A', MyName, ThisLink + 'A');
 242                                                HostP->Mapping[NewUnit - 1].Topology[NewLink].Unit = ThisUnit;
 243                                                HostP->Mapping[NewUnit - 1].Topology[NewLink].Link = ThisLink;
 244                                        }
 245                                }
 246                                RIOSetChange(p);
 247                                RIOCheckIsolated(p, HostP, OldUnit);
 248                        }
 249                }
 250                return 1;
 251        }
 252
 253        /*
 254         ** The only other command we recognise is a route_request command
 255         */
 256        if (readb(&PktCmdP->Command) != ROUTE_REQUEST) {
 257                rio_dprintk(RIO_DEBUG_ROUTE, "Unknown command %d received on rup %d host %p ROUTE_RUP\n", readb(&PktCmdP->Command), Rup, HostP);
 258                return 1;
 259        }
 260
 261        RtaUniq = (readb(&PktCmdP->UniqNum[0])) + (readb(&PktCmdP->UniqNum[1]) << 8) + (readb(&PktCmdP->UniqNum[2]) << 16) + (readb(&PktCmdP->UniqNum[3]) << 24);
 262
 263        /*
 264         ** Determine if 8 or 16 port RTA
 265         */
 266        RtaType = GetUnitType(RtaUniq);
 267
 268        rio_dprintk(RIO_DEBUG_ROUTE, "Received a request for an ID for serial number %x\n", RtaUniq);
 269
 270        Mod = readb(&PktCmdP->ModuleTypes);
 271        Mod1 = LONYBLE(Mod);
 272        if (RtaType == TYPE_RTA16) {
 273                /*
 274                 ** Only one ident is set for a 16 port RTA. To make compatible
 275                 ** with 8 port, set 2nd ident in Mod2 to the same as Mod1.
 276                 */
 277                Mod2 = Mod1;
 278                rio_dprintk(RIO_DEBUG_ROUTE, "Backplane type is %s (all ports)\n", p->RIOModuleTypes[Mod1].Name);
 279        } else {
 280                Mod2 = HINYBLE(Mod);
 281                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);
 282        }
 283
 284        /*
 285         ** try to unhook a command block from the command free list.
 286         */
 287        if (!(CmdBlkP = RIOGetCmdBlk())) {
 288                rio_dprintk(RIO_DEBUG_ROUTE, "No command blocks to route RTA! come back later.\n");
 289                return 0;
 290        }
 291
 292        /*
 293         ** Fill in the default info on the command block
 294         */
 295        CmdBlkP->Packet.dest_unit = Rup;
 296        CmdBlkP->Packet.dest_port = ROUTE_RUP;
 297        CmdBlkP->Packet.src_unit = HOST_ID;
 298        CmdBlkP->Packet.src_port = ROUTE_RUP;
 299        CmdBlkP->Packet.len = PKT_CMD_BIT | 1;
 300        CmdBlkP->PreFuncP = CmdBlkP->PostFuncP = NULL;
 301        PktReplyP = (struct PktCmd_M *) CmdBlkP->Packet.data;
 302
 303        if (!RIOBootOk(p, HostP, RtaUniq)) {
 304                rio_dprintk(RIO_DEBUG_ROUTE, "RTA %x tried to get an ID, but does not belong - FOAD it!\n", RtaUniq);
 305                PktReplyP->Command = ROUTE_FOAD;
 306                memcpy(PktReplyP->CommandText, "RT_FOAD", 7);
 307                RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
 308                return 1;
 309        }
 310
 311        /*
 312         ** Check to see if the RTA is configured for this host
 313         */
 314        for (ThisUnit = 0; ThisUnit < MAX_RUP; ThisUnit++) {
 315                rio_dprintk(RIO_DEBUG_ROUTE, "Entry %d Flags=%s %s UniqueNum=0x%x\n",
 316                            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);
 317
 318                /*
 319                 ** We have an entry for it.
 320                 */
 321                if ((HostP->Mapping[ThisUnit].Flags & (SLOT_IN_USE | SLOT_TENTATIVE)) && (HostP->Mapping[ThisUnit].RtaUniqueNum == RtaUniq)) {
 322                        if (RtaType == TYPE_RTA16) {
 323                                ThisUnit2 = HostP->Mapping[ThisUnit].ID2 - 1;
 324                                rio_dprintk(RIO_DEBUG_ROUTE, "Found unit 0x%x at slots %d+%d\n", RtaUniq, ThisUnit, ThisUnit2);
 325                        } else
 326                                rio_dprintk(RIO_DEBUG_ROUTE, "Found unit 0x%x at slot %d\n", RtaUniq, ThisUnit);
 327                        /*
 328                         ** If we have no knowledge of booting it, then the host has
 329                         ** been re-booted, and so we must kill the RTA, so that it
 330                         ** will be booted again (potentially with new bins)
 331                         ** and it will then re-ask for an ID, which we will service.
 332                         */
 333                        if ((HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE) && !(HostP->Mapping[ThisUnit].Flags & RTA_BOOTED)) {
 334                                if (!(HostP->Mapping[ThisUnit].Flags & MSG_DONE)) {
 335                                        if (!p->RIONoMessage)
 336                                                printk(KERN_DEBUG "rio: RTA '%s' is being updated.\n", HostP->Mapping[ThisUnit].Name);
 337                                        HostP->Mapping[ThisUnit].Flags |= MSG_DONE;
 338                                }
 339                                PktReplyP->Command = ROUTE_FOAD;
 340                                memcpy(PktReplyP->CommandText, "RT_FOAD", 7);
 341                                RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
 342                                return 1;
 343                        }
 344
 345                        /*
 346                         ** Send the ID (entry) to this RTA. The ID number is implicit as
 347                         ** the offset into the table. It is worth noting at this stage
 348                         ** that offset zero in the table contains the entries for the
 349                         ** RTA with ID 1!!!!
 350                         */
 351                        PktReplyP->Command = ROUTE_ALLOCATE;
 352                        PktReplyP->IDNum = ThisUnit + 1;
 353                        if (RtaType == TYPE_RTA16) {
 354                                if (HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE)
 355                                        /*
 356                                         ** Adjust the phb and tx pkt dest_units for 2nd block of 8
 357                                         ** only if the RTA has ports associated (SLOT_IN_USE)
 358                                         */
 359                                        RIOFixPhbs(p, HostP, ThisUnit2);
 360                                PktReplyP->IDNum2 = ThisUnit2 + 1;
 361                                rio_dprintk(RIO_DEBUG_ROUTE, "RTA '%s' has been allocated IDs %d+%d\n", HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum, PktReplyP->IDNum2);
 362                        } else {
 363                                PktReplyP->IDNum2 = ROUTE_NO_ID;
 364                                rio_dprintk(RIO_DEBUG_ROUTE, "RTA '%s' has been allocated ID %d\n", HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum);
 365                        }
 366                        memcpy(PktReplyP->CommandText, "RT_ALLOCAT", 10);
 367
 368                        RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
 369
 370                        /*
 371                         ** If this is a freshly booted RTA, then we need to re-open
 372                         ** the ports, if any where open, so that data may once more
 373                         ** flow around the system!
 374                         */
 375                        if ((HostP->Mapping[ThisUnit].Flags & RTA_NEWBOOT) && (HostP->Mapping[ThisUnit].SysPort != NO_PORT)) {
 376                                /*
 377                                 ** look at the ports associated with this beast and
 378                                 ** see if any where open. If they was, then re-open
 379                                 ** them, using the info from the tty flags.
 380                                 */
 381                                for (port = 0; port < PORTS_PER_RTA; port++) {
 382                                        PortP = p->RIOPortp[port + HostP->Mapping[ThisUnit].SysPort];
 383                                        if (PortP->State & (RIO_MOPEN | RIO_LOPEN)) {
 384                                                rio_dprintk(RIO_DEBUG_ROUTE, "Re-opened this port\n");
 385                                                rio_spin_lock_irqsave(&PortP->portSem, flags);
 386                                                PortP->MagicFlags |= MAGIC_REBOOT;
 387                                                rio_spin_unlock_irqrestore(&PortP->portSem, flags);
 388                                        }
 389                                }
 390                                if (RtaType == TYPE_RTA16) {
 391                                        for (port = 0; port < PORTS_PER_RTA; port++) {
 392                                                PortP = p->RIOPortp[port + HostP->Mapping[ThisUnit2].SysPort];
 393                                                if (PortP->State & (RIO_MOPEN | RIO_LOPEN)) {
 394                                                        rio_dprintk(RIO_DEBUG_ROUTE, "Re-opened this port\n");
 395                                                        rio_spin_lock_irqsave(&PortP->portSem, flags);
 396                                                        PortP->MagicFlags |= MAGIC_REBOOT;
 397                                                        rio_spin_unlock_irqrestore(&PortP->portSem, flags);
 398                                                }
 399                                        }
 400                                }
 401                        }
 402
 403                        /*
 404                         ** keep a copy of the module types!
 405                         */
 406                        HostP->UnixRups[ThisUnit].ModTypes = Mod;
 407                        if (RtaType == TYPE_RTA16)
 408                                HostP->UnixRups[ThisUnit2].ModTypes = Mod;
 409
 410                        /*
 411                         ** If either of the modules on this unit is read-only or write-only
 412                         ** or none-xprint, then we need to transfer that info over to the
 413                         ** relevant ports.
 414                         */
 415                        if (HostP->Mapping[ThisUnit].SysPort != NO_PORT) {
 416                                for (port = 0; port < PORTS_PER_MODULE; port++) {
 417                                        p->RIOPortp[port + HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK;
 418                                        p->RIOPortp[port + HostP->Mapping[ThisUnit].SysPort]->Config |= p->RIOModuleTypes[Mod1].Flags[port];
 419                                        p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK;
 420                                        p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port];
 421                                }
 422                                if (RtaType == TYPE_RTA16) {
 423                                        for (port = 0; port < PORTS_PER_MODULE; port++) {
 424                                                p->RIOPortp[port + HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK;
 425                                                p->RIOPortp[port + HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod1].Flags[port];
 426                                                p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK;
 427                                                p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port];
 428                                        }
 429                                }
 430                        }
 431
 432                        /*
 433                         ** Job done, get on with the interrupts!
 434                         */
 435                        return 1;
 436                }
 437        }
 438        /*
 439         ** There is no table entry for this RTA at all.
 440         **
 441         ** Lets check to see if we actually booted this unit - if not,
 442         ** then we reset it and it will go round the loop of being booted
 443         ** we can then worry about trying to fit it into the table.
 444         */
 445        for (ThisUnit = 0; ThisUnit < HostP->NumExtraBooted; ThisUnit++)
 446                if (HostP->ExtraUnits[ThisUnit] == RtaUniq)
 447                        break;
 448        if (ThisUnit == HostP->NumExtraBooted && ThisUnit != MAX_EXTRA_UNITS) {
 449                /*
 450                 ** if the unit wasn't in the table, and the table wasn't full, then
 451                 ** we reset the unit, because we didn't boot it.
 452                 ** However, if the table is full, it could be that we did boot
 453                 ** this unit, and so we won't reboot it, because it isn't really
 454                 ** all that disasterous to keep the old bins in most cases. This
 455                 ** is a rather tacky feature, but we are on the edge of reallity
 456                 ** here, because the implication is that someone has connected
 457                 ** 16+MAX_EXTRA_UNITS onto one host.
 458                 */
 459                static int UnknownMesgDone = 0;
 460
 461                if (!UnknownMesgDone) {
 462                        if (!p->RIONoMessage)
 463                                printk(KERN_DEBUG "rio: One or more unknown RTAs are being updated.\n");
 464                        UnknownMesgDone = 1;
 465                }
 466
 467                PktReplyP->Command = ROUTE_FOAD;
 468                memcpy(PktReplyP->CommandText, "RT_FOAD", 7);
 469        } else {
 470                /*
 471                 ** we did boot it (as an extra), and there may now be a table
 472                 ** slot free (because of a delete), so we will try to make
 473                 ** a tentative entry for it, so that the configurator can see it
 474                 ** and fill in the details for us.
 475                 */
 476                if (RtaType == TYPE_RTA16) {
 477                        if (RIOFindFreeID(p, HostP, &ThisUnit, &ThisUnit2) == 0) {
 478                                RIODefaultName(p, HostP, ThisUnit);
 479                                rio_fill_host_slot(ThisUnit, ThisUnit2, RtaUniq, HostP);
 480                        }
 481                } else {
 482                        if (RIOFindFreeID(p, HostP, &ThisUnit, NULL) == 0) {
 483                                RIODefaultName(p, HostP, ThisUnit);
 484                                rio_fill_host_slot(ThisUnit, 0, RtaUniq, HostP);
 485                        }
 486                }
 487                PktReplyP->Command = ROUTE_USED;
 488                memcpy(PktReplyP->CommandText, "RT_USED", 7);
 489        }
 490        RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
 491        return 1;
 492}
 493
 494
 495void RIOFixPhbs(struct rio_info *p, struct Host *HostP, unsigned int unit)
 496{
 497        unsigned short link, port;
 498        struct Port *PortP;
 499        unsigned long flags;
 500        int PortN = HostP->Mapping[unit].SysPort;
 501
 502        rio_dprintk(RIO_DEBUG_ROUTE, "RIOFixPhbs unit %d sysport %d\n", unit, PortN);
 503
 504        if (PortN != -1) {
 505                unsigned short dest_unit = HostP->Mapping[unit].ID2;
 506
 507                /*
 508                 ** Get the link number used for the 1st 8 phbs on this unit.
 509                 */
 510                PortP = p->RIOPortp[HostP->Mapping[dest_unit - 1].SysPort];
 511
 512                link = readw(&PortP->PhbP->link);
 513
 514                for (port = 0; port < PORTS_PER_RTA; port++, PortN++) {
 515                        unsigned short dest_port = port + 8;
 516                        u16 __iomem *TxPktP;
 517                        struct PKT __iomem *Pkt;
 518
 519                        PortP = p->RIOPortp[PortN];
 520
 521                        rio_spin_lock_irqsave(&PortP->portSem, flags);
 522                        /*
 523                         ** If RTA is not powered on, the tx packets will be
 524                         ** unset, so go no further.
 525                         */
 526                        if (!PortP->TxStart) {
 527                                rio_dprintk(RIO_DEBUG_ROUTE, "Tx pkts not set up yet\n");
 528                                rio_spin_unlock_irqrestore(&PortP->portSem, flags);
 529                                break;
 530                        }
 531
 532                        /*
 533                         ** For the second slot of a 16 port RTA, the driver needs to
 534                         ** sort out the phb to port mappings. The dest_unit for this
 535                         ** group of 8 phbs is set to the dest_unit of the accompanying
 536                         ** 8 port block. The dest_port of the second unit is set to
 537                         ** be in the range 8-15 (i.e. 8 is added). Thus, for a 16 port
 538                         ** RTA with IDs 5 and 6, traffic bound for port 6 of unit 6
 539                         ** (being the second map ID) will be sent to dest_unit 5, port
 540                         ** 14. When this RTA is deleted, dest_unit for ID 6 will be
 541                         ** restored, and the dest_port will be reduced by 8.
 542                         ** Transmit packets also have a destination field which needs
 543                         ** adjusting in the same manner.
 544                         ** Note that the unit/port bytes in 'dest' are swapped.
 545                         ** We also need to adjust the phb and rup link numbers for the
 546                         ** second block of 8 ttys.
 547                         */
 548                        for (TxPktP = PortP->TxStart; TxPktP <= PortP->TxEnd; TxPktP++) {
 549                                /*
 550                                 ** *TxPktP is the pointer to the transmit packet on the host
 551                                 ** card. This needs to be translated into a 32 bit pointer
 552                                 ** so it can be accessed from the driver.
 553                                 */
 554                                Pkt = (struct PKT __iomem *) RIO_PTR(HostP->Caddr, readw(TxPktP));
 555
 556                                /*
 557                                 ** If the packet is used, reset it.
 558                                 */
 559                                Pkt = (struct PKT __iomem *) ((unsigned long) Pkt & ~PKT_IN_USE);
 560                                writeb(dest_unit, &Pkt->dest_unit);
 561                                writeb(dest_port, &Pkt->dest_port);
 562                        }
 563                        rio_dprintk(RIO_DEBUG_ROUTE, "phb dest: Old %x:%x New %x:%x\n", readw(&PortP->PhbP->destination) & 0xff, (readw(&PortP->PhbP->destination) >> 8) & 0xff, dest_unit, dest_port);
 564                        writew(dest_unit + (dest_port << 8), &PortP->PhbP->destination);
 565                        writew(link, &PortP->PhbP->link);
 566
 567                        rio_spin_unlock_irqrestore(&PortP->portSem, flags);
 568                }
 569                /*
 570                 ** Now make sure the range of ports to be serviced includes
 571                 ** the 2nd 8 on this 16 port RTA.
 572                 */
 573                if (link > 3)
 574                        return;
 575                if (((unit * 8) + 7) > readw(&HostP->LinkStrP[link].last_port)) {
 576                        rio_dprintk(RIO_DEBUG_ROUTE, "last port on host link %d: %d\n", link, (unit * 8) + 7);
 577                        writew((unit * 8) + 7, &HostP->LinkStrP[link].last_port);
 578                }
 579        }
 580}
 581
 582/*
 583** Check to see if the new disconnection has isolated this unit.
 584** If it has, then invalidate all its link information, and tell
 585** the world about it. This is done to ensure that the configurator
 586** only gets up-to-date information about what is going on.
 587*/
 588static int RIOCheckIsolated(struct rio_info *p, struct Host *HostP, unsigned int UnitId)
 589{
 590        unsigned long flags;
 591        rio_spin_lock_irqsave(&HostP->HostLock, flags);
 592
 593        if (RIOCheck(HostP, UnitId)) {
 594                rio_dprintk(RIO_DEBUG_ROUTE, "Unit %d is NOT isolated\n", UnitId);
 595                rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
 596                return (0);
 597        }
 598
 599        RIOIsolate(p, HostP, UnitId);
 600        RIOSetChange(p);
 601        rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
 602        return 1;
 603}
 604
 605/*
 606** Invalidate all the link interconnectivity of this unit, and of
 607** all the units attached to it. This will mean that the entire
 608** subnet will re-introduce itself.
 609*/
 610static int RIOIsolate(struct rio_info *p, struct Host *HostP, unsigned int UnitId)
 611{
 612        unsigned int link, unit;
 613
 614        UnitId--;                /* this trick relies on the Unit Id being UNSIGNED! */
 615
 616        if (UnitId >= MAX_RUP)        /* dontcha just lurv unsigned maths! */
 617                return (0);
 618
 619        if (HostP->Mapping[UnitId].Flags & BEEN_HERE)
 620                return (0);
 621
 622        HostP->Mapping[UnitId].Flags |= BEEN_HERE;
 623
 624        if (p->RIOPrintDisabled == DO_PRINT)
 625                rio_dprintk(RIO_DEBUG_ROUTE, "RIOMesgIsolated %s", HostP->Mapping[UnitId].Name);
 626
 627        for (link = 0; link < LINKS_PER_UNIT; link++) {
 628                unit = HostP->Mapping[UnitId].Topology[link].Unit;
 629                HostP->Mapping[UnitId].Topology[link].Unit = ROUTE_DISCONNECT;
 630                HostP->Mapping[UnitId].Topology[link].Link = NO_LINK;
 631                RIOIsolate(p, HostP, unit);
 632        }
 633        HostP->Mapping[UnitId].Flags &= ~BEEN_HERE;
 634        return 1;
 635}
 636
 637static int RIOCheck(struct Host *HostP, unsigned int UnitId)
 638{
 639        unsigned char link;
 640
 641/*         rio_dprint(RIO_DEBUG_ROUTE, ("Check to see if unit %d has a route to the host\n",UnitId)); */
 642        rio_dprintk(RIO_DEBUG_ROUTE, "RIOCheck : UnitID = %d\n", UnitId);
 643
 644        if (UnitId == HOST_ID) {
 645                /* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is NOT isolated - it IS the host!\n", UnitId)); */
 646                return 1;
 647        }
 648
 649        UnitId--;
 650
 651        if (UnitId >= MAX_RUP) {
 652                /* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d - ignored.\n", UnitId)); */
 653                return 0;
 654        }
 655
 656        for (link = 0; link < LINKS_PER_UNIT; link++) {
 657                if (HostP->Mapping[UnitId].Topology[link].Unit == HOST_ID) {
 658                        /* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is connected directly to host via link (%c).\n", 
 659                           UnitId, 'A'+link)); */
 660                        return 1;
 661                }
 662        }
 663
 664        if (HostP->Mapping[UnitId].Flags & BEEN_HERE) {
 665                /* rio_dprint(RIO_DEBUG_ROUTE, ("Been to Unit %d before - ignoring\n", UnitId)); */
 666                return 0;
 667        }
 668
 669        HostP->Mapping[UnitId].Flags |= BEEN_HERE;
 670
 671        for (link = 0; link < LINKS_PER_UNIT; link++) {
 672                /* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d check link (%c)\n", UnitId,'A'+link)); */
 673                if (RIOCheck(HostP, HostP->Mapping[UnitId].Topology[link].Unit)) {
 674                        /* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is connected to something that knows the host via link (%c)\n", UnitId,link+'A')); */
 675                        HostP->Mapping[UnitId].Flags &= ~BEEN_HERE;
 676                        return 1;
 677                }
 678        }
 679
 680        HostP->Mapping[UnitId].Flags &= ~BEEN_HERE;
 681
 682        /* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d DOESNT KNOW THE HOST!\n", UnitId)); */
 683
 684        return 0;
 685}
 686
 687/*
 688** Returns the type of unit (host, 16/8 port RTA)
 689*/
 690
 691unsigned int GetUnitType(unsigned int Uniq)
 692{
 693        switch ((Uniq >> 28) & 0xf) {
 694        case RIO_AT:
 695        case RIO_MCA:
 696        case RIO_EISA:
 697        case RIO_PCI:
 698                rio_dprintk(RIO_DEBUG_ROUTE, "Unit type: Host\n");
 699                return (TYPE_HOST);
 700        case RIO_RTA_16:
 701                rio_dprintk(RIO_DEBUG_ROUTE, "Unit type: 16 port RTA\n");
 702                return (TYPE_RTA16);
 703        case RIO_RTA:
 704                rio_dprintk(RIO_DEBUG_ROUTE, "Unit type: 8 port RTA\n");
 705                return (TYPE_RTA8);
 706        default:
 707                rio_dprintk(RIO_DEBUG_ROUTE, "Unit type: Unrecognised\n");
 708                return (99);
 709        }
 710}
 711
 712int RIOSetChange(struct rio_info *p)
 713{
 714        if (p->RIOQuickCheck != NOT_CHANGED)
 715                return (0);
 716        p->RIOQuickCheck = CHANGED;
 717        if (p->RIOSignalProcess) {
 718                rio_dprintk(RIO_DEBUG_ROUTE, "Send SIG-HUP");
 719                /*
 720                   psignal( RIOSignalProcess, SIGHUP );
 721                 */
 722        }
 723        return (0);
 724}
 725
 726static void RIOConCon(struct rio_info *p,
 727                      struct Host *HostP,
 728                      unsigned int FromId,
 729                      unsigned int FromLink,
 730                      unsigned int ToId,
 731                      unsigned int ToLink,
 732                      int Change)
 733{
 734        char *FromName;
 735        char *FromType;
 736        char *ToName;
 737        char *ToType;
 738        unsigned int tp;
 739
 740/*
 741** 15.10.1998 ARG - ESIL 0759
 742** (Part) fix for port being trashed when opened whilst RTA "disconnected"
 743**
 744** What's this doing in here anyway ?
 745** It was causing the port to be 'unmapped' if opened whilst RTA "disconnected"
 746**
 747** 09.12.1998 ARG - ESIL 0776 - part fix
 748** Okay, We've found out what this was all about now !
 749** Someone had botched this to use RIOHalted to indicated the number of RTAs
 750** 'disconnected'. The value in RIOHalted was then being used in the
 751** 'RIO_QUICK_CHECK' ioctl. A none zero value indicating that a least one RTA
 752** is 'disconnected'. The change was put in to satisfy a customer's needs.
 753** Having taken this bit of code out 'RIO_QUICK_CHECK' now no longer works for
 754** the customer.
 755**
 756    if (Change == CONNECT) {
 757                if (p->RIOHalted) p->RIOHalted --;
 758         }
 759         else {
 760                p->RIOHalted ++;
 761         }
 762**
 763** So - we need to implement it slightly differently - a new member of the
 764** rio_info struct - RIORtaDisCons (RIO RTA connections) keeps track of RTA
 765** connections and disconnections. 
 766*/
 767        if (Change == CONNECT) {
 768                if (p->RIORtaDisCons)
 769                        p->RIORtaDisCons--;
 770        } else {
 771                p->RIORtaDisCons++;
 772        }
 773
 774        if (p->RIOPrintDisabled == DONT_PRINT)
 775                return;
 776
 777        if (FromId > ToId) {
 778                tp = FromId;
 779                FromId = ToId;
 780                ToId = tp;
 781                tp = FromLink;
 782                FromLink = ToLink;
 783                ToLink = tp;
 784        }
 785
 786        FromName = FromId ? HostP->Mapping[FromId - 1].Name : HostP->Name;
 787        FromType = FromId ? "RTA" : "HOST";
 788        ToName = ToId ? HostP->Mapping[ToId - 1].Name : HostP->Name;
 789        ToType = ToId ? "RTA" : "HOST";
 790
 791        rio_dprintk(RIO_DEBUG_ROUTE, "Link between %s '%s' (%c) and %s '%s' (%c) %s.\n", FromType, FromName, 'A' + FromLink, ToType, ToName, 'A' + ToLink, (Change == CONNECT) ? "established" : "disconnected");
 792        printk(KERN_DEBUG "rio: Link between %s '%s' (%c) and %s '%s' (%c) %s.\n", FromType, FromName, 'A' + FromLink, ToType, ToName, 'A' + ToLink, (Change == CONNECT) ? "established" : "disconnected");
 793}
 794
 795/*
 796** RIORemoveFromSavedTable :
 797**
 798** Delete and RTA entry from the saved table given to us
 799** by the configuration program.
 800*/
 801static int RIORemoveFromSavedTable(struct rio_info *p, struct Map *pMap)
 802{
 803        int entry;
 804
 805        /*
 806         ** We loop for all entries even after finding an entry and
 807         ** zeroing it because we may have two entries to delete if
 808         ** it's a 16 port RTA.
 809         */
 810        for (entry = 0; entry < TOTAL_MAP_ENTRIES; entry++) {
 811                if (p->RIOSavedTable[entry].RtaUniqueNum == pMap->RtaUniqueNum) {
 812                        memset(&p->RIOSavedTable[entry], 0, sizeof(struct Map));
 813                }
 814        }
 815        return 0;
 816}
 817
 818
 819/*
 820** RIOCheckDisconnected :
 821**
 822** Scan the unit links to and return zero if the unit is completely
 823** disconnected.
 824*/
 825static int RIOFreeDisconnected(struct rio_info *p, struct Host *HostP, int unit)
 826{
 827        int link;
 828
 829
 830        rio_dprintk(RIO_DEBUG_ROUTE, "RIOFreeDisconnect unit %d\n", unit);
 831        /*
 832         ** If the slot is tentative and does not belong to the
 833         ** second half of a 16 port RTA then scan to see if
 834         ** is disconnected.
 835         */
 836        for (link = 0; link < LINKS_PER_UNIT; link++) {
 837                if (HostP->Mapping[unit].Topology[link].Unit != ROUTE_DISCONNECT)
 838                        break;
 839        }
 840
 841        /*
 842         ** If not all links are disconnected then we can forget about it.
 843         */
 844        if (link < LINKS_PER_UNIT)
 845                return 1;
 846
 847#ifdef NEED_TO_FIX_THIS
 848        /* Ok so all the links are disconnected. But we may have only just
 849         ** made this slot tentative and not yet received a topology update.
 850         ** Lets check how long ago we made it tentative.
 851         */
 852        rio_dprintk(RIO_DEBUG_ROUTE, "Just about to check LBOLT on entry %d\n", unit);
 853        if (drv_getparm(LBOLT, (ulong_t *) & current_time))
 854                rio_dprintk(RIO_DEBUG_ROUTE, "drv_getparm(LBOLT,....) Failed.\n");
 855
 856        elapse_time = current_time - TentTime[unit];
 857        rio_dprintk(RIO_DEBUG_ROUTE, "elapse %d = current %d - tent %d (%d usec)\n", elapse_time, current_time, TentTime[unit], drv_hztousec(elapse_time));
 858        if (drv_hztousec(elapse_time) < WAIT_TO_FINISH) {
 859                rio_dprintk(RIO_DEBUG_ROUTE, "Skipping slot %d, not timed out yet %d\n", unit, drv_hztousec(elapse_time));
 860                return 1;
 861        }
 862#endif
 863
 864        /*
 865         ** We have found an usable slot.
 866         ** If it is half of a 16 port RTA then delete the other half.
 867         */
 868        if (HostP->Mapping[unit].ID2 != 0) {
 869                int nOther = (HostP->Mapping[unit].ID2) - 1;
 870
 871                rio_dprintk(RIO_DEBUG_ROUTE, "RioFreedis second slot %d.\n", nOther);
 872                memset(&HostP->Mapping[nOther], 0, sizeof(struct Map));
 873        }
 874        RIORemoveFromSavedTable(p, &HostP->Mapping[unit]);
 875
 876        return 0;
 877}
 878
 879
 880/*
 881** RIOFindFreeID :
 882**
 883** This function scans the given host table for either one
 884** or two free unit ID's.
 885*/
 886
 887int RIOFindFreeID(struct rio_info *p, struct Host *HostP, unsigned int * pID1, unsigned int * pID2)
 888{
 889        int unit, tempID;
 890
 891        /*
 892         ** Initialise the ID's to MAX_RUP.
 893         ** We do this to make the loop for setting the ID's as simple as
 894         ** possible.
 895         */
 896        *pID1 = MAX_RUP;
 897        if (pID2 != NULL)
 898                *pID2 = MAX_RUP;
 899
 900        /*
 901         ** Scan all entries of the host mapping table for free slots.
 902         ** We scan for free slots first and then if that is not successful
 903         ** we start all over again looking for tentative slots we can re-use.
 904         */
 905        for (unit = 0; unit < MAX_RUP; unit++) {
 906                rio_dprintk(RIO_DEBUG_ROUTE, "Scanning unit %d\n", unit);
 907                /*
 908                 ** If the flags are zero then the slot is empty.
 909                 */
 910                if (HostP->Mapping[unit].Flags == 0) {
 911                        rio_dprintk(RIO_DEBUG_ROUTE, "      This slot is empty.\n");
 912                        /*
 913                         ** If we haven't allocated the first ID then do it now.
 914                         */
 915                        if (*pID1 == MAX_RUP) {
 916                                rio_dprintk(RIO_DEBUG_ROUTE, "Make tentative entry for first unit %d\n", unit);
 917                                *pID1 = unit;
 918
 919                                /*
 920                                 ** If the second ID is not needed then we can return
 921                                 ** now.
 922                                 */
 923                                if (pID2 == NULL)
 924                                        return 0;
 925                        } else {
 926                                /*
 927                                 ** Allocate the second slot and return.
 928                                 */
 929                                rio_dprintk(RIO_DEBUG_ROUTE, "Make tentative entry for second unit %d\n", unit);
 930                                *pID2 = unit;
 931                                return 0;
 932                        }
 933                }
 934        }
 935
 936        /*
 937         ** If we manage to come out of the free slot loop then we
 938         ** need to start all over again looking for tentative slots
 939         ** that we can re-use.
 940         */
 941        rio_dprintk(RIO_DEBUG_ROUTE, "Starting to scan for tentative slots\n");
 942        for (unit = 0; unit < MAX_RUP; unit++) {
 943                if (((HostP->Mapping[unit].Flags & SLOT_TENTATIVE) || (HostP->Mapping[unit].Flags == 0)) && !(HostP->Mapping[unit].Flags & RTA16_SECOND_SLOT)) {
 944                        rio_dprintk(RIO_DEBUG_ROUTE, "    Slot %d looks promising.\n", unit);
 945
 946                        if (unit == *pID1) {
 947                                rio_dprintk(RIO_DEBUG_ROUTE, "    No it isn't, its the 1st half\n");
 948                                continue;
 949                        }
 950
 951                        /*
 952                         ** Slot is Tentative or Empty, but not a tentative second
 953                         ** slot of a 16 porter.
 954                         ** Attempt to free up this slot (and its parnter if
 955                         ** it is a 16 port slot. The second slot will become
 956                         ** empty after a call to RIOFreeDisconnected so thats why
 957                         ** we look for empty slots above  as well).
 958                         */
 959                        if (HostP->Mapping[unit].Flags != 0)
 960                                if (RIOFreeDisconnected(p, HostP, unit) != 0)
 961                                        continue;
 962                        /*
 963                         ** If we haven't allocated the first ID then do it now.
 964                         */
 965                        if (*pID1 == MAX_RUP) {
 966                                rio_dprintk(RIO_DEBUG_ROUTE, "Grab tentative entry for first unit %d\n", unit);
 967                                *pID1 = unit;
 968
 969                                /*
 970                                 ** Clear out this slot now that we intend to use it.
 971                                 */
 972                                memset(&HostP->Mapping[unit], 0, sizeof(struct Map));
 973
 974                                /*
 975                                 ** If the second ID is not needed then we can return
 976                                 ** now.
 977                                 */
 978                                if (pID2 == NULL)
 979                                        return 0;
 980                        } else {
 981                                /*
 982                                 ** Allocate the second slot and return.
 983                                 */
 984                                rio_dprintk(RIO_DEBUG_ROUTE, "Grab tentative/empty  entry for second unit %d\n", unit);
 985                                *pID2 = unit;
 986
 987                                /*
 988                                 ** Clear out this slot now that we intend to use it.
 989                                 */
 990                                memset(&HostP->Mapping[unit], 0, sizeof(struct Map));
 991
 992                                /* At this point under the right(wrong?) conditions
 993                                 ** we may have a first unit ID being higher than the
 994                                 ** second unit ID. This is a bad idea if we are about
 995                                 ** to fill the slots with a 16 port RTA.
 996                                 ** Better check and swap them over.
 997                                 */
 998
 999                                if (*pID1 > *pID2) {
1000                                        rio_dprintk(RIO_DEBUG_ROUTE, "Swapping IDS %d %d\n", *pID1, *pID2);
1001                                        tempID = *pID1;
1002                                        *pID1 = *pID2;
1003                                        *pID2 = tempID;
1004                                }
1005                                return 0;
1006                        }
1007                }
1008        }
1009
1010        /*
1011         ** If we manage to get to the end of the second loop then we
1012         ** can give up and return a failure.
1013         */
1014        return 1;
1015}
1016
1017
1018/*
1019** The link switch scenario.
1020**
1021** Rta Wun (A) is connected to Tuw (A).
1022** The tables are all up to date, and the system is OK.
1023**
1024** If Wun (A) is now moved to Wun (B) before Wun (A) can
1025** become disconnected, then the follow happens:
1026**
1027** Tuw (A) spots the change of unit:link at the other end
1028** of its link and Tuw sends a topology packet reflecting
1029** the change: Tuw (A) now disconnected from Wun (A), and
1030** this is closely followed by a packet indicating that 
1031** Tuw (A) is now connected to Wun (B).
1032**
1033** Wun (B) will spot that it has now become connected, and
1034** Wun will send a topology packet, which indicates that
1035** both Wun (A) and Wun (B) is connected to Tuw (A).
1036**
1037** Eventually Wun (A) realises that it is now disconnected
1038** and Wun will send out a topology packet indicating that
1039** Wun (A) is now disconnected.
1040*/