source: trunk/src/lbatest/lbatest.c@ 50

Last change on this file since 50 was 50, checked in by markus, 15 years ago

started rewrite of lbatest (old version is limited to 2GB...)

File size: 9.2 KB
Line 
1/******************************************************************************
2
3 lbatest.c - simple (dumb) test program for os2ahci
4
5 Writes the actual LBA to each sector on a hard disk. The purpose is to
6 find out if the sector mapping of os2ahci.add is correct.
7
8 To run the test, attach a HD to an AHCI controller with os2ahci.add loaded
9 and run the test in write mode, then attach the disk to an IDE adapter
10 with an S506 driver and run lbatest in read mode.
11
12 Author: Markus Thielen
13
14 Compilation (Watcom): wcl386 -bt=os2 lbatest.c
15
16 Copyright (c) 2010 by thi.guten Software development, www.thiguten.de
17
18 This program is free software; you can redistribute it and/or modify
19 it under the terms of the GNU General Public License as published by
20 the Free Software Foundation; either version 2 of the License, or
21 (at your option) any later version.
22
23 This program is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
27
28 You should have received a copy of the GNU General Public License
29 along with this program; if not, write to the Free Software
30 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31
32******************************************************************************/
33
34/*---- includes -------------------------------------------------------------*/
35
36#define INCL_DOS
37#define INCL_ERRORS
38#define INCL_DOSDEVICES
39#define INCL_DOSDEVIOCTL
40#include <os2.h>
41#include <stdio.h>
42#include <stddef.h>
43#include <stdlib.h>
44#include <ctype.h>
45#include <string.h>
46#include <signal.h>
47
48#define SECTOR_SIZE 512
49#define SECTORS_PER_WRITE 32
50
51
52/*--- function prototypes ---------------------------------------------------*/
53
54void usage (void);
55
56int write_test (char *drv);
57
58int read_test (char *drv);
59
60void signal_handler (int sig_no);
61
62/*--- global data -----------------------------------------------------------*/
63
64DEVICEPARAMETERBLOCK dev_parms;
65
66
67/*--- start of code ---------------------------------------------------------*/
68
69/******************************************************************************
70 * main()
71 */
72int main(int argc, char **argv)
73{
74 char *drv;
75 HFILE hf;
76
77 if (argc < 3) {
78 usage();
79 return -1;
80 }
81
82 /* get arguments */
83 drv = argv[1];
84 mode = toupper(argv[2][0]);
85 if (mode != 'W' && mode != 'R') {
86 usage();
87 return -1;
88 }
89
90 if (drv[1] != ':' && drv[2] != '\0') {
91 /* we want a drive letter, which is a letter and a colon */
92 usage();
93 return -1;
94 }
95
96 /* determine physical drive layout */
97 get_drive_layout(drv);
98
99 if (mode == 'W') {
100 return write_test(drv);
101 }
102 if (mode == 'R') {
103 return read_test(drv);
104 }
105
106 return 0;
107}
108
109/******************************************************************************
110 * determine CHS layout of the drive we're running on
111 */
112void get_drive_layout(char *disk)
113{
114
115
116}
117
118
119/******************************************************************************
120 * write_test() - write each sector's address to the sector itself
121 */
122int write_test(char *drv)
123{
124 unsigned long lba;
125 unsigned long ret;
126 HFILE hf_disk;
127 unsigned long action;
128 unsigned long cb_written;
129 int rc = 0;
130 float gbf = 1024.0 * 1024.0 * 1024.0 / 512.0;
131 unsigned long i;
132 unsigned char *wbuf;
133 char buf[100];
134 unsigned long cbtake = SECTOR_SIZE * SECTORS_PER_WRITE;
135 unsigned long cb;
136
137 /* ask for confirmation, we destroy the drive's contents */
138 printf("I'm going to destroy ALL DATA on drive %s now.\n"
139 "type 'DESTROY' to continue, anything else to bail out.\n", drv);
140 if (gets(buf) == NULL || strcmp(buf, "DESTROY")) {
141 return -1;
142 }
143
144 /* open drive */
145 ret = DosOpen(drv, &hf_disk, &action, 0, 0, OPEN_ACTION_OPEN_IF_EXISTS,
146 OPEN_FLAGS_DASD | OPEN_FLAGS_FAIL_ON_ERROR |
147 OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_NO_CACHE |
148 OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_WRITEONLY,
149 NULL);
150 if (ret != NO_ERROR) {
151 fprintf(stderr, "Failed to open disk %s for writing: %d\n", drv, ret);
152 return -1;
153 }
154
155 /* lock disk */
156 ret = DosDevIOCtl(hf_disk, IOCTL_DISK, DSK_LOCKDRIVE, NULL, 0,
157 &action, NULL, 0, &cb_written);
158 if (ret != NO_ERROR) {
159 fprintf(stderr, "Failed to lock drive, code %d\n", ret);
160 rc = -1;
161 goto cleanup;
162 }
163
164 /* allocate big write buffer */
165 wbuf = calloc(SECTOR_SIZE, SECTORS_PER_WRITE);
166
167 /* go... */
168 for (lba = 0; ; lba += SECTORS_PER_WRITE) {
169
170 /* prepare buffer; set the first 4 bytes of each sector
171 * to its LBA */
172 for (i = 0; i < SECTORS_PER_WRITE; i++) {
173 *((unsigned long *)(wbuf + i * SECTOR_SIZE)) = lba + i;
174 }
175
176 /* write buffer to disk */
177 cb = cbtake;
178 while (cb) {
179 ret = DosWrite(hf_disk, wbuf + cbtake - cb, cb, &cb_written);
180 if (ret != NO_ERROR) {
181 fprintf(stderr, "\nFailed to write to disk %s, code %d\n", drv, ret);
182 rc = -1;
183 goto cleanup;
184 }
185 if (cb_written >= cb) {
186 break;
187 }
188
189 if (cb_written == 0) {
190 /* what the heck... */
191 fprintf(stderr, "\nWrote 0 bytes of %u, no error return code\n",
192 cb);
193 ret = DosSetFilePtr(hf_disk, lba * SECTOR_SIZE + cbtake - cb,
194 FILE_BEGIN, &action);
195 if (ret != NO_ERROR) {
196 fprintf(stderr, "Failed to set file pointer after writing "
197 "0 bytes: %d\n", ret);
198 goto cleanup;
199 }
200 }
201 cb -= cb_written;
202 }
203
204 /* write progress */
205 printf("\r%dk sectors written (%0.02f GB)", lba / 1000, (float)lba / gbf);
206
207 }
208
209cleanup:
210 /* unlock drive */
211 DosDevIOCtl(hf_disk, IOCTL_DISK, DSK_UNLOCKDRIVE, NULL, 0, &action,
212 NULL, 0, &cb_written);
213 DosClose(hf_disk);
214 free(wbuf);
215 return rc;
216
217}
218
219/******************************************************************************
220 * read_test() - read each sector's first 4 bytes and compare to its LBA
221 */
222int read_test(char *drv)
223{
224 unsigned long ret;
225 HFILE hf_disk;
226 unsigned long action;
227 unsigned long cb_read;
228 char buf[SECTOR_SIZE];
229 int rc = 0;
230 unsigned long err_cnt = 0;
231 float gbf = 1024.0 * 1024.0 * 1024.0 / 512.0;
232
233 /* open drive */
234 ret = DosOpen(drv, &hf_disk, &action, 0, 0, OPEN_ACTION_OPEN_IF_EXISTS,
235 OPEN_FLAGS_DASD | OPEN_FLAGS_FAIL_ON_ERROR |
236 OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_NO_CACHE |
237 OPEN_FLAGS_SEQUENTIAL | OPEN_SHARE_DENYREADWRITE |
238 OPEN_ACCESS_READONLY,
239 NULL);
240 if (ret != NO_ERROR) {
241 fprintf(stderr, "Failed to open disk %s for reading: %d\n", drv, ret);
242 return -1;
243 }
244
245 /* lock disk */
246 ret = DosDevIOCtl(hf_disk, IOCTL_DISK, DSK_LOCKDRIVE, NULL, 0,
247 &action, NULL, 0, &cb_read);
248 if (ret != NO_ERROR) {
249 fprintf(stderr, "Failed to lock drive, code %d\n", ret);
250 rc = -1;
251 goto cleanup;
252 }
253
254 /* catch Ctrl+C */
255 signal(SIGINT, signal_handler);
256
257 /* go... */
258 memset(buf, 0x00, sizeof(buf));
259 for (lba_pos = 0; ; lba_pos++) {
260 ret = DosRead(hf_disk, buf, SECTOR_SIZE, &cb_read);
261 if (ret != NO_ERROR) {
262 fprintf(stderr, "\nFailed to read from disk %s, code %d\n", drv, ret);
263 rc = -1;
264 goto cleanup;
265 }
266
267 if (*((unsigned long*) buf) != lba_pos) {
268 printf("\nWrong sector number: read %d from sector %d\n",
269 *((unsigned long*) buf), lba_pos);
270 err_cnt++;
271 if (first_wrong_sector == 0xffffffff) {
272 first_wrong_sector = lba_pos;
273 }
274 }
275
276 /* progress */
277 if (lba_pos % 100 == 0) {
278 printf("\r%dk sectors read (%0.02f GB)", lba_pos / 1000,
279 (float) lba_pos / gbf);
280 }
281 }
282
283cleanup:
284 /* unlock drive */
285 DosDevIOCtl(hf_disk, IOCTL_DISK, DSK_UNLOCKDRIVE, NULL, 0, &action,
286 NULL, 0, &cb_read);
287 DosClose(hf_disk);
288
289 /* print summary */
290 printf("Found %d logical errors\n", err_cnt);
291 if (first_wrong_sector != 0xffffffff) {
292 printf("First wrong sector was %u.\n", err_cnt, first_wrong_sector);
293 }
294
295 return rc;
296}
297
298/******************************************************************************
299 * usage() - print usage summary to STDOUT
300 */
301void usage(void)
302{
303 printf("lbatest for os2ahci.add\n"
304 "Usage:\n\n"
305 "lbatest <drive letter> <mode>\n\n"
306 "where mode is either W for writing or R for reading.\n\n"
307 "In write mode, this program COMPLETELY DESTROYS ALL DATA on the specified\n"
308 "partition/disc. It writes the address of each sector to the sector itself.\n\n"
309 "In read mode, each sector is read and its address verified.\n");
310}
311
312
313/******************************************************************************
314 * signal_handler for SIGINT - prints summary to STDOUT
315 */
316void signal_handler(int sig_no)
317{
318
319 if (sig_no == SIGINT && mode == 'R') {
320 /* read mode interrupted; show summary */
321 printf("\n\nLast block read: %u\n", lba_pos);
322 if (first_wrong_sector != 0xffffffff) {
323 printf("First wrong sector: %u\n", first_wrong_sector);
324 } else {
325 printf("All sectors read ok\n");
326 }
327 }
328
329 exit(0);
330
331}
Note: See TracBrowser for help on using the repository browser.