- Fix Linux build.
[reactos.git] / reactos / base / applications / atactl / atactl.cpp
1 #include <windows.h>
2 #include <winioctl.h>
3 #include <stdio.h>
4 //#include <ntdddisk.h>
5 //#include <ntddscsi.h>
6 #include <ntddscsi.h>
7 #include <atapi.h>
8 #include <bm_devs.h>
9 #include <uata_ctl.h>
10 #include <tools.h>
11 #include <uniata_ver.h>
12
13 #include "helper.h"
14
15 #define DEFAULT_REMOVAL_LOCK_TIMEOUT 20
16
17 #define MOV_DW_SWP(a,b) \
18 do \
19 { \
20 *(unsigned short *)&(a) = _byteswap_ushort(*(unsigned short *)&(b)); \
21 } \
22 while (0)
23
24 #define MOV_DD_SWP(a,b) \
25 { \
26 PFOUR_BYTE _from_, _to_; \
27 _from_ = ((PFOUR_BYTE)&(b)); \
28 _to_ = ((PFOUR_BYTE)&(a)); \
29 __asm mov ebx,_from_ \
30 __asm mov eax,[ebx] \
31 __asm bswap eax \
32 __asm mov ebx,_to_ \
33 __asm mov [ebx],eax \
34 }
35
36 int g_extended = 0;
37 int g_adapter_info = 0;
38 char* g_bb_list = NULL;
39 int gRadix = 16;
40
41 void print_help() {
42 printf("Usage:\n"
43 " atactl -<switches> c|s<controller id>:b<bus id>:d<device id>[:l<lun>]\n"
44 "Switches:\n"
45 " l (L)ist devices on SCSI and ATA controllers bus(es)\n"
46 " Note: ATA Pri/Sec controller are usually represented\n"
47 " as Scsi0/Scsi1 under NT-family OSes\n"
48 " x show e(X)tended info\n"
49 " a show (A)dapter info\n"
50 " s (S)can for new devices on ATA/SATA bus(es) (experimental)\n"
51 " S (S)can for new devices on ATA/SATA bus(es) (experimental)\n"
52 " device, hidden with 'H' can be redetected\n"
53 " h (H)ide device on ATA/SATA bus for removal (experimental)\n"
54 " device can be redetected\n"
55 " H (H)ide device on ATA/SATA bus (experimental)\n"
56 " device can not be redetected until 'h' or 'S' is issued\n"
57 " m [MODE] set i/o (M)ode for device or revert to default\n"
58 " available MODEs are PIO, PIO0-PIO5, DMA, WDMA0-WDMA2,\n"
59 " UDMA33/44/66/100/133, UDMA0-UDMA5\n"
60 " d [XXX] lock ATA/SATA bus for device removal for XXX seconds or\n"
61 " for %d seconds if no lock timeout specified.\n"
62 " can be used with -h, -m or standalone.\n"
63 " r (R)eset device\n"
64 " ba (A)ssign (B)ad-block list\n"
65 " bl get assigned (B)ad-block (L)ist\n"
66 " br (R)eset assigned (B)ad-block list\n"
67 " f specify (F)ile for bad-block list\n"
68 " n XXX block (n)ubmering radix. XXX can be hex or dec\n"
69 "------\n"
70 "Examples:\n"
71 " atactl -l\n"
72 " will list all scsi buses and all connected devices\n"
73 " atactl -m udma0 s2:b1:d1\n"
74 " will switch device at Scsi2, bus 1, taget_id 1 to UDMA0 mode\n"
75 " atactl -h -d 30 c1:b0:d0:l0 \n"
76 " will hide Master (d0:l0) device on secondary (c1:b0) IDE channel\n"
77 " and lock i/o on this channel for 30 seconds to ensure safity\n"
78 " of removal process"
79 "------\n"
80 "Device address format:\n"
81 "\n"
82 "s<controller id> number of controller in system. Is assigned during hardware\n"
83 " detection. Usually s0/s1 are ATA Pri/Sec.\n"
84 " Note, due do NT internal desing ATA controllers are represented\n"
85 " as SCSI controllers.\n"
86 "b<bus id> For ATA controllers it is channel number.\n"
87 " Note, usually onboard controller is represented as 2 legacy\n"
88 " ISA-compatible single-channel controllers (Scsi9/Scsi1). Additional\n"
89 " ATA, ATA-RAID and some specific onboard controllers are represented\n"
90 " as multichannel controllers.\n"
91 "d<device id> For ATA controllers d0 is Master, d1 is Slave.\n"
92 "l<lun> Not used in ATA controller drivers, alway 0\n"
93 "------\n"
94 "Bad-block list format:\n"
95 "\n"
96 "# Comment\n"
97 "; Still one comment\n"
98 "hex: switch to hexadecimal mode\n"
99 "<Bad Area 1 Start LBA, e.g. FD50> <Block count 1, e.g. 60>\n"
100 "<Bad Area 2 Start LBA> <Block count 2>\n"
101 "...\n"
102 "dec: switch to decimal mode\n"
103 "<Bad Area N Start LBA, e.g. 16384> <Block count N, e.g. 48>\n"
104 "...\n"
105 "------\n"
106 "",
107 DEFAULT_REMOVAL_LOCK_TIMEOUT
108 );
109 exit(0);
110 }
111
112 #define CMD_ATA_LIST 0x01
113 #define CMD_ATA_FIND 0x02
114 #define CMD_ATA_HIDE 0x03
115 #define CMD_ATA_MODE 0x04
116 #define CMD_ATA_RESET 0x05
117 #define CMD_ATA_BBLK 0x06
118
119 HANDLE
120 ata_open_dev(
121 char* Name
122 )
123 {
124 ULONG i;
125 HANDLE h;
126
127 for(i=0; i<4; i++) {
128 h = CreateFile(Name,
129 READ_CONTROL | GENERIC_READ | GENERIC_WRITE ,
130 ((i & 1) ? 0 : FILE_SHARE_READ) | ((i & 2) ? 0 : FILE_SHARE_WRITE),
131 NULL,
132 OPEN_EXISTING,
133 FILE_ATTRIBUTE_NORMAL,
134 NULL);
135 if(h && (h != ((HANDLE)(-1))) ) {
136 return h;
137 }
138 }
139
140 for(i=0; i<4; i++) {
141 h = CreateFile(Name,
142 GENERIC_READ | GENERIC_WRITE ,
143 ((i & 1) ? 0 : FILE_SHARE_READ) | ((i & 2) ? 0 : FILE_SHARE_WRITE),
144 NULL,
145 OPEN_EXISTING,
146 FILE_ATTRIBUTE_NORMAL,
147 NULL);
148 if(h && (h != ((HANDLE)(-1))) ) {
149 return h;
150 }
151 }
152
153 for(i=0; i<4; i++) {
154 h = CreateFile(Name,
155 GENERIC_READ,
156 ((i & 1) ? 0 : FILE_SHARE_READ) | ((i & 2) ? 0 : FILE_SHARE_WRITE),
157 NULL,
158 OPEN_EXISTING,
159 FILE_ATTRIBUTE_NORMAL,
160 NULL);
161 if(h && (h != ((HANDLE)(-1))) ) {
162 return h;
163 }
164 }
165
166 for(i=0; i<4; i++) {
167 h = CreateFile(Name,
168 READ_CONTROL,
169 ((i & 1) ? 0 : FILE_SHARE_READ) | ((i & 2) ? 0 : FILE_SHARE_WRITE),
170 NULL,
171 OPEN_EXISTING,
172 FILE_ATTRIBUTE_NORMAL,
173 NULL);
174 if(h && (h != ((HANDLE)(-1))) ) {
175 return h;
176 }
177 }
178
179 return NULL;
180 } // end ata_open_dev()
181
182 HANDLE
183 ata_open_file(
184 char* Name,
185 BOOLEAN create
186 )
187 {
188 ULONG i;
189 HANDLE h;
190
191 if(!Name) {
192 if(create) {
193 return GetStdHandle(STD_OUTPUT_HANDLE);
194 } else {
195 return GetStdHandle(STD_INPUT_HANDLE);
196 }
197 }
198
199 for(i=0; i<4; i++) {
200 h = CreateFile(Name,
201 create ? GENERIC_WRITE : GENERIC_READ ,
202 ((i & 1) ? 0 : FILE_SHARE_READ) | ((i & 2) ? 0 : FILE_SHARE_WRITE),
203 NULL,
204 create ? CREATE_NEW : OPEN_EXISTING,
205 FILE_ATTRIBUTE_NORMAL,
206 NULL);
207 if(h && (h != ((HANDLE)(-1))) ) {
208 return h;
209 }
210 }
211
212 return NULL;
213 } // end ata_open_file()
214
215 void
216 ata_close_dev(
217 HANDLE h
218 )
219 {
220 CloseHandle(h);
221 } // end ata_close_dev()
222
223 int
224 ata_send_ioctl(
225 HANDLE h,
226 PSCSI_ADDRESS addr,
227 PCHAR Signature,
228 ULONG Ioctl,
229 PVOID inBuffer,
230 ULONG inBufferLength,
231 PVOID outBuffer,
232 ULONG outBufferLength,
233 PULONG returned
234 )
235 {
236 ULONG status;
237 PUNIATA_CTL AtaCtl;
238 ULONG data_len = max(inBufferLength, outBufferLength);
239 ULONG len;
240
241 if(addr) {
242 len = data_len + offsetof(UNIATA_CTL, RawData);
243 } else {
244 len = data_len + sizeof(AtaCtl->hdr);
245 }
246 AtaCtl = (PUNIATA_CTL)GlobalAlloc(GMEM_FIXED, len);
247 AtaCtl->hdr.HeaderLength = sizeof(SRB_IO_CONTROL);
248 if(addr) {
249 AtaCtl->hdr.Length = data_len + offsetof(UNIATA_CTL, RawData) - sizeof(AtaCtl->hdr);
250 } else {
251 AtaCtl->hdr.Length = data_len;
252 }
253
254 memcpy(&AtaCtl->hdr.Signature, Signature, 8);
255
256 AtaCtl->hdr.Timeout = 10000;
257 AtaCtl->hdr.ControlCode = Ioctl;
258 AtaCtl->hdr.ReturnCode = 0;
259
260 if(addr) {
261 AtaCtl->addr = *addr;
262 AtaCtl->addr.Length = sizeof(AtaCtl->addr);
263 }
264
265 if(inBuffer && inBufferLength) {
266 if(addr) {
267 memcpy(&AtaCtl->RawData, inBuffer, inBufferLength);
268 } else {
269 memcpy(&AtaCtl->addr, inBuffer, inBufferLength);
270 }
271 }
272
273 status = DeviceIoControl(h,
274 IOCTL_SCSI_MINIPORT,
275 AtaCtl,
276 len,
277 AtaCtl,
278 len,
279 returned,
280 FALSE);
281
282 if(outBuffer && outBufferLength) {
283 if(addr) {
284 memcpy(outBuffer, &AtaCtl->RawData, outBufferLength);
285 } else {
286 memcpy(outBuffer, &AtaCtl->addr, outBufferLength);
287 }
288 }
289 GlobalFree(AtaCtl);
290
291 if(!status) {
292 status = GetLastError();
293 return FALSE;
294 }
295 return TRUE;
296 } // end ata_send_ioctl()
297
298 IO_SCSI_CAPABILITIES g_capabilities;
299 UCHAR g_inquiry_buffer[2048];
300
301 int
302 ata_is_sata(
303 PIDENTIFY_DATA ident
304 )
305 {
306 return (ident->SataEnable && ident->SataEnable != 0xffff);
307 }
308
309 int
310 ata_cur_mode_from_ident(
311 PIDENTIFY_DATA ident
312 )
313 {
314 if(ata_is_sata(ident)) {
315 return ATA_SA150-1;
316 }
317
318 if (ident->UdmaModesValid) {
319 if (ident->UltraDMAActive & 0x40)
320 return ATA_UDMA0+6;
321 if (ident->UltraDMAActive & 0x20)
322 return ATA_UDMA0+5;
323 if (ident->UltraDMAActive & 0x10)
324 return ATA_UDMA0+4;
325 if (ident->UltraDMAActive & 0x08)
326 return ATA_UDMA0+3;
327 if (ident->UltraDMAActive & 0x04)
328 return ATA_UDMA0+2;
329 if (ident->UltraDMAActive & 0x02)
330 return ATA_UDMA0+1;
331 if (ident->UltraDMAActive & 0x01)
332 return ATA_UDMA0+0;
333 }
334
335 if (ident->MultiWordDMAActive & 0x04)
336 return ATA_WDMA0+2;
337 if (ident->MultiWordDMAActive & 0x02)
338 return ATA_WDMA0+1;
339 if (ident->MultiWordDMAActive & 0x01)
340 return ATA_WDMA0+0;
341
342 if (ident->SingleWordDMAActive & 0x04)
343 return ATA_SDMA0+2;
344 if (ident->SingleWordDMAActive & 0x02)
345 return ATA_SDMA0+1;
346 if (ident->SingleWordDMAActive & 0x01)
347 return ATA_SDMA0+0;
348
349 if (ident->PioTimingsValid) {
350 if (ident->AdvancedPIOModes & AdvancedPIOModes_5)
351 return ATA_PIO0+5;
352 if (ident->AdvancedPIOModes & AdvancedPIOModes_4)
353 return ATA_PIO0+4;
354 if (ident->AdvancedPIOModes & AdvancedPIOModes_3)
355 return ATA_PIO0+3;
356 }
357 if (ident->PioCycleTimingMode == 2)
358 return ATA_PIO0+2;
359 if (ident->PioCycleTimingMode == 1)
360 return ATA_PIO0+1;
361 if (ident->PioCycleTimingMode == 0)
362 return ATA_PIO0+0;
363
364 return ATA_PIO;
365 } // end ata_cur_mode_from_ident()
366
367 void
368 ata_mode_to_str(
369 char* str,
370 int mode
371 )
372 {
373 if(mode == ATA_SA150-1) {
374 sprintf(str, "SATA");
375 } else
376 if(mode >= ATA_SA300) {
377 sprintf(str, "SATA-300");
378 } else
379 if(mode >= ATA_SA150) {
380 sprintf(str, "SATA-150");
381 } else
382 if(mode >= ATA_UDMA0) {
383 sprintf(str, "UDMA%d", mode-ATA_UDMA0);
384 } else
385 if(mode >= ATA_WDMA0) {
386 sprintf(str, "WDMA%d", mode-ATA_WDMA0);
387 } else
388 if(mode >= ATA_SDMA0) {
389 sprintf(str, "SDMA%d", mode-ATA_SDMA0);
390 } else
391 if(mode >= ATA_PIO0) {
392 sprintf(str, "PIO%d", mode-ATA_PIO0);
393 } else
394 if(mode == ATA_PIO_NRDY) {
395 sprintf(str, "PIO nRDY");
396 } else
397 {
398 sprintf(str, "PIO");
399 }
400 } // end ata_mode_to_str()
401
402 #define check_atamode_str(str, mode) \
403 (!_stricmp(str, "UDMA" #mode) || \
404 !_stricmp(str, "UDMA-" #mode) || \
405 !_stricmp(str, "ATA-" #mode) || \
406 !_stricmp(str, "ATA#" #mode))
407
408 int
409 ata_str_to_mode(
410 char* str
411 )
412 {
413 int mode;
414 int len;
415
416 if(!_stricmp(str, "SATA"))
417 return ATA_SA150;
418
419 if(check_atamode_str(str, 16))
420 return ATA_UDMA0;
421 if(check_atamode_str(str, 25))
422 return ATA_UDMA1;
423 if(check_atamode_str(str, 33))
424 return ATA_UDMA2;
425 if(check_atamode_str(str, 44))
426 return ATA_UDMA3;
427 if(check_atamode_str(str, 66))
428 return ATA_UDMA4;
429 if(check_atamode_str(str, 100))
430 return ATA_UDMA5;
431 if(check_atamode_str(str, 122))
432 return ATA_UDMA6;
433
434 len = strlen(str);
435
436 if(len >= 4 && !_memicmp(str, "UDMA", 4)) {
437 if(len == 4)
438 return ATA_UDMA0;
439 if(len > 5)
440 return -1;
441 mode = str[4] - '0';
442 if(mode < 0 || mode > 7)
443 return -1;
444 return ATA_UDMA0+mode;
445 }
446 if(len >= 4 && !_memicmp(str, "WDMA", 4)) {
447 if(len == 4)
448 return ATA_WDMA0;
449 if(len > 5)
450 return -1;
451 mode = str[4] - '0';
452 if(mode < 0 || mode > 2)
453 return -1;
454 return ATA_WDMA0+mode;
455 }
456 if(len >= 4 && !_memicmp(str, "SDMA", 4)) {
457 if(len == 4)
458 return ATA_SDMA0;
459 if(len > 5)
460 return -1;
461 mode = str[4] - '0';
462 if(mode < 0 || mode > 2)
463 return -1;
464 return ATA_SDMA0+mode;
465 }
466 if(len == 4 && !_memicmp(str, "DMA", 4)) {
467 return ATA_SDMA0;
468 }
469 if(len >= 3 && !_memicmp(str, "PIO", 3)) {
470 if(len == 3)
471 return ATA_PIO;
472 if(len > 4)
473 return -1;
474 mode = str[3] - '0';
475 if(mode < 0 || mode > 5)
476 return -1;
477 return ATA_PIO0+mode;
478 }
479
480 return -1;
481 } // end ata_str_to_mode()
482
483 ULONG
484 EncodeVendorStr(
485 OUT char* Buffer,
486 IN PUCHAR Str,
487 IN ULONG Length,
488 IN ULONG Xorer
489 )
490 {
491 ULONG i,j;
492 UCHAR a;
493
494 for(i=0, j=0; i<Length; i++, j++) {
495 a = Str[i ^ Xorer];
496 if(!a) {
497 Buffer[j] = 0;
498 return j;
499 } else
500 if(a == ' ') {
501 Buffer[j] = '_';
502 } else
503 if((a == '_') ||
504 (a == '#') ||
505 (a == '\\') ||
506 (a == '\"') ||
507 (a == '\'') ||
508 (a < ' ') ||
509 (a >= 127)) {
510 Buffer[j] = '#';
511 j++;
512 sprintf(Buffer+j, "%2.2x", a);
513 j++;
514 } else {
515 Buffer[j] = a;
516 }
517 }
518 Buffer[j] = 0;
519 return j;
520 } // end EncodeVendorStr()
521
522 HKEY
523 ata_get_bblist_regh(
524 IN PIDENTIFY_DATA ident,
525 OUT char* DevSerial,
526 BOOLEAN read_only
527 )
528 {
529 HKEY hKey = NULL;
530 HKEY hKey2 = NULL;
531 ULONG Length;
532 REGSAM access = read_only ? KEY_READ : KEY_ALL_ACCESS;
533
534 Length = EncodeVendorStr(DevSerial, (PUCHAR)ident->ModelNumber, sizeof(ident->ModelNumber), 0x01);
535 DevSerial[Length] = '-';
536 Length++;
537 Length += EncodeVendorStr(DevSerial+Length, ident->SerialNumber, sizeof(ident->SerialNumber), 0x01);
538
539 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\UniATA", NULL, access, &hKey) != ERROR_SUCCESS) {
540 hKey = NULL;
541 goto exit;
542 }
543 if(RegOpenKey(hKey, "Parameters", &hKey2) != ERROR_SUCCESS) {
544 hKey2 = NULL;
545 if(read_only || (RegCreateKey(hKey, "Parameters", &hKey2) != ERROR_SUCCESS)) {
546 hKey2 = NULL;
547 goto exit;
548 }
549 }
550 RegCloseKey(hKey2);
551 if(RegOpenKey(hKey, "Parameters\\BadBlocks", &hKey2) != ERROR_SUCCESS) {
552 hKey2 = NULL;
553 if(read_only || (RegCreateKey(hKey, "Parameters\\BadBlocks", &hKey2) != ERROR_SUCCESS)) {
554 hKey2 = NULL;
555 goto exit;
556 }
557 }
558
559 exit:
560 if(hKey)
561 RegCloseKey(hKey);
562
563 return hKey2;
564 } // end ata_get_bblist_regh()
565
566 IDENTIFY_DATA g_ident;
567
568 int
569 ata_check_unit(
570 HANDLE h, // handle to ScsiXXX:
571 int dev_id
572 )
573 {
574 ULONG status;
575 ULONG returned;
576
577 PSCSI_ADAPTER_BUS_INFO adapterInfo;
578 PSCSI_INQUIRY_DATA inquiryData;
579 SCSI_ADDRESS addr;
580 ULONG i, j;
581 int l_dev_id;
582 ULONG len;
583 GETTRANSFERMODE IoMode;
584 PSENDCMDOUTPARAMS pout;
585 PIDENTIFY_DATA ident;
586 char buff[sizeof(SENDCMDOUTPARAMS)+/*sizeof(IDENTIFY_DATA)*/2048];
587 char mode_str[12];
588 ULONG bus_id = (dev_id >> 24) & 0xff;
589 BOOLEAN found = FALSE;
590 SENDCMDINPARAMS pin;
591 int io_mode = -1;
592 char SerNum[128];
593 char DevSerial[128];
594 char lun_str[10];
595 HKEY hKey2;
596 ULONGLONG max_lba = -1;
597 USHORT chs[3];
598
599 if(dev_id != -1) {
600 dev_id &= 0x00ffffff;
601 }
602 if(dev_id == 0x007f7f7f) {
603 return TRUE;
604 }
605
606 pout = (PSENDCMDOUTPARAMS)buff;
607 ident = (PIDENTIFY_DATA)&(pout->bBuffer);
608
609 status = DeviceIoControl(h,
610 IOCTL_SCSI_GET_INQUIRY_DATA,
611 NULL,
612 0,
613 g_inquiry_buffer,
614 sizeof(g_inquiry_buffer),
615 &returned,
616 FALSE);
617
618 if(!status) {
619 printf("Can't get device info\n");
620 return FALSE;
621 }
622
623 adapterInfo = (PSCSI_ADAPTER_BUS_INFO)g_inquiry_buffer;
624 for (i = 0; i < adapterInfo->NumberOfBuses; i++) {
625 inquiryData = (PSCSI_INQUIRY_DATA) (g_inquiry_buffer +
626 adapterInfo->BusData[i].InquiryDataOffset);
627 while (adapterInfo->BusData[i].InquiryDataOffset) {
628 /*
629 if(dev_id/adapterInfo->BusData[i].NumberOfLogicalUnits ==
630 inquiryData->TargetId &&
631 dev_id%adapterInfo->BusData[i].NumberOfLogicalUnits ==
632 inquiryData->Lun) {
633 printf(" %d %d %3d %s %.28s ",
634 i,
635 inquiryData->TargetId,
636 inquiryData->Lun,
637 (inquiryData->DeviceClaimed) ? "Y" : "N",
638 &inquiryData->InquiryData[8]);
639 }*/
640 l_dev_id = (i << 16) | ((ULONG)(inquiryData->TargetId) << 8) | inquiryData->Lun;
641
642 if(l_dev_id == dev_id || dev_id == -1) {
643
644 if(!memcmp(&inquiryData->InquiryData[8], UNIATA_COMM_PORT_VENDOR_STR, 24)) {
645 // skip communication port
646 goto next_dev;
647 }
648
649 found = TRUE;
650
651 if(inquiryData->Lun) {
652 sprintf(lun_str, ":l%d", inquiryData->Lun);
653 } else {
654 sprintf(lun_str, " ", inquiryData->Lun);
655 }
656
657
658 /*
659 for (j = 0; j < 8; j++) {
660 printf("%02X ", inquiryData->InquiryData[j]);
661 }
662 */
663
664 addr.PortNumber = -1;
665 addr.PathId = inquiryData->PathId;
666 addr.TargetId = inquiryData->TargetId;
667 addr.Lun = inquiryData->Lun;
668 status = ata_send_ioctl(h, &addr, "-UNIATA-",
669 IOCTL_SCSI_MINIPORT_UNIATA_GET_MODE,
670 NULL, 0,
671 &IoMode, sizeof(IoMode),
672 &returned);
673 if(status) {
674 //io_mode = min(IoMode.CurrentMode, IoMode.MaxMode);
675 io_mode = min(max(IoMode.CurrentMode,IoMode.OrigMode),IoMode.MaxMode);
676 } else {
677 io_mode = -1;
678 }
679
680 memset(&pin, 0, sizeof(pin));
681 memset(buff, 0, sizeof(buff));
682 pin.irDriveRegs.bCommandReg = ID_CMD;
683 // this is valid for IDE/ATA, where only 2 devices can be attached to the bus.
684 // probably, we shall change this in future to support SATA splitters
685 pin.bDriveNumber = inquiryData->PathId*2+inquiryData->TargetId;
686
687 status = ata_send_ioctl(h, NULL, "SCSIDISK",
688 IOCTL_SCSI_MINIPORT_IDENTIFY,
689 &pin, sizeof(pin),
690 buff, sizeof(buff),
691 &returned);
692
693 if(!status) {
694 memset(&pin, 0, sizeof(pin));
695 memset(buff, 0, sizeof(buff));
696 pin.irDriveRegs.bCommandReg = ATAPI_ID_CMD;
697 // this is valid for IDE/ATA, where only 2 devices can be attached to the bus.
698 // probably, we shall change this in future to support SATA splitters
699 pin.bDriveNumber = inquiryData->PathId*2+inquiryData->TargetId;
700
701 status = ata_send_ioctl(h, NULL, "SCSIDISK",
702 IOCTL_SCSI_MINIPORT_IDENTIFY,
703 &pin, sizeof(pin),
704 buff, sizeof(buff),
705 &returned);
706
707 }
708
709 if(status) {
710 if(!g_extended) {
711 printf(" b%d:d%d%s %24.24s %4.4s ",
712 i,
713 inquiryData->TargetId,
714 lun_str,
715 /*(inquiryData->DeviceClaimed) ? "Y" : "N",*/
716 (g_extended ? (PUCHAR)"" : &inquiryData->InquiryData[8]),
717 (g_extended ? (PUCHAR)"" : &inquiryData->InquiryData[8+24])
718 );
719 } else {
720 printf(" b%d:d%d%s ",
721 i,
722 inquiryData->TargetId,
723 lun_str
724 );
725 }
726 if(io_mode == -1) {
727 io_mode = ata_cur_mode_from_ident(ident);
728 }
729 } else {
730 goto next_dev;
731
732 }
733 if(io_mode != -1) {
734 ata_mode_to_str(mode_str, io_mode);
735 }
736 if(!g_extended || !status) {
737 if(g_extended) {
738 printf(" %24.24s %4.4s ",
739 (&inquiryData->InquiryData[8]),
740 (&inquiryData->InquiryData[8+24])
741 );
742 }
743 if(io_mode != -1) {
744 printf(" %.12s ", mode_str);
745 }
746 }
747 printf("\n");
748
749 if(status && g_extended) {
750
751 BOOLEAN BlockMode_valid = TRUE;
752 BOOLEAN print_geom = FALSE;
753
754 switch(ident->DeviceType) {
755 case ATAPI_TYPE_DIRECT:
756 if(ident->Removable) {
757 printf(" Floppy ");
758 } else {
759 printf(" Hard Drive ");
760 }
761 break;
762 case ATAPI_TYPE_TAPE:
763 printf(" Tape Drive ");
764 break;
765 case ATAPI_TYPE_CDROM:
766 printf(" CD/DVD Drive ");
767 BlockMode_valid = FALSE;
768 break;
769 case ATAPI_TYPE_OPTICAL:
770 printf(" Optical Drive ");
771 BlockMode_valid = FALSE;
772 break;
773 default:
774 printf(" Hard Drive ");
775 print_geom = 1;
776 //MOV_DD_SWP(max_lba, ident->UserAddressableSectors);
777 max_lba = ident->UserAddressableSectors;
778 if(ident->FeaturesSupport.Address48) {
779 max_lba = ident->UserAddressableSectors48;
780 }
781 //MOV_DW_SWP(chs[0], ident->NumberOfCylinders);
782 //MOV_DW_SWP(chs[1], ident->NumberOfHeads);
783 //MOV_DW_SWP(chs[2], ident->SectorsPerTrack);
784 chs[0] = ident->NumberOfCylinders;
785 chs[1] = ident->NumberOfHeads;
786 chs[2] = ident->SectorsPerTrack;
787 }
788 if(io_mode != -1) {
789 printf(" %.12s\n", mode_str);
790 }
791 for (j = 0; j < 40; j += 2) {
792 MOV_DW_SWP(SerNum[j], ((PUCHAR)ident->ModelNumber)[j]);
793 }
794 printf(" Mod: %40.40s\n", SerNum);
795 for (j = 0; j < 8; j += 2) {
796 MOV_DW_SWP(SerNum[j], ((PUCHAR)ident->FirmwareRevision)[j]);
797 }
798 printf(" Rev: %8.8s\n", SerNum);
799 for (j = 0; j < 20; j += 2) {
800 MOV_DW_SWP(SerNum[j], ((PUCHAR)ident->SerialNumber)[j]);
801 }
802 printf(" S/N: %20.20s\n", SerNum);
803
804 if(BlockMode_valid) {
805 if(ident->MaximumBlockTransfer) {
806 printf(" Multi-block mode: %d block%s\n", ident->MaximumBlockTransfer, ident->MaximumBlockTransfer == 1 ? "" : "s");
807 } else {
808 printf(" Multi-block mode: N/A\n");
809 }
810 }
811 if(print_geom) {
812 printf(" C/H/S: %d/%d/%d \n", chs[0], chs[1], chs[2]);
813 printf(" LBA: %d \n", max_lba);
814 if(max_lba < 2) {
815 printf(" Size: %d kb\n", max_lba/2);
816 } else
817 if(max_lba < 2*1024*1024) {
818 printf(" Size: %d Mb\n", max_lba/2048);
819 } else
820 if(max_lba < (ULONG)2*1024*1024*1024) {
821 printf(" Size: %d.%d (%d) Gb\n", (ULONG)(max_lba/2048/1024),
822 (ULONG)(((max_lba/2048)%1024)/10),
823 (ULONG)(max_lba*512/1000/1000/1000)
824 );
825 } else {
826 printf(" Size: %d.%d (%d) Tb\n", (ULONG)(max_lba/2048/1024/1024),
827 (ULONG)((max_lba/2048/1024)%1024)/10,
828 (ULONG)(max_lba*512/1000/1000/1000)
829 );
830 }
831 }
832 len = 0;
833 if(hKey2 = ata_get_bblist_regh(ident, DevSerial, TRUE)) {
834 if(RegQueryValueEx(hKey2, DevSerial, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
835 printf(" !!! Assigned bad-block list !!!\n");
836 }
837 RegCloseKey(hKey2);
838 }
839
840 }
841 memcpy(&g_ident, ident, sizeof(IDENTIFY_DATA));
842 }
843 next_dev:
844 if (inquiryData->NextInquiryDataOffset == 0) {
845 break;
846 }
847
848 inquiryData = (PSCSI_INQUIRY_DATA) (g_inquiry_buffer +
849 inquiryData->NextInquiryDataOffset);
850 }
851 }
852 if(!found) {
853 printf(" No device(s) found.\n");
854 return FALSE;
855 }
856
857 return TRUE;
858 } // end ata_check_unit()
859
860 BOOLEAN
861 ata_adapter_info(
862 int bus_id,
863 int print_info
864 )
865 {
866 char dev_name[64];
867 HANDLE h;
868 ADAPTERINFO AdapterInfo;
869 ULONG status;
870 ULONG returned;
871 SCSI_ADDRESS addr;
872 PCI_SLOT_NUMBER slotData;
873
874 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
875 h = ata_open_dev(dev_name);
876 if(!h)
877 return FALSE;
878 addr.PortNumber = bus_id;
879
880 memset(&AdapterInfo, 0, sizeof(AdapterInfo));
881
882 status = ata_send_ioctl(h, &addr, "-UNIATA-",
883 IOCTL_SCSI_MINIPORT_UNIATA_ADAPTER_INFO,
884 &AdapterInfo, sizeof(AdapterInfo),
885 &AdapterInfo, sizeof(AdapterInfo),
886 &returned);
887 printf("Scsi%d: %s\n", bus_id, status ? "[UniATA]" : "");
888 if(print_info) {
889 if(!status) {
890 printf("Can't get adapter info\n");
891 } else {
892 if(AdapterInfo.AdapterInterfaceType == PCIBus) {
893 slotData.u.AsULONG = AdapterInfo.slotNumber;
894 printf(" PCI Bus/Dev/Func: %d/%d/%d%s\n",
895 AdapterInfo.SystemIoBusNumber, slotData.u.bits.DeviceNumber, slotData.u.bits.FunctionNumber,
896 AdapterInfo.AdapterInterfaceType == AdapterInfo.OrigAdapterInterfaceType ? "" : " (ISA-Bridged)");
897 printf(" VendorId/DevId/Rev: %#04x/%#04x/%#02x\n", AdapterInfo.DevID >> 16, AdapterInfo.DevID & 0xffff, AdapterInfo.RevID);
898 if(AdapterInfo.DeviceName[0]) {
899 printf(" Name: %s\n", AdapterInfo.DeviceName);
900 }
901 } else
902 if(AdapterInfo.AdapterInterfaceType == Isa) {
903 printf(" ISA Bus\n");
904 }
905 printf(" IRQ: %d\n", AdapterInfo.BusInterruptLevel);
906 }
907 }
908 ata_close_dev(h);
909 return status ? TRUE : FALSE;
910 } // end ata_adapter_info()
911
912 int
913 ata_check_controller(
914 HANDLE h, // handle to ScsiXXX:
915 PIO_SCSI_CAPABILITIES capabilities
916 )
917 {
918 ULONG status;
919 ULONG returned;
920
921 status = DeviceIoControl(h,
922 IOCTL_SCSI_GET_CAPABILITIES,
923 NULL,
924 0,
925 capabilities,
926 sizeof(IO_SCSI_CAPABILITIES),
927 &returned,
928 FALSE);
929 return status;
930 } // end ata_check_controller()
931
932 BOOLEAN
933 ata_list(
934 int bus_id,
935 int dev_id
936 )
937 {
938 char dev_name[64];
939 HANDLE h;
940 BOOLEAN uniata_driven;
941
942 if(bus_id == -1) {
943 for(bus_id=0; TRUE; bus_id++) {
944 if(!ata_list(bus_id, dev_id))
945 break;
946 }
947 return TRUE;
948 }
949 uniata_driven = ata_adapter_info(bus_id, g_adapter_info);
950 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
951 h = ata_open_dev(dev_name);
952 if(!h)
953 return FALSE;
954 if(dev_id == -1) {
955 ata_check_controller(h, &g_capabilities);
956 ata_check_unit(h, -1);
957 ata_close_dev(h);
958 return TRUE;
959 }
960 ata_check_unit(h, dev_id | (bus_id << 24));
961 ata_close_dev(h);
962 return TRUE;
963 } // end ata_list()
964
965 BOOLEAN
966 ata_mode(
967 int bus_id,
968 int dev_id,
969 int mode
970 )
971 {
972 char dev_name[64];
973 HANDLE h;
974 SETTRANSFERMODE IoMode;
975 ULONG status;
976 ULONG returned;
977 SCSI_ADDRESS addr;
978
979 if(dev_id == -1) {
980 return FALSE;
981 }
982 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
983 h = ata_open_dev(dev_name);
984 if(!h)
985 return FALSE;
986 addr.PortNumber = bus_id;
987 addr.PathId = (UCHAR)(dev_id >> 16);
988 addr.TargetId = (UCHAR)(dev_id >> 8);
989 addr.Lun = (UCHAR)(dev_id);
990
991 IoMode.MaxMode = mode;
992 IoMode.ApplyImmediately = FALSE;
993 // IoMode.ApplyImmediately = TRUE;
994 IoMode.OrigMode = mode;
995
996 status = ata_send_ioctl(h, &addr, "-UNIATA-",
997 IOCTL_SCSI_MINIPORT_UNIATA_SET_MAX_MODE,
998 &IoMode, sizeof(IoMode),
999 NULL, 0,
1000 &returned);
1001 if(!status) {
1002 printf("Can't apply specified transfer mode\n");
1003 } else {
1004 ata_mode_to_str(dev_name, mode);
1005 printf("Transfer rate switched to %s\n", dev_name);
1006 }
1007 ata_close_dev(h);
1008 return status ? TRUE : FALSE;
1009 } // end ata_mode()
1010
1011 BOOLEAN
1012 ata_reset(
1013 int bus_id,
1014 int dev_id
1015 )
1016 {
1017 char dev_name[64];
1018 HANDLE h;
1019 ULONG status;
1020 ULONG returned;
1021 SCSI_ADDRESS addr;
1022
1023 if(dev_id == -1) {
1024 return FALSE;
1025 }
1026 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
1027 h = ata_open_dev(dev_name);
1028 if(!h)
1029 return FALSE;
1030 addr.PortNumber = bus_id;
1031 addr.PathId = (UCHAR)(dev_id >> 16);
1032 addr.TargetId = (UCHAR)(dev_id >> 8);
1033 addr.Lun = (UCHAR)(dev_id);
1034
1035 if(addr.TargetId == 0x7f && addr.Lun == 0x7f) {
1036 addr.TargetId = (UCHAR)0xff;
1037 addr.Lun = 0;
1038 printf("Resetting channel...\n");
1039 } else {
1040 printf("Resetting device...\n");
1041 }
1042
1043 status = ata_send_ioctl(h, &addr, "-UNIATA-",
1044 IOCTL_SCSI_MINIPORT_UNIATA_RESET_DEVICE,
1045 NULL, 0,
1046 NULL, 0,
1047 &returned);
1048 if(!status) {
1049 printf("Reset failed\n");
1050 } else {
1051 printf("Channel reset done\n");
1052 }
1053 ata_close_dev(h);
1054 return TRUE;
1055 } // end ata_reset()
1056
1057 BOOLEAN
1058 ata_hide(
1059 int bus_id,
1060 int dev_id,
1061 int lock,
1062 int persistent_hide
1063 )
1064 {
1065 char dev_name[64];
1066 HANDLE h;
1067 ULONG status;
1068 ULONG returned;
1069 SCSI_ADDRESS addr;
1070 ADDREMOVEDEV to;
1071
1072 if(dev_id == -1) {
1073 return FALSE;
1074 }
1075 if(lock < 0) {
1076 lock = DEFAULT_REMOVAL_LOCK_TIMEOUT;
1077 }
1078 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
1079 h = ata_open_dev(dev_name);
1080 if(!h)
1081 return FALSE;
1082 addr.PortNumber = bus_id;
1083 addr.PathId = (UCHAR)(dev_id >> 16);
1084 addr.TargetId = (UCHAR)(dev_id >> 8);
1085 addr.Lun = (UCHAR)(dev_id);
1086
1087 to.WaitForPhysicalLink = lock;
1088 to.Flags = persistent_hide ? UNIATA_REMOVE_FLAGS_HIDE : 0;
1089
1090 printf("Deleting device.\n");
1091 if(lock) {
1092 printf("ATTENTION: you have %d seconds to disconnect cable\n", lock);
1093 }
1094 status = ata_send_ioctl(h, &addr, "-UNIATA-",
1095 IOCTL_SCSI_MINIPORT_UNIATA_DELETE_DEVICE,
1096 &to, sizeof(to),
1097 NULL, 0,
1098 &returned);
1099 ata_close_dev(h);
1100 return TRUE;
1101 } // end ata_hide()
1102
1103 BOOLEAN
1104 ata_scan(
1105 int bus_id,
1106 int dev_id,
1107 int lock,
1108 int unhide
1109 )
1110 {
1111 char dev_name[64];
1112 HANDLE h;
1113 ULONG status;
1114 ULONG returned;
1115 SCSI_ADDRESS addr;
1116 ADDREMOVEDEV to;
1117
1118 if(dev_id == -1) {
1119 return FALSE;
1120 }
1121 if(lock < 0) {
1122 lock = DEFAULT_REMOVAL_LOCK_TIMEOUT;
1123 }
1124 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
1125 h = ata_open_dev(dev_name);
1126 if(!h)
1127 return FALSE;
1128
1129 if((UCHAR)(dev_id) != 0xff &&
1130 (UCHAR)(dev_id >> 8) != 0xff) {
1131
1132 addr.PortNumber = bus_id;
1133 addr.PathId = (UCHAR)(dev_id >> 16);
1134 addr.TargetId = 0;
1135 addr.Lun = 0;
1136
1137 to.WaitForPhysicalLink = lock;
1138 to.Flags = unhide ? UNIATA_ADD_FLAGS_UNHIDE : 0;
1139
1140 printf("Scaning bus for new devices.\n");
1141 if(lock) {
1142 printf("You have %d seconds to connect device.\n", lock);
1143 }
1144 status = ata_send_ioctl(h, &addr, "-UNIATA-",
1145 IOCTL_SCSI_MINIPORT_UNIATA_FIND_DEVICES,
1146 &to, sizeof(to),
1147 NULL, 0,
1148 &returned);
1149 } else {
1150 status = DeviceIoControl(h,
1151 IOCTL_SCSI_RESCAN_BUS,
1152 NULL, 0,
1153 NULL, 0,
1154 &returned,
1155 FALSE);
1156 }
1157 ata_close_dev(h);
1158 return TRUE;
1159 } // end ata_scan()
1160
1161 CHAR*
1162 _fgets(
1163 CHAR *string,
1164 int count,
1165 HANDLE stream
1166 )
1167 {
1168 CHAR *pointer = string;
1169 ULONG read_bytes;
1170
1171 CHAR *retval = string;
1172 int ch = 0;
1173
1174 if (count <= 0)
1175 return(NULL);
1176
1177 while (--count)
1178 {
1179 if(!ReadFile(stream, &ch, 1, &read_bytes, NULL) ||
1180 !read_bytes)
1181 {
1182 if (pointer == string) {
1183 retval=NULL;
1184 goto done;
1185 }
1186 break;
1187 }
1188
1189 if ((*pointer++ = (CHAR)ch) == '\n') {
1190 break;
1191 }
1192 }
1193
1194 *pointer = '\0';
1195
1196 /* Common return */
1197 done:
1198 return(retval);
1199 } // end _fgets()
1200
1201 BOOLEAN
1202 ata_bblk(
1203 int bus_id,
1204 int dev_id,
1205 int list_bb
1206 )
1207 {
1208 char dev_name[64];
1209 char tmp[64];
1210 char DevSerial[128];
1211 HANDLE h = NULL;
1212 HANDLE hf = NULL;
1213 ULONG status;
1214 ULONG returned;
1215 SCSI_ADDRESS addr;
1216 ULONG len;
1217 ULONG Length;
1218 BOOLEAN retval = FALSE;
1219 HKEY hKey2 = NULL;
1220 char* bblist = NULL;
1221 LONGLONG tmp_bb_lba;
1222 LONGLONG tmp_bb_len;
1223 char BB_Msg[256];
1224 int radix=gRadix;
1225 int i, j;
1226 ULONG b;
1227
1228 if(dev_id == -1) {
1229 printf("\nERROR: Target device/bus ID must be specified\n\n");
1230 print_help();
1231 return FALSE;
1232 }
1233 if((dev_id >> 16) & 0xff == 0xff) {
1234 printf("\nERROR: Target device bus number (channel) must be specified with b:<bus id>\n\n");
1235 print_help();
1236 return FALSE;
1237 }
1238 if((dev_id >> 8) & 0xff == 0xff) {
1239 printf("\nERROR: Target device ID must be specified with d:<device id>\n\n");
1240 print_help();
1241 return FALSE;
1242 }
1243 sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
1244 h = ata_open_dev(dev_name);
1245 if(!h) {
1246 if(bus_id == -1) {
1247 printf("Controller number must be specified\n");
1248 } else {
1249 printf("Can't open Controller %d\n", bus_id);
1250 }
1251 return FALSE;
1252 }
1253
1254 if(list_bb == 0) {
1255 hf = ata_open_file(g_bb_list, FALSE);
1256 if(!hf) {
1257 printf("Can't open bad block list file:\n %s\n", g_bb_list);
1258 ata_close_dev(h);
1259 return FALSE;
1260 }
1261
1262 len = GetFileSize(hf, NULL);
1263 if(!len || len == -1)
1264 goto exit;
1265 bblist = (char*)GlobalAlloc(GMEM_FIXED, len*8);
1266 }
1267
1268 if(!ata_check_unit(h, dev_id | (bus_id << 24))) {
1269 goto exit;
1270 }
1271
1272 hKey2 = ata_get_bblist_regh(&g_ident, DevSerial, list_bb==1);
1273 if(!hKey2) {
1274 printf("Can't open registry key:\n HKLM\\SYSTEM\\CurrentControlSet\\Services\\UniATA\\Parameters\\BadBlocks\n");
1275 goto exit;
1276 }
1277
1278 if(list_bb == -1) {
1279 if(RegDeleteValue(hKey2, DevSerial) != ERROR_SUCCESS) {
1280 printf("Can't delete registry value:\n %s\n", DevSerial);
1281 goto exit;
1282 }
1283
1284 addr.PortNumber = bus_id;
1285 addr.PathId = (UCHAR)(dev_id >> 16);
1286 addr.TargetId = (UCHAR)(dev_id >> 8);
1287 addr.Lun = (UCHAR)(dev_id);
1288
1289 status = ata_send_ioctl(h, &addr, "-UNIATA-",
1290 IOCTL_SCSI_MINIPORT_UNIATA_RESETBB,
1291 NULL, 0,
1292 NULL, 0,
1293 &returned);
1294 if(!status) {
1295 printf("Bad block list shall be cleared after reboot.\n");
1296 } else {
1297 printf("Bad block list cleared\n");
1298 }
1299 } else
1300 if(list_bb == 0) {
1301 LONGLONG* pData = ((LONGLONG*)bblist);
1302 char a;
1303 int k, k0;
1304 Length=0;
1305 i=0;
1306 j=0;
1307 k=0;
1308 while(_fgets(BB_Msg, sizeof(BB_Msg), hf)) {
1309 j++;
1310 BB_Msg[sizeof(BB_Msg)-1] = 0;
1311 k=0;
1312 while(a = BB_Msg[k]) {
1313 if(a == ' ' || a == '\t' || a == '\r') {
1314 k++;
1315 continue;
1316 }
1317 break;
1318 }
1319 if(!a || a == ';' || a == '#') {
1320 continue;
1321 }
1322 if(!strncmp(BB_Msg+k, "hex:", 4)) {
1323 radix=16;
1324 continue;
1325 }
1326 if(!strncmp(BB_Msg+k, "dec:", 4)) {
1327 radix=10;
1328 continue;
1329 }
1330 k0 = k;
1331 while(a = BB_Msg[k]) {
1332 if(a == ' ' || a == '\t' || a == '\r') {
1333 BB_Msg[k] = '\t';
1334 }
1335 k++;
1336 if(a == ';' || a == '#') {
1337 break;
1338 }
1339 if(a >= '0' && a <= '9') {
1340 continue;
1341 }
1342 if(radix == 16 && ((a >= 'A' && a <= 'F') || (a >= 'a' && a <= 'f'))) {
1343 continue;
1344 }
1345 printf("Bad input BB list file:\n %s\n", g_bb_list);
1346 printf("Illegal character '%1.1s' in line %d:\n%s\n", BB_Msg+k-1, j, BB_Msg);
1347 k0=-1;
1348 break;
1349 }
1350 if(k0 == -1) {
1351 continue;
1352 }
1353 k = k0;
1354 if(radix == 10) {
1355 b = sscanf(BB_Msg+k, "%I64d\t%I64d", &tmp_bb_lba, &tmp_bb_len);
1356 } else {
1357 b = sscanf(BB_Msg+k, "%I64x\t%I64x", &tmp_bb_lba, &tmp_bb_len);
1358 }
1359 if(b == 1) {
1360 tmp_bb_len = 1;
1361 } else
1362 if(b != 2) {
1363 printf("Bad input BB list file:\n %s\n", g_bb_list);
1364 printf("Can't parse line %d:\n%s\n", j, BB_Msg);
1365 continue;
1366 }
1367 if(!tmp_bb_len) {
1368 printf("Bad input BB list file:\n %s\n", g_bb_list);
1369 printf("BlockCount evaluated to 0 in line %d:\n%s\n", j, BB_Msg);
1370 continue;
1371 }
1372 if(tmp_bb_lba < 0) {
1373 printf("Bad input BB list file:\n %s\n", g_bb_list);
1374 printf("Start LBA evaluated to negative in line %d:\n%s\n", j, BB_Msg);
1375 continue;
1376 }
1377 if(tmp_bb_len < 0) {
1378 printf("Bad input BB list file:\n %s\n", g_bb_list);
1379 printf("BlockCount evaluated to negative in line %d:\n%s\n", j, BB_Msg);
1380 continue;
1381 }
1382
1383 if(i &&
1384 (pData[(i-1)*2+1] == tmp_bb_lba)) {
1385 pData[(i-1)*2+1]+=tmp_bb_len;
1386 } else {
1387 pData[i*2+0]=tmp_bb_lba;
1388 pData[i*2+1]=tmp_bb_lba+tmp_bb_len;
1389 i++;
1390 Length += sizeof(LONGLONG)*2;
1391 }
1392 }
1393
1394 if(RegSetValueEx(hKey2, DevSerial, NULL, REG_BINARY, (const UCHAR*)bblist, Length) != ERROR_SUCCESS) {
1395 printf("Can't set registry value:\n %s\n", DevSerial);
1396 goto exit;
1397 }
1398 /*
1399 addr.PortNumber = bus_id;
1400 addr.PathId = (UCHAR)(dev_id >> 16);
1401 addr.TargetId = (UCHAR)(dev_id >> 8);
1402 addr.Lun = (UCHAR)(dev_id);
1403
1404 status = ata_send_ioctl(h, &addr, "-UNIATA-",
1405 IOCTL_SCSI_MINIPORT_UNIATA_SETBB,
1406 NULL, 0,
1407 NULL, 0,
1408 &returned);
1409 */
1410 printf("Bad block list shall be applied after reboot\n");
1411 } else {
1412 len = 0;
1413 returned = RegQueryValueEx(hKey2, DevSerial, NULL, NULL, NULL, &len);
1414 if(returned == 2) {
1415 printf("No bad block list assigned\n");
1416 goto exit;
1417 } else
1418 if(returned != ERROR_SUCCESS) {
1419 printf("Can't get registry value:\n %s\n", DevSerial);
1420 goto exit;
1421 }
1422
1423 hf = ata_open_file(g_bb_list, TRUE);
1424 if(!hf) {
1425 printf("Can't create bad block list file:\n %s\n", g_bb_list);
1426 goto exit;
1427 }
1428
1429 bblist = (char*)GlobalAlloc(GMEM_FIXED, len);
1430 if(RegQueryValueEx(hKey2, DevSerial, NULL, NULL, (UCHAR*)bblist, &len) != ERROR_SUCCESS) {
1431 printf("Can't get registry value:\n %s\n", DevSerial);
1432 goto exit;
1433 }
1434 if(g_bb_list) {
1435 for (j = 0; j < 20; j += 2) {
1436 MOV_DW_SWP(tmp[j], ((PUCHAR)(&g_ident.ModelNumber))[j]);
1437 }
1438 b = sprintf(BB_Msg, "#model: %20.20s\n", tmp);
1439 WriteFile(hf, BB_Msg, b, &returned, NULL);
1440 for (j = 0; j < 4; j += 2) {
1441 MOV_DW_SWP(tmp[j], ((PUCHAR)(&g_ident.FirmwareRevision))[j]);
1442 }
1443 b = sprintf(BB_Msg, "#rev: %4.4s\n", tmp);
1444 WriteFile(hf, BB_Msg, b, &returned, NULL);
1445 for (j = 0; j < 20; j += 2) {
1446 MOV_DW_SWP(tmp[j], ((PUCHAR)(&g_ident.SerialNumber))[j]);
1447 }
1448 b = sprintf(BB_Msg, "#s/n: %20.20s\n", tmp);
1449 WriteFile(hf, BB_Msg, b, &returned, NULL);
1450 b = sprintf(BB_Msg, "#%s\n", DevSerial);
1451 WriteFile(hf, BB_Msg, b, &returned, NULL);
1452 b = sprintf(BB_Msg, "#Starting LBA\tNum. of Blocks\n");
1453 WriteFile(hf, BB_Msg, b, &returned, NULL);
1454 b = sprintf(BB_Msg, "hex:\n");
1455 WriteFile(hf, BB_Msg, b, &returned, NULL);
1456 } else {
1457 b = sprintf(BB_Msg, "Starting LBA\tNum. of Blocks (HEX)\n");
1458 WriteFile(hf, BB_Msg, b, &returned, NULL);
1459 }
1460 i = 0;
1461 while(len >= sizeof(LONGLONG)*2) {
1462 tmp_bb_lba = ((LONGLONG*)bblist)[i*2+0];
1463 tmp_bb_len = ((LONGLONG*)bblist)[i*2+1] - tmp_bb_lba;
1464 b = sprintf(BB_Msg, "%I64x\t%I64x\n", tmp_bb_lba, tmp_bb_len);
1465 WriteFile(hf, BB_Msg, b, &returned, NULL);
1466 i++;
1467 len -= sizeof(LONGLONG)*2;
1468 }
1469 }
1470 retval = TRUE;
1471 exit:
1472 if(hKey2)
1473 RegCloseKey(hKey2);
1474 if(bblist) {
1475 GlobalFree(bblist);
1476 }
1477 ata_close_dev(hf);
1478 ata_close_dev(h);
1479 return retval;
1480 } // end ata_bblk()
1481
1482 int
1483 ata_num_to_x_dev(
1484 char a
1485 )
1486 {
1487 if(a >= '0' && a <= '9')
1488 return a-'0';
1489 return -1;
1490 }
1491
1492 int
1493 main (
1494 int argc,
1495 char* argv[]
1496 )
1497 {
1498 ULONG Flags = 0;
1499 int i, j;
1500 char a;
1501 int bus_id = -1;
1502 int dev_id = -1;
1503 int cmd = 0;
1504 int lock = -1;
1505 int b_dev=-1, d_dev=-1, l_dev=0;
1506 int mode=-1;
1507 int list_bb=0;
1508 int persistent_hide=0;
1509
1510 printf("Console ATA control utility for Windows NT3.51/NT4/2000/XP/2003\n"
1511 "Version 0." UNIATA_VER_STR ", Copyright (c) Alexander A. Telyatnikov, 2003-2008\n"
1512 "Home site: http://alter.org.ua\n");
1513
1514 for(i=1; i<argc; i++) {
1515 if(!argv[i])
1516 continue;
1517 if((a = argv[i][0]) != '-') {
1518 for(j=0; a = argv[i][j]; j++) {
1519 switch(a) {
1520 case 'a' :
1521 case 's' :
1522 case 'c' :
1523 j++;
1524 bus_id = ata_num_to_x_dev(argv[i][j]);
1525 break;
1526 case 'b' :
1527 j++;
1528 b_dev = ata_num_to_x_dev(argv[i][j]);
1529 break;
1530 case 'd' :
1531 j++;
1532 d_dev = ata_num_to_x_dev(argv[i][j]);
1533 break;
1534 case 'l' :
1535 j++;
1536 l_dev = ata_num_to_x_dev(argv[i][j]);
1537 break;
1538 case ':' :
1539 break;
1540 default:
1541 print_help();
1542 }
1543 }
1544 continue;
1545 }
1546 j=1;
1547 while(argv[i] && (a = argv[i][j]) && (a != ' ') && (a != '\t')) {
1548 switch(a) {
1549 case 'l' :
1550 if(cmd || lock>0) {
1551 print_help();
1552 }
1553 cmd = CMD_ATA_LIST;
1554 break;
1555 case 'x' :
1556 g_extended = 1;
1557 break;
1558 case 'a' :
1559 g_adapter_info = 1;
1560 break;
1561 case 'S' :
1562 persistent_hide = 1;
1563 case 's' :
1564 if(cmd || lock>0) {
1565 print_help();
1566 }
1567 cmd = CMD_ATA_FIND;
1568 d_dev = 0;
1569 break;
1570 case 'H' :
1571 persistent_hide = 1;
1572 case 'h' :
1573 if(cmd) {
1574 print_help();
1575 }
1576 cmd = CMD_ATA_HIDE;
1577 d_dev = 0;
1578 break;
1579 case 'm' :
1580 if(cmd) {
1581 print_help();
1582 }
1583 cmd = CMD_ATA_MODE;
1584 i++;
1585 if(!argv[i]) {
1586 print_help();
1587 }
1588 mode = ata_str_to_mode(argv[i]);
1589 if(mode == -1) {
1590 i--;
1591 } else {
1592 j = strlen(argv[i])-1;
1593 }
1594 break;
1595 case 'r' :
1596 if(cmd) {
1597 print_help();
1598 }
1599 cmd = CMD_ATA_RESET;
1600 break;
1601 case 'b' :
1602 if(cmd) {
1603 print_help();
1604 }
1605 switch(argv[i][j+1]) {
1606 case 'l':
1607 list_bb = 1;
1608 break;
1609 case 'a':
1610 list_bb = 0;
1611 break;
1612 case 'r':
1613 list_bb = -1;
1614 break;
1615 default:
1616 j--;
1617 }
1618 j++;
1619 cmd = CMD_ATA_BBLK;
1620 break;
1621 case 'f' :
1622 if(cmd != CMD_ATA_BBLK) {
1623 print_help();
1624 }
1625 i++;
1626 if(!argv[i]) {
1627 print_help();
1628 }
1629 g_bb_list=argv[i];
1630 j = strlen(argv[i])-1;
1631 break;
1632 case 'd' :
1633 if(cmd && cmd != CMD_ATA_FIND && cmd != CMD_ATA_HIDE) {
1634 print_help();
1635 }
1636 i++;
1637 if(!argv[i]) {
1638 print_help();
1639 }
1640 if(!sscanf(argv[i], "%d", &lock)) {
1641 lock = DEFAULT_REMOVAL_LOCK_TIMEOUT;
1642 i--;
1643 }
1644 j = strlen(argv[i])-1;
1645 break;
1646 case 'n' :
1647 if(cmd != CMD_ATA_BBLK) {
1648 print_help();
1649 }
1650 i++;
1651 if(!argv[i]) {
1652 print_help();
1653 }
1654 if(!strcmp(argv[i], "hex") ||
1655 !strcmp(argv[i], "16")) {
1656 gRadix = 16;
1657 } else
1658 if(!strcmp(argv[i], "dec") ||
1659 !strcmp(argv[i], "10")) {
1660 gRadix = 10;
1661 } else {
1662 print_help();
1663 }
1664 j = strlen(argv[i])-1;
1665 break;
1666 case '?' :
1667 default:
1668 print_help();
1669 }
1670 j++;
1671 }
1672 }
1673
1674 if(g_adapter_info && !cmd) {
1675 cmd = CMD_ATA_LIST;
1676 b_dev = 127;
1677 d_dev = 127;
1678 l_dev = 127;
1679 } else
1680 if(d_dev == -1 && b_dev != -1) {
1681 d_dev = 127;
1682 l_dev = 127;
1683 }
1684
1685 if(d_dev != -1 && b_dev != -1) {
1686 dev_id = (b_dev << 16) | (d_dev << 8) | l_dev;
1687 }
1688 if(cmd == CMD_ATA_LIST) {
1689 ata_list(bus_id, dev_id);
1690 } else
1691 if(cmd == CMD_ATA_MODE) {
1692 ata_mode(bus_id, dev_id, mode);
1693 } else
1694 if(cmd == CMD_ATA_RESET) {
1695 ata_reset(bus_id, dev_id);
1696 } else
1697 if(cmd == CMD_ATA_FIND) {
1698 ata_scan(bus_id, dev_id, lock, persistent_hide);
1699 } else
1700 if(cmd == CMD_ATA_HIDE) {
1701 ata_hide(bus_id, dev_id, lock, persistent_hide);
1702 } else
1703 if(cmd == CMD_ATA_BBLK) {
1704 ata_bblk(bus_id, dev_id, list_bb);
1705 } else {
1706 print_help();
1707 }
1708 exit(0);
1709 }
1710