PageRenderTime 58ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/usr/src/cmd/sa/sadp.c

https://bitbucket.org/nexenta/illumos-nexenta
C | 1449 lines | 1059 code | 137 blank | 253 comment | 265 complexity | 7fbf26be1c53d12354091697a6638995 MD5 | raw file
Possible License(s): LGPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, MPL-2.0-no-copyleft-exception, AGPL-1.0, GPL-3.0, LGPL-3.0, BSD-2-Clause, AGPL-3.0, BSD-3-Clause, GPL-2.0, LGPL-2.1, 0BSD
  1. /*
  2. * CDDL HEADER START
  3. *
  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
  7. * with the License.
  8. *
  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.
  13. *
  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]
  19. *
  20. * CDDL HEADER END
  21. */
  22. /*
  23. * Copyright 1994 Sun Microsystems, Inc. All rights reserved.
  24. * Use is subject to license terms.
  25. */
  26. /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
  27. /* All Rights Reserved */
  28. #pragma ident "%Z%%M% %I% %E% SMI"
  29. /* sadp.c 1.14.1.12 of 8/9/89 */
  30. /* sadp.c - For VAX and PDP11 machines,
  31. disk profiler profiles rp06, rm05 and general disk drives.
  32. It reads system buffer header pool, physical buffer header
  33. pool and swap buffer header pool once every second,
  34. to examine disk drive's I/O queue.
  35. For 3b20s system, it profiles the regular disk drives,
  36. it reads the circular output queue for each drive
  37. once every second.
  38. usage : sadp [-th][-d device[-drive]] s [n]
  39. */
  40. #include <stdio.h>
  41. #include <sys/types.h>
  42. #include <sys/param.h>
  43. #include <sys/sysmacros.h>
  44. #include <sys/buf.h>
  45. #include <sys/elog.h>
  46. #include <nlist.h>
  47. #include <string.h>
  48. #include <fcntl.h>
  49. #include <sys/dkio.h>
  50. #ifdef FIXME
  51. #include <sys/dk.h>
  52. #endif
  53. #include <time.h>
  54. #include <sys/utsname.h>
  55. #include <sys/var.h>
  56. #include <ctype.h>
  57. #include <sys/sysinfo.h>
  58. #include <kvm.h>
  59. /*
  60. * These includes are for dealing with scsi targets.
  61. */
  62. #include <sys/dditypes.h>
  63. #include <sys/scsi/scsi.h>
  64. #include <sys/scsi/conf/device.h>
  65. #include <sys/scsi/targets/sddef.h>
  66. /* cylinder profiling */
  67. #define BLANK ' '
  68. #define BLOB '*'
  69. #define TRACE '.'
  70. #define BRK '='
  71. #define FOOT '-'
  72. #define CYLNO 1
  73. #define SEEKD 2
  74. struct dk_geom dk_geom;
  75. #define CHUNK 16
  76. #define CHUNKSHIFT 4
  77. #define PHYS_CYL dk_geom.dkg_pcyl
  78. #define CHPERCYL (int)(PHYS_CYL/CHUNK) /*
  79. * the number of CHUNK cylinder
  80. * chunks on a disk
  81. */
  82. #define SECTPERTRK (int)(dk_geom.dkg_nsect) /* sectors per track */
  83. #define SECTPERCYL (SECTPERTRK * (int)(dk_geom.dkg_nhead))
  84. #define ERR_BAD_DEV "Device %s is not defined, valid devices are: "
  85. #define ERR_BAD_UNIT \
  86. "Invalid drive specified for device %s, valid drives are: "
  87. #define ERR_NO_DEV "Please specify a device type, valid devices are: "
  88. #define DRVNUM(devname) strpbrk(devname, "0123456789")
  89. #define cylin b_resid
  90. #define NDRIVE 10
  91. #define SNDRIVE NDRIVE /* Not used */
  92. #define MAX_HDISK_REP NDRIVE
  93. #define MAXDRIVE 20 /* maximum number of configured disks */
  94. #define NAMESIZE 10 /* size of device names */
  95. struct nlist setup[] = {
  96. #define X1_V 0
  97. {"v"},
  98. #define X1_BUF 1
  99. {"buf"},
  100. #define X1_PBUF 2
  101. {"pbuf"},
  102. #define X1_SDUNITS 3
  103. {"sdunits"},
  104. #ifdef FIXME
  105. #define X1_DK_NDRIVE 4
  106. {"dk_ndrive"},
  107. #define X1_DK_BUSY 5
  108. {"dk_busy"},
  109. #define X1_DK_TIME 6
  110. {"dk_time"},
  111. #define X1_DK_SEEK 7
  112. {"dk_seek"},
  113. #define X1_DK_XFER 8
  114. {"dk_xfer"},
  115. #define X1_DK_WDS 9
  116. {"dk_wds"},
  117. #define X1_DK_BPS 10
  118. {"dk_bps"},
  119. #define X1_DK_READ 11
  120. {"dk_read"},
  121. #define X1_DK_IVEC 12
  122. {"dk_ivec"},
  123. #define X1_NUMSYMBOLS 13
  124. #else
  125. #define X1_NUMSYMBOLS 4
  126. #endif
  127. {0}
  128. };
  129. void do_disk_stats ();
  130. void usage ();
  131. void prthist ();
  132. void pline ();
  133. void cylhdr ();
  134. void cylftr ();
  135. void cylhist ();
  136. void validate_device ();
  137. void validate_drive ();
  138. void init_geom ();
  139. void bad_device ();
  140. void read_devinfo_names ();
  141. void fail ();
  142. void init_disk ();
  143. void safe_kvm_read ();
  144. #undef n_name /* to resolve conflict with <syms.h> */
  145. #define MAXINTSIZE 12 /* sizeof "-2147483648" + 1 */
  146. int debug = 1;
  147. #define Debug if (debug)
  148. #define dfprintf if (debug) fprintf
  149. /*
  150. * FETCH_XYZ naming convention:
  151. * X = I for nlist index, A for actual address
  152. * Y = V for regular variable, A for array variable
  153. * Z = L if length explicitly specified
  154. */
  155. #define FETCH_AAL(addr, var, len, vname)\
  156. safe_kvm_read(kd, (unsigned long) addr, \
  157. (char *) var, len, vname)
  158. #define FETCH_IV(index, var)\
  159. safe_kvm_read(kd, (unsigned long) setup[index].n_value, \
  160. (char *) &var, sizeof (var), setup[index].n_name)
  161. #define FETCH_IAL(index, var, len)\
  162. safe_kvm_read(kd, (unsigned long)setup[index].n_value, \
  163. (char *) var, len, setup[index].n_name)
  164. int dk_ndrive;
  165. int ndrives;
  166. int all = 0; /*
  167. * indicate whether all drives
  168. * are implicitly specified
  169. */
  170. char *cmdname = "sadp";
  171. char device[NAMESIZE];
  172. char dr_name[NDRIVE][NAMESIZE];
  173. long dk_bps[NDRIVE];
  174. struct {
  175. long dk_busy[NDRIVE];
  176. long dk_time[NDRIVE];
  177. long dk_wds[NDRIVE];
  178. long dk_seek[NDRIVE];
  179. long dk_xfer[NDRIVE];
  180. long dk_read[NDRIVE];
  181. } dk;
  182. struct var tbl;
  183. char *sbuf, *phybuf;
  184. struct buf bp[2]; /* for swap buffers */
  185. int nonblk;
  186. int index;
  187. int index1;
  188. unsigned temp1;
  189. #define devnm dr_name
  190. int fflg, dflg, tflg, hflg, errflg;
  191. int s, n, ct;
  192. static int ub = 8;
  193. int sdist;
  194. int m;
  195. int dev;
  196. int temp;
  197. int f;
  198. int i;
  199. int n1, dleng, dashb, k, devlen;
  200. int dashf;
  201. int dn;
  202. int drvlist[NDRIVE];
  203. int Sdrvlist[SNDRIVE]; /* SCSI */
  204. struct HISTDATA {
  205. long hdata[1];
  206. };
  207. struct utsname name;
  208. char *nopt;
  209. char empty[30];
  210. char drive[30];
  211. char *malloc();
  212. int SCSI; /* SCSI */
  213. int ALL;
  214. long lseek();
  215. long **dkcyl;
  216. long **skcyl;
  217. long *iocnt;
  218. static kvm_t *kd = NULL;
  219. struct scsi_device *sdunits[SD_MAXUNIT];
  220. struct scsi_device sdunit[NDRIVE];
  221. int cyl_no, prev_cyl_no;
  222. int cyl_bk, prev_cyl_bk;
  223. int seek_dist, seek_bk;
  224. int max_cyl_no = 0;
  225. int max_seek_dist = 0;
  226. main(argc, argv)
  227. int argc;
  228. char **argv;
  229. {
  230. unsigned sleep();
  231. extern int optind;
  232. extern char *optarg;
  233. int c, j;
  234. char *ctime(), *stime;
  235. long curt;
  236. extern time_t time();
  237. long *skdist;
  238. long *disk;
  239. fail("sadp does not work yet -- no disk statistics in the kernel", 0);
  240. while ((c = getopt(argc, argv, "thd:")) != EOF)
  241. switch (c) {
  242. case 't':
  243. tflg++;
  244. break;
  245. case 'h':
  246. hflg++;
  247. break;
  248. case 'd':
  249. dleng = strlen(optarg);
  250. /*
  251. * Controller types can be arbitrary length.
  252. */
  253. devlen = strchr(optarg, '-') ?
  254. strchr(optarg, '-') - optarg : dleng;
  255. SCSI = 0;
  256. strncpy(device, optarg, devlen);
  257. if (dleng == (devlen+1)) {
  258. errflg++;
  259. break;
  260. }
  261. if (dleng > devlen) {
  262. for (i = (devlen+1), n1 = (devlen+1); i < dleng; i++){
  263. if (optarg[i] == ','){
  264. if (n1 == i){
  265. errflg++;
  266. break;
  267. }
  268. if (getdrvn() != 0) {
  269. errflg++;
  270. break;
  271. }
  272. if (dashf != 0) {
  273. if (dashb >= dn){
  274. errflg++;
  275. break;
  276. }
  277. for (j = dashb; j < dn+1; j++){
  278. if (SCSI) /* SCSI */
  279. Sdrvlist[j] = 1;
  280. else
  281. drvlist[j] = 1;
  282. }
  283. dashb = 0;
  284. dashf = 0;
  285. }
  286. else
  287. {
  288. if (SCSI)
  289. Sdrvlist[dn] = 1;
  290. else
  291. drvlist[dn] = 1;
  292. }
  293. n1 = i+1;
  294. } else {
  295. if (optarg[i] == '-'){
  296. if (dashf != 0) {
  297. errflg++;
  298. break;
  299. }
  300. if (getdrvn() != 0) {
  301. errflg++;
  302. break;
  303. }
  304. if (SCSI)
  305. Sdrvlist[dn] = 1;
  306. else
  307. drvlist[dn] = 1;
  308. dashb = dn;
  309. dashf = 1;
  310. n1 = i+1;
  311. } else {
  312. if (i == dleng-1){
  313. i++;
  314. if (getdrvn() != 0) {
  315. errflg++;
  316. break;
  317. }
  318. if (dashf != 0)
  319. for (j = dashb; j < dn+1; j++){
  320. if (SCSI)
  321. Sdrvlist[j] = 1;
  322. else
  323. drvlist[j] = 1;
  324. }
  325. else
  326. {
  327. if (SCSI)
  328. Sdrvlist[dn] = 1;
  329. else
  330. drvlist[dn] = 1;
  331. }
  332. }
  333. }
  334. }
  335. }
  336. } else {
  337. if (dleng != devlen){
  338. errflg++;
  339. break;
  340. }
  341. all++;
  342. if (SCSI)
  343. ALL++;
  344. else
  345. for (i = 0; i < MAX_HDISK_REP; i++)
  346. drvlist[i] = 1;
  347. }
  348. if (errflg)
  349. break;
  350. dflg++;
  351. break;
  352. case '?':
  353. errflg++;
  354. break;
  355. }
  356. if (errflg) {
  357. fprintf (stderr, "%s: errors in arguments\n", cmdname);
  358. usage();
  359. }
  360. /*
  361. * If no frequency arguments present, exit.
  362. */
  363. if (optind == argc)
  364. usage();
  365. /*
  366. * If a non-dash field is presented as an argument,
  367. * check if it is a numerical arg.
  368. */
  369. nopt = argv[optind];
  370. if (tstdigit(nopt) != 0)
  371. usage();
  372. /*
  373. * For frequency arguments, if only s is presented , set n to 1
  374. */
  375. if ((optind +1) == argc) {
  376. s = atoi(argv[optind]);
  377. n = 1;
  378. }
  379. /*
  380. * If both s and n are specified, check if
  381. * arg n is numeric.
  382. */
  383. if ((optind +1) < argc) {
  384. nopt = argv[optind + 1];
  385. if (tstdigit(nopt) != 0)
  386. usage();
  387. s = atoi(argv[optind]);
  388. n = atoi(argv[optind+1]);
  389. }
  390. if (s <= 0)
  391. fail("bad value of s", 0);
  392. if (n <= 0)
  393. fail("bad value of n", 0);
  394. ct = s;
  395. /*
  396. * Get entries defined in setup from /stand/unix
  397. */
  398. if ((kd = kvm_open (NULL, NULL, NULL, O_RDONLY, "Bad kvm open"))
  399. == NULL)
  400. fail("kvm_open failed", 1);
  401. dfprintf (stderr, "main: successful kvm_open\n");
  402. /*
  403. * Search name list to get offsets.
  404. */
  405. dfprintf (stderr, "main: about to kvm_nlist\n");
  406. if (kvm_nlist(kd, setup) == -1) {
  407. fail("kvm_nlist failed", 1);
  408. }
  409. dfprintf (stderr, "main: good nlist\n");
  410. Debug dump_nlist (setup, "main");
  411. /*
  412. * Initialize buffers and get disk info.
  413. */
  414. init_disk();
  415. dfprintf (stderr, "init_disk\n");
  416. skdist = (long *)calloc(dk_ndrive, sizeof (long));
  417. disk = (long *)calloc(dk_ndrive, sizeof (long));
  418. /*
  419. * Make sure device and drive specified is legitimate.
  420. */
  421. validate_device();
  422. dfprintf (stderr, "validate_device\n");
  423. validate_drive();
  424. dfprintf (stderr, "validate_drive\n");
  425. /*
  426. * Get storage from memory for sysbuf pool and physical buf pool
  427. */
  428. FETCH_IV (X1_V, tbl);
  429. Debug dump_v_struct (&tbl);
  430. sbuf = malloc(sizeof (struct buf) * tbl.v_buf);
  431. if (sbuf == NULL)
  432. fail("malloc of sbuf failed", 1);
  433. phybuf = malloc(sizeof (struct buf) * tbl.v_pbuf);
  434. if (phybuf == NULL)
  435. fail("malloc of physbuf failed", 1);
  436. /*
  437. * Determine the number of CHUNK cylinder chunks on the disk.
  438. * This will be referenced as CHPERCYL.
  439. */
  440. init_geom();
  441. dfprintf (stderr, "init_geom\n");
  442. ub = dk_ndrive;
  443. #ifdef FIXME
  444. FETCH_IAL(X1_DK_XFER, dk.dk_xfer, dk_ndrive*sizeof (long));
  445. FETCH_IAL(X1_DK_READ, dk.dk_read, dk_ndrive*sizeof (long));
  446. FETCH_IAL(X1_DK_SEEK, dk.dk_seek, dk_ndrive*sizeof (long));
  447. FETCH_IAL(X1_DK_WDS, dk.dk_wds, dk_ndrive*sizeof (long));
  448. FETCH_IAL(X1_DK_TIME, dk.dk_time, dk_ndrive*sizeof (long));
  449. #endif
  450. dfprintf (stderr, "%s: ub %d\n", cmdname, ub);
  451. /*
  452. * Get the list of scsi device pointers from kernel space.
  453. */
  454. FETCH_IAL(X1_SDUNITS, sdunits, SD_MAXUNIT);
  455. for (i = 0; i < SD_MAXUNIT; i++) {
  456. dfprintf (stderr, "sdunits[%d] 0x%x ", i, (int)sdunits[i]);
  457. }
  458. dfprintf (stderr, "\n");
  459. for (k = 0, i = 0; k < ub; k++) {
  460. if (drvlist[k] == 0)
  461. continue;
  462. /*
  463. * Make sure that there is a scsi_device struct for
  464. * the chosen device.
  465. */
  466. if (!sdunits[k]) {
  467. fprintf (stderr, "%s: no valid scsi_device struct\n",
  468. cmdname);
  469. }
  470. dfprintf (stderr, "%s: read unit %d\n", cmdname, k);
  471. /*
  472. * Read the scsi_device struct for the device.
  473. */
  474. FETCH_AAL(sdunits[k], &sdunit[k],
  475. sizeof (struct scsi_device), "sdunits");
  476. dfprintf (stderr, "%s: sd_private 0x%x\n",
  477. cmdname, (int)sdunit[k].sd_private);
  478. }
  479. /*
  480. * Get current I/O count for each drive.
  481. */
  482. for (;;) {
  483. s = ct;
  484. for (k = 0, i = 0; k < ub; k++) {
  485. if (drvlist[k] == 0)
  486. continue;
  487. for (j = 0; j < CHPERCYL; j++) {
  488. dkcyl[i][j] = 0;
  489. skcyl[i][j] = 0;
  490. }
  491. iocnt[i] = 0;
  492. disk[i] = 0;
  493. skdist[i] = 0;
  494. i++;
  495. }
  496. /*
  497. * If no drives are selected or illegal drive number
  498. * is specified, exit.
  499. */
  500. if (i == 0)
  501. usage();
  502. /*
  503. * Get i/o count for each disk.
  504. */
  505. for (k = 0, i = 0; k < ub; k++) {
  506. if (drvlist[k] == 0)
  507. continue;
  508. iocnt[i] = dk.dk_xfer[k];
  509. i++;
  510. }
  511. cyl_no = 0; prev_cyl_no = 0; cyl_bk = 0; prev_cyl_bk = 0; seek_dist = 0;
  512. for (;;) {
  513. /*
  514. * Take a snapshot of buffer header pool, swap
  515. * buffer pool and physical buffer header.
  516. */
  517. /*
  518. * read system buffer header pool.
  519. */
  520. FETCH_IAL(X1_BUF, sbuf, tbl.v_buf*sizeof (struct buf));
  521. /*
  522. * Read physical buffer header pool.
  523. */
  524. FETCH_IAL(X1_PBUF, phybuf, tbl.v_pbuf*sizeof (struct buf));
  525. for (k = 0, i = 0; k < ub; k++) {
  526. if (drvlist[k] == 0)
  527. continue;
  528. do_disk_stats (i, k);
  529. i++;
  530. dfprintf (stderr, "%s: i %d\n", cmdname, i);
  531. }
  532. /* TBD - get more samples */
  533. if (--s)
  534. sleep(1);
  535. else {
  536. /*
  537. * At the end of sampling, get the present I/O
  538. * count, and system name.
  539. */
  540. uname(&name);
  541. /*
  542. * Print the report, there are two parts:
  543. * cylinder profile, seeking distance profile.
  544. */
  545. curt = time((long *) 0);
  546. stime = ctime (&curt);
  547. printf("\n\n%s\n", stime);
  548. printf("%s %s %s %s %s\n",
  549. name.sysname,
  550. name.nodename,
  551. name.release,
  552. name.version,
  553. name.machine);
  554. for (k = 0, i = 0; k < ub; k++) {
  555. if (drvlist[k] == 0)
  556. continue;
  557. for (j = 0; j < CHPERCYL; j++) {
  558. disk[i] = disk[i] +dkcyl[i][j];
  559. skdist[i] = skdist[i] + skcyl[i][j];
  560. }
  561. i++;
  562. }
  563. if ((tflg == 0) && (hflg == 0))
  564. tflg = 1;
  565. if (tflg){
  566. printf("\nCYLINDER ACCESS PROFILE\n");
  567. for (k = 0, i = 0; k < ub; k++) {
  568. if (drvlist[k] == 0)
  569. continue;
  570. if (disk[i] != 0){
  571. iocnt[i] = dk.dk_xfer[k] - iocnt[i];
  572. printf("\n%s-%d:\n",
  573. device, k);
  574. printf("Cylinders\tTransfers\n");
  575. for (j = 0; j < CHPERCYL; j++) {
  576. if (dkcyl[i][j] > 0)
  577. printf("%3d - %3d\t%ld\n",
  578. j*8, j*8+7, dkcyl[i][j]);
  579. }
  580. printf("\nSampled I/O = %ld, Actual I/O = %ld\n",
  581. disk[i], iocnt[i]);
  582. if (iocnt[i] > 0)
  583. printf("Percentage of I/O sampled = %2.2f\n",
  584. ((float)disk[i] /(float)iocnt[i]) * 100.0);
  585. }
  586. i++;
  587. }
  588. printf("\n\n\nSEEK DISTANCE PROFILE\n");
  589. for (k = 0, i = 0; k < ub; k++) {
  590. if (drvlist[k] == 0)
  591. continue;
  592. if (skdist[i] != 0){
  593. printf("\n%s-%d:\n",
  594. device, k);
  595. printf("Seek Distance\tSeeks\n");
  596. for (j = 0; j < CHPERCYL; j++)
  597. if (skcyl[i][j] > 0){
  598. if (j == 0)
  599. printf(" 0\t%ld\n",
  600. skcyl[i][j]);
  601. else
  602. printf("%3d - %3d\t%ld\n",
  603. j*8-7, j*8, skcyl[i][j]);
  604. }
  605. printf("Total Seeks = %ld\n", skdist[i]);
  606. }
  607. i++;
  608. }
  609. }
  610. if (hflg){
  611. for (k = 0, i = 0; k < ub; k++) {
  612. if (drvlist[k] == 0)
  613. continue;
  614. if (disk[i] != 0) {
  615. cylhdr(CYLNO, disk[i]);
  616. cylhist(disk[i], dkcyl[i]);
  617. cylftr(CYLNO);
  618. }
  619. i++;
  620. }
  621. for (k = 0, i = 0; k < ub; k++) {
  622. if (drvlist[k] == 0)
  623. continue;
  624. if (skdist[i] != 0){
  625. cylhdr(SEEKD, skdist[i]);
  626. cylhist(skdist[i], skcyl[i]);
  627. cylftr(SEEKD);
  628. }
  629. i++;
  630. }
  631. }
  632. break;
  633. }
  634. }
  635. if (--n)
  636. continue;
  637. exit(0);
  638. }
  639. }
  640. void
  641. do_disk_stats (i, k)
  642. {
  643. #ifdef fixed
  644. struct scsi_disk sddisk[NDRIVE];
  645. struct diskhd *dp;
  646. struct buf buffer, *bp;
  647. struct buf *last_bp = 0;
  648. dfprintf (stderr, "do_disk_stats (i %d, k %d)\n", i, k);
  649. /*
  650. * In each scsi_device struct there is a sd_private
  651. * pointer to a specialised scsi_disk struct which
  652. * describes the disk.
  653. */
  654. do {
  655. FETCH_AAL(sdunit[k].sd_private, &sddisk[k],
  656. sizeof (struct scsi_disk), "sdunit");
  657. /*
  658. * The diskhd struct describing the active and waiting
  659. * queues is embedded in the scsi_disk struct.
  660. */
  661. dp = &sddisk[k].un_utab;
  662. Debug dump_diskhd (dp);
  663. /*
  664. * The current SunOS sd.c driver uses the b_forw
  665. * pointer for the currently active buffer, and the
  666. * b_actf (av_forw) pointer for the waiting queue
  667. * of buffers.
  668. */
  669. dfprintf (stderr, "%s: b_forw 0x%x\n", cmdname, (int)dp->b_forw);
  670. /*
  671. * Trace disk queue for I/O location, seek distance.
  672. */
  673. if (dp->b_forw) {
  674. if (dp->b_forw == last_bp) {
  675. continue;
  676. } else {
  677. last_bp = dp->b_forw;
  678. }
  679. dfprintf (stderr, "%s: b_forw 0x%x\n",
  680. cmdname, (int)dp->b_forw);
  681. FETCH_AAL(dp->b_forw, &buffer, sizeof (struct buf),
  682. "b_forw");
  683. bp = &buffer;
  684. dfprintf (stderr, "%s: b_lblkno 0x%x b_blkno 0x%x\n",
  685. cmdname, bp->b_lblkno, bp->b_blkno);
  686. cyl_no = bp->b_blkno / SECTPERCYL;
  687. cyl_bk = cyl_no >> CHUNKSHIFT;
  688. seek_dist = prev_cyl_no - cyl_no;
  689. if (seek_dist < 0)
  690. seek_dist = -seek_dist;
  691. seek_bk = prev_cyl_bk - cyl_bk;
  692. if (seek_bk < 0)
  693. seek_bk = -seek_bk;
  694. prev_cyl_no = cyl_no;
  695. prev_cyl_bk = cyl_bk;
  696. if (cyl_no > max_cyl_no) {
  697. max_cyl_no = cyl_no;
  698. }
  699. if (seek_dist > max_seek_dist) {
  700. max_seek_dist = seek_dist;
  701. }
  702. skcyl[i][seek_bk]++;
  703. dkcyl[i][cyl_bk]++;
  704. }
  705. } while (dp->b_forw);
  706. #endif
  707. }
  708. /*
  709. * Determine if the I/O is from system buffer pool,
  710. * or swap buffer pool or physical buffer.
  711. */
  712. int
  713. testbuf()
  714. {
  715. if ((temp1 < setup[X1_BUF].n_value) || (index > tbl.v_buf)){
  716. index = (int)(temp1 -setup[X1_PBUF].n_value)/
  717. (sizeof (struct buf));
  718. if (index < tbl.v_pbuf){
  719. nonblk = 1;
  720. return (0);
  721. }
  722. /* TBD - Is it possible to access swap buffers on Sun? */
  723. #ifndef sun
  724. index = (int)(temp1 -setup[SWP].n_value)/
  725. (sizeof (struct buf));
  726. if (index < NSWP) {
  727. m = index;
  728. nonblk = 2;
  729. return (0);
  730. }
  731. #endif
  732. return (-1);
  733. }
  734. return (0);
  735. }
  736. /*
  737. * Verify the I/O, get the cylinder number.
  738. */
  739. ckbits(x)
  740. register struct buf *x;
  741. {
  742. register p;
  743. for (p = 0; p < index; p++, x++)
  744. continue;
  745. if ((x->b_flags & B_BUSY) &&
  746. ((x->b_flags & B_DONE) == 0)){
  747. temp = x->cylin;
  748. temp1 = (unsigned)x->av_forw;
  749. return (0);
  750. }
  751. else
  752. return (-1);
  753. }
  754. int
  755. testdev()
  756. {
  757. if ((nonblk == 0) && (ckbits((struct buf *)sbuf) != -1))
  758. goto endtest;
  759. else {
  760. if ((nonblk == 1) && (ckbits((struct buf *)phybuf) != -1))
  761. goto endtest;
  762. else {
  763. if ((nonblk == 2) &&
  764. ((bp[m].b_flags & B_BUSY) &&
  765. ((bp[m].b_flags & B_DONE) == 0))){
  766. temp = bp[m].cylin;
  767. temp1 = (unsigned)bp[m].av_forw;
  768. } else {
  769. dfprintf (stderr, "testdev -1\n");
  770. return (-1);
  771. }
  772. }
  773. }
  774. endtest:
  775. dkcyl[i][temp >> 3]++;
  776. return (0);
  777. }
  778. /*
  779. * Get drive number routine.
  780. */
  781. getdrvn()
  782. {
  783. extern char *optarg;
  784. char *strcpy();
  785. char *strncat();
  786. strcpy(drive, empty);
  787. strncat(drive, &optarg[n1], i-n1);
  788. if (tstdigit(drive) != 0)
  789. return (-1);
  790. dn = atoi(drive);
  791. if (SCSI) {
  792. if (dn >= SNDRIVE)
  793. return (-1);
  794. } else {
  795. if (dn >= NDRIVE)
  796. return (-1);
  797. }
  798. return (0);
  799. }
  800. void
  801. usage()
  802. {
  803. fprintf(stderr, "usage: sadp [-th][-d device[-drive]] s [n]\n");
  804. exit(1);
  805. }
  806. int tstdigit(ss)
  807. char *ss;
  808. {
  809. int kk, cc;
  810. kk = 0;
  811. while ((cc = ss[kk]) != '\0'){
  812. if (isdigit(cc) == 0)
  813. return (-1);
  814. kk++;
  815. }
  816. return (0);
  817. }
  818. /*
  819. * The following routines are obtained from iostat.
  820. *
  821. * Output Cylinder Histogram.
  822. */
  823. void
  824. cylhist(at, dp)
  825. long at;
  826. register struct HISTDATA *dp;
  827. {
  828. register ii;
  829. int maxrow;
  830. long *graph = (long *)calloc(CHPERCYL, sizeof (long));
  831. long max, max2;
  832. long data;
  833. long scale;
  834. for (ii = 0; ii < CHPERCYL; ii++) {
  835. dfprintf (stderr, "(%d %d) ", ii, (int)dp->hdata[ii]);
  836. }
  837. dfprintf (stderr, "\n");
  838. max = 0;
  839. for (ii = 0; ii < CHPERCYL; ii++) {
  840. if (data = dp->hdata[ii]) {
  841. maxrow = ii;
  842. if (data > max) {
  843. max2 = max;
  844. max = data;
  845. } else if (data > max2 && data != max)
  846. max2 = data;
  847. }
  848. }
  849. maxrow++;
  850. /* determine scaling */
  851. scale = 1;
  852. if (max2) {
  853. scale = at / (max2 * 2);
  854. if (scale > 48)
  855. scale = 48;
  856. }
  857. for (ii = 0; ii < maxrow; ii++) {
  858. if (dp->hdata[ii])
  859. graph[ii] = (scale * 100 * dp->hdata[ii]) / at;
  860. else
  861. graph[ii] = -1;
  862. }
  863. prthist(graph, maxrow, scale, (long) (max*100*scale/at));
  864. }
  865. /*
  866. * Print Histogram.
  867. */
  868. void
  869. prthist(array, mrow, scale, gmax)
  870. long array[], scale, gmax;
  871. register mrow;
  872. {
  873. long line;
  874. line = 50;
  875. /* handle overflow in scaling */
  876. if (gmax > 51) {
  877. line = 52;
  878. printf("\n%2ld%% -|", gmax/scale);
  879. pline(line--, array, mrow, BLOB);
  880. printf("\n %c", BRK);
  881. pline(line--, array, mrow, BRK);
  882. } else if (gmax = 51)
  883. line = 51;
  884. while (line > 0) {
  885. if ((line & 07) == 0) {
  886. printf("\n%2ld%% -|", line/scale);
  887. } else {
  888. printf("\n |");
  889. }
  890. pline(line--, array, mrow, BLOB);
  891. }
  892. printf("\n 0%% -+");
  893. line = -1;
  894. pline(line, array, mrow, FOOT);
  895. }
  896. /*
  897. * Print Histogram Line.
  898. */
  899. void
  900. pline(line, array, mrow, dot)
  901. long line, array[];
  902. int mrow;
  903. char dot;
  904. {
  905. register ii;
  906. register char *lp;
  907. char lbuff[132];
  908. dfprintf (stderr,
  909. "pline(line 0x%x, array 0x%x, mrow 0x%x, dot 0x%x)\n",
  910. line, array, mrow, dot);
  911. lp = lbuff;
  912. for (ii = 0; ii < mrow; ii++)
  913. if (array[ii] < line)
  914. if (line == 1 && array[ii] == 0)
  915. *lp++ = TRACE;
  916. else
  917. *lp++ = BLANK;
  918. else
  919. *lp++ = dot;
  920. *lp++ = 0;
  921. printf("%s", lbuff);
  922. }
  923. /*
  924. * Print Cylinder Profiling Headers.
  925. */
  926. void
  927. cylhdr(flag, total)
  928. long total;
  929. {
  930. dfprintf (stderr, "cylhdr(flag 0x%x, total 0x%x)\n", flag, total);
  931. if (fflg)
  932. printf("\014\n");
  933. if (flag == CYLNO)
  934. printf("\nCYLINDER ACCESS HISTOGRAM\n");
  935. if (flag == SEEKD)
  936. printf("\nSEEK DISTANCE HISTOGRAM\n");
  937. printf("\n%s-%d:\n",
  938. device, k);
  939. printf("Total %s = %ld\n",
  940. flag == CYLNO ? "transfers" : "seeks", total);
  941. }
  942. #define MAXCOL 80
  943. /* Print Histogram Footers */
  944. void
  945. cylftr(flag)
  946. {
  947. int i;
  948. int chunk_mult = 1;
  949. int col;
  950. char footer[4][MAXCOL];
  951. char digits[] = "0123456789";
  952. int significant = 0;
  953. dfprintf (stderr, "cylftr(flag 0x%x)\n", flag);
  954. if (flag == CYLNO)
  955. printf("\n \t\t\tCylinder number, granularity=%d", CHUNK);
  956. else
  957. printf("\n =<< ");
  958. for (i = 0; i < 4; i++) {
  959. for (col = 0; col < MAXCOL - 1; col++) {
  960. footer[i][col] = ' ';
  961. }
  962. footer[i][MAXCOL - 1] = '\0';
  963. }
  964. for (i = 0, col = 0; i < (int)PHYS_CYL;
  965. i += (chunk_mult * CHUNK), col += chunk_mult, significant = 0) {
  966. if ((i / 1000) > 0) {
  967. footer[0][col] = digits[(i / 1000)];
  968. significant = 1;
  969. }
  970. if ((significant) || (((i % 1000) / 100) > 0)) {
  971. footer[1][col] = digits[((i % 1000) / 100)];
  972. significant = 1;
  973. }
  974. if ((significant) || (((i % 100) / 10) > 0)) {
  975. footer[2][col] = digits[((i % 100) / 10)];
  976. significant = 1;
  977. }
  978. if ((i == 0) || (significant) || ((i % 10) > 0)) {
  979. footer[3][col] = digits[(i % 10)];
  980. }
  981. if (i > CHUNK) {
  982. chunk_mult = 2;
  983. }
  984. if (i > (3 * CHUNK)) {
  985. chunk_mult = 4;
  986. if (flag != CYLNO)
  987. printf ("< ");
  988. }
  989. }
  990. for (i = 0; i < 4; i++) {
  991. printf (" %s\n", footer[i]);
  992. }
  993. printf ("\n");
  994. }
  995. void
  996. validate_device()
  997. {
  998. int i;
  999. char tempdev[NAMESIZE];
  1000. if (dflg == 0) {
  1001. /*
  1002. * No device specified, so default to the first
  1003. * one if it is the only one, otherwise prompt
  1004. * user to enter one.
  1005. */
  1006. strcpy(device, devnm[0]);
  1007. *DRVNUM(device) = NULL;
  1008. devlen = strlen(device);
  1009. for (i = 0; i < dk_ndrive; i++)
  1010. drvlist[i] = 1;
  1011. if (dk_ndrive > 1)
  1012. bad_device(device, ERR_NO_DEV);
  1013. dev = 0;
  1014. } else {
  1015. /*
  1016. * Device was specified. Make sure it matches
  1017. * one that is configured in the system.
  1018. */
  1019. for (i = 0; i < dk_ndrive; i++) {
  1020. strncpy(tempdev, devnm[i], DRVNUM(devnm[i])-devnm[i]);
  1021. tempdev[DRVNUM(devnm[i])-devnm[i]] = NULL;
  1022. if (strcmp(device, tempdev) == 0)
  1023. break;
  1024. }
  1025. if (i == dk_ndrive)
  1026. bad_device(device, ERR_BAD_DEV);
  1027. dev = i;
  1028. }
  1029. }
  1030. void
  1031. validate_drive()
  1032. {
  1033. int i, j, c;
  1034. /*
  1035. * For each controller number specified, make sure it exists
  1036. * in the configured device list.
  1037. */
  1038. for (i = 0; i < dk_ndrive; i++) {
  1039. if (drvlist[i] == 0)
  1040. continue;
  1041. /*
  1042. * Since this controller number (i) was specified,
  1043. * find the corresponding entry (j) in the device list.
  1044. * If found, save the device list index in drvlist[].
  1045. */
  1046. for (j = 0; j < dk_ndrive; j++) {
  1047. if (strncmp(device, devnm[j], devlen) != 0)
  1048. continue;
  1049. c = atoi(DRVNUM(devnm[j]));
  1050. if (c == i) {
  1051. /*
  1052. * NOTE: saved value actual index+1
  1053. * as entries with 0 imply don't care.
  1054. */
  1055. drvlist[i] = j+1; /* not a flag anymore! */
  1056. break;
  1057. }
  1058. }
  1059. /*
  1060. * If not found, output error, except if all drives
  1061. * were implied by only specifying controller type.
  1062. * In this case, flag it as don't care.
  1063. */
  1064. if (j == dk_ndrive) {
  1065. if (all)
  1066. drvlist[i] = 0;
  1067. else
  1068. bad_device(device, ERR_BAD_UNIT);
  1069. }
  1070. }
  1071. }
  1072. void
  1073. init_geom()
  1074. {
  1075. char tempdev[NAMESIZE];
  1076. int i, fd;
  1077. /*
  1078. * When the new device naming convention is in effect, switch to it
  1079. */
  1080. #ifdef NEW_DEVICE_NAMES
  1081. #define DEV_PREFIX "/dev/rdsk/"
  1082. #else
  1083. #define DEV_PREFIX "/dev/r"
  1084. #endif
  1085. for (i = 0; drvlist[i] == 0; i++);
  1086. sprintf(tempdev, "%s%s%da", DEV_PREFIX, device, i);
  1087. if ((fd = open(tempdev, O_RDONLY)) == -1)
  1088. fail("open failed", 1);
  1089. if (ioctl(fd, DKIOCGGEOM, &dk_geom) == -1) {
  1090. close(fd);
  1091. fail("ioctl failed", 1);
  1092. }
  1093. close(fd);
  1094. /*
  1095. * dk_geom structure now has data, and the number
  1096. * of 8 cylinder chunks on the disk can now be
  1097. * referenced via the CHPERCYL macro. So allocate
  1098. * appropriate buffers based on this value.
  1099. */
  1100. iocnt = (long *)calloc(dk_ndrive, sizeof (long));
  1101. dkcyl = (long **)calloc(dk_ndrive, sizeof (long *));
  1102. skcyl = (long **)calloc(dk_ndrive, sizeof (long *));
  1103. for (i = 0; i < dk_ndrive; i++) {
  1104. dkcyl[i] = (long *)calloc(CHPERCYL, sizeof (long));
  1105. skcyl[i] = (long *)calloc(CHPERCYL, sizeof (long));
  1106. }
  1107. }
  1108. /*
  1109. * General routine for printing out an error message
  1110. * when the specified device/drive is insufficient.
  1111. */
  1112. void
  1113. bad_device(device, errmsg)
  1114. char *device;
  1115. char *errmsg;
  1116. {
  1117. int i, j;
  1118. int unique = 0;
  1119. char *p, *p1, **buf;
  1120. char s[NAMESIZE];
  1121. char *msg;
  1122. /*
  1123. * Print usage statement if no device is specified.
  1124. */
  1125. if (device[0] == NULL)
  1126. usage();
  1127. /*
  1128. * Compose a list of unique device controller types, or
  1129. * unit numbers for a specified controller type, from
  1130. * the complete device list.
  1131. */
  1132. buf = (char **)calloc(dk_ndrive, sizeof (char *));
  1133. for (i = 0; i < dk_ndrive; i++) {
  1134. /*
  1135. * Get controller type or unit
  1136. */
  1137. p = devnm[i];
  1138. p1 = DRVNUM(devnm[i]);
  1139. if (!strcmp(errmsg, ERR_BAD_UNIT)) {
  1140. if (strncmp(devnm[i], device, devlen))
  1141. continue;
  1142. p = p1;
  1143. p1++;
  1144. }
  1145. strncpy(s, p, p1-p);
  1146. s[p1-p] = NULL;
  1147. /*
  1148. * Have we already logged this one as unique?
  1149. * If not, then do so now.
  1150. */
  1151. for (j = 0; j < unique; j++)
  1152. if (!strcmp(s, buf[j]))
  1153. break;
  1154. if (j == unique)
  1155. buf[unique++] = strdup(s);
  1156. }
  1157. /*
  1158. * Invalid device was specified. Compose message containing
  1159. * list of valid devices.
  1160. */
  1161. msg = (char *)malloc(strlen(errmsg) +
  1162. strlen(device) + unique*(NAMESIZE+1) + 1);
  1163. sprintf(msg, errmsg, device);
  1164. for (p = msg + strlen(msg), i = 0; i < unique; i++) {
  1165. sprintf(p, "%s ", buf[i]);
  1166. p += (strlen(buf[i])+ 1);
  1167. }
  1168. /*
  1169. * Output the message and exit.
  1170. */
  1171. fail(msg, 0);
  1172. }
  1173. /*
  1174. * Code below here was taken from the SunOS 5.0 iostat command.
  1175. */
  1176. #ifdef FIXME
  1177. void
  1178. read_devinfo_names()
  1179. {
  1180. int i;
  1181. struct dk_ivec dkivec[NDRIVE];
  1182. safe_kvm_read (kd, nl_4c[X1_DK_IVEC].n_value, dkivec, sizeof dkivec,
  1183. "dk_ivec");
  1184. for (i = 0; i < NDRIVE; i++) {
  1185. if (dkivec[i].dk_name) {
  1186. safe_kvm_read (kd, dkivec[i].dk_name, dr_name[i], 2,
  1187. "dk_name");
  1188. sprintf(dr_name[i] + 2, "%d", dkivec[i].dk_unit);
  1189. }
  1190. }
  1191. }
  1192. #endif
  1193. void
  1194. init_disk()
  1195. {
  1196. #ifdef FIXME
  1197. int i;
  1198. for (i = 0; i < NDRIVE; i++) {
  1199. dr_select[i] = 0;
  1200. dk_bps[i] = 0;
  1201. }
  1202. /*
  1203. * The default device names: dk#
  1204. */
  1205. for (i = 0; i < dk_ndrive; i++) {
  1206. dr_name[i] = buf;
  1207. (void) sprintf(buf, "dk%d", i);
  1208. buf += NAMESIZE;
  1209. }
  1210. /*
  1211. * Device names must be discovered in this program, and output
  1212. * with its io data via the "sa" structure.
  1213. */
  1214. read_devinfo_names();
  1215. #else
  1216. return;
  1217. #endif
  1218. }
  1219. /*
  1220. * issue failure message and exit
  1221. */
  1222. void
  1223. fail(message, doperror)
  1224. char *message;
  1225. int doperror;
  1226. {
  1227. if (kd != NULL)
  1228. (void) kvm_close(kd);
  1229. if (doperror) {
  1230. fprintf(stderr, "%s: ", cmdname);
  1231. perror(message);
  1232. }
  1233. fprintf(stderr, "%s: %s\n", cmdname, message);
  1234. exit(2);
  1235. }
  1236. void
  1237. safe_kvm_read(kd, addr, buf, size, who)
  1238. kvm_t *kd;
  1239. unsigned long addr;
  1240. char *buf;
  1241. unsigned size;
  1242. {
  1243. int ret_code;
  1244. char errmsg[100];
  1245. if (addr == 0) {
  1246. sprintf(errmsg, "kvm_read of %s failed -- no address", who);
  1247. fail(errmsg, 0);
  1248. }
  1249. ret_code = kvm_read(kd, addr, buf, size);
  1250. if (ret_code != size) {
  1251. sprintf(errmsg, "kvm_read of %s failed with code %d",
  1252. who, ret_code);
  1253. fail(errmsg, 0);
  1254. }
  1255. }
  1256. /*
  1257. * code for debugging dumps
  1258. */
  1259. #include <sys/tuneable.h>
  1260. #include <sys/var.h>
  1261. #include <sys/file.h>
  1262. #include <sys/vnode.h>
  1263. #include <sys/stat.h>
  1264. #include <sys/buf.h>
  1265. #include <sys/fs/rf_acct.h>
  1266. int dump_iodev ();
  1267. dump_diskhd (dp)
  1268. struct diskhd *dp;
  1269. {
  1270. dfprintf (stderr, "dump_diskhd: dp 0x%x\n", (int)dp);
  1271. 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",
  1272. (int)dp->b_flags, (int)dp->b_forw, (int)dp->b_back,
  1273. (int)dp->av_forw, (int)dp->av_back, (int)dp->b_bcount);
  1274. return (0);
  1275. }
  1276. dump_nlist (nlist, str)
  1277. struct nlist nlist[];
  1278. char *str;
  1279. {
  1280. int i;
  1281. for (i = 0; nlist[i].n_name; i++) {
  1282. dfprintf (stderr, "%s: i %d n_name '%s' n_value 0x%x\n",
  1283. str, i, nlist[i].n_name, (int)nlist[i].n_value);
  1284. }
  1285. return (0);
  1286. }
  1287. dump_v_struct (tbl)
  1288. struct var *tbl;
  1289. {
  1290. dfprintf (stderr, "dump_v_struct: tbl 0x%x\n", (int)tbl);
  1291. dfprintf (stderr, "v_buf\tv_call\tv_proc\tv_nglobpris\n%d\t%d\t%d\t%d\n",
  1292. tbl->v_buf, tbl->v_call, tbl->v_proc, tbl->v_nglobpris);
  1293. dfprintf (stderr, "v_maxsyspri\tv_clist\tv_maxup\tv_hbuf\n%d\t\t%d\t%d\t%d\n",
  1294. tbl->v_maxsyspri, tbl->v_clist, tbl->v_maxup, tbl->v_hbuf);
  1295. dfprintf (stderr, "v_hmask\tv_pbuf\tv_sptmap\tv_maxpmem\n0x%x\t%d\t%d\t\t%d\n",
  1296. tbl->v_hmask, tbl->v_pbuf, tbl->v_sptmap, tbl->v_maxpmem);
  1297. dfprintf (stderr, "v_autoup\tv_bufhwm\n%d\t\t%d\n",
  1298. tbl->v_autoup, tbl->v_bufhwm);
  1299. return (0);
  1300. }
  1301. dump_tblmap (tbl, size)
  1302. int *tbl;
  1303. int size;
  1304. {
  1305. int i;
  1306. dfprintf (stderr, "tblmap size %d/4 = %d ", size, size/4);
  1307. for (i = 0; i < size/4; i++) {
  1308. dfprintf (stderr, "tblmap[%d] %d ", i, tbl[i]);
  1309. }
  1310. dfprintf (stderr, "\n");
  1311. return (0);
  1312. }