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