1113287Sphk/*- 2113287Sphk * Copyright (c) 2003 Poul-Henning Kamp 3113287Sphk * All rights reserved. 4113287Sphk * 5113287Sphk * Redistribution and use in source and binary forms, with or without 6113287Sphk * modification, are permitted provided that the following conditions 7113287Sphk * are met: 8113287Sphk * 1. Redistributions of source code must retain the above copyright 9113287Sphk * notice, this list of conditions and the following disclaimer. 10113287Sphk * 2. Redistributions in binary form must reproduce the above copyright 11113287Sphk * notice, this list of conditions and the following disclaimer in the 12113287Sphk * documentation and/or other materials provided with the distribution. 13113287Sphk * 3. The names of the authors may not be used to endorse or promote 14113287Sphk * products derived from this software without specific prior written 15113287Sphk * permission. 16113287Sphk * 17113287Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18113287Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19113287Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20113287Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21113287Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22113287Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23113287Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24113287Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25113287Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26113287Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27113287Sphk * SUCH DAMAGE. 28113287Sphk * 29113287Sphk * $FreeBSD: stable/10/usr.sbin/diskinfo/diskinfo.c 313103 2017-02-02 19:50:28Z asomers $ 30113287Sphk */ 31113287Sphk 32113287Sphk#include <stdio.h> 33113287Sphk#include <stdint.h> 34127884Sphk#include <stdlib.h> 35224250Smav#include <strings.h> 36113287Sphk#include <unistd.h> 37113287Sphk#include <errno.h> 38113287Sphk#include <fcntl.h> 39129679Spjd#include <libutil.h> 40113287Sphk#include <paths.h> 41113287Sphk#include <err.h> 42113287Sphk#include <sys/disk.h> 43223089Sgibbs#include <sys/param.h> 44127884Sphk#include <sys/time.h> 45113287Sphk 46113287Sphkstatic void 47113287Sphkusage(void) 48113287Sphk{ 49140058Sru fprintf(stderr, "usage: diskinfo [-ctv] disk ...\n"); 50113287Sphk exit (1); 51113287Sphk} 52113287Sphk 53137456Ssosstatic int opt_c, opt_t, opt_v; 54113287Sphk 55127884Sphkstatic void speeddisk(int fd, off_t mediasize, u_int sectorsize); 56137456Ssosstatic void commandtime(int fd, off_t mediasize, u_int sectorsize); 57113287Sphk 58113287Sphkint 59113287Sphkmain(int argc, char **argv) 60113287Sphk{ 61218432Sdelphij int i, ch, fd, error, exitval = 0; 62223089Sgibbs char buf[BUFSIZ], ident[DISK_IDENT_SIZE], physpath[MAXPATHLEN]; 63200968Smav off_t mediasize, stripesize, stripeoffset; 64113287Sphk u_int sectorsize, fwsectors, fwheads; 65113287Sphk 66137456Ssos while ((ch = getopt(argc, argv, "ctv")) != -1) { 67113287Sphk switch (ch) { 68137456Ssos case 'c': 69137456Ssos opt_c = 1; 70137456Ssos opt_v = 1; 71137456Ssos break; 72113287Sphk case 't': 73113287Sphk opt_t = 1; 74113287Sphk opt_v = 1; 75113287Sphk break; 76113287Sphk case 'v': 77113287Sphk opt_v = 1; 78113287Sphk break; 79113287Sphk default: 80113287Sphk usage(); 81113287Sphk } 82113287Sphk } 83113287Sphk argc -= optind; 84113287Sphk argv += optind; 85113287Sphk 86127610Sru if (argc < 1) 87127610Sru usage(); 88127610Sru 89113287Sphk for (i = 0; i < argc; i++) { 90113287Sphk fd = open(argv[i], O_RDONLY); 91113287Sphk if (fd < 0 && errno == ENOENT && *argv[i] != '/') { 92313103Sasomers snprintf(buf, BUFSIZ, "%s%s", _PATH_DEV, argv[i]); 93113287Sphk fd = open(buf, O_RDONLY); 94113287Sphk } 95218432Sdelphij if (fd < 0) { 96218432Sdelphij warn("%s", argv[i]); 97313103Sasomers exit(1); 98218432Sdelphij } 99113287Sphk error = ioctl(fd, DIOCGMEDIASIZE, &mediasize); 100218432Sdelphij if (error) { 101232738Strasz warnx("%s: ioctl(DIOCGMEDIASIZE) failed, probably not a disk.", argv[i]); 102218432Sdelphij exitval = 1; 103218432Sdelphij goto out; 104218432Sdelphij } 105113287Sphk error = ioctl(fd, DIOCGSECTORSIZE, §orsize); 106218432Sdelphij if (error) { 107232738Strasz warnx("%s: ioctl(DIOCGSECTORSIZE) failed, probably not a disk.", argv[i]); 108218432Sdelphij exitval = 1; 109218432Sdelphij goto out; 110218432Sdelphij } 111113287Sphk error = ioctl(fd, DIOCGFWSECTORS, &fwsectors); 112113287Sphk if (error) 113113287Sphk fwsectors = 0; 114113287Sphk error = ioctl(fd, DIOCGFWHEADS, &fwheads); 115113287Sphk if (error) 116113287Sphk fwheads = 0; 117200968Smav error = ioctl(fd, DIOCGSTRIPESIZE, &stripesize); 118200968Smav if (error) 119200968Smav stripesize = 0; 120200968Smav error = ioctl(fd, DIOCGSTRIPEOFFSET, &stripeoffset); 121200968Smav if (error) 122200968Smav stripeoffset = 0; 123113287Sphk if (!opt_v) { 124113287Sphk printf("%s", argv[i]); 125113287Sphk printf("\t%u", sectorsize); 126113287Sphk printf("\t%jd", (intmax_t)mediasize); 127113287Sphk printf("\t%jd", (intmax_t)mediasize/sectorsize); 128200968Smav printf("\t%jd", (intmax_t)stripesize); 129200968Smav printf("\t%jd", (intmax_t)stripeoffset); 130113287Sphk if (fwsectors != 0 && fwheads != 0) { 131113287Sphk printf("\t%jd", (intmax_t)mediasize / 132113287Sphk (fwsectors * fwheads * sectorsize)); 133113287Sphk printf("\t%u", fwheads); 134113287Sphk printf("\t%u", fwsectors); 135113287Sphk } 136113287Sphk } else { 137129712Spjd humanize_number(buf, 5, (int64_t)mediasize, "", 138129679Spjd HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 139113287Sphk printf("%s\n", argv[i]); 140113287Sphk printf("\t%-12u\t# sectorsize\n", sectorsize); 141129679Spjd printf("\t%-12jd\t# mediasize in bytes (%s)\n", 142129679Spjd (intmax_t)mediasize, buf); 143113287Sphk printf("\t%-12jd\t# mediasize in sectors\n", 144113287Sphk (intmax_t)mediasize/sectorsize); 145200968Smav printf("\t%-12jd\t# stripesize\n", stripesize); 146200968Smav printf("\t%-12jd\t# stripeoffset\n", stripeoffset); 147113287Sphk if (fwsectors != 0 && fwheads != 0) { 148113287Sphk printf("\t%-12jd\t# Cylinders according to firmware.\n", (intmax_t)mediasize / 149113287Sphk (fwsectors * fwheads * sectorsize)); 150113287Sphk printf("\t%-12u\t# Heads according to firmware.\n", fwheads); 151113287Sphk printf("\t%-12u\t# Sectors according to firmware.\n", fwsectors); 152113287Sphk } 153196799Spjd if (ioctl(fd, DIOCGIDENT, ident) == 0) 154169296Spjd printf("\t%-12s\t# Disk ident.\n", ident); 155223089Sgibbs if (ioctl(fd, DIOCGPHYSPATH, physpath) == 0) 156223089Sgibbs printf("\t%-12s\t# Physical path\n", physpath); 157113287Sphk } 158113287Sphk printf("\n"); 159137456Ssos if (opt_c) 160137456Ssos commandtime(fd, mediasize, sectorsize); 161113287Sphk if (opt_t) 162127884Sphk speeddisk(fd, mediasize, sectorsize); 163218432Sdelphijout: 164113287Sphk close(fd); 165113287Sphk } 166218432Sdelphij exit (exitval); 167113287Sphk} 168113287Sphk 169113287Sphk 170113287Sphkstatic char sector[65536]; 171113287Sphkstatic char mega[1024 * 1024]; 172113287Sphk 173113287Sphkstatic void 174224250Smavrdsect(int fd, off_t blockno, u_int sectorsize) 175113287Sphk{ 176113287Sphk int error; 177113287Sphk 178313103Sasomers if (lseek(fd, (off_t)blockno * sectorsize, SEEK_SET) == -1) 179313103Sasomers err(1, "lseek"); 180113287Sphk error = read(fd, sector, sectorsize); 181232738Strasz if (error == -1) 182232738Strasz err(1, "read"); 183127884Sphk if (error != (int)sectorsize) 184232738Strasz errx(1, "disk too small for test."); 185113287Sphk} 186113287Sphk 187113287Sphkstatic void 188113287Sphkrdmega(int fd) 189113287Sphk{ 190113287Sphk int error; 191113287Sphk 192113287Sphk error = read(fd, mega, sizeof(mega)); 193232738Strasz if (error == -1) 194232738Strasz err(1, "read"); 195113287Sphk if (error != sizeof(mega)) 196232738Strasz errx(1, "disk too small for test."); 197113287Sphk} 198113287Sphk 199113287Sphkstatic struct timeval tv1, tv2; 200113287Sphk 201113287Sphkstatic void 202113287SphkT0(void) 203113287Sphk{ 204113287Sphk 205113287Sphk fflush(stdout); 206113287Sphk sync(); 207113287Sphk sleep(1); 208113287Sphk sync(); 209113287Sphk sync(); 210113287Sphk gettimeofday(&tv1, NULL); 211113287Sphk} 212113287Sphk 213113287Sphkstatic void 214113287SphkTN(int count) 215113287Sphk{ 216113287Sphk double dt; 217113287Sphk 218113287Sphk gettimeofday(&tv2, NULL); 219113287Sphk dt = (tv2.tv_usec - tv1.tv_usec) / 1e6; 220113287Sphk dt += (tv2.tv_sec - tv1.tv_sec); 221113287Sphk printf("%5d iter in %10.6f sec = %8.3f msec\n", 222113287Sphk count, dt, dt * 1000.0 / count); 223113287Sphk} 224113287Sphk 225113287Sphkstatic void 226113287SphkTR(double count) 227113287Sphk{ 228113287Sphk double dt; 229113287Sphk 230113287Sphk gettimeofday(&tv2, NULL); 231113287Sphk dt = (tv2.tv_usec - tv1.tv_usec) / 1e6; 232113287Sphk dt += (tv2.tv_sec - tv1.tv_sec); 233113287Sphk printf("%8.0f kbytes in %10.6f sec = %8.0f kbytes/sec\n", 234113287Sphk count, dt, count / dt); 235113287Sphk} 236113287Sphk 237113287Sphkstatic void 238127884Sphkspeeddisk(int fd, off_t mediasize, u_int sectorsize) 239113287Sphk{ 240224250Smav int bulk, i; 241224250Smav off_t b0, b1, sectorcount, step; 242113287Sphk 243113287Sphk sectorcount = mediasize / sectorsize; 244313103Sasomers if (sectorcount <= 0) 245313103Sasomers return; /* Can't test devices with no sectors */ 246313103Sasomers 247224250Smav step = 1ULL << (flsll(sectorcount / (4 * 200)) - 1); 248224250Smav if (step > 16384) 249224250Smav step = 16384; 250224250Smav bulk = mediasize / (1024 * 1024); 251224250Smav if (bulk > 100) 252224250Smav bulk = 100; 253113287Sphk 254113287Sphk printf("Seek times:\n"); 255113287Sphk printf("\tFull stroke:\t"); 256113287Sphk b0 = 0; 257224250Smav b1 = sectorcount - step; 258113287Sphk T0(); 259113287Sphk for (i = 0; i < 125; i++) { 260113287Sphk rdsect(fd, b0, sectorsize); 261224250Smav b0 += step; 262113287Sphk rdsect(fd, b1, sectorsize); 263224250Smav b1 -= step; 264113287Sphk } 265113287Sphk TN(250); 266113287Sphk 267113287Sphk printf("\tHalf stroke:\t"); 268113287Sphk b0 = sectorcount / 4; 269113287Sphk b1 = b0 + sectorcount / 2; 270113287Sphk T0(); 271113287Sphk for (i = 0; i < 125; i++) { 272113287Sphk rdsect(fd, b0, sectorsize); 273224250Smav b0 += step; 274113287Sphk rdsect(fd, b1, sectorsize); 275224250Smav b1 += step; 276113287Sphk } 277113287Sphk TN(250); 278113287Sphk printf("\tQuarter stroke:\t"); 279113287Sphk b0 = sectorcount / 4; 280113287Sphk b1 = b0 + sectorcount / 4; 281113287Sphk T0(); 282113287Sphk for (i = 0; i < 250; i++) { 283113287Sphk rdsect(fd, b0, sectorsize); 284224250Smav b0 += step; 285113287Sphk rdsect(fd, b1, sectorsize); 286224250Smav b1 += step; 287113287Sphk } 288113287Sphk TN(500); 289113287Sphk 290113287Sphk printf("\tShort forward:\t"); 291113287Sphk b0 = sectorcount / 2; 292113287Sphk T0(); 293113295Sphk for (i = 0; i < 400; i++) { 294113287Sphk rdsect(fd, b0, sectorsize); 295224250Smav b0 += step; 296113287Sphk } 297113295Sphk TN(400); 298113287Sphk 299113287Sphk printf("\tShort backward:\t"); 300113287Sphk b0 = sectorcount / 2; 301113287Sphk T0(); 302113295Sphk for (i = 0; i < 400; i++) { 303113287Sphk rdsect(fd, b0, sectorsize); 304224250Smav b0 -= step; 305113287Sphk } 306113295Sphk TN(400); 307113287Sphk 308113287Sphk printf("\tSeq outer:\t"); 309113287Sphk b0 = 0; 310113287Sphk T0(); 311113295Sphk for (i = 0; i < 2048; i++) { 312113287Sphk rdsect(fd, b0, sectorsize); 313113287Sphk b0++; 314113287Sphk } 315113295Sphk TN(2048); 316113287Sphk 317113287Sphk printf("\tSeq inner:\t"); 318224250Smav b0 = sectorcount - 2048; 319113287Sphk T0(); 320113295Sphk for (i = 0; i < 2048; i++) { 321113287Sphk rdsect(fd, b0, sectorsize); 322113287Sphk b0++; 323113287Sphk } 324113295Sphk TN(2048); 325113287Sphk 326113287Sphk printf("Transfer rates:\n"); 327113287Sphk printf("\toutside: "); 328113287Sphk rdsect(fd, 0, sectorsize); 329113287Sphk T0(); 330224250Smav for (i = 0; i < bulk; i++) { 331113287Sphk rdmega(fd); 332113287Sphk } 333224250Smav TR(bulk * 1024); 334113287Sphk 335113287Sphk printf("\tmiddle: "); 336224250Smav b0 = sectorcount / 2 - bulk * (1024*1024 / sectorsize) / 2 - 1; 337113287Sphk rdsect(fd, b0, sectorsize); 338113287Sphk T0(); 339224250Smav for (i = 0; i < bulk; i++) { 340113287Sphk rdmega(fd); 341113287Sphk } 342224250Smav TR(bulk * 1024); 343113287Sphk 344113287Sphk printf("\tinside: "); 345241844Seadler b0 = sectorcount - bulk * (1024*1024 / sectorsize) - 1; 346113287Sphk rdsect(fd, b0, sectorsize); 347113287Sphk T0(); 348224250Smav for (i = 0; i < bulk; i++) { 349113287Sphk rdmega(fd); 350113287Sphk } 351224250Smav TR(bulk * 1024); 352113287Sphk 353113287Sphk printf("\n"); 354137456Ssos return; 355137456Ssos} 356113287Sphk 357137456Ssosstatic void 358137456Ssoscommandtime(int fd, off_t mediasize, u_int sectorsize) 359137456Ssos{ 360137456Ssos double dtmega, dtsector; 361137456Ssos int i; 362137456Ssos 363137456Ssos printf("I/O command overhead:\n"); 364137456Ssos i = mediasize; 365137456Ssos rdsect(fd, 0, sectorsize); 366137456Ssos T0(); 367137456Ssos for (i = 0; i < 10; i++) 368137456Ssos rdmega(fd); 369137456Ssos gettimeofday(&tv2, NULL); 370137456Ssos dtmega = (tv2.tv_usec - tv1.tv_usec) / 1e6; 371137456Ssos dtmega += (tv2.tv_sec - tv1.tv_sec); 372137456Ssos 373137456Ssos printf("\ttime to read 10MB block %10.6f sec\t= %8.3f msec/sector\n", 374137456Ssos dtmega, dtmega*100/2048); 375137456Ssos 376137456Ssos rdsect(fd, 0, sectorsize); 377137456Ssos T0(); 378137456Ssos for (i = 0; i < 20480; i++) 379137456Ssos rdsect(fd, 0, sectorsize); 380137456Ssos gettimeofday(&tv2, NULL); 381137456Ssos dtsector = (tv2.tv_usec - tv1.tv_usec) / 1e6; 382137456Ssos dtsector += (tv2.tv_sec - tv1.tv_sec); 383137456Ssos 384137456Ssos printf("\ttime to read 20480 sectors %10.6f sec\t= %8.3f msec/sector\n", 385137456Ssos dtsector, dtsector*100/2048); 386137456Ssos printf("\tcalculated command overhead\t\t\t= %8.3f msec/sector\n", 387137456Ssos (dtsector - dtmega)*100/2048); 388137456Ssos 389137456Ssos printf("\n"); 390113287Sphk return; 391113287Sphk} 392