Old s-ncr.c
1 /* System dependent file for NCR System V Release 4 MP/RAS */
2
3 /* $Id: s-ncr.c,v 1.2 1994/09/07 00:44:31 jdd Exp $ */
4
5 #include "s.h"
6 #include <stdio.h>
7 #include <nlist.h>
8 #include <sys/types.h>
9 #include <sys/fcntl.h>
10 #include <sys/unistd.h>
11 #include <sys/mman.h>
12
13 #include <sys/utsname.h>
14 #include <sys/pic.h>
15 #include <sys/sysinfo.h>
16 #include <sys/mp/percpu.h>
17 #include <sys/immu.h>
18
19 #include <sys/scsi/cs.h>
20
21 #include <errno.h>
22
23 extern int diskflag, cpuflag;
24 extern char *kernelSymbols;
25
26 extern void draw_bar(int bar_num, int *states, int num_states);
27 extern void display_bars(int);
28
29 struct cpu_names
30 {
31 int cpu_type;
32 char cpu_type_name[8];
33 };
34
35 const struct cpu_names cpu_model_names[] =
36 {
37 { CPU_386, "i386" },
38 { CPU_486, "i486" },
39 #ifdef CPU_586
40 { CPU_586, "Pentium" },
41 #elif defined CPU_Pentium
42 { CPU_Pentium, "Pentium" },
43 #endif
44 };
45
46
47 /* The following defines are used to index the variable kernel_nl[] */
48 #define KERNEL_UTSNAME 0
49 #define KERNEL_PERCPUP 1
50 #define KERNEL_CPU_INFOS 2
51 #define KERNEL_NCPU 3
52 #define KERNEL_SCSI_STAT 4
53 #define KERNEL_LBOLT 5
54
55 /* kernel_nl[] -- list of symbol addresses needed.
56 */
57 static struct nlist kernel_nl[] =
58 {
59 { "utsname", 0 },
60 { "percpup", 0 },
61 { "cpu_infos", 0 },
62 { "ncpu", 0 },
63 { "SCSI_Stat_Ptr", 0 },
64 { "lbolt", 0 },
65
66 { 0, 0 }
67 };
68
69
70
71 /* kernel_symbols[] -- list of places to look for the running kernel's symbols
72 */
73 char *kernel_symbols[] = {
74 0, /* used by -kernel option */
75 "/stand/unix.diag",
76 "/stand/unix",
77 "/stand/unix.old",
78
79 0
80 };
81
82
83
84 enum stype
85 {
86 CPU_STATE,
87 DISK_STATE,
88 };
89
90 enum stype state = CPU_STATE;
91 int kmem; /* file descriptor for /dev/kmem */
92 char *kernel_name; /* name of kernel (/stand/unix) */
93 struct utsname nodename; /* nodename.nodename */
94 int kmem_is_mapped;
95 int kmem_is_reading;
96 int kmem_can_map = 1;
97
98
99 /* Fake kernel memory mapping information
100 */
101 typedef struct kmem_map
102 {
103 struct kmem_map *km_next;
104 void *km_addr;
105 size_t km_size;
106 char km_buf[4];
107 } kmem_map_t;
108
109 kmem_map_t *kmem_list; /* linked list of fake memory mappings */
110
111 /* CPU Information
112 */
113 int kncpu; /* maximum number of cpu's on system */
114 int ncpus; /* number of cpu's which exist */
115 percpu_t **kpercpup; /* array of percpu_t pointers */
116 percpu_t **xpercpup; /* percpu_t pointers when mmapped */
117 percpu_t **mypercpup = 0; /* Pointers to each cpu's percpu area */
118 time_t *lastcpu; /* last snapshot of each cpu's times */
119 cpu_info_t *kcpu_infos; /* State of each cpu */
120
121
122 /* SCSI Disk Information
123 */
124 int ndisks;
125 long kscsi_stat_ptr_addr;
126 long kaddr;
127
128 typedef struct diskinfo
129 {
130 dev_t di_dev;
131 SCSI_Device_t *di_kscsi;
132 StatStructure_t di_stats;
133 } diskinfo_t;
134
135 long *lboltp;
136 long last_lbolt, new_lbolt;
137 diskinfo_t *kscsi_stat;
138 SCSI_Device_t *lscsi_stat;
139 SCSI_Device_t tscsi_stat;
140
141
142
143 /* The size of the array which holds the cpu
144 execution information.
145 */
146 #if defined( CPU_Pentium )
147 #define MPSYSINFO c_sysinfo
148 #else
149 #define MPSYSINFO c_mpinfo
150 #endif
151
152 #define CPU_STATE_SZ sizeof(mypercpup[0]->MPSYSINFO.cpu)
153
154
155 /* Computes the time spent in the specified state.
156 */
157
158 #define delta(state) \
159 ((int) mypercpup[cpu]->MPSYSINFO.cpu[state] - cputime[state])
160
161
162 /* Save the state times for a specific cpu
163 */
164 #define savecpuinfo(cpu) \
165 memcpy(cputime, mypercpup[cpu]->MPSYSINFO.cpu, CPU_STATE_SZ);
166
167
168 /* The size of the local state time array
169 */
170 #define NSTATES CPU_STATE_SZ
171 #define CPUSTATES (CPU_STATE_SZ / sizeof(mypercpup[0]->MPSYSINFO.cpu[0]))-1
172
173 /* Display an error message based upon errno and
174 return 0 to caller
175 */
176 #define ERR_EXIT(msg) \
177 { \
178 perror(msg); \
179 return 0; \
180 }
181
182
183 /* Read a specified number of bytes of kernel memory
184 and report any error conditions which might arise.
185 */
186 #define seekreadok(desc, seekpos, buf, sz, msg) \
187 if (-1 == lseek(desc, seekpos, SEEK_SET)) \
188 ERR_EXIT("lseeking " msg); \
189 \
190 if ((sz) != read(desc, buf, (sz))) \
191 ERR_EXIT("reading " msg);
192
193 #define seekreaderr(desc, seekpos, buf, sz, msg) \
194 ( -1 == lseek(desc, seekpos, SEEK_SET) || \
195 (sz) != read(desc, buf, (sz)))
196
197
198 /* fakethis() -- provide faked out memory mappings if unable to mmap kernel.
199 */
200 void *
201 fakethis(void *loc, size_t sz)
202 {
203 kmem_map_t *mapping = (kmem_map_t *)malloc( sizeof(kmem_map_t) + sz );
204
205 if (!mapping)
206 return 0;
207
208 mapping->km_addr = loc;
209 mapping->km_size = sz;
210 mapping->km_next = kmem_list;
211
212 seekreadok(kmem, mapping->km_addr, mapping->km_buf, mapping->km_size,
213 "faking mmap");
214
215 if (!kmem_list && kmem_can_map)
216 fprintf(stderr, "Unable to mmap kernel addresses, using lseek/read\n");
217
218 kmem_list = mapping;
219 kmem_is_reading++;
220
221 return (void *) mapping->km_buf;
222 }
223
224 /* refreshfakes() -- Refresh fake mmap snapshots.
225 */
226 int
227 refreshfakes(void)
228 {
229 kmem_map_t *mapping;
230 int errs = 0;
231
232 for (mapping = kmem_list; mapping; mapping = mapping->km_next)
233 if (seekreaderr(kmem, mapping->km_addr, mapping->km_buf, mapping->km_size,
234 "refreshing fake mmap's"))
235 errs++;
236
237 return errs;
238 }
239
240 /* Given an address (and size in bytes) in kernel virtual memory,
241 this function uses the mmap function to provide a mapping for
242 those addresses in the current process. The result is either
243 a pointer to the data in this processes virtual space or
244 (void *)-1 if unable to provide the mapping.
245 */
246 void *
247 mapthis(int desc, void *locp, unsigned long sz)
248 {
249 unsigned long pgoffs = (unsigned long) locp & POFFMASK;
250 unsigned long pgstrt = (unsigned long) locp & PG_ADDR;
251 unsigned long pgend = ((unsigned long) locp + sz) & PG_ADDR;
252 unsigned long mapsz = pgend - pgstrt + NBPP;
253 char *map = (char *)-1;
254
255 if (kmem_can_map)
256 map = mmap(0, mapsz, PROT_READ, MAP_SHARED, desc, pgstrt);
257
258 if ((char *)-1 == map)
259 {
260 if (kmem_is_mapped)
261 fprintf(stderr, "Mixing mapping and lseek/read kernel memory?\n");
262
263 map = fakethis(locp, sz);
264 return map ? map : (void *)-1;
265 }
266
267 kmem_is_mapped++;
268 return (void *) (map + pgoffs);
269 }
270
271
272
273 /* get_kernel_symbols -- Find the file containing the symbol definitions
274 for the currently running kernel.
275
276 The kernel must be running out of /stand (on an svr4 system) and the
277 symbol value for utsname must match the name returned by the uname()
278 system call.
279
280 This function is called given a list of possible files from /stand which
281 may be running and returns the name of the first file which appears
282 to be correct.
283 */
284
285 char *
286 get_kernel_symbols(int kmemfd, char **knamelist)
287 {
288 char **cpp;
289 int nf, errs;
290 int nsz = strlen(nodename.nodename) + 1;
291 struct utsname nname;
292
293 if (1 >= nsz)
294 fprintf(stderr, "xcpustate: Empty node name\n");
295
296 if (kernelSymbols)
297 *knamelist = kernelSymbols;
298
299 if (!*knamelist) knamelist++; /* skip over initial NULL pointer */
300
301 for (cpp = knamelist; *cpp; cpp++)
302 {
303 for (nf = 0; kernel_nl[nf].n_name; nf++)
304 kernel_nl[nf].n_value = 0;
305
306 nf = nlist(*cpp, kernel_nl);
307 if (-1 == nf || 0 == kernel_nl[KERNEL_UTSNAME].n_value)
308 continue;
309
310 if (!seekreaderr(kmemfd, kernel_nl[KERNEL_UTSNAME].n_value,
311 &nname.nodename, nsz, "utsname") &&
312 0 == strncmp(nodename.nodename, nname.nodename, nsz))
313 {
314 for (errs = nf = 0; kernel_nl[nf].n_name; nf ++)
315 if (0 == kernel_nl[nf].n_value)
316 {
317 fprintf(stderr, "kernel symbol `%s' not found\n",
318 kernel_nl[nf].n_name);
319 errs++;
320 }
321
322 if (errs)
323 return 0;
324
325 return *cpp;
326 }
327 }
328
329 fprintf(stderr, "xcpustate: No kernel symbol file matches running kernel\n");
330 return 0;
331 }
332
333
334
335 /* init_cpu_init() -- Initialize for CPU display
336 */
337 int
338 init_cpu_info(void)
339 {
340 int nf;
341
342 seekreadok(kmem,
343 kernel_nl[KERNEL_NCPU].n_value,
344 &kncpu,
345 sizeof(kncpu),
346 "/dev/kmem [ncpu]");
347
348 if (kncpu > 64 || kncpu < 0)
349 {
350 fprintf(stderr, "Unlikely value for ncpu found.\n");
351 return 0;
352 }
353
354 kcpu_infos = mapthis(kmem,
355 (void *)kernel_nl[KERNEL_CPU_INFOS].n_value,
356 kncpu*sizeof(cpu_info_t));
357 if (-1 == (int)kcpu_infos)
358 ERR_EXIT("mapping cpu_infos[]");
359
360 kpercpup = mapthis(kmem,
361 (void *)kernel_nl[KERNEL_PERCPUP].n_value,
362 kncpu * sizeof(percpu_t *));
363 if (-1 == (int)kpercpup)
364 ERR_EXIT("mapping percpup[]");
365
366 mypercpup = (percpu_t **) malloc( sizeof(percpu_t *) * kncpu );
367 if (!mypercpup)
368 ERR_EXIT("allocating memory");
369
370 xpercpup = (percpu_t **) malloc( kncpu * sizeof(percpu_t *));
371 if (!kpercpup)
372 ERR_EXIT("allocating memory");
373
374 memset(xpercpup, 0, kncpu * sizeof(percpu_t *));
375
376 for (ncpus = nf = 0; nf < kncpu; nf++)
377 if (kcpu_infos[nf].cpu_flag & CPU_EXISTS)
378 {
379 if (kpercpup[nf])
380 {
381 xpercpup[ncpus] = kpercpup[nf];
382 mypercpup[ncpus] = mapthis(kmem,
383 xpercpup[ncpus],
384 sizeof(*(kpercpup[nf])));
385 if (-1 == mypercpup[ncpus])
386 ERR_EXIT("mapping percpu area");
387 }
388 ncpus++;
389 }
390
391 nf = ncpus * CPU_STATE_SZ;
392 lastcpu = (time_t *) malloc(nf);
393 memset(lastcpu, 0, nf);
394
395 return ncpus;
396 }
397
398
399 /* scsitype() -- return string naming scsi device type.
400 */
401 char *
402 scsitype(int t)
403 {
404 switch (t)
405 {
406 case SCSI_DAD_TYPE: return "disk";
407 case SCSI_SAD_TYPE: return "tape";
408 case SCSI_PRT_TYPE: return "printer";
409 case SCSI_PROC_TYPE: return "proc";
410 case SCSI_WORM_TYPE: return "worm";
411 case SCSI_CD_ROM_TYPE: return "cdrom";
412 case SCSI_SCAN_TYPE: return "scanner";
413 case SCSI_OPTICAL_TYPE: return "optical";
414 case SCSI_CHANGER_TYPE: return "changer";
415 case SCSI_COMM_TYPE: return "comm";
416 }
417
418 return "<unknown>";
419 }
420
421
422 /* diskname() -- Return string naming disk device.
423 */
424 char *
425 diskname(Partition_Identifier_t *s)
426 {
427 static char name[52];
428
429 if (0 == s->IO_Bus)
430 {
431 if (0 == s->SCSI_Controller)
432 sprintf(name, "c%xt%xd%xs%x",
433 s->SCSI_Bus,
434 s->PUN, s->LUN, s->Partition);
435 else
436 sprintf(name, "c%x%xt%xd%xs%x",
437 s->SCSI_Controller, s->SCSI_Bus,
438 s->PUN, s->LUN, s->Partition);
439 }
440 else
441 sprintf(name, "c%x%x%xt%xd%xs%x",
442 s->IO_Bus, s->SCSI_Controller, s->SCSI_Bus,
443 s->PUN, s->LUN, s->Partition);
444
445 return name;
446 }
447
448 int
449 init_disk_info(void)
450 {
451 long kaddr;
452 int cdisk;
453 int head = 0, nprocs = 0, ncdroms = 0, ntapes = 0;
454
455 seekreadok(kmem,
456 kernel_nl[KERNEL_SCSI_STAT].n_value,
457 &kscsi_stat_ptr_addr,
458 sizeof(kscsi_stat_ptr_addr),
459 "/dev/kmem [SCSI_Stat_Ptr]");
460
461 kaddr = kscsi_stat_ptr_addr;
462 ndisks = 0;
463
464 do
465 {
466 seekreadok(kmem,kaddr,&tscsi_stat,sizeof(tscsi_stat),"/dev/kmem [SCSI]");
467 switch (tscsi_stat.inquiry_data.Periph_Device_Type)
468 {
469 case SCSI_DAD_TYPE: ndisks++; break;
470 case SCSI_SAD_TYPE: ntapes++; break;
471 case SCSI_CD_ROM_TYPE: ncdroms++; break;
472 case SCSI_PROC_TYPE: nprocs++; break;
473 }
474 kaddr = (long) tscsi_stat.Statistics.ForwardPointer;
475 }
476 while (kscsi_stat_ptr_addr != kaddr);
477
478 fprintf(stderr, "SCSI: %d disks, %d tapes, %d cdroms, %d controllers\n",
479 ndisks, ntapes, ncdroms, nprocs);
480
481 kscsi_stat = (diskinfo_t *) malloc((1+ndisks) * sizeof(diskinfo_t));
482 if (!kscsi_stat)
483 ERR_EXIT("Allocate SCSI Disk memory");
484 #if 0
485 lscsi_stat = (SCSI_Device_t *) malloc((1+ndisks) * sizeof(SCSI_Device_t));
486 if (!lscsi_stat)
487 ERR_EXIT("Allocate SCSI Statistics array");
488 memset(lscsi_stat, 0, ndisks * sizeof(SCSI_Device_t));
489 #endif
490
491 kaddr = kscsi_stat_ptr_addr;
492 cdisk = 0;
493
494 lboltp = (long *) mapthis(kmem, (void *)kernel_nl[KERNEL_LBOLT].n_value,
495 sizeof(long));
496 if (-1 == (long) lboltp)
497 {
498 perror("Can't map lbolt");
499 return 0;
500 }
501 last_lbolt = *lboltp;
502
503 do
504 {
505 lscsi_stat = (SCSI_Device_t *) mapthis(kmem, (void *)kaddr,
506 sizeof(tscsi_stat));
507 if (-1 == (long) lscsi_stat)
508 {
509 perror("Can't map SCSI information");
510 return 0;
511 }
512
513 kscsi_stat[cdisk].di_kscsi = (SCSI_Device_t *) lscsi_stat;
514 kscsi_stat[cdisk].di_dev = lscsi_stat->dev;
515 memcpy(&kscsi_stat[cdisk].di_stats, &lscsi_stat->Statistics,
516 sizeof(lscsi_stat->Statistics));
517
518 if (!head++)
519 fprintf(stderr," # Bus Ctrlr SBus PUN LUN Part dev_num Name\n");
520
521 fprintf(stderr, "%3d %3d %5d %4d %3d %3d %4d %08x %s (%s)\n",
522 cdisk,
523 lscsi_stat->SCSI_device.IO_Bus,
524 lscsi_stat->SCSI_device.SCSI_Controller,
525 lscsi_stat->SCSI_device.SCSI_Bus,
526 lscsi_stat->SCSI_device.PUN,
527 lscsi_stat->SCSI_device.LUN,
528 lscsi_stat->SCSI_device.Partition,
529 lscsi_stat->dev,
530 diskname(&lscsi_stat->SCSI_device),
531 scsitype(lscsi_stat->inquiry_data.Periph_Device_Type));
532
533 kaddr = (long) lscsi_stat->Statistics.ForwardPointer;
534
535 if (SCSI_DAD_TYPE == lscsi_stat->inquiry_data.Periph_Device_Type)
536 cdisk++;
537 }
538 while (kscsi_stat_ptr_addr != kaddr);
539
540 if (cdisk != ndisks)
541 ERR_EXIT("Error counting disks");
542
543 return ndisks;
544 }
545
546
547
548 /* Called at the beginning to inquire how many bars are needed
549 */
550 int
551 num_bars(void)
552 {
553 int nf;
554 int errs;
555 int sz;
556 char *pgs = 0;
557
558 kmem = open("/dev/kmem", O_RDONLY);
559 if (-1 == kmem)
560 ERR_EXIT("opening /dev/kmem");
561
562 if (-1 == uname(&nodename))
563 ERR_EXIT("uname");
564
565 kernel_name = get_kernel_symbols(kmem, kernel_symbols);
566 if (!kernel_name)
567 return 0;
568
569 if (diskflag)
570 {
571 if (cpuflag)
572 fprintf(stderr, "Only disk or cpu state can be monitored\n");
573 state = DISK_STATE;
574 return init_disk_info();
575 }
576
577 return init_cpu_info();
578 }
579
580
581
582
583 /*
584 * Indicates how many levels each bar has. For most machines, each bar will
585 * have the same stuff. But one can, for instance, display memory use on one
586 * bar, processor levels on others, etc.
587 */
588 void
589 bar_items(nbars, items)
590 int nbars;
591 int items[]; /* nbars items in this */
592 {
593 int i;
594 int nlevels = (DISK_STATE == state) ? 2 : CPUSTATES;
595
596 for (i = 0; i < nbars; )
597 items[i++] = nlevels;
598 }
599
600
601 /* Called after num_bars to ask for bar names */
602 char **
603 label_cpu_bars(nbars)
604 {
605 char **names;
606 int hsz = strlen(nodename.nodename);
607 /***** ' ' '#' %d ' ' 'i486' ' ' *****/
608 int rowsz = hsz + 1 + 1 + 3 + 1 + 7 + 2;
609 int sz = nbars * rowsz;
610 int cpu, i;
611 char *cp;
612
613 shorten(nodename.nodename);
614
615 names = (char **)malloc(sz + sizeof(char *) * nbars);
616
617 cp = (char *)names + sizeof(char *) * nbars;
618
619 for (cpu = i = 0; i < kncpu; i++)
620 if (kcpu_infos[i].cpu_flag & CPU_EXISTS)
621 {
622 names[cpu++] = cp;
623
624 if (1 == ncpus)
625 sprintf(cp, "%s", nodename.nodename);
626 else if (0 == i)
627 sprintf(cp, "%s #%d", nodename.nodename, i);
628 else
629 sprintf(cp, "%*s #%d", hsz, "", i);
630
631 cp += rowsz;
632 }
633
634 return names;
635 }
636
637 char **
638 label_disk_bars(nbars)
639 {
640 char **names;
641 char *cp;
642 int i;
643 int hsz = sizeof("cxxxtxdxsx");
644
645 names = (char **) malloc( hsz * nbars + nbars * sizeof(char *) );
646 cp = (char *) names + sizeof(char *) * nbars;
647
648 for (i = 0; i < nbars; i++)
649 {
650 names[i] = cp;
651 lscsi_stat = kscsi_stat[i].di_kscsi;
652 strcpy(cp, diskname(&lscsi_stat->SCSI_device));
653 cp += hsz;
654 }
655
656 return names;
657 }
658
659
660 char **
661 label_bars(nbars)
662 {
663 switch (state)
664 {
665 case CPU_STATE: return label_cpu_bars(nbars);
666 case DISK_STATE: return label_disk_bars(nbars);
667 }
668
669 return NULL;
670 }
671
672
673 /* Called after the bars are created to do machine dependent inits */
674 void
675 init_bars(nbars)
676 int nbars;
677 {
678 (void) display_bars(nbars);
679 }
680
681
682
683
684 /*
685 This function is called every interval to compute and display
686 the bars. It should call draw_bar() with the bar number, the array of
687 integer values to display in the bar, and the number of values in the
688 array.
689 */
690 void
691 display_cpu_bars(nbars)
692 {
693 int states[NSTATES];
694 int nstates;
695 int cpu, i;
696 time_t *cputime = lastcpu;
697
698 for (i = cpu = 0; i < kncpu && cpu < nbars; i++)
699 {
700 if (0 == (kcpu_infos[i].cpu_flag & CPU_EXISTS))
701 continue;
702
703 nstates = 0;
704
705 if (kcpu_infos[i].cpu_flag & CPU_RUNNING && kpercpup[i])
706 {
707 if (kpercpup[cpu] != xpercpup[i])
708 { /* mapping changed or became available */
709 xpercpup[cpu] = kpercpup[i];
710 mypercpup[ i] = mapthis(kmem, xpercpup[cpu],
711 sizeof(*(xpercpup[cpu])));
712 }
713 states[nstates++] = delta(CPU_IDLE);
714 states[nstates++] = delta(CPU_USER);
715 states[nstates++] = delta(CPU_KERNEL);
716 states[nstates++] = delta(CPU_WAIT) + delta(CPU_SXBRK);
717 #if 0
718 states[nstates++] = delta(CPU_SXBRK);
719 #endif
720 }
721 else
722 {
723 states[nstates++] = 100; /* CPU_IDLE */
724 states[nstates++] = 0; /* CPU_USER */
725 states[nstates++] = 0; /* CPU_KERNEL */
726 states[nstates++] = 0; /* CPU_WAIT */
727 #if 0
728 states[nstates++] = 0; /* CPU_SXBRK */
729 #endif
730 }
731 savecpuinfo(cpu);
732 draw_bar(cpu, states, nstates);
733
734 cpu++;
735 cputime += CPU_STATE_SZ / sizeof(time_t);
736 }
737 }
738
739
740 void
741 display_disk_bars(nbars)
742 {
743 int states[2];
744 int i;
745 time_t t;
746 static time_t maxt = 0;
747 static int npr = 0;
748 time_t dlt;
749 struct iotime *new, *old;
750
751 new_lbolt = *lboltp;
752 dlt = new_lbolt - last_lbolt;
753 last_lbolt = new_lbolt;
754
755 for (i = 0; i < ndisks; i++)
756 {
757 lscsi_stat = kscsi_stat[i].di_kscsi;
758
759 if (kscsi_stat[i].di_dev != lscsi_stat->dev)
760 { /* device changed */
761 states[0] = 100; /* idle */
762 states[1] = 0; /* busy */
763 }
764 else
765 {
766 new = &lscsi_stat->Statistics.SCSI_Stats;
767 old = &kscsi_stat[i].di_stats.SCSI_Stats;
768 t = new->io_act - old->io_act;
769
770 states[1] = t;
771 if (states[1] > dlt)
772 states[0] = 0;
773 else
774 states[0] = dlt - states[1];
775
776 old->io_act = new->io_act;
777 old->io_resp = new->io_resp;
778 }
779 draw_bar(i, states, 2);
780 }
781 }
782
783 void
784 display_bars(nbars)
785 {
786 if (kmem_list)
787 refreshfakes();
788
789 switch (state)
790 {
791 case CPU_STATE: display_cpu_bars(nbars);
792 case DISK_STATE: display_disk_bars(nbars);
793 }
794
795 return;
796 }