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