2 * Copyright (c) 2003 Poul-Henning Kamp
3 * Copyright (c) 2015 Spectra Logic Corporation
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The names of the authors may not be used to endorse or promote
15 * products derived from this software without specific prior written
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 #include <sys/param.h>
51 fprintf(stderr, "usage: diskinfo [-ctv] disk ...\n");
55 static int opt_c, opt_t, opt_v;
57 static void speeddisk(int fd, off_t mediasize, u_int sectorsize);
58 static void commandtime(int fd, off_t mediasize, u_int sectorsize);
59 static int zonecheck(int fd, uint32_t *zone_mode, char *zone_str,
63 main(int argc, char **argv)
66 int i, ch, fd, error, exitval = 0;
67 char buf[BUFSIZ], ident[DISK_IDENT_SIZE], physpath[MAXPATHLEN];
69 off_t mediasize, stripesize, stripeoffset;
70 u_int sectorsize, fwsectors, fwheads, zoned = 0;
73 while ((ch = getopt(argc, argv, "ctv")) != -1) {
96 for (i = 0; i < argc; i++) {
97 fd = open(argv[i], O_RDONLY | O_DIRECT);
98 if (fd < 0 && errno == ENOENT && *argv[i] != '/') {
99 sprintf(buf, "%s%s", _PATH_DEV, argv[i]);
100 fd = open(buf, O_RDONLY);
107 error = fstat(fd, &sb);
109 warn("cannot stat %s", argv[i]);
113 if (S_ISREG(sb.st_mode)) {
114 mediasize = sb.st_size;
115 sectorsize = S_BLKSIZE;
118 stripesize = sb.st_blksize;
121 error = ioctl(fd, DIOCGMEDIASIZE, &mediasize);
123 warnx("%s: ioctl(DIOCGMEDIASIZE) failed, probably not a disk.", argv[i]);
127 error = ioctl(fd, DIOCGSECTORSIZE, §orsize);
129 warnx("%s: ioctl(DIOCGSECTORSIZE) failed, probably not a disk.", argv[i]);
133 error = ioctl(fd, DIOCGFWSECTORS, &fwsectors);
136 error = ioctl(fd, DIOCGFWHEADS, &fwheads);
139 error = ioctl(fd, DIOCGSTRIPESIZE, &stripesize);
142 error = ioctl(fd, DIOCGSTRIPEOFFSET, &stripeoffset);
145 error = zonecheck(fd, &zone_mode, zone_desc, sizeof(zone_desc));
150 printf("%s", argv[i]);
151 printf("\t%u", sectorsize);
152 printf("\t%jd", (intmax_t)mediasize);
153 printf("\t%jd", (intmax_t)mediasize/sectorsize);
154 printf("\t%jd", (intmax_t)stripesize);
155 printf("\t%jd", (intmax_t)stripeoffset);
156 if (fwsectors != 0 && fwheads != 0) {
157 printf("\t%jd", (intmax_t)mediasize /
158 (fwsectors * fwheads * sectorsize));
159 printf("\t%u", fwheads);
160 printf("\t%u", fwsectors);
163 humanize_number(buf, 5, (int64_t)mediasize, "",
164 HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
165 printf("%s\n", argv[i]);
166 printf("\t%-12u\t# sectorsize\n", sectorsize);
167 printf("\t%-12jd\t# mediasize in bytes (%s)\n",
168 (intmax_t)mediasize, buf);
169 printf("\t%-12jd\t# mediasize in sectors\n",
170 (intmax_t)mediasize/sectorsize);
171 printf("\t%-12jd\t# stripesize\n", stripesize);
172 printf("\t%-12jd\t# stripeoffset\n", stripeoffset);
173 if (fwsectors != 0 && fwheads != 0) {
174 printf("\t%-12jd\t# Cylinders according to firmware.\n", (intmax_t)mediasize /
175 (fwsectors * fwheads * sectorsize));
176 printf("\t%-12u\t# Heads according to firmware.\n", fwheads);
177 printf("\t%-12u\t# Sectors according to firmware.\n", fwsectors);
179 if (ioctl(fd, DIOCGIDENT, ident) == 0)
180 printf("\t%-12s\t# Disk ident.\n", ident);
181 if (ioctl(fd, DIOCGPHYSPATH, physpath) == 0)
182 printf("\t%-12s\t# Physical path\n", physpath);
184 printf("\t%-12s\t# Zone Mode\n", zone_desc);
188 commandtime(fd, mediasize, sectorsize);
190 speeddisk(fd, mediasize, sectorsize);
198 static char sector[65536];
199 static char mega[1024 * 1024];
202 rdsect(int fd, off_t blockno, u_int sectorsize)
206 lseek(fd, (off_t)blockno * sectorsize, SEEK_SET);
207 error = read(fd, sector, sectorsize);
210 if (error != (int)sectorsize)
211 errx(1, "disk too small for test.");
219 error = read(fd, mega, sizeof(mega));
222 if (error != sizeof(mega))
223 errx(1, "disk too small for test.");
226 static struct timeval tv1, tv2;
237 gettimeofday(&tv1, NULL);
245 gettimeofday(&tv2, NULL);
246 dt = (tv2.tv_usec - tv1.tv_usec) / 1e6;
247 dt += (tv2.tv_sec - tv1.tv_sec);
248 printf("%5d iter in %10.6f sec = %8.3f msec\n",
249 count, dt, dt * 1000.0 / count);
257 gettimeofday(&tv2, NULL);
258 dt = (tv2.tv_usec - tv1.tv_usec) / 1e6;
259 dt += (tv2.tv_sec - tv1.tv_sec);
260 printf("%8.0f kbytes in %10.6f sec = %8.0f kbytes/sec\n",
261 count, dt, count / dt);
265 speeddisk(int fd, off_t mediasize, u_int sectorsize)
268 off_t b0, b1, sectorcount, step;
270 sectorcount = mediasize / sectorsize;
271 step = 1ULL << (flsll(sectorcount / (4 * 200)) - 1);
274 bulk = mediasize / (1024 * 1024);
278 printf("Seek times:\n");
279 printf("\tFull stroke:\t");
281 b1 = sectorcount - step;
283 for (i = 0; i < 125; i++) {
284 rdsect(fd, b0, sectorsize);
286 rdsect(fd, b1, sectorsize);
291 printf("\tHalf stroke:\t");
292 b0 = sectorcount / 4;
293 b1 = b0 + sectorcount / 2;
295 for (i = 0; i < 125; i++) {
296 rdsect(fd, b0, sectorsize);
298 rdsect(fd, b1, sectorsize);
302 printf("\tQuarter stroke:\t");
303 b0 = sectorcount / 4;
304 b1 = b0 + sectorcount / 4;
306 for (i = 0; i < 250; i++) {
307 rdsect(fd, b0, sectorsize);
309 rdsect(fd, b1, sectorsize);
314 printf("\tShort forward:\t");
315 b0 = sectorcount / 2;
317 for (i = 0; i < 400; i++) {
318 rdsect(fd, b0, sectorsize);
323 printf("\tShort backward:\t");
324 b0 = sectorcount / 2;
326 for (i = 0; i < 400; i++) {
327 rdsect(fd, b0, sectorsize);
332 printf("\tSeq outer:\t");
335 for (i = 0; i < 2048; i++) {
336 rdsect(fd, b0, sectorsize);
341 printf("\tSeq inner:\t");
342 b0 = sectorcount - 2048;
344 for (i = 0; i < 2048; i++) {
345 rdsect(fd, b0, sectorsize);
350 printf("Transfer rates:\n");
351 printf("\toutside: ");
352 rdsect(fd, 0, sectorsize);
354 for (i = 0; i < bulk; i++) {
359 printf("\tmiddle: ");
360 b0 = sectorcount / 2 - bulk * (1024*1024 / sectorsize) / 2 - 1;
361 rdsect(fd, b0, sectorsize);
363 for (i = 0; i < bulk; i++) {
368 printf("\tinside: ");
369 b0 = sectorcount - bulk * (1024*1024 / sectorsize) - 1;
370 rdsect(fd, b0, sectorsize);
372 for (i = 0; i < bulk; i++) {
382 commandtime(int fd, off_t mediasize, u_int sectorsize)
384 double dtmega, dtsector;
387 printf("I/O command overhead:\n");
389 rdsect(fd, 0, sectorsize);
391 for (i = 0; i < 10; i++)
393 gettimeofday(&tv2, NULL);
394 dtmega = (tv2.tv_usec - tv1.tv_usec) / 1e6;
395 dtmega += (tv2.tv_sec - tv1.tv_sec);
397 printf("\ttime to read 10MB block %10.6f sec\t= %8.3f msec/sector\n",
398 dtmega, dtmega*100/2048);
400 rdsect(fd, 0, sectorsize);
402 for (i = 0; i < 20480; i++)
403 rdsect(fd, 0, sectorsize);
404 gettimeofday(&tv2, NULL);
405 dtsector = (tv2.tv_usec - tv1.tv_usec) / 1e6;
406 dtsector += (tv2.tv_sec - tv1.tv_sec);
408 printf("\ttime to read 20480 sectors %10.6f sec\t= %8.3f msec/sector\n",
409 dtsector, dtsector*100/2048);
410 printf("\tcalculated command overhead\t\t\t= %8.3f msec/sector\n",
411 (dtsector - dtmega)*100/2048);
418 zonecheck(int fd, uint32_t *zone_mode, char *zone_str, size_t zone_str_len)
420 struct disk_zone_args zone_args;
423 bzero(&zone_args, sizeof(zone_args));
425 zone_args.zone_cmd = DISK_ZONE_GET_PARAMS;
426 error = ioctl(fd, DIOCZONECMD, &zone_args);
429 *zone_mode = zone_args.zone_params.disk_params.zone_mode;
431 switch (*zone_mode) {
432 case DISK_ZONE_MODE_NONE:
433 snprintf(zone_str, zone_str_len, "Not_Zoned");
435 case DISK_ZONE_MODE_HOST_AWARE:
436 snprintf(zone_str, zone_str_len, "Host_Aware");
438 case DISK_ZONE_MODE_DRIVE_MANAGED:
439 snprintf(zone_str, zone_str_len, "Drive_Managed");
441 case DISK_ZONE_MODE_HOST_MANAGED:
442 snprintf(zone_str, zone_str_len, "Host_Managed");
445 snprintf(zone_str, zone_str_len, "Unknown_zone_mode_%u",