1/*
2 * Copyright 2004-2006, Haiku, Inc. All RightsReserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <SupportDefs.h>
8
9#include <errno.h>
10#include <fcntl.h>
11#include <stdio.h>
12#include <string.h>
13
14// This one comes from Thomas Kurschel's IDE bus manager.
15#include "ide_device_infoblock.h"
16
17extern const char *__progname;
18
19/* why isn't that documented ? */
20#define IDE_GET_INFO 0x2710
21#define IDE_GET_STATUS 0x2711
22
23typedef struct {
24	uint8 dummy;
25	uint8 dma_status;
26	uint8 pio_mode;
27	uint8 dma_mode;
28} _PACKED ide_status_t;
29
30
31#define kNotSupported	"not supported"
32#define kSupported		"supported"
33
34char *dma_mode_strings[] = {
35	"Multiword DMA Mode 0 - 4.2 MB/s",
36	"Multiword DMA Mode 1 - 13.3 MB/s",
37	"Multiword DMA Mode 2 - 16.7 MB/s",
38	"Invalid",
39	"Invalid",
40	"Invalid",
41	"Invalid",
42	"Invalid",
43	"Invalid",
44	"Invalid",
45	"Invalid",
46	"Invalid",
47	"Invalid",
48	"Invalid",
49	"Invalid",
50	"Invalid",
51	"Ultra DMA Mode 0 - 16.7 MB/s",
52	"Ultra DMA Mode 1 - 25 MB/s",
53	"Ultra DMA Mode 2 - 33.3 MB/s",
54	"Ultra DMA Mode 3 - 44.4 MB/s",
55	"Ultra DMA Mode 4 - 66.7 MB/s",
56	"Ultra DMA Mode 5 - 100 MB/s",
57	"Ultra DMA Mode 6 - 133 MB/s"
58};
59
60static void
61sizeAsString(off_t size, char *string)
62{
63	double kb = size / 1024.0;
64	float mb, gb, tb;
65	if (kb < 1.0) {
66		sprintf(string, "%Ld B", size);
67		return;
68	}
69	mb = kb / 1024.0;
70	if (mb < 1.0) {
71		sprintf(string, "%3.1f KB", kb);
72		return;
73	}
74	gb = mb / 1024.0;
75	if (gb < 1.0) {
76		sprintf(string, "%3.1f MB", mb);
77		return;
78	}
79	tb = gb / 1024.0;
80	if (tb < 1.0) {
81		sprintf(string, "%3.1f GB", gb);
82		return;
83	}
84	sprintf(string, "%.1f TB", tb);
85}
86
87
88int
89main(int argc, char **argv)
90{
91	int fd;
92	ide_device_infoblock ide_info;
93	off_t capacity = 0;
94	char capacityString[20];
95	bool removable;
96
97	if (argc < 2) {
98		fprintf(stderr, "usage: %s <device>\n", __progname);
99		return 1;
100	}
101
102	fd = open(argv[1], O_RDONLY);
103	if (fd < 0) {
104		fprintf(stderr, "could not open %s: %s\n", argv[1], strerror(errno));
105		return 2;
106	}
107
108	if (ioctl(fd, IDE_GET_INFO, &ide_info, sizeof(ide_device_infoblock)) < 0) {
109		fprintf(stderr, "could not get ide info for %s\n", argv[1]);
110		return 3;
111	}
112
113	printf("Model Number:     %.40s\n", ide_info.model_number);
114	printf("Serial Number:    %.20s\n", ide_info.serial_number);
115	printf("Firmware Version: %.8s\n", ide_info.firmware_version);
116	printf("\n");
117
118 	if (ide_info._48_bit_addresses_supported) {
119		capacity = ide_info.LBA48_total_sectors * 512LL;
120	} else if (ide_info.LBA_supported) {
121		capacity = ide_info.LBA_total_sectors * 512LL;
122	} else {
123		capacity = (ide_info.cylinders * ide_info.heads *
124					ide_info.sectors) * 512LL;
125	}
126
127	sizeAsString(capacity, capacityString);
128	printf("Capacity: %s\n", capacityString);
129	printf("LBA supported: %s\n", ide_info.LBA_supported ? "yes" : "no");
130	printf("\n");
131
132	printf("DMA supported: %s\n", ide_info.DMA_supported ? "yes" : "no");
133
134	if (ide_info.DMA_supported) {
135		ide_status_t st = {0x01, 0x00, 0x00, 0x80}; /* God knows... */
136
137		if (ioctl(fd, IDE_GET_STATUS, &st, sizeof(ide_status_t *)) < 0) {
138			fprintf(stderr, "could not get ide status for %s\n", argv[1]);
139			return 3;
140		}
141
142		if (st.dma_status > 6)
143			printf("Bad dma_status field\n");
144		else
145			printf("DMA mode: %s\n", dma_mode_strings[st.dma_mode]);
146	}
147
148	printf("READ/WRITE DMA QUEUED: %s\n",
149			ide_info.DMA_QUEUED_supported ? kSupported : kNotSupported);
150	printf("\n");
151
152	printf("Write Cache: %s\n",
153			ide_info.write_cache_supported ? kSupported : kNotSupported);
154	printf("Look Ahead: %s\n",
155			ide_info.look_ahead_supported ? kSupported : kNotSupported);
156	printf("Bus Release IRQ: %s\n",
157			ide_info.RELEASE_irq_supported ? kSupported : kNotSupported);
158	printf("Service start transfer IRQ: %s\n",
159			ide_info.SERVICE_irq_supported ? kSupported : kNotSupported);
160	printf("NOP: %s\n",
161			ide_info.NOP_supported ? kSupported : kNotSupported);
162	printf("FLUSH CACHE: %s\n",
163			ide_info.FLUSH_CACHE_supported ? kSupported : kNotSupported);
164	printf("FLUSH CACHE EXT: %s\n",
165			ide_info.FLUSH_CACHE_EXT_supported ? kSupported : kNotSupported);
166	printf("\n");
167
168	printf("CFA features: %s\n",
169			ide_info.CFA_supported ? kSupported : kNotSupported);
170
171	removable = ide_info._0.ata.removable_media ||
172				ide_info._0.atapi.removable_media;
173
174	printf("Removable: %s\n", removable ? "yes" : "no");
175
176	printf("Removable Media State Notification features: %s\n",
177			(ide_info._127_RMSN_support == 1) ? kSupported : kNotSupported);
178	printf("\n");
179
180	// Not in original ideinfo:
181	printf("Microcode download: %s\n",
182			ide_info.DOWNLOAD_MICROCODE_supported ? kSupported : kNotSupported);
183	printf("S.M.A.R.T: %s\n",
184			ide_info.SMART_supported ? kSupported : kNotSupported);
185	printf("Power Management: %s\n",
186			ide_info.PM_supported ? kSupported : kNotSupported);
187	printf("\n");
188
189	// TODO: where do we find these fields?
190/*
191	printf("Statistics (for entire IDE bus)\n");
192	printf("Overlappable commands: %d\n", ide_info.);
193	printf("Started as overlapped: %d\n", ide_info.);
194	printf("Started as non-overlapped: %d\n", ide_info.);
195	printf("Average queue depth (of overlapped commands): %d\n", ide_info.);
196	printf("Non-Overlappable commands: %d\n", ide_info.);
197	printf("Bus released by device: %d\n", ide_info.);
198*/
199
200	close(fd);
201	return 0;
202}
203