diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/char/rio/rioboot.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/char/rio/rioboot.c')
-rw-r--r-- | drivers/char/rio/rioboot.c | 1360 |
1 files changed, 1360 insertions, 0 deletions
diff --git a/drivers/char/rio/rioboot.c b/drivers/char/rio/rioboot.c new file mode 100644 index 000000000000..a8be11dfcba3 --- /dev/null +++ b/drivers/char/rio/rioboot.c | |||
@@ -0,0 +1,1360 @@ | |||
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 : rioboot.c | ||
24 | ** SID : 1.3 | ||
25 | ** Last Modified : 11/6/98 10:33:36 | ||
26 | ** Retrieved : 11/6/98 10:33:48 | ||
27 | ** | ||
28 | ** ident @(#)rioboot.c 1.3 | ||
29 | ** | ||
30 | ** ----------------------------------------------------------------------------- | ||
31 | */ | ||
32 | |||
33 | #ifdef SCCS_LABELS | ||
34 | static char *_rioboot_c_sccs_ = "@(#)rioboot.c 1.3"; | ||
35 | #endif | ||
36 | |||
37 | #include <linux/module.h> | ||
38 | #include <linux/slab.h> | ||
39 | #include <linux/errno.h> | ||
40 | #include <linux/interrupt.h> | ||
41 | #include <asm/io.h> | ||
42 | #include <asm/system.h> | ||
43 | #include <asm/string.h> | ||
44 | #include <asm/semaphore.h> | ||
45 | |||
46 | |||
47 | #include <linux/termios.h> | ||
48 | #include <linux/serial.h> | ||
49 | |||
50 | #include <linux/generic_serial.h> | ||
51 | |||
52 | |||
53 | |||
54 | #include "linux_compat.h" | ||
55 | #include "rio_linux.h" | ||
56 | #include "typdef.h" | ||
57 | #include "pkt.h" | ||
58 | #include "daemon.h" | ||
59 | #include "rio.h" | ||
60 | #include "riospace.h" | ||
61 | #include "top.h" | ||
62 | #include "cmdpkt.h" | ||
63 | #include "map.h" | ||
64 | #include "riotypes.h" | ||
65 | #include "rup.h" | ||
66 | #include "port.h" | ||
67 | #include "riodrvr.h" | ||
68 | #include "rioinfo.h" | ||
69 | #include "func.h" | ||
70 | #include "errors.h" | ||
71 | #include "pci.h" | ||
72 | |||
73 | #include "parmmap.h" | ||
74 | #include "unixrup.h" | ||
75 | #include "board.h" | ||
76 | #include "host.h" | ||
77 | #include "error.h" | ||
78 | #include "phb.h" | ||
79 | #include "link.h" | ||
80 | #include "cmdblk.h" | ||
81 | #include "route.h" | ||
82 | |||
83 | static int RIOBootComplete( struct rio_info *p, struct Host *HostP, uint Rup, struct PktCmd *PktCmdP ); | ||
84 | |||
85 | static uchar | ||
86 | RIOAtVec2Ctrl[] = | ||
87 | { | ||
88 | /* 0 */ INTERRUPT_DISABLE, | ||
89 | /* 1 */ INTERRUPT_DISABLE, | ||
90 | /* 2 */ INTERRUPT_DISABLE, | ||
91 | /* 3 */ INTERRUPT_DISABLE, | ||
92 | /* 4 */ INTERRUPT_DISABLE, | ||
93 | /* 5 */ INTERRUPT_DISABLE, | ||
94 | /* 6 */ INTERRUPT_DISABLE, | ||
95 | /* 7 */ INTERRUPT_DISABLE, | ||
96 | /* 8 */ INTERRUPT_DISABLE, | ||
97 | /* 9 */ IRQ_9|INTERRUPT_ENABLE, | ||
98 | /* 10 */ INTERRUPT_DISABLE, | ||
99 | /* 11 */ IRQ_11|INTERRUPT_ENABLE, | ||
100 | /* 12 */ IRQ_12|INTERRUPT_ENABLE, | ||
101 | /* 13 */ INTERRUPT_DISABLE, | ||
102 | /* 14 */ INTERRUPT_DISABLE, | ||
103 | /* 15 */ IRQ_15|INTERRUPT_ENABLE | ||
104 | }; | ||
105 | |||
106 | /* | ||
107 | ** Load in the RTA boot code. | ||
108 | */ | ||
109 | int | ||
110 | RIOBootCodeRTA(p, rbp) | ||
111 | struct rio_info * p; | ||
112 | struct DownLoad * rbp; | ||
113 | { | ||
114 | int offset; | ||
115 | |||
116 | func_enter (); | ||
117 | |||
118 | /* Linux doesn't allow you to disable interrupts during a | ||
119 | "copyin". (Crash when a pagefault occurs). */ | ||
120 | /* disable(oldspl); */ | ||
121 | |||
122 | rio_dprintk (RIO_DEBUG_BOOT, "Data at user address 0x%x\n",(int)rbp->DataP); | ||
123 | |||
124 | /* | ||
125 | ** Check that we have set asside enough memory for this | ||
126 | */ | ||
127 | if ( rbp->Count > SIXTY_FOUR_K ) { | ||
128 | rio_dprintk (RIO_DEBUG_BOOT, "RTA Boot Code Too Large!\n"); | ||
129 | p->RIOError.Error = HOST_FILE_TOO_LARGE; | ||
130 | /* restore(oldspl); */ | ||
131 | func_exit (); | ||
132 | return -ENOMEM; | ||
133 | } | ||
134 | |||
135 | if ( p->RIOBooting ) { | ||
136 | rio_dprintk (RIO_DEBUG_BOOT, "RTA Boot Code : BUSY BUSY BUSY!\n"); | ||
137 | p->RIOError.Error = BOOT_IN_PROGRESS; | ||
138 | /* restore(oldspl); */ | ||
139 | func_exit (); | ||
140 | return -EBUSY; | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | ** The data we load in must end on a (RTA_BOOT_DATA_SIZE) byte boundary, | ||
145 | ** so calculate how far we have to move the data up the buffer | ||
146 | ** to achieve this. | ||
147 | */ | ||
148 | offset = (RTA_BOOT_DATA_SIZE - (rbp->Count % RTA_BOOT_DATA_SIZE)) % | ||
149 | RTA_BOOT_DATA_SIZE; | ||
150 | |||
151 | /* | ||
152 | ** Be clean, and clear the 'unused' portion of the boot buffer, | ||
153 | ** because it will (eventually) be part of the Rta run time environment | ||
154 | ** and so should be zeroed. | ||
155 | */ | ||
156 | bzero( (caddr_t)p->RIOBootPackets, offset ); | ||
157 | |||
158 | /* | ||
159 | ** Copy the data from user space. | ||
160 | */ | ||
161 | |||
162 | if ( copyin((int)rbp->DataP,((caddr_t)(p->RIOBootPackets))+offset, | ||
163 | rbp->Count) ==COPYFAIL ) { | ||
164 | rio_dprintk (RIO_DEBUG_BOOT, "Bad data copy from user space\n"); | ||
165 | p->RIOError.Error = COPYIN_FAILED; | ||
166 | /* restore(oldspl); */ | ||
167 | func_exit (); | ||
168 | return -EFAULT; | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | ** Make sure that our copy of the size includes that offset we discussed | ||
173 | ** earlier. | ||
174 | */ | ||
175 | p->RIONumBootPkts = (rbp->Count+offset)/RTA_BOOT_DATA_SIZE; | ||
176 | p->RIOBootCount = rbp->Count; | ||
177 | |||
178 | /* restore(oldspl); */ | ||
179 | func_exit(); | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | void rio_start_card_running (struct Host * HostP) | ||
184 | { | ||
185 | func_enter (); | ||
186 | |||
187 | switch ( HostP->Type ) { | ||
188 | case RIO_AT: | ||
189 | rio_dprintk (RIO_DEBUG_BOOT, "Start ISA card running\n"); | ||
190 | WBYTE(HostP->Control, | ||
191 | BOOT_FROM_RAM | EXTERNAL_BUS_ON | ||
192 | | HostP->Mode | ||
193 | | RIOAtVec2Ctrl[HostP->Ivec & 0xF] ); | ||
194 | break; | ||
195 | |||
196 | #ifdef FUTURE_RELEASE | ||
197 | case RIO_MCA: | ||
198 | /* | ||
199 | ** MCA handles IRQ vectors differently, so we don't write | ||
200 | ** them to this register. | ||
201 | */ | ||
202 | rio_dprintk (RIO_DEBUG_BOOT, "Start MCA card running\n"); | ||
203 | WBYTE(HostP->Control, McaTpBootFromRam | McaTpBusEnable | HostP->Mode); | ||
204 | break; | ||
205 | |||
206 | case RIO_EISA: | ||
207 | /* | ||
208 | ** EISA is totally different and expects OUTBZs to turn it on. | ||
209 | */ | ||
210 | rio_dprintk (RIO_DEBUG_BOOT, "Start EISA card running\n"); | ||
211 | OUTBZ( HostP->Slot, EISA_CONTROL_PORT, HostP->Mode | RIOEisaVec2Ctrl[HostP->Ivec] | EISA_TP_RUN | EISA_TP_BUS_ENABLE | EISA_TP_BOOT_FROM_RAM ); | ||
212 | break; | ||
213 | #endif | ||
214 | |||
215 | case RIO_PCI: | ||
216 | /* | ||
217 | ** PCI is much the same as MCA. Everything is once again memory | ||
218 | ** mapped, so we are writing to memory registers instead of io | ||
219 | ** ports. | ||
220 | */ | ||
221 | rio_dprintk (RIO_DEBUG_BOOT, "Start PCI card running\n"); | ||
222 | WBYTE(HostP->Control, PCITpBootFromRam | PCITpBusEnable | HostP->Mode); | ||
223 | break; | ||
224 | default: | ||
225 | rio_dprintk (RIO_DEBUG_BOOT, "Unknown host type %d\n", HostP->Type); | ||
226 | break; | ||
227 | } | ||
228 | /* | ||
229 | printk (KERN_INFO "Done with starting the card\n"); | ||
230 | func_exit (); | ||
231 | */ | ||
232 | return; | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | ** Load in the host boot code - load it directly onto all halted hosts | ||
237 | ** of the correct type. | ||
238 | ** | ||
239 | ** Put your rubber pants on before messing with this code - even the magic | ||
240 | ** numbers have trouble understanding what they are doing here. | ||
241 | */ | ||
242 | int | ||
243 | RIOBootCodeHOST(p, rbp) | ||
244 | struct rio_info * p; | ||
245 | register struct DownLoad *rbp; | ||
246 | { | ||
247 | register struct Host *HostP; | ||
248 | register caddr_t Cad; | ||
249 | register PARM_MAP *ParmMapP; | ||
250 | register int RupN; | ||
251 | int PortN; | ||
252 | uint host; | ||
253 | caddr_t StartP; | ||
254 | BYTE *DestP; | ||
255 | int wait_count; | ||
256 | ushort OldParmMap; | ||
257 | ushort offset; /* It is very important that this is a ushort */ | ||
258 | /* uint byte; */ | ||
259 | caddr_t DownCode = NULL; | ||
260 | unsigned long flags; | ||
261 | |||
262 | HostP = NULL; /* Assure the compiler we've initialized it */ | ||
263 | for ( host=0; host<p->RIONumHosts; host++ ) { | ||
264 | rio_dprintk (RIO_DEBUG_BOOT, "Attempt to boot host %d\n",host); | ||
265 | HostP = &p->RIOHosts[host]; | ||
266 | |||
267 | rio_dprintk (RIO_DEBUG_BOOT, "Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n", | ||
268 | HostP->Type, HostP->Mode, HostP->Ivec); | ||
269 | |||
270 | |||
271 | if ( (HostP->Flags & RUN_STATE) != RC_WAITING ) { | ||
272 | rio_dprintk (RIO_DEBUG_BOOT, "%s %d already running\n","Host",host); | ||
273 | continue; | ||
274 | } | ||
275 | |||
276 | /* | ||
277 | ** Grab a 32 bit pointer to the card. | ||
278 | */ | ||
279 | Cad = HostP->Caddr; | ||
280 | |||
281 | /* | ||
282 | ** We are going to (try) and load in rbp->Count bytes. | ||
283 | ** The last byte will reside at p->RIOConf.HostLoadBase-1; | ||
284 | ** Therefore, we need to start copying at address | ||
285 | ** (caddr+p->RIOConf.HostLoadBase-rbp->Count) | ||
286 | */ | ||
287 | StartP = (caddr_t)&Cad[p->RIOConf.HostLoadBase-rbp->Count]; | ||
288 | |||
289 | rio_dprintk (RIO_DEBUG_BOOT, "kernel virtual address for host is 0x%x\n", (int)Cad ); | ||
290 | rio_dprintk (RIO_DEBUG_BOOT, "kernel virtual address for download is 0x%x\n", (int)StartP); | ||
291 | rio_dprintk (RIO_DEBUG_BOOT, "host loadbase is 0x%x\n",p->RIOConf.HostLoadBase); | ||
292 | rio_dprintk (RIO_DEBUG_BOOT, "size of download is 0x%x\n", rbp->Count); | ||
293 | |||
294 | if ( p->RIOConf.HostLoadBase < rbp->Count ) { | ||
295 | rio_dprintk (RIO_DEBUG_BOOT, "Bin too large\n"); | ||
296 | p->RIOError.Error = HOST_FILE_TOO_LARGE; | ||
297 | func_exit (); | ||
298 | return -EFBIG; | ||
299 | } | ||
300 | /* | ||
301 | ** Ensure that the host really is stopped. | ||
302 | ** Disable it's external bus & twang its reset line. | ||
303 | */ | ||
304 | RIOHostReset( HostP->Type, (struct DpRam *)HostP->CardP, HostP->Slot ); | ||
305 | |||
306 | /* | ||
307 | ** Copy the data directly from user space to the SRAM. | ||
308 | ** This ain't going to be none too clever if the download | ||
309 | ** code is bigger than this segment. | ||
310 | */ | ||
311 | rio_dprintk (RIO_DEBUG_BOOT, "Copy in code\n"); | ||
312 | |||
313 | /* | ||
314 | ** PCI hostcard can't cope with 32 bit accesses and so need to copy | ||
315 | ** data to a local buffer, and then dripfeed the card. | ||
316 | */ | ||
317 | if ( HostP->Type == RIO_PCI ) { | ||
318 | /* int offset; */ | ||
319 | |||
320 | DownCode = sysbrk(rbp->Count); | ||
321 | if ( !DownCode ) { | ||
322 | rio_dprintk (RIO_DEBUG_BOOT, "No system memory available\n"); | ||
323 | p->RIOError.Error = NOT_ENOUGH_CORE_FOR_PCI_COPY; | ||
324 | func_exit (); | ||
325 | return -ENOMEM; | ||
326 | } | ||
327 | bzero(DownCode, rbp->Count); | ||
328 | |||
329 | if ( copyin((int)rbp->DataP,DownCode,rbp->Count)==COPYFAIL ) { | ||
330 | rio_dprintk (RIO_DEBUG_BOOT, "Bad copyin of host data\n"); | ||
331 | sysfree( DownCode, rbp->Count ); | ||
332 | p->RIOError.Error = COPYIN_FAILED; | ||
333 | func_exit (); | ||
334 | return -EFAULT; | ||
335 | } | ||
336 | |||
337 | HostP->Copy( DownCode, StartP, rbp->Count ); | ||
338 | |||
339 | sysfree( DownCode, rbp->Count ); | ||
340 | } | ||
341 | else if ( copyin((int)rbp->DataP,StartP,rbp->Count)==COPYFAIL ) { | ||
342 | rio_dprintk (RIO_DEBUG_BOOT, "Bad copyin of host data\n"); | ||
343 | p->RIOError.Error = COPYIN_FAILED; | ||
344 | func_exit (); | ||
345 | return -EFAULT; | ||
346 | } | ||
347 | |||
348 | rio_dprintk (RIO_DEBUG_BOOT, "Copy completed\n"); | ||
349 | |||
350 | /* | ||
351 | ** S T O P ! | ||
352 | ** | ||
353 | ** Upto this point the code has been fairly rational, and possibly | ||
354 | ** even straight forward. What follows is a pile of crud that will | ||
355 | ** magically turn into six bytes of transputer assembler. Normally | ||
356 | ** you would expect an array or something, but, being me, I have | ||
357 | ** chosen [been told] to use a technique whereby the startup code | ||
358 | ** will be correct if we change the loadbase for the code. Which | ||
359 | ** brings us onto another issue - the loadbase is the *end* of the | ||
360 | ** code, not the start. | ||
361 | ** | ||
362 | ** If I were you I wouldn't start from here. | ||
363 | */ | ||
364 | |||
365 | /* | ||
366 | ** We now need to insert a short boot section into | ||
367 | ** the memory at the end of Sram2. This is normally (de)composed | ||
368 | ** of the last eight bytes of the download code. The | ||
369 | ** download has been assembled/compiled to expect to be | ||
370 | ** loaded from 0x7FFF downwards. We have loaded it | ||
371 | ** at some other address. The startup code goes into the small | ||
372 | ** ram window at Sram2, in the last 8 bytes, which are really | ||
373 | ** at addresses 0x7FF8-0x7FFF. | ||
374 | ** | ||
375 | ** If the loadbase is, say, 0x7C00, then we need to branch to | ||
376 | ** address 0x7BFE to run the host.bin startup code. We assemble | ||
377 | ** this jump manually. | ||
378 | ** | ||
379 | ** The two byte sequence 60 08 is loaded into memory at address | ||
380 | ** 0x7FFE,F. This is a local branch to location 0x7FF8 (60 is nfix 0, | ||
381 | ** which adds '0' to the .O register, complements .O, and then shifts | ||
382 | ** it left by 4 bit positions, 08 is a jump .O+8 instruction. This will | ||
383 | ** add 8 to .O (which was 0xFFF0), and will branch RELATIVE to the new | ||
384 | ** location. Now, the branch starts from the value of .PC (or .IP or | ||
385 | ** whatever the bloody register is called on this chip), and the .PC | ||
386 | ** will be pointing to the location AFTER the branch, in this case | ||
387 | ** .PC == 0x8000, so the branch will be to 0x8000+0xFFF8 = 0x7FF8. | ||
388 | ** | ||
389 | ** A long branch is coded at 0x7FF8. This consists of loading a four | ||
390 | ** byte offset into .O using nfix (as above) and pfix operators. The | ||
391 | ** pfix operates in exactly the same way as the nfix operator, but | ||
392 | ** without the complement operation. The offset, of course, must be | ||
393 | ** relative to the address of the byte AFTER the branch instruction, | ||
394 | ** which will be (urm) 0x7FFC, so, our final destination of the branch | ||
395 | ** (loadbase-2), has to be reached from here. Imagine that the loadbase | ||
396 | ** is 0x7C00 (which it is), then we will need to branch to 0x7BFE (which | ||
397 | ** is the first byte of the initial two byte short local branch of the | ||
398 | ** download code). | ||
399 | ** | ||
400 | ** To code a jump from 0x7FFC (which is where the branch will start | ||
401 | ** from) to 0x7BFE, we will need to branch 0xFC02 bytes (0x7FFC+0xFC02)= | ||
402 | ** 0x7BFE. | ||
403 | ** This will be coded as four bytes: | ||
404 | ** 60 2C 20 02 | ||
405 | ** being nfix .O+0 | ||
406 | ** pfix .O+C | ||
407 | ** pfix .O+0 | ||
408 | ** jump .O+2 | ||
409 | ** | ||
410 | ** The nfix operator is used, so that the startup code will be | ||
411 | ** compatible with the whole Tp family. (lies, damn lies, it'll never | ||
412 | ** work in a month of Sundays). | ||
413 | ** | ||
414 | ** The nfix nyble is the 1s complement of the nyble value you | ||
415 | ** want to load - in this case we wanted 'F' so we nfix loaded '0'. | ||
416 | */ | ||
417 | |||
418 | |||
419 | /* | ||
420 | ** Dest points to the top 8 bytes of Sram2. The Tp jumps | ||
421 | ** to 0x7FFE at reset time, and starts executing. This is | ||
422 | ** a short branch to 0x7FF8, where a long branch is coded. | ||
423 | */ | ||
424 | |||
425 | DestP = (BYTE *)&Cad[0x7FF8]; /* <<<---- READ THE ABOVE COMMENTS */ | ||
426 | |||
427 | #define NFIX(N) (0x60 | (N)) /* .O = (~(.O + N))<<4 */ | ||
428 | #define PFIX(N) (0x20 | (N)) /* .O = (.O + N)<<4 */ | ||
429 | #define JUMP(N) (0x00 | (N)) /* .PC = .PC + .O */ | ||
430 | |||
431 | /* | ||
432 | ** 0x7FFC is the address of the location following the last byte of | ||
433 | ** the four byte jump instruction. | ||
434 | ** READ THE ABOVE COMMENTS | ||
435 | ** | ||
436 | ** offset is (TO-FROM) % MEMSIZE, but with compound buggering about. | ||
437 | ** Memsize is 64K for this range of Tp, so offset is a short (unsigned, | ||
438 | ** cos I don't understand 2's complement). | ||
439 | */ | ||
440 | offset = (p->RIOConf.HostLoadBase-2)-0x7FFC; | ||
441 | WBYTE( DestP[0] , NFIX(((ushort)(~offset) >> (ushort)12) & 0xF) ); | ||
442 | WBYTE( DestP[1] , PFIX(( offset >> 8) & 0xF) ); | ||
443 | WBYTE( DestP[2] , PFIX(( offset >> 4) & 0xF) ); | ||
444 | WBYTE( DestP[3] , JUMP( offset & 0xF) ); | ||
445 | |||
446 | WBYTE( DestP[6] , NFIX(0) ); | ||
447 | WBYTE( DestP[7] , JUMP(8) ); | ||
448 | |||
449 | rio_dprintk (RIO_DEBUG_BOOT, "host loadbase is 0x%x\n",p->RIOConf.HostLoadBase); | ||
450 | rio_dprintk (RIO_DEBUG_BOOT, "startup offset is 0x%x\n",offset); | ||
451 | |||
452 | /* | ||
453 | ** Flag what is going on | ||
454 | */ | ||
455 | HostP->Flags &= ~RUN_STATE; | ||
456 | HostP->Flags |= RC_STARTUP; | ||
457 | |||
458 | /* | ||
459 | ** Grab a copy of the current ParmMap pointer, so we | ||
460 | ** can tell when it has changed. | ||
461 | */ | ||
462 | OldParmMap = RWORD(HostP->__ParmMapR); | ||
463 | |||
464 | rio_dprintk (RIO_DEBUG_BOOT, "Original parmmap is 0x%x\n",OldParmMap); | ||
465 | |||
466 | /* | ||
467 | ** And start it running (I hope). | ||
468 | ** As there is nothing dodgy or obscure about the | ||
469 | ** above code, this is guaranteed to work every time. | ||
470 | */ | ||
471 | rio_dprintk (RIO_DEBUG_BOOT, "Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n", | ||
472 | HostP->Type, HostP->Mode, HostP->Ivec); | ||
473 | |||
474 | rio_start_card_running(HostP); | ||
475 | |||
476 | rio_dprintk (RIO_DEBUG_BOOT, "Set control port\n"); | ||
477 | |||
478 | /* | ||
479 | ** Now, wait for upto five seconds for the Tp to setup the parmmap | ||
480 | ** pointer: | ||
481 | */ | ||
482 | for ( wait_count=0; (wait_count<p->RIOConf.StartupTime)&& | ||
483 | (RWORD(HostP->__ParmMapR)==OldParmMap); wait_count++ ) { | ||
484 | rio_dprintk (RIO_DEBUG_BOOT, "Checkout %d, 0x%x\n",wait_count,RWORD(HostP->__ParmMapR)); | ||
485 | delay(HostP, HUNDRED_MS); | ||
486 | |||
487 | } | ||
488 | |||
489 | /* | ||
490 | ** If the parmmap pointer is unchanged, then the host code | ||
491 | ** has crashed & burned in a really spectacular way | ||
492 | */ | ||
493 | if ( RWORD(HostP->__ParmMapR) == OldParmMap ) { | ||
494 | rio_dprintk (RIO_DEBUG_BOOT, "parmmap 0x%x\n", RWORD(HostP->__ParmMapR)); | ||
495 | rio_dprintk (RIO_DEBUG_BOOT, "RIO Mesg Run Fail\n"); | ||
496 | |||
497 | #define HOST_DISABLE \ | ||
498 | HostP->Flags &= ~RUN_STATE; \ | ||
499 | HostP->Flags |= RC_STUFFED; \ | ||
500 | RIOHostReset( HostP->Type, (struct DpRam *)HostP->CardP, HostP->Slot );\ | ||
501 | continue | ||
502 | |||
503 | HOST_DISABLE; | ||
504 | } | ||
505 | |||
506 | rio_dprintk (RIO_DEBUG_BOOT, "Running 0x%x\n", RWORD(HostP->__ParmMapR)); | ||
507 | |||
508 | /* | ||
509 | ** Well, the board thought it was OK, and setup its parmmap | ||
510 | ** pointer. For the time being, we will pretend that this | ||
511 | ** board is running, and check out what the error flag says. | ||
512 | */ | ||
513 | |||
514 | /* | ||
515 | ** Grab a 32 bit pointer to the parmmap structure | ||
516 | */ | ||
517 | ParmMapP = (PARM_MAP *)RIO_PTR(Cad,RWORD(HostP->__ParmMapR)); | ||
518 | rio_dprintk (RIO_DEBUG_BOOT, "ParmMapP : %x\n", (int)ParmMapP); | ||
519 | ParmMapP = (PARM_MAP *)((unsigned long)Cad + | ||
520 | (unsigned long)((RWORD((HostP->__ParmMapR))) & 0xFFFF)); | ||
521 | rio_dprintk (RIO_DEBUG_BOOT, "ParmMapP : %x\n", (int)ParmMapP); | ||
522 | |||
523 | /* | ||
524 | ** The links entry should be 0xFFFF; we set it up | ||
525 | ** with a mask to say how many PHBs to use, and | ||
526 | ** which links to use. | ||
527 | */ | ||
528 | if ( (RWORD(ParmMapP->links) & 0xFFFF) != 0xFFFF ) { | ||
529 | rio_dprintk (RIO_DEBUG_BOOT, "RIO Mesg Run Fail %s\n", HostP->Name); | ||
530 | rio_dprintk (RIO_DEBUG_BOOT, "Links = 0x%x\n",RWORD(ParmMapP->links)); | ||
531 | HOST_DISABLE; | ||
532 | } | ||
533 | |||
534 | WWORD(ParmMapP->links , RIO_LINK_ENABLE); | ||
535 | |||
536 | /* | ||
537 | ** now wait for the card to set all the parmmap->XXX stuff | ||
538 | ** this is a wait of upto two seconds.... | ||
539 | */ | ||
540 | rio_dprintk (RIO_DEBUG_BOOT, "Looking for init_done - %d ticks\n",p->RIOConf.StartupTime); | ||
541 | HostP->timeout_id = 0; | ||
542 | for ( wait_count=0; (wait_count<p->RIOConf.StartupTime) && | ||
543 | !RWORD(ParmMapP->init_done); wait_count++ ) { | ||
544 | rio_dprintk (RIO_DEBUG_BOOT, "Waiting for init_done\n"); | ||
545 | delay(HostP, HUNDRED_MS); | ||
546 | } | ||
547 | rio_dprintk (RIO_DEBUG_BOOT, "OK! init_done!\n"); | ||
548 | |||
549 | if (RWORD(ParmMapP->error) != E_NO_ERROR || | ||
550 | !RWORD(ParmMapP->init_done) ) { | ||
551 | rio_dprintk (RIO_DEBUG_BOOT, "RIO Mesg Run Fail %s\n", HostP->Name); | ||
552 | rio_dprintk (RIO_DEBUG_BOOT, "Timedout waiting for init_done\n"); | ||
553 | HOST_DISABLE; | ||
554 | } | ||
555 | |||
556 | rio_dprintk (RIO_DEBUG_BOOT, "Got init_done\n"); | ||
557 | |||
558 | /* | ||
559 | ** It runs! It runs! | ||
560 | */ | ||
561 | rio_dprintk (RIO_DEBUG_BOOT, "Host ID %x Running\n",HostP->UniqueNum); | ||
562 | |||
563 | /* | ||
564 | ** set the time period between interrupts. | ||
565 | */ | ||
566 | WWORD(ParmMapP->timer, (short)p->RIOConf.Timer ); | ||
567 | |||
568 | /* | ||
569 | ** Translate all the 16 bit pointers in the __ParmMapR into | ||
570 | ** 32 bit pointers for the driver. | ||
571 | */ | ||
572 | HostP->ParmMapP = ParmMapP; | ||
573 | HostP->PhbP = (PHB*)RIO_PTR(Cad,RWORD(ParmMapP->phb_ptr)); | ||
574 | HostP->RupP = (RUP*)RIO_PTR(Cad,RWORD(ParmMapP->rups)); | ||
575 | HostP->PhbNumP = (ushort*)RIO_PTR(Cad,RWORD(ParmMapP->phb_num_ptr)); | ||
576 | HostP->LinkStrP = (LPB*)RIO_PTR(Cad,RWORD(ParmMapP->link_str_ptr)); | ||
577 | |||
578 | /* | ||
579 | ** point the UnixRups at the real Rups | ||
580 | */ | ||
581 | for ( RupN = 0; RupN<MAX_RUP; RupN++ ) { | ||
582 | HostP->UnixRups[RupN].RupP = &HostP->RupP[RupN]; | ||
583 | HostP->UnixRups[RupN].Id = RupN+1; | ||
584 | HostP->UnixRups[RupN].BaseSysPort = NO_PORT; | ||
585 | spin_lock_init(&HostP->UnixRups[RupN].RupLock); | ||
586 | } | ||
587 | |||
588 | for ( RupN = 0; RupN<LINKS_PER_UNIT; RupN++ ) { | ||
589 | HostP->UnixRups[RupN+MAX_RUP].RupP = &HostP->LinkStrP[RupN].rup; | ||
590 | HostP->UnixRups[RupN+MAX_RUP].Id = 0; | ||
591 | HostP->UnixRups[RupN+MAX_RUP].BaseSysPort = NO_PORT; | ||
592 | spin_lock_init(&HostP->UnixRups[RupN+MAX_RUP].RupLock); | ||
593 | } | ||
594 | |||
595 | /* | ||
596 | ** point the PortP->Phbs at the real Phbs | ||
597 | */ | ||
598 | for ( PortN=p->RIOFirstPortsMapped; | ||
599 | PortN<p->RIOLastPortsMapped+PORTS_PER_RTA; PortN++ ) { | ||
600 | if ( p->RIOPortp[PortN]->HostP == HostP ) { | ||
601 | struct Port *PortP = p->RIOPortp[PortN]; | ||
602 | struct PHB *PhbP; | ||
603 | /* int oldspl; */ | ||
604 | |||
605 | if ( !PortP->Mapped ) | ||
606 | continue; | ||
607 | |||
608 | PhbP = &HostP->PhbP[PortP->HostPort]; | ||
609 | rio_spin_lock_irqsave(&PortP->portSem, flags); | ||
610 | |||
611 | PortP->PhbP = PhbP; | ||
612 | |||
613 | PortP->TxAdd = (WORD *)RIO_PTR(Cad,RWORD(PhbP->tx_add)); | ||
614 | PortP->TxStart = (WORD *)RIO_PTR(Cad,RWORD(PhbP->tx_start)); | ||
615 | PortP->TxEnd = (WORD *)RIO_PTR(Cad,RWORD(PhbP->tx_end)); | ||
616 | PortP->RxRemove = (WORD *)RIO_PTR(Cad,RWORD(PhbP->rx_remove)); | ||
617 | PortP->RxStart = (WORD *)RIO_PTR(Cad,RWORD(PhbP->rx_start)); | ||
618 | PortP->RxEnd = (WORD *)RIO_PTR(Cad,RWORD(PhbP->rx_end)); | ||
619 | |||
620 | rio_spin_unlock_irqrestore(&PortP->portSem, flags); | ||
621 | /* | ||
622 | ** point the UnixRup at the base SysPort | ||
623 | */ | ||
624 | if ( !(PortN % PORTS_PER_RTA) ) | ||
625 | HostP->UnixRups[PortP->RupNum].BaseSysPort = PortN; | ||
626 | } | ||
627 | } | ||
628 | |||
629 | rio_dprintk (RIO_DEBUG_BOOT, "Set the card running... \n"); | ||
630 | /* | ||
631 | ** last thing - show the world that everything is in place | ||
632 | */ | ||
633 | HostP->Flags &= ~RUN_STATE; | ||
634 | HostP->Flags |= RC_RUNNING; | ||
635 | } | ||
636 | /* | ||
637 | ** MPX always uses a poller. This is actually patched into the system | ||
638 | ** configuration and called directly from each clock tick. | ||
639 | ** | ||
640 | */ | ||
641 | p->RIOPolling = 1; | ||
642 | |||
643 | p->RIOSystemUp++; | ||
644 | |||
645 | rio_dprintk (RIO_DEBUG_BOOT, "Done everything %x\n", HostP->Ivec); | ||
646 | func_exit (); | ||
647 | return 0; | ||
648 | } | ||
649 | |||
650 | |||
651 | |||
652 | /* | ||
653 | ** Boot an RTA. If we have successfully processed this boot, then | ||
654 | ** return 1. If we havent, then return 0. | ||
655 | */ | ||
656 | int | ||
657 | RIOBootRup( p, Rup, HostP, PacketP) | ||
658 | struct rio_info * p; | ||
659 | uint Rup; | ||
660 | struct Host *HostP; | ||
661 | struct PKT *PacketP; | ||
662 | { | ||
663 | struct PktCmd *PktCmdP = (struct PktCmd *)PacketP->data; | ||
664 | struct PktCmd_M *PktReplyP; | ||
665 | struct CmdBlk *CmdBlkP; | ||
666 | uint sequence; | ||
667 | |||
668 | #ifdef CHECK | ||
669 | CheckHost(Host); | ||
670 | CheckRup(Rup); | ||
671 | CheckHostP(HostP); | ||
672 | CheckPacketP(PacketP); | ||
673 | #endif | ||
674 | |||
675 | /* | ||
676 | ** If we haven't been told what to boot, we can't boot it. | ||
677 | */ | ||
678 | if ( p->RIONumBootPkts == 0 ) { | ||
679 | rio_dprintk (RIO_DEBUG_BOOT, "No RTA code to download yet\n"); | ||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | /* rio_dprint(RIO_DEBUG_BOOT, NULL,DBG_BOOT,"Incoming command packet\n"); */ | ||
684 | /* ShowPacket( DBG_BOOT, PacketP ); */ | ||
685 | |||
686 | /* | ||
687 | ** Special case of boot completed - if we get one of these then we | ||
688 | ** don't need a command block. For all other cases we do, so handle | ||
689 | ** this first and then get a command block, then handle every other | ||
690 | ** case, relinquishing the command block if disaster strikes! | ||
691 | */ | ||
692 | if ( (RBYTE(PacketP->len) & PKT_CMD_BIT) && | ||
693 | (RBYTE(PktCmdP->Command)==BOOT_COMPLETED) ) | ||
694 | return RIOBootComplete(p, HostP, Rup, PktCmdP ); | ||
695 | |||
696 | /* | ||
697 | ** try to unhook a command block from the command free list. | ||
698 | */ | ||
699 | if ( !(CmdBlkP = RIOGetCmdBlk()) ) { | ||
700 | rio_dprintk (RIO_DEBUG_BOOT, "No command blocks to boot RTA! come back later.\n"); | ||
701 | return 0; | ||
702 | } | ||
703 | |||
704 | /* | ||
705 | ** Fill in the default info on the command block | ||
706 | */ | ||
707 | CmdBlkP->Packet.dest_unit = Rup < (ushort)MAX_RUP ? Rup : 0; | ||
708 | CmdBlkP->Packet.dest_port = BOOT_RUP; | ||
709 | CmdBlkP->Packet.src_unit = 0; | ||
710 | CmdBlkP->Packet.src_port = BOOT_RUP; | ||
711 | |||
712 | CmdBlkP->PreFuncP = CmdBlkP->PostFuncP = NULL; | ||
713 | PktReplyP = (struct PktCmd_M *)CmdBlkP->Packet.data; | ||
714 | |||
715 | /* | ||
716 | ** process COMMANDS on the boot rup! | ||
717 | */ | ||
718 | if ( RBYTE(PacketP->len) & PKT_CMD_BIT ) { | ||
719 | /* | ||
720 | ** We only expect one type of command - a BOOT_REQUEST! | ||
721 | */ | ||
722 | if ( RBYTE(PktCmdP->Command) != BOOT_REQUEST ) { | ||
723 | rio_dprintk (RIO_DEBUG_BOOT, "Unexpected command %d on BOOT RUP %d of host %d\n", | ||
724 | PktCmdP->Command,Rup,HostP-p->RIOHosts); | ||
725 | ShowPacket( DBG_BOOT, PacketP ); | ||
726 | RIOFreeCmdBlk( CmdBlkP ); | ||
727 | return 1; | ||
728 | } | ||
729 | |||
730 | /* | ||
731 | ** Build a Boot Sequence command block | ||
732 | ** | ||
733 | ** 02.03.1999 ARG - ESIL 0820 fix | ||
734 | ** We no longer need to use "Boot Mode", we'll always allow | ||
735 | ** boot requests - the boot will not complete if the device | ||
736 | ** appears in the bindings table. | ||
737 | ** So, this conditional is not required ... | ||
738 | ** | ||
739 | if (p->RIOBootMode == RC_BOOT_NONE) | ||
740 | ** | ||
741 | ** If the system is in slave mode, and a boot request is | ||
742 | ** received, set command to BOOT_ABORT so that the boot | ||
743 | ** will not complete. | ||
744 | ** | ||
745 | PktReplyP->Command = BOOT_ABORT; | ||
746 | else | ||
747 | ** | ||
748 | ** We'll just (always) set the command field in packet reply | ||
749 | ** to allow an attempted boot sequence : | ||
750 | */ | ||
751 | PktReplyP->Command = BOOT_SEQUENCE; | ||
752 | |||
753 | PktReplyP->BootSequence.NumPackets = p->RIONumBootPkts; | ||
754 | PktReplyP->BootSequence.LoadBase = p->RIOConf.RtaLoadBase; | ||
755 | PktReplyP->BootSequence.CodeSize = p->RIOBootCount; | ||
756 | |||
757 | CmdBlkP->Packet.len = BOOT_SEQUENCE_LEN | PKT_CMD_BIT; | ||
758 | |||
759 | bcopy("BOOT",(void *)&CmdBlkP->Packet.data[BOOT_SEQUENCE_LEN],4); | ||
760 | |||
761 | rio_dprintk (RIO_DEBUG_BOOT, "Boot RTA on Host %d Rup %d - %d (0x%x) packets to 0x%x\n", | ||
762 | HostP-p->RIOHosts, Rup, p->RIONumBootPkts, p->RIONumBootPkts, | ||
763 | p->RIOConf.RtaLoadBase); | ||
764 | |||
765 | /* | ||
766 | ** If this host is in slave mode, send the RTA an invalid boot | ||
767 | ** sequence command block to force it to kill the boot. We wait | ||
768 | ** for half a second before sending this packet to prevent the RTA | ||
769 | ** attempting to boot too often. The master host should then grab | ||
770 | ** the RTA and make it its own. | ||
771 | */ | ||
772 | p->RIOBooting++; | ||
773 | RIOQueueCmdBlk( HostP, Rup, CmdBlkP ); | ||
774 | return 1; | ||
775 | } | ||
776 | |||
777 | /* | ||
778 | ** It is a request for boot data. | ||
779 | */ | ||
780 | sequence = RWORD(PktCmdP->Sequence); | ||
781 | |||
782 | rio_dprintk (RIO_DEBUG_BOOT, "Boot block %d on Host %d Rup%d\n",sequence,HostP-p->RIOHosts,Rup); | ||
783 | |||
784 | if ( sequence >= p->RIONumBootPkts ) { | ||
785 | rio_dprintk (RIO_DEBUG_BOOT, "Got a request for packet %d, max is %d\n", sequence, | ||
786 | p->RIONumBootPkts); | ||
787 | ShowPacket( DBG_BOOT, PacketP ); | ||
788 | } | ||
789 | |||
790 | PktReplyP->Sequence = sequence; | ||
791 | |||
792 | bcopy( p->RIOBootPackets[ p->RIONumBootPkts - sequence - 1 ], | ||
793 | PktReplyP->BootData, RTA_BOOT_DATA_SIZE ); | ||
794 | |||
795 | CmdBlkP->Packet.len = PKT_MAX_DATA_LEN; | ||
796 | ShowPacket( DBG_BOOT, &CmdBlkP->Packet ); | ||
797 | RIOQueueCmdBlk( HostP, Rup, CmdBlkP ); | ||
798 | return 1; | ||
799 | } | ||
800 | |||
801 | /* | ||
802 | ** This function is called when an RTA been booted. | ||
803 | ** If booted by a host, HostP->HostUniqueNum is the booting host. | ||
804 | ** If booted by an RTA, HostP->Mapping[Rup].RtaUniqueNum is the booting RTA. | ||
805 | ** RtaUniq is the booted RTA. | ||
806 | */ | ||
807 | static int RIOBootComplete( struct rio_info *p, struct Host *HostP, uint Rup, struct PktCmd *PktCmdP ) | ||
808 | { | ||
809 | struct Map *MapP = NULL; | ||
810 | struct Map *MapP2 = NULL; | ||
811 | int Flag; | ||
812 | int found; | ||
813 | int host, rta; | ||
814 | int EmptySlot = -1; | ||
815 | int entry, entry2; | ||
816 | char *MyType, *MyName; | ||
817 | uint MyLink; | ||
818 | ushort RtaType; | ||
819 | uint RtaUniq = (RBYTE(PktCmdP->UniqNum[0])) + | ||
820 | (RBYTE(PktCmdP->UniqNum[1]) << 8) + | ||
821 | (RBYTE(PktCmdP->UniqNum[2]) << 16) + | ||
822 | (RBYTE(PktCmdP->UniqNum[3]) << 24); | ||
823 | |||
824 | /* Was RIOBooting-- . That's bad. If an RTA sends two of them, the | ||
825 | driver will never think that the RTA has booted... -- REW */ | ||
826 | p->RIOBooting = 0; | ||
827 | |||
828 | rio_dprintk (RIO_DEBUG_BOOT, "RTA Boot completed - BootInProgress now %d\n", p->RIOBooting); | ||
829 | |||
830 | /* | ||
831 | ** Determine type of unit (16/8 port RTA). | ||
832 | */ | ||
833 | RtaType = GetUnitType(RtaUniq); | ||
834 | if ( Rup >= (ushort)MAX_RUP ) { | ||
835 | rio_dprintk (RIO_DEBUG_BOOT, "RIO: Host %s has booted an RTA(%d) on link %c\n", | ||
836 | HostP->Name, 8 * RtaType, RBYTE(PktCmdP->LinkNum)+'A'); | ||
837 | } else { | ||
838 | rio_dprintk (RIO_DEBUG_BOOT, "RIO: RTA %s has booted an RTA(%d) on link %c\n", | ||
839 | HostP->Mapping[Rup].Name, 8 * RtaType, | ||
840 | RBYTE(PktCmdP->LinkNum)+'A'); | ||
841 | } | ||
842 | |||
843 | rio_dprintk (RIO_DEBUG_BOOT, "UniqNum is 0x%x\n",RtaUniq); | ||
844 | |||
845 | if ( ( RtaUniq == 0x00000000 ) || ( RtaUniq == 0xffffffff ) ) | ||
846 | { | ||
847 | rio_dprintk (RIO_DEBUG_BOOT, "Illegal RTA Uniq Number\n"); | ||
848 | return TRUE; | ||
849 | } | ||
850 | |||
851 | /* | ||
852 | ** If this RTA has just booted an RTA which doesn't belong to this | ||
853 | ** system, or the system is in slave mode, do not attempt to create | ||
854 | ** a new table entry for it. | ||
855 | */ | ||
856 | if (!RIOBootOk(p, HostP, RtaUniq)) | ||
857 | { | ||
858 | MyLink = RBYTE(PktCmdP->LinkNum); | ||
859 | if (Rup < (ushort) MAX_RUP) | ||
860 | { | ||
861 | /* | ||
862 | ** RtaUniq was clone booted (by this RTA). Instruct this RTA | ||
863 | ** to hold off further attempts to boot on this link for 30 | ||
864 | ** seconds. | ||
865 | */ | ||
866 | if (RIOSuspendBootRta(HostP, HostP->Mapping[Rup].ID, MyLink)) | ||
867 | { | ||
868 | rio_dprintk (RIO_DEBUG_BOOT, "RTA failed to suspend booting on link %c\n", | ||
869 | 'A' + MyLink); | ||
870 | } | ||
871 | } | ||
872 | else | ||
873 | { | ||
874 | /* | ||
875 | ** RtaUniq was booted by this host. Set the booting link | ||
876 | ** to hold off for 30 seconds to give another unit a | ||
877 | ** chance to boot it. | ||
878 | */ | ||
879 | WWORD(HostP->LinkStrP[MyLink].WaitNoBoot, 30); | ||
880 | } | ||
881 | rio_dprintk (RIO_DEBUG_BOOT, "RTA %x not owned - suspend booting down link %c on unit %x\n", | ||
882 | RtaUniq, 'A' + MyLink, HostP->Mapping[Rup].RtaUniqueNum); | ||
883 | return TRUE; | ||
884 | } | ||
885 | |||
886 | /* | ||
887 | ** Check for a SLOT_IN_USE entry for this RTA attached to the | ||
888 | ** current host card in the driver table. | ||
889 | ** | ||
890 | ** If it exists, make a note that we have booted it. Other parts of | ||
891 | ** the driver are interested in this information at a later date, | ||
892 | ** in particular when the booting RTA asks for an ID for this unit, | ||
893 | ** we must have set the BOOTED flag, and the NEWBOOT flag is used | ||
894 | ** to force an open on any ports that where previously open on this | ||
895 | ** unit. | ||
896 | */ | ||
897 | for ( entry=0; entry<MAX_RUP; entry++ ) | ||
898 | { | ||
899 | uint sysport; | ||
900 | |||
901 | if ((HostP->Mapping[entry].Flags & SLOT_IN_USE) && | ||
902 | (HostP->Mapping[entry].RtaUniqueNum==RtaUniq)) | ||
903 | { | ||
904 | HostP->Mapping[entry].Flags |= RTA_BOOTED|RTA_NEWBOOT; | ||
905 | #if NEED_TO_FIX | ||
906 | RIO_SV_BROADCAST(HostP->svFlags[entry]); | ||
907 | #endif | ||
908 | if ( (sysport=HostP->Mapping[entry].SysPort) != NO_PORT ) | ||
909 | { | ||
910 | if ( sysport < p->RIOFirstPortsBooted ) | ||
911 | p->RIOFirstPortsBooted = sysport; | ||
912 | if ( sysport > p->RIOLastPortsBooted ) | ||
913 | p->RIOLastPortsBooted = sysport; | ||
914 | /* | ||
915 | ** For a 16 port RTA, check the second bank of 8 ports | ||
916 | */ | ||
917 | if (RtaType == TYPE_RTA16) | ||
918 | { | ||
919 | entry2 = HostP->Mapping[entry].ID2 - 1; | ||
920 | HostP->Mapping[entry2].Flags |= RTA_BOOTED|RTA_NEWBOOT; | ||
921 | #if NEED_TO_FIX | ||
922 | RIO_SV_BROADCAST(HostP->svFlags[entry2]); | ||
923 | #endif | ||
924 | sysport = HostP->Mapping[entry2].SysPort; | ||
925 | if ( sysport < p->RIOFirstPortsBooted ) | ||
926 | p->RIOFirstPortsBooted = sysport; | ||
927 | if ( sysport > p->RIOLastPortsBooted ) | ||
928 | p->RIOLastPortsBooted = sysport; | ||
929 | } | ||
930 | } | ||
931 | if (RtaType == TYPE_RTA16) { | ||
932 | rio_dprintk (RIO_DEBUG_BOOT, "RTA will be given IDs %d+%d\n", | ||
933 | entry+1, entry2+1); | ||
934 | } else { | ||
935 | rio_dprintk (RIO_DEBUG_BOOT, "RTA will be given ID %d\n",entry+1); | ||
936 | } | ||
937 | return TRUE; | ||
938 | } | ||
939 | } | ||
940 | |||
941 | rio_dprintk (RIO_DEBUG_BOOT, "RTA not configured for this host\n"); | ||
942 | |||
943 | if ( Rup >= (ushort)MAX_RUP ) | ||
944 | { | ||
945 | /* | ||
946 | ** It was a host that did the booting | ||
947 | */ | ||
948 | MyType = "Host"; | ||
949 | MyName = HostP->Name; | ||
950 | } | ||
951 | else | ||
952 | { | ||
953 | /* | ||
954 | ** It was an RTA that did the booting | ||
955 | */ | ||
956 | MyType = "RTA"; | ||
957 | MyName = HostP->Mapping[Rup].Name; | ||
958 | } | ||
959 | #ifdef CHECK | ||
960 | CheckString(MyType); | ||
961 | CheckString(MyName); | ||
962 | #endif | ||
963 | |||
964 | MyLink = RBYTE(PktCmdP->LinkNum); | ||
965 | |||
966 | /* | ||
967 | ** There is no SLOT_IN_USE entry for this RTA attached to the current | ||
968 | ** host card in the driver table. | ||
969 | ** | ||
970 | ** Check for a SLOT_TENTATIVE entry for this RTA attached to the | ||
971 | ** current host card in the driver table. | ||
972 | ** | ||
973 | ** If we find one, then we re-use that slot. | ||
974 | */ | ||
975 | for ( entry=0; entry<MAX_RUP; entry++ ) | ||
976 | { | ||
977 | if ( (HostP->Mapping[entry].Flags & SLOT_TENTATIVE) && | ||
978 | (HostP->Mapping[entry].RtaUniqueNum == RtaUniq) ) | ||
979 | { | ||
980 | if (RtaType == TYPE_RTA16) | ||
981 | { | ||
982 | entry2 = HostP->Mapping[entry].ID2 - 1; | ||
983 | if ( (HostP->Mapping[entry2].Flags & SLOT_TENTATIVE) && | ||
984 | (HostP->Mapping[entry2].RtaUniqueNum == RtaUniq) ) | ||
985 | rio_dprintk (RIO_DEBUG_BOOT, "Found previous tentative slots (%d+%d)\n", | ||
986 | entry, entry2); | ||
987 | else | ||
988 | continue; | ||
989 | } | ||
990 | else | ||
991 | rio_dprintk (RIO_DEBUG_BOOT, "Found previous tentative slot (%d)\n",entry); | ||
992 | if (! p->RIONoMessage) | ||
993 | cprintf("RTA connected to %s '%s' (%c) not configured.\n",MyType,MyName,MyLink+'A'); | ||
994 | return TRUE; | ||
995 | } | ||
996 | } | ||
997 | |||
998 | /* | ||
999 | ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA | ||
1000 | ** attached to the current host card in the driver table. | ||
1001 | ** | ||
1002 | ** Check if there is a SLOT_IN_USE or SLOT_TENTATIVE entry on another | ||
1003 | ** host for this RTA in the driver table. | ||
1004 | ** | ||
1005 | ** For a SLOT_IN_USE entry on another host, we need to delete the RTA | ||
1006 | ** entry from the other host and add it to this host (using some of | ||
1007 | ** the functions from table.c which do this). | ||
1008 | ** For a SLOT_TENTATIVE entry on another host, we must cope with the | ||
1009 | ** following scenario: | ||
1010 | ** | ||
1011 | ** + Plug 8 port RTA into host A. (This creates SLOT_TENTATIVE entry | ||
1012 | ** in table) | ||
1013 | ** + Unplug RTA and plug into host B. (We now have 2 SLOT_TENTATIVE | ||
1014 | ** entries) | ||
1015 | ** + Configure RTA on host B. (This slot now becomes SLOT_IN_USE) | ||
1016 | ** + Unplug RTA and plug back into host A. | ||
1017 | ** + Configure RTA on host A. We now have the same RTA configured | ||
1018 | ** with different ports on two different hosts. | ||
1019 | */ | ||
1020 | rio_dprintk (RIO_DEBUG_BOOT, "Have we seen RTA %x before?\n", RtaUniq ); | ||
1021 | found = 0; | ||
1022 | Flag = 0; /* Convince the compiler this variable is initialized */ | ||
1023 | for ( host = 0; !found && (host < p->RIONumHosts); host++ ) | ||
1024 | { | ||
1025 | for ( rta=0; rta<MAX_RUP; rta++ ) | ||
1026 | { | ||
1027 | if ((p->RIOHosts[host].Mapping[rta].Flags & | ||
1028 | (SLOT_IN_USE | SLOT_TENTATIVE)) && | ||
1029 | (p->RIOHosts[host].Mapping[rta].RtaUniqueNum==RtaUniq)) | ||
1030 | { | ||
1031 | Flag = p->RIOHosts[host].Mapping[rta].Flags; | ||
1032 | MapP = &p->RIOHosts[host].Mapping[rta]; | ||
1033 | if (RtaType == TYPE_RTA16) | ||
1034 | { | ||
1035 | MapP2 = &p->RIOHosts[host].Mapping[MapP->ID2 - 1]; | ||
1036 | rio_dprintk (RIO_DEBUG_BOOT, "This RTA is units %d+%d from host %s\n", | ||
1037 | rta+1, MapP->ID2, p->RIOHosts[host].Name); | ||
1038 | } | ||
1039 | else | ||
1040 | rio_dprintk (RIO_DEBUG_BOOT, "This RTA is unit %d from host %s\n", | ||
1041 | rta+1, p->RIOHosts[host].Name); | ||
1042 | found = 1; | ||
1043 | break; | ||
1044 | } | ||
1045 | } | ||
1046 | } | ||
1047 | |||
1048 | /* | ||
1049 | ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA | ||
1050 | ** attached to the current host card in the driver table. | ||
1051 | ** | ||
1052 | ** If we have not found a SLOT_IN_USE or SLOT_TENTATIVE entry on | ||
1053 | ** another host for this RTA in the driver table... | ||
1054 | ** | ||
1055 | ** Check for a SLOT_IN_USE entry for this RTA in the config table. | ||
1056 | */ | ||
1057 | if ( !MapP ) | ||
1058 | { | ||
1059 | rio_dprintk (RIO_DEBUG_BOOT, "Look for RTA %x in RIOSavedTable\n",RtaUniq); | ||
1060 | for ( rta=0; rta < TOTAL_MAP_ENTRIES; rta++ ) | ||
1061 | { | ||
1062 | rio_dprintk (RIO_DEBUG_BOOT, "Check table entry %d (%x)", | ||
1063 | rta, | ||
1064 | p->RIOSavedTable[rta].RtaUniqueNum); | ||
1065 | |||
1066 | if ( (p->RIOSavedTable[rta].Flags & SLOT_IN_USE) && | ||
1067 | (p->RIOSavedTable[rta].RtaUniqueNum == RtaUniq) ) | ||
1068 | { | ||
1069 | MapP = &p->RIOSavedTable[rta]; | ||
1070 | Flag = p->RIOSavedTable[rta].Flags; | ||
1071 | if (RtaType == TYPE_RTA16) | ||
1072 | { | ||
1073 | for (entry2 = rta + 1; entry2 < TOTAL_MAP_ENTRIES; | ||
1074 | entry2++) | ||
1075 | { | ||
1076 | if (p->RIOSavedTable[entry2].RtaUniqueNum == RtaUniq) | ||
1077 | break; | ||
1078 | } | ||
1079 | MapP2 = &p->RIOSavedTable[entry2]; | ||
1080 | rio_dprintk (RIO_DEBUG_BOOT, "This RTA is from table entries %d+%d\n", | ||
1081 | rta, entry2); | ||
1082 | } | ||
1083 | else | ||
1084 | rio_dprintk (RIO_DEBUG_BOOT, "This RTA is from table entry %d\n", rta); | ||
1085 | break; | ||
1086 | } | ||
1087 | } | ||
1088 | } | ||
1089 | |||
1090 | /* | ||
1091 | ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA | ||
1092 | ** attached to the current host card in the driver table. | ||
1093 | ** | ||
1094 | ** We may have found a SLOT_IN_USE entry on another host for this | ||
1095 | ** RTA in the config table, or a SLOT_IN_USE or SLOT_TENTATIVE entry | ||
1096 | ** on another host for this RTA in the driver table. | ||
1097 | ** | ||
1098 | ** Check the driver table for room to fit this newly discovered RTA. | ||
1099 | ** RIOFindFreeID() first looks for free slots and if it does not | ||
1100 | ** find any free slots it will then attempt to oust any | ||
1101 | ** tentative entry in the table. | ||
1102 | */ | ||
1103 | EmptySlot = 1; | ||
1104 | if (RtaType == TYPE_RTA16) | ||
1105 | { | ||
1106 | if (RIOFindFreeID(p, HostP, &entry, &entry2) == 0) | ||
1107 | { | ||
1108 | RIODefaultName(p, HostP, entry); | ||
1109 | FillSlot(entry, entry2, RtaUniq, HostP); | ||
1110 | EmptySlot = 0; | ||
1111 | } | ||
1112 | } | ||
1113 | else | ||
1114 | { | ||
1115 | if (RIOFindFreeID(p, HostP, &entry, NULL) == 0) | ||
1116 | { | ||
1117 | RIODefaultName(p, HostP, entry); | ||
1118 | FillSlot(entry, 0, RtaUniq, HostP); | ||
1119 | EmptySlot = 0; | ||
1120 | } | ||
1121 | } | ||
1122 | |||
1123 | /* | ||
1124 | ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA | ||
1125 | ** attached to the current host card in the driver table. | ||
1126 | ** | ||
1127 | ** If we found a SLOT_IN_USE entry on another host for this | ||
1128 | ** RTA in the config or driver table, and there are enough free | ||
1129 | ** slots in the driver table, then we need to move it over and | ||
1130 | ** delete it from the other host. | ||
1131 | ** If we found a SLOT_TENTATIVE entry on another host for this | ||
1132 | ** RTA in the driver table, just delete the other host entry. | ||
1133 | */ | ||
1134 | if (EmptySlot == 0) | ||
1135 | { | ||
1136 | if ( MapP ) | ||
1137 | { | ||
1138 | if (Flag & SLOT_IN_USE) | ||
1139 | { | ||
1140 | rio_dprintk (RIO_DEBUG_BOOT, | ||
1141 | "This RTA configured on another host - move entry to current host (1)\n"); | ||
1142 | HostP->Mapping[entry].SysPort = MapP->SysPort; | ||
1143 | CCOPY( MapP->Name, HostP->Mapping[entry].Name, MAX_NAME_LEN ); | ||
1144 | HostP->Mapping[entry].Flags = | ||
1145 | SLOT_IN_USE | RTA_BOOTED | RTA_NEWBOOT; | ||
1146 | #if NEED_TO_FIX | ||
1147 | RIO_SV_BROADCAST(HostP->svFlags[entry]); | ||
1148 | #endif | ||
1149 | RIOReMapPorts( p, HostP, &HostP->Mapping[entry] ); | ||
1150 | if ( HostP->Mapping[entry].SysPort < p->RIOFirstPortsBooted ) | ||
1151 | p->RIOFirstPortsBooted = HostP->Mapping[entry].SysPort; | ||
1152 | if ( HostP->Mapping[entry].SysPort > p->RIOLastPortsBooted ) | ||
1153 | p->RIOLastPortsBooted = HostP->Mapping[entry].SysPort; | ||
1154 | rio_dprintk (RIO_DEBUG_BOOT, "SysPort %d, Name %s\n",(int)MapP->SysPort,MapP->Name); | ||
1155 | } | ||
1156 | else | ||
1157 | { | ||
1158 | rio_dprintk (RIO_DEBUG_BOOT, | ||
1159 | "This RTA has a tentative entry on another host - delete that entry (1)\n"); | ||
1160 | HostP->Mapping[entry].Flags = | ||
1161 | SLOT_TENTATIVE | RTA_BOOTED | RTA_NEWBOOT; | ||
1162 | #if NEED_TO_FIX | ||
1163 | RIO_SV_BROADCAST(HostP->svFlags[entry]); | ||
1164 | #endif | ||
1165 | } | ||
1166 | if (RtaType == TYPE_RTA16) | ||
1167 | { | ||
1168 | if (Flag & SLOT_IN_USE) | ||
1169 | { | ||
1170 | HostP->Mapping[entry2].Flags = SLOT_IN_USE | | ||
1171 | RTA_BOOTED | RTA_NEWBOOT | RTA16_SECOND_SLOT; | ||
1172 | #if NEED_TO_FIX | ||
1173 | RIO_SV_BROADCAST(HostP->svFlags[entry2]); | ||
1174 | #endif | ||
1175 | HostP->Mapping[entry2].SysPort = MapP2->SysPort; | ||
1176 | /* | ||
1177 | ** Map second block of ttys for 16 port RTA | ||
1178 | */ | ||
1179 | RIOReMapPorts( p, HostP, &HostP->Mapping[entry2] ); | ||
1180 | if (HostP->Mapping[entry2].SysPort < p->RIOFirstPortsBooted) | ||
1181 | p->RIOFirstPortsBooted = HostP->Mapping[entry2].SysPort; | ||
1182 | if (HostP->Mapping[entry2].SysPort > p->RIOLastPortsBooted) | ||
1183 | p->RIOLastPortsBooted = HostP->Mapping[entry2].SysPort; | ||
1184 | rio_dprintk (RIO_DEBUG_BOOT, "SysPort %d, Name %s\n", | ||
1185 | (int)HostP->Mapping[entry2].SysPort, | ||
1186 | HostP->Mapping[entry].Name); | ||
1187 | } | ||
1188 | else | ||
1189 | HostP->Mapping[entry2].Flags = SLOT_TENTATIVE | | ||
1190 | RTA_BOOTED | RTA_NEWBOOT | RTA16_SECOND_SLOT; | ||
1191 | #if NEED_TO_FIX | ||
1192 | RIO_SV_BROADCAST(HostP->svFlags[entry2]); | ||
1193 | #endif | ||
1194 | bzero( (caddr_t)MapP2, sizeof(struct Map) ); | ||
1195 | } | ||
1196 | bzero( (caddr_t)MapP, sizeof(struct Map) ); | ||
1197 | if (! p->RIONoMessage) | ||
1198 | cprintf("An orphaned RTA has been adopted by %s '%s' (%c).\n",MyType,MyName,MyLink+'A'); | ||
1199 | } | ||
1200 | else if (! p->RIONoMessage) | ||
1201 | cprintf("RTA connected to %s '%s' (%c) not configured.\n",MyType,MyName,MyLink+'A'); | ||
1202 | RIOSetChange(p); | ||
1203 | return TRUE; | ||
1204 | } | ||
1205 | |||
1206 | /* | ||
1207 | ** There is no room in the driver table to make an entry for the | ||
1208 | ** booted RTA. Keep a note of its Uniq Num in the overflow table, | ||
1209 | ** so we can ignore it's ID requests. | ||
1210 | */ | ||
1211 | if (! p->RIONoMessage) | ||
1212 | cprintf("The RTA connected to %s '%s' (%c) cannot be configured. You cannot configure more than 128 ports to one host card.\n",MyType,MyName,MyLink+'A'); | ||
1213 | for ( entry=0; entry<HostP->NumExtraBooted; entry++ ) | ||
1214 | { | ||
1215 | if ( HostP->ExtraUnits[entry] == RtaUniq ) | ||
1216 | { | ||
1217 | /* | ||
1218 | ** already got it! | ||
1219 | */ | ||
1220 | return TRUE; | ||
1221 | } | ||
1222 | } | ||
1223 | /* | ||
1224 | ** If there is room, add the unit to the list of extras | ||
1225 | */ | ||
1226 | if ( HostP->NumExtraBooted < MAX_EXTRA_UNITS ) | ||
1227 | HostP->ExtraUnits[HostP->NumExtraBooted++] = RtaUniq; | ||
1228 | return TRUE; | ||
1229 | } | ||
1230 | |||
1231 | |||
1232 | /* | ||
1233 | ** If the RTA or its host appears in the RIOBindTab[] structure then | ||
1234 | ** we mustn't boot the RTA and should return FALSE. | ||
1235 | ** This operation is slightly different from the other drivers for RIO | ||
1236 | ** in that this is designed to work with the new utilities | ||
1237 | ** not config.rio and is FAR SIMPLER. | ||
1238 | ** We no longer support the RIOBootMode variable. It is all done from the | ||
1239 | ** "boot/noboot" field in the rio.cf file. | ||
1240 | */ | ||
1241 | int | ||
1242 | RIOBootOk(p, HostP, RtaUniq) | ||
1243 | struct rio_info * p; | ||
1244 | struct Host * HostP; | ||
1245 | ulong RtaUniq; | ||
1246 | { | ||
1247 | int Entry; | ||
1248 | uint HostUniq = HostP->UniqueNum; | ||
1249 | |||
1250 | /* | ||
1251 | ** Search bindings table for RTA or its parent. | ||
1252 | ** If it exists, return 0, else 1. | ||
1253 | */ | ||
1254 | for (Entry = 0; | ||
1255 | ( Entry < MAX_RTA_BINDINGS ) && ( p->RIOBindTab[Entry] != 0 ); | ||
1256 | Entry++) | ||
1257 | { | ||
1258 | if ( (p->RIOBindTab[Entry] == HostUniq) || | ||
1259 | (p->RIOBindTab[Entry] == RtaUniq) ) | ||
1260 | return 0; | ||
1261 | } | ||
1262 | return 1; | ||
1263 | } | ||
1264 | |||
1265 | /* | ||
1266 | ** Make an empty slot tentative. If this is a 16 port RTA, make both | ||
1267 | ** slots tentative, and the second one RTA_SECOND_SLOT as well. | ||
1268 | */ | ||
1269 | |||
1270 | void | ||
1271 | FillSlot(entry, entry2, RtaUniq, HostP) | ||
1272 | int entry; | ||
1273 | int entry2; | ||
1274 | uint RtaUniq; | ||
1275 | struct Host *HostP; | ||
1276 | { | ||
1277 | int link; | ||
1278 | |||
1279 | rio_dprintk (RIO_DEBUG_BOOT, "FillSlot(%d, %d, 0x%x...)\n", entry, entry2, RtaUniq); | ||
1280 | |||
1281 | HostP->Mapping[entry].Flags = (RTA_BOOTED | RTA_NEWBOOT | SLOT_TENTATIVE); | ||
1282 | HostP->Mapping[entry].SysPort = NO_PORT; | ||
1283 | HostP->Mapping[entry].RtaUniqueNum = RtaUniq; | ||
1284 | HostP->Mapping[entry].HostUniqueNum = HostP->UniqueNum; | ||
1285 | HostP->Mapping[entry].ID = entry + 1; | ||
1286 | HostP->Mapping[entry].ID2 = 0; | ||
1287 | if (entry2) { | ||
1288 | HostP->Mapping[entry2].Flags = (RTA_BOOTED | RTA_NEWBOOT | | ||
1289 | SLOT_TENTATIVE | RTA16_SECOND_SLOT); | ||
1290 | HostP->Mapping[entry2].SysPort = NO_PORT; | ||
1291 | HostP->Mapping[entry2].RtaUniqueNum = RtaUniq; | ||
1292 | HostP->Mapping[entry2].HostUniqueNum = HostP->UniqueNum; | ||
1293 | HostP->Mapping[entry2].Name[0] = '\0'; | ||
1294 | HostP->Mapping[entry2].ID = entry2 + 1; | ||
1295 | HostP->Mapping[entry2].ID2 = entry + 1; | ||
1296 | HostP->Mapping[entry].ID2 = entry2 + 1; | ||
1297 | } | ||
1298 | /* | ||
1299 | ** Must set these up, so that utilities show | ||
1300 | ** topology of 16 port RTAs correctly | ||
1301 | */ | ||
1302 | for ( link=0; link<LINKS_PER_UNIT; link++ ) { | ||
1303 | HostP->Mapping[entry].Topology[link].Unit = ROUTE_DISCONNECT; | ||
1304 | HostP->Mapping[entry].Topology[link].Link = NO_LINK; | ||
1305 | if (entry2) { | ||
1306 | HostP->Mapping[entry2].Topology[link].Unit = ROUTE_DISCONNECT; | ||
1307 | HostP->Mapping[entry2].Topology[link].Link = NO_LINK; | ||
1308 | } | ||
1309 | } | ||
1310 | } | ||
1311 | |||
1312 | #if 0 | ||
1313 | /* | ||
1314 | Function: This function is to disable the disk interrupt | ||
1315 | Returns : Nothing | ||
1316 | */ | ||
1317 | void | ||
1318 | disable_interrupt(vector) | ||
1319 | int vector; | ||
1320 | { | ||
1321 | int ps; | ||
1322 | int val; | ||
1323 | |||
1324 | disable(ps); | ||
1325 | if (vector > 40) { | ||
1326 | val = 1 << (vector - 40); | ||
1327 | __outb(S8259+1, __inb(S8259+1) | val); | ||
1328 | } | ||
1329 | else { | ||
1330 | val = 1 << (vector - 32); | ||
1331 | __outb(M8259+1, __inb(M8259+1) | val); | ||
1332 | } | ||
1333 | restore(ps); | ||
1334 | } | ||
1335 | |||
1336 | /* | ||
1337 | Function: This function is to enable the disk interrupt | ||
1338 | Returns : Nothing | ||
1339 | */ | ||
1340 | void | ||
1341 | enable_interrupt(vector) | ||
1342 | int vector; | ||
1343 | { | ||
1344 | int ps; | ||
1345 | int val; | ||
1346 | |||
1347 | disable(ps); | ||
1348 | if (vector > 40) { | ||
1349 | val = 1 << (vector - 40); | ||
1350 | val = ~val; | ||
1351 | __outb(S8259+1, __inb(S8259+1) & val); | ||
1352 | } | ||
1353 | else { | ||
1354 | val = 1 << (vector - 32); | ||
1355 | val = ~val; | ||
1356 | __outb(M8259+1, __inb(M8259+1) & val); | ||
1357 | } | ||
1358 | restore(ps); | ||
1359 | } | ||
1360 | #endif | ||