4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 1994 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
30 #pragma ident "%Z%%M% %I% %E% SMI"
32 /* sadp.c 1.14.1.12 of 8/9/89 */
33 /* sadp.c - For VAX and PDP11 machines,
34 disk profiler profiles rp06, rm05 and general disk drives.
35 It reads system buffer header pool, physical buffer header
36 pool and swap buffer header pool once every second,
37 to examine disk drive's I/O queue.
38 For 3b20s system, it profiles the regular disk drives,
39 it reads the circular output queue for each drive
41 usage : sadp [-th][-d device[-drive]] s [n]
45 #include <sys/types.h>
46 #include <sys/param.h>
47 #include <sys/sysmacros.h>
60 #include <sys/utsname.h>
63 #include <sys/sysinfo.h>
67 * These includes are for dealing with scsi targets.
69 #include <sys/dditypes.h>
70 #include <sys/scsi/scsi.h>
71 #include <sys/scsi/conf/device.h>
72 #include <sys/scsi/targets/sddef.h>
75 /* cylinder profiling */
84 struct dk_geom dk_geom
;
87 #define PHYS_CYL dk_geom.dkg_pcyl
88 #define CHPERCYL (int)(PHYS_CYL/CHUNK) /*
89 * the number of CHUNK cylinder
92 #define SECTPERTRK (int)(dk_geom.dkg_nsect) /* sectors per track */
93 #define SECTPERCYL (SECTPERTRK * (int)(dk_geom.dkg_nhead))
94 #define ERR_BAD_DEV "Device %s is not defined, valid devices are: "
95 #define ERR_BAD_UNIT \
96 "Invalid drive specified for device %s, valid drives are: "
97 #define ERR_NO_DEV "Please specify a device type, valid devices are: "
98 #define DRVNUM(devname) strpbrk(devname, "0123456789")
100 #define cylin b_resid
102 #define SNDRIVE NDRIVE /* Not used */
103 #define MAX_HDISK_REP NDRIVE
104 #define MAXDRIVE 20 /* maximum number of configured disks */
105 #define NAMESIZE 10 /* size of device names */
108 struct nlist setup
[] = {
119 #define X1_DK_NDRIVE 4
133 #define X1_DK_READ 11
135 #define X1_DK_IVEC 12
137 #define X1_NUMSYMBOLS 13
139 #define X1_NUMSYMBOLS 4
144 void do_disk_stats ();
151 void validate_device ();
152 void validate_drive ();
155 void read_devinfo_names ();
158 void safe_kvm_read ();
160 #undef n_name /* to resolve conflict with <syms.h> */
161 #define MAXINTSIZE 12 /* sizeof "-2147483648" + 1 */
165 #define Debug if (debug)
166 #define dfprintf if (debug) fprintf
169 * FETCH_XYZ naming convention:
170 * X = I for nlist index, A for actual address
171 * Y = V for regular variable, A for array variable
172 * Z = L if length explicitly specified
175 #define FETCH_AAL(addr, var, len, vname)\
176 safe_kvm_read(kd, (unsigned long) addr, \
177 (char *) var, len, vname)
179 #define FETCH_IV(index, var)\
180 safe_kvm_read(kd, (unsigned long) setup[index].n_value, \
181 (char *) &var, sizeof (var), setup[index].n_name)
183 #define FETCH_IAL(index, var, len)\
184 safe_kvm_read(kd, (unsigned long)setup[index].n_value, \
185 (char *) var, len, setup[index].n_name)
190 * indicate whether all drives
191 * are implicitly specified
193 char *cmdname
= "sadp";
194 char device
[NAMESIZE
];
195 char dr_name
[NDRIVE
][NAMESIZE
];
199 long dk_busy
[NDRIVE
];
200 long dk_time
[NDRIVE
];
202 long dk_seek
[NDRIVE
];
203 long dk_xfer
[NDRIVE
];
204 long dk_read
[NDRIVE
];
209 struct buf bp
[2]; /* for swap buffers */
214 #define devnm dr_name
216 int fflg
, dflg
, tflg
, hflg
, errflg
;
225 int n1
, dleng
, dashb
, k
, devlen
;
230 int Sdrvlist
[SNDRIVE
]; /* SCSI */
249 static kvm_t
*kd
= NULL
;
250 struct scsi_device
*sdunits
[SD_MAXUNIT
];
251 struct scsi_device sdunit
[NDRIVE
];
252 int cyl_no
, prev_cyl_no
;
253 int cyl_bk
, prev_cyl_bk
;
254 int seek_dist
, seek_bk
;
256 int max_seek_dist
= 0;
266 char *ctime(), *stime
;
268 extern time_t time();
272 fail("sadp does not work yet -- no disk statistics in the kernel", 0);
274 while ((c
= getopt(argc
, argv
, "thd:")) != EOF
)
283 dleng
= strlen(optarg
);
286 * Controller types can be arbitrary length.
288 devlen
= strchr(optarg
, '-') ?
289 strchr(optarg
, '-') - optarg
: dleng
;
291 strncpy(device
, optarg
, devlen
);
293 if (dleng
== (devlen
+1)) {
297 if (dleng
> devlen
) {
298 for (i
= (devlen
+1), n1
= (devlen
+1); i
< dleng
; i
++){
300 if (optarg
[i
] == ','){
305 if (getdrvn() != 0) {
314 for (j
= dashb
; j
< dn
+1; j
++){
332 if (optarg
[i
] == '-'){
337 if (getdrvn() != 0) {
351 if (getdrvn() != 0) {
356 for (j
= dashb
; j
< dn
+1; j
++){
374 if (dleng
!= devlen
){
382 for (i
= 0; i
< MAX_HDISK_REP
; i
++)
394 fprintf (stderr
, "%s: errors in arguments\n", cmdname
);
399 * If no frequency arguments present, exit.
404 * If a non-dash field is presented as an argument,
405 * check if it is a numerical arg.
408 if (tstdigit(nopt
) != 0)
411 * For frequency arguments, if only s is presented , set n to 1
413 if ((optind
+1) == argc
) {
414 s
= atoi(argv
[optind
]);
418 * If both s and n are specified, check if
421 if ((optind
+1) < argc
) {
422 nopt
= argv
[optind
+ 1];
423 if (tstdigit(nopt
) != 0)
425 s
= atoi(argv
[optind
]);
426 n
= atoi(argv
[optind
+1]);
429 fail("bad value of s", 0);
431 fail("bad value of n", 0);
434 * Get entries defined in setup from /stand/unix
436 if ((kd
= kvm_open (NULL
, NULL
, NULL
, O_RDONLY
, "Bad kvm open"))
438 fail("kvm_open failed", 1);
440 dfprintf (stderr
, "main: successful kvm_open\n");
442 * Search name list to get offsets.
444 dfprintf (stderr
, "main: about to kvm_nlist\n");
445 if (kvm_nlist(kd
, setup
) == -1) {
446 fail("kvm_nlist failed", 1);
448 dfprintf (stderr
, "main: good nlist\n");
449 Debug
dump_nlist (setup
, "main");
452 * Initialize buffers and get disk info.
455 dfprintf (stderr
, "init_disk\n");
456 skdist
= (long *)calloc(dk_ndrive
, sizeof (long));
457 disk
= (long *)calloc(dk_ndrive
, sizeof (long));
460 * Make sure device and drive specified is legitimate.
463 dfprintf (stderr
, "validate_device\n");
465 dfprintf (stderr
, "validate_drive\n");
468 * Get storage from memory for sysbuf pool and physical buf pool
470 FETCH_IV (X1_V
, tbl
);
471 Debug
dump_v_struct (&tbl
);
472 sbuf
= malloc(sizeof (struct buf
) * tbl
.v_buf
);
474 fail("malloc of sbuf failed", 1);
475 phybuf
= malloc(sizeof (struct buf
) * tbl
.v_pbuf
);
477 fail("malloc of physbuf failed", 1);
480 * Determine the number of CHUNK cylinder chunks on the disk.
481 * This will be referenced as CHPERCYL.
484 dfprintf (stderr
, "init_geom\n");
488 FETCH_IAL(X1_DK_XFER
, dk
.dk_xfer
, dk_ndrive
*sizeof (long));
489 FETCH_IAL(X1_DK_READ
, dk
.dk_read
, dk_ndrive
*sizeof (long));
490 FETCH_IAL(X1_DK_SEEK
, dk
.dk_seek
, dk_ndrive
*sizeof (long));
491 FETCH_IAL(X1_DK_WDS
, dk
.dk_wds
, dk_ndrive
*sizeof (long));
492 FETCH_IAL(X1_DK_TIME
, dk
.dk_time
, dk_ndrive
*sizeof (long));
494 dfprintf (stderr
, "%s: ub %d\n", cmdname
, ub
);
496 * Get the list of scsi device pointers from kernel space.
498 FETCH_IAL(X1_SDUNITS
, sdunits
, SD_MAXUNIT
);
499 for (i
= 0; i
< SD_MAXUNIT
; i
++) {
500 dfprintf (stderr
, "sdunits[%d] 0x%x ", i
, (int)sdunits
[i
]);
502 dfprintf (stderr
, "\n");
503 for (k
= 0, i
= 0; k
< ub
; k
++) {
507 * Make sure that there is a scsi_device struct for
511 fprintf (stderr
, "%s: no valid scsi_device struct\n",
514 dfprintf (stderr
, "%s: read unit %d\n", cmdname
, k
);
516 * Read the scsi_device struct for the device.
518 FETCH_AAL(sdunits
[k
], &sdunit
[k
],
519 sizeof (struct scsi_device
), "sdunits");
520 dfprintf (stderr
, "%s: sd_private 0x%x\n",
521 cmdname
, (int)sdunit
[k
].sd_private
);
525 * Get current I/O count for each drive.
529 for (k
= 0, i
= 0; k
< ub
; k
++) {
532 for (j
= 0; j
< CHPERCYL
; j
++) {
542 * If no drives are selected or illegal drive number
543 * is specified, exit.
549 * Get i/o count for each disk.
552 for (k
= 0, i
= 0; k
< ub
; k
++) {
555 iocnt
[i
] = dk
.dk_xfer
[k
];
559 cyl_no
= 0; prev_cyl_no
= 0; cyl_bk
= 0; prev_cyl_bk
= 0; seek_dist
= 0;
563 * Take a snapshot of buffer header pool, swap
564 * buffer pool and physical buffer header.
568 * read system buffer header pool.
570 FETCH_IAL(X1_BUF
, sbuf
, tbl
.v_buf
*sizeof (struct buf
));
573 * Read physical buffer header pool.
575 FETCH_IAL(X1_PBUF
, phybuf
, tbl
.v_pbuf
*sizeof (struct buf
));
577 for (k
= 0, i
= 0; k
< ub
; k
++) {
580 do_disk_stats (i
, k
);
582 dfprintf (stderr
, "%s: i %d\n", cmdname
, i
);
585 /* TBD - get more samples */
592 * At the end of sampling, get the present I/O
593 * count, and system name.
598 * Print the report, there are two parts:
599 * cylinder profile, seeking distance profile.
601 curt
= time((long *) 0);
602 stime
= ctime (&curt
);
603 printf("\n\n%s\n", stime
);
604 printf("%s %s %s %s %s\n",
610 for (k
= 0, i
= 0; k
< ub
; k
++) {
613 for (j
= 0; j
< CHPERCYL
; j
++) {
614 disk
[i
] = disk
[i
] +dkcyl
[i
][j
];
615 skdist
[i
] = skdist
[i
] + skcyl
[i
][j
];
620 if ((tflg
== 0) && (hflg
== 0))
623 printf("\nCYLINDER ACCESS PROFILE\n");
624 for (k
= 0, i
= 0; k
< ub
; k
++) {
628 iocnt
[i
] = dk
.dk_xfer
[k
] - iocnt
[i
];
631 printf("Cylinders\tTransfers\n");
632 for (j
= 0; j
< CHPERCYL
; j
++) {
634 printf("%3d - %3d\t%ld\n",
635 j
*8, j
*8+7, dkcyl
[i
][j
]);
637 printf("\nSampled I/O = %ld, Actual I/O = %ld\n",
640 printf("Percentage of I/O sampled = %2.2f\n",
641 ((float)disk
[i
] /(float)iocnt
[i
]) * 100.0);
646 printf("\n\n\nSEEK DISTANCE PROFILE\n");
647 for (k
= 0, i
= 0; k
< ub
; k
++) {
653 printf("Seek Distance\tSeeks\n");
654 for (j
= 0; j
< CHPERCYL
; j
++)
656 if (skcyl
[i
][j
] > 0){
661 printf("%3d - %3d\t%ld\n",
662 j
*8-7, j
*8, skcyl
[i
][j
]);
664 printf("Total Seeks = %ld\n", skdist
[i
]);
670 for (k
= 0, i
= 0; k
< ub
; k
++) {
674 cylhdr(CYLNO
, disk
[i
]);
675 cylhist(disk
[i
], dkcyl
[i
]);
680 for (k
= 0, i
= 0; k
< ub
; k
++) {
684 cylhdr(SEEKD
, skdist
[i
]);
685 cylhist(skdist
[i
], skcyl
[i
]);
705 struct scsi_disk sddisk
[NDRIVE
];
707 struct buf buffer
, *bp
;
708 struct buf
*last_bp
= 0;
710 dfprintf (stderr
, "do_disk_stats (i %d, k %d)\n", i
, k
);
712 * In each scsi_device struct there is a sd_private
713 * pointer to a specialised scsi_disk struct which
714 * describes the disk.
717 FETCH_AAL(sdunit
[k
].sd_private
, &sddisk
[k
],
718 sizeof (struct scsi_disk
), "sdunit");
720 * The diskhd struct describing the active and waiting
721 * queues is embedded in the scsi_disk struct.
723 dp
= &sddisk
[k
].un_utab
;
724 Debug
dump_diskhd (dp
);
726 * The current SunOS sd.c driver uses the b_forw
727 * pointer for the currently active buffer, and the
728 * b_actf (av_forw) pointer for the waiting queue
731 dfprintf (stderr
, "%s: b_forw 0x%x\n", cmdname
, (int)dp
->b_forw
);
733 * Trace disk queue for I/O location, seek distance.
736 if (dp
->b_forw
== last_bp
) {
739 last_bp
= dp
->b_forw
;
741 dfprintf (stderr
, "%s: b_forw 0x%x\n",
742 cmdname
, (int)dp
->b_forw
);
743 FETCH_AAL(dp
->b_forw
, &buffer
, sizeof (struct buf
),
746 dfprintf (stderr
, "%s: b_lblkno 0x%x b_blkno 0x%x\n",
747 cmdname
, bp
->b_lblkno
, bp
->b_blkno
);
748 cyl_no
= bp
->b_blkno
/ SECTPERCYL
;
749 cyl_bk
= cyl_no
>> CHUNKSHIFT
;
750 seek_dist
= prev_cyl_no
- cyl_no
;
752 seek_dist
= -seek_dist
;
753 seek_bk
= prev_cyl_bk
- cyl_bk
;
756 prev_cyl_no
= cyl_no
;
757 prev_cyl_bk
= cyl_bk
;
758 if (cyl_no
> max_cyl_no
) {
761 if (seek_dist
> max_seek_dist
) {
762 max_seek_dist
= seek_dist
;
767 } while (dp
->b_forw
);
773 * Determine if the I/O is from system buffer pool,
774 * or swap buffer pool or physical buffer.
780 if ((temp1
< setup
[X1_BUF
].n_value
) || (index
> tbl
.v_buf
)){
781 index
= (int)(temp1
-setup
[X1_PBUF
].n_value
)/
782 (sizeof (struct buf
));
783 if (index
< tbl
.v_pbuf
){
788 /* TBD - Is it possible to access swap buffers on Sun? */
790 index
= (int)(temp1
-setup
[SWP
].n_value
)/
791 (sizeof (struct buf
));
804 * Verify the I/O, get the cylinder number.
808 register struct buf
*x
;
811 for (p
= 0; p
< index
; p
++, x
++)
813 if ((x
->b_flags
& B_BUSY
) &&
814 ((x
->b_flags
& B_DONE
) == 0)){
816 temp1
= (unsigned)x
->av_forw
;
826 if ((nonblk
== 0) && (ckbits((struct buf
*)sbuf
) != -1))
829 if ((nonblk
== 1) && (ckbits((struct buf
*)phybuf
) != -1))
835 ((bp
[m
].b_flags
& B_BUSY
) &&
836 ((bp
[m
].b_flags
& B_DONE
) == 0))){
838 temp1
= (unsigned)bp
[m
].av_forw
;
840 dfprintf (stderr
, "testdev -1\n");
846 dkcyl
[i
][temp
>> 3]++;
853 * Get drive number routine.
861 strcpy(drive
, empty
);
862 strncat(drive
, &optarg
[n1
], i
-n1
);
863 if (tstdigit(drive
) != 0)
879 fprintf(stderr
, "usage: sadp [-th][-d device[-drive]] s [n]\n");
888 while ((cc
= ss
[kk
]) != '\0'){
889 if (isdigit(cc
) == 0)
897 * The following routines are obtained from iostat.
899 * Output Cylinder Histogram.
904 register struct HISTDATA
*dp
;
908 long *graph
= (long *)calloc(CHPERCYL
, sizeof (long));
913 for (ii
= 0; ii
< CHPERCYL
; ii
++) {
914 dfprintf (stderr
, "(%d %d) ", ii
, (int)dp
->hdata
[ii
]);
916 dfprintf (stderr
, "\n");
918 for (ii
= 0; ii
< CHPERCYL
; ii
++) {
919 if (data
= dp
->hdata
[ii
]) {
924 } else if (data
> max2
&& data
!= max
)
930 /* determine scaling */
933 scale
= at
/ (max2
* 2);
938 for (ii
= 0; ii
< maxrow
; ii
++) {
940 graph
[ii
] = (scale
* 100 * dp
->hdata
[ii
]) / at
;
945 prthist(graph
, maxrow
, scale
, (long) (max
*100*scale
/at
));
951 prthist(array
, mrow
, scale
, gmax
)
952 long array
[], scale
, gmax
;
958 /* handle overflow in scaling */
961 printf("\n%2ld%% -|", gmax
/scale
);
962 pline(line
--, array
, mrow
, BLOB
);
963 printf("\n %c", BRK
);
964 pline(line
--, array
, mrow
, BRK
);
965 } else if (gmax
= 51)
968 if ((line
& 07) == 0) {
969 printf("\n%2ld%% -|", line
/scale
);
973 pline(line
--, array
, mrow
, BLOB
);
977 pline(line
, array
, mrow
, FOOT
);
981 * Print Histogram Line.
984 pline(line
, array
, mrow
, dot
)
994 "pline(line 0x%x, array 0x%x, mrow 0x%x, dot 0x%x)\n",
995 line
, array
, mrow
, dot
);
997 for (ii
= 0; ii
< mrow
; ii
++)
998 if (array
[ii
] < line
)
999 if (line
== 1 && array
[ii
] == 0)
1006 printf("%s", lbuff
);
1009 * Print Cylinder Profiling Headers.
1016 dfprintf (stderr
, "cylhdr(flag 0x%x, total 0x%x)\n", flag
, total
);
1020 printf("\nCYLINDER ACCESS HISTOGRAM\n");
1022 printf("\nSEEK DISTANCE HISTOGRAM\n");
1023 printf("\n%s-%d:\n",
1025 printf("Total %s = %ld\n",
1026 flag
== CYLNO
? "transfers" : "seeks", total
);
1030 /* Print Histogram Footers */
1037 char footer
[4][MAXCOL
];
1038 char digits
[] = "0123456789";
1039 int significant
= 0;
1041 dfprintf (stderr
, "cylftr(flag 0x%x)\n", flag
);
1043 printf("\n \t\t\tCylinder number, granularity=%d", CHUNK
);
1046 for (i
= 0; i
< 4; i
++) {
1047 for (col
= 0; col
< MAXCOL
- 1; col
++) {
1048 footer
[i
][col
] = ' ';
1050 footer
[i
][MAXCOL
- 1] = '\0';
1052 for (i
= 0, col
= 0; i
< (int)PHYS_CYL
;
1053 i
+= (chunk_mult
* CHUNK
), col
+= chunk_mult
, significant
= 0) {
1054 if ((i
/ 1000) > 0) {
1055 footer
[0][col
] = digits
[(i
/ 1000)];
1058 if ((significant
) || (((i
% 1000) / 100) > 0)) {
1059 footer
[1][col
] = digits
[((i
% 1000) / 100)];
1062 if ((significant
) || (((i
% 100) / 10) > 0)) {
1063 footer
[2][col
] = digits
[((i
% 100) / 10)];
1066 if ((i
== 0) || (significant
) || ((i
% 10) > 0)) {
1067 footer
[3][col
] = digits
[(i
% 10)];
1072 if (i
> (3 * CHUNK
)) {
1078 for (i
= 0; i
< 4; i
++) {
1079 printf (" %s\n", footer
[i
]);
1088 char tempdev
[NAMESIZE
];
1093 * No device specified, so default to the first
1094 * one if it is the only one, otherwise prompt
1095 * user to enter one.
1097 strcpy(device
, devnm
[0]);
1098 *DRVNUM(device
) = NULL
;
1099 devlen
= strlen(device
);
1100 for (i
= 0; i
< dk_ndrive
; i
++)
1103 bad_device(device
, ERR_NO_DEV
);
1108 * Device was specified. Make sure it matches
1109 * one that is configured in the system.
1111 for (i
= 0; i
< dk_ndrive
; i
++) {
1112 strncpy(tempdev
, devnm
[i
], DRVNUM(devnm
[i
])-devnm
[i
]);
1113 tempdev
[DRVNUM(devnm
[i
])-devnm
[i
]] = NULL
;
1114 if (strcmp(device
, tempdev
) == 0)
1118 bad_device(device
, ERR_BAD_DEV
);
1129 * For each controller number specified, make sure it exists
1130 * in the configured device list.
1132 for (i
= 0; i
< dk_ndrive
; i
++) {
1133 if (drvlist
[i
] == 0)
1137 * Since this controller number (i) was specified,
1138 * find the corresponding entry (j) in the device list.
1139 * If found, save the device list index in drvlist[].
1141 for (j
= 0; j
< dk_ndrive
; j
++) {
1142 if (strncmp(device
, devnm
[j
], devlen
) != 0)
1144 c
= atoi(DRVNUM(devnm
[j
]));
1147 * NOTE: saved value actual index+1
1148 * as entries with 0 imply don't care.
1150 drvlist
[i
] = j
+1; /* not a flag anymore! */
1157 * If not found, output error, except if all drives
1158 * were implied by only specifying controller type.
1159 * In this case, flag it as don't care.
1161 if (j
== dk_ndrive
) {
1165 bad_device(device
, ERR_BAD_UNIT
);
1173 char tempdev
[NAMESIZE
];
1176 * When the new device naming convention is in effect, switch to it
1178 #ifdef NEW_DEVICE_NAMES
1179 #define DEV_PREFIX "/dev/rdsk/"
1181 #define DEV_PREFIX "/dev/r"
1184 for (i
= 0; drvlist
[i
] == 0; i
++);
1185 sprintf(tempdev
, "%s%s%da", DEV_PREFIX
, device
, i
);
1186 if ((fd
= open(tempdev
, O_RDONLY
)) == -1)
1187 fail("open failed", 1);
1188 if (ioctl(fd
, DKIOCGGEOM
, &dk_geom
) == -1) {
1190 fail("ioctl failed", 1);
1195 * dk_geom structure now has data, and the number
1196 * of 8 cylinder chunks on the disk can now be
1197 * referenced via the CHPERCYL macro. So allocate
1198 * appropriate buffers based on this value.
1200 iocnt
= (long *)calloc(dk_ndrive
, sizeof (long));
1201 dkcyl
= (long **)calloc(dk_ndrive
, sizeof (long *));
1202 skcyl
= (long **)calloc(dk_ndrive
, sizeof (long *));
1203 for (i
= 0; i
< dk_ndrive
; i
++) {
1204 dkcyl
[i
] = (long *)calloc(CHPERCYL
, sizeof (long));
1205 skcyl
[i
] = (long *)calloc(CHPERCYL
, sizeof (long));
1210 * General routine for printing out an error message
1211 * when the specified device/drive is insufficient.
1214 bad_device(device
, errmsg
)
1220 char *p
, *p1
, **buf
;
1226 * Print usage statement if no device is specified.
1228 if (device
[0] == NULL
)
1232 * Compose a list of unique device controller types, or
1233 * unit numbers for a specified controller type, from
1234 * the complete device list.
1236 buf
= (char **)calloc(dk_ndrive
, sizeof (char *));
1237 for (i
= 0; i
< dk_ndrive
; i
++) {
1240 * Get controller type or unit
1243 p1
= DRVNUM(devnm
[i
]);
1244 if (!strcmp(errmsg
, ERR_BAD_UNIT
)) {
1245 if (strncmp(devnm
[i
], device
, devlen
))
1250 strncpy(s
, p
, p1
-p
);
1254 * Have we already logged this one as unique?
1255 * If not, then do so now.
1257 for (j
= 0; j
< unique
; j
++)
1258 if (!strcmp(s
, buf
[j
]))
1261 buf
[unique
++] = strdup(s
);
1265 * Invalid device was specified. Compose message containing
1266 * list of valid devices.
1268 msg
= (char *)malloc(strlen(errmsg
) +
1269 strlen(device
) + unique
*(NAMESIZE
+1) + 1);
1270 sprintf(msg
, errmsg
, device
);
1271 for (p
= msg
+ strlen(msg
), i
= 0; i
< unique
; i
++) {
1272 sprintf(p
, "%s ", buf
[i
]);
1273 p
+= (strlen(buf
[i
])+ 1);
1277 * Output the message and exit.
1283 * Code below here was taken from the SunOS 5.0 iostat command.
1289 read_devinfo_names()
1292 struct dk_ivec dkivec
[NDRIVE
];
1294 safe_kvm_read (kd
, nl_4c
[X1_DK_IVEC
].n_value
, dkivec
, sizeof dkivec
,
1296 for (i
= 0; i
< NDRIVE
; i
++) {
1297 if (dkivec
[i
].dk_name
) {
1298 safe_kvm_read (kd
, dkivec
[i
].dk_name
, dr_name
[i
], 2,
1300 sprintf(dr_name
[i
] + 2, "%d", dkivec
[i
].dk_unit
);
1313 for (i
= 0; i
< NDRIVE
; i
++) {
1319 * The default device names: dk#
1321 for (i
= 0; i
< dk_ndrive
; i
++) {
1323 (void) sprintf(buf
, "dk%d", i
);
1328 * Device names must be discovered in this program, and output
1329 * with its io data via the "sa" structure.
1332 read_devinfo_names();
1339 * issue failure message and exit
1342 fail(message
, doperror
)
1347 (void) kvm_close(kd
);
1350 fprintf(stderr
, "%s: ", cmdname
);
1353 fprintf(stderr
, "%s: %s\n", cmdname
, message
);
1358 safe_kvm_read(kd
, addr
, buf
, size
, who
)
1368 sprintf(errmsg
, "kvm_read of %s failed -- no address", who
);
1372 ret_code
= kvm_read(kd
, addr
, buf
, size
);
1373 if (ret_code
!= size
) {
1374 sprintf(errmsg
, "kvm_read of %s failed with code %d",
1381 * code for debugging dumps
1384 #include <sys/tuneable.h>
1385 #include <sys/var.h>
1386 #include <sys/file.h>
1387 #include <sys/vnode.h>
1388 #include <sys/stat.h>
1389 #include <sys/buf.h>
1390 #include <sys/fs/rf_acct.h>
1398 dfprintf (stderr
, "dump_diskhd: dp 0x%x\n", (int)dp
);
1399 dfprintf (stderr
, "flags\tb_forw\tb_back\tav_forw\tav_back\tb_bcount\n0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t%d\n",
1400 (int)dp
->b_flags
, (int)dp
->b_forw
, (int)dp
->b_back
,
1401 (int)dp
->av_forw
, (int)dp
->av_back
, (int)dp
->b_bcount
);
1406 dump_nlist (nlist
, str
)
1407 struct nlist nlist
[];
1412 for (i
= 0; nlist
[i
].n_name
; i
++) {
1413 dfprintf (stderr
, "%s: i %d n_name '%s' n_value 0x%x\n",
1414 str
, i
, nlist
[i
].n_name
, (int)nlist
[i
].n_value
);
1423 dfprintf (stderr
, "dump_v_struct: tbl 0x%x\n", (int)tbl
);
1424 dfprintf (stderr
, "v_buf\tv_call\tv_proc\tv_nglobpris\n%d\t%d\t%d\t%d\n",
1425 tbl
->v_buf
, tbl
->v_call
, tbl
->v_proc
, tbl
->v_nglobpris
);
1426 dfprintf (stderr
, "v_maxsyspri\tv_clist\tv_maxup\tv_hbuf\n%d\t\t%d\t%d\t%d\n",
1427 tbl
->v_maxsyspri
, tbl
->v_clist
, tbl
->v_maxup
, tbl
->v_hbuf
);
1428 dfprintf (stderr
, "v_hmask\tv_pbuf\tv_sptmap\tv_maxpmem\n0x%x\t%d\t%d\t\t%d\n",
1429 tbl
->v_hmask
, tbl
->v_pbuf
, tbl
->v_sptmap
, tbl
->v_maxpmem
);
1430 dfprintf (stderr
, "v_autoup\tv_bufhwm\n%d\t\t%d\n",
1431 tbl
->v_autoup
, tbl
->v_bufhwm
);
1436 dump_tblmap (tbl
, size
)
1442 dfprintf (stderr
, "tblmap size %d/4 = %d ", size
, size
/4);
1443 for (i
= 0; i
< size
/4; i
++) {
1444 dfprintf (stderr
, "tblmap[%d] %d ", i
, tbl
[i
]);
1446 dfprintf (stderr
, "\n");