4 //#include <ntdddisk.h>
5 //#include <ntddscsi.h>
11 #include <uniata_ver.h>
15 #define DEFAULT_REMOVAL_LOCK_TIMEOUT 20
17 #define MOV_DW_SWP(a,b) \
20 *(unsigned short *)&(a) = _byteswap_ushort(*(unsigned short *)&(b)); \
24 #define MOV_DD_SWP(a,b) \
26 PFOUR_BYTE _from_, _to_; \
27 _from_ = ((PFOUR_BYTE)&(b)); \
28 _to_ = ((PFOUR_BYTE)&(a)); \
29 __asm mov ebx,_from_ \
37 int g_adapter_info
= 0;
38 char* g_bb_list
= NULL
;
43 " atactl -<switches> c|s<controller id>:b<bus id>:d<device id>[:l<lun>]\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"
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"
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"
80 "Device address format:\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"
94 "Bad-block list format:\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"
102 "dec: switch to decimal mode\n"
103 "<Bad Area N Start LBA, e.g. 16384> <Block count N, e.g. 48>\n"
107 DEFAULT_REMOVAL_LOCK_TIMEOUT
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
129 READ_CONTROL
| GENERIC_READ
| GENERIC_WRITE
,
130 ((i
& 1) ? 0 : FILE_SHARE_READ
) | ((i
& 2) ? 0 : FILE_SHARE_WRITE
),
133 FILE_ATTRIBUTE_NORMAL
,
135 if(h
&& (h
!= ((HANDLE
)(-1))) ) {
142 GENERIC_READ
| GENERIC_WRITE
,
143 ((i
& 1) ? 0 : FILE_SHARE_READ
) | ((i
& 2) ? 0 : FILE_SHARE_WRITE
),
146 FILE_ATTRIBUTE_NORMAL
,
148 if(h
&& (h
!= ((HANDLE
)(-1))) ) {
156 ((i
& 1) ? 0 : FILE_SHARE_READ
) | ((i
& 2) ? 0 : FILE_SHARE_WRITE
),
159 FILE_ATTRIBUTE_NORMAL
,
161 if(h
&& (h
!= ((HANDLE
)(-1))) ) {
169 ((i
& 1) ? 0 : FILE_SHARE_READ
) | ((i
& 2) ? 0 : FILE_SHARE_WRITE
),
172 FILE_ATTRIBUTE_NORMAL
,
174 if(h
&& (h
!= ((HANDLE
)(-1))) ) {
180 } // end ata_open_dev()
193 return GetStdHandle(STD_OUTPUT_HANDLE
);
195 return GetStdHandle(STD_INPUT_HANDLE
);
201 create
? GENERIC_WRITE
: GENERIC_READ
,
202 ((i
& 1) ? 0 : FILE_SHARE_READ
) | ((i
& 2) ? 0 : FILE_SHARE_WRITE
),
204 create
? CREATE_NEW
: OPEN_EXISTING
,
205 FILE_ATTRIBUTE_NORMAL
,
207 if(h
&& (h
!= ((HANDLE
)(-1))) ) {
213 } // end ata_open_file()
221 } // end ata_close_dev()
230 ULONG inBufferLength
,
232 ULONG outBufferLength
,
238 ULONG data_len
= max(inBufferLength
, outBufferLength
);
242 len
= data_len
+ offsetof(UNIATA_CTL
, RawData
);
244 len
= data_len
+ sizeof(AtaCtl
->hdr
);
246 AtaCtl
= (PUNIATA_CTL
)GlobalAlloc(GMEM_FIXED
, len
);
247 AtaCtl
->hdr
.HeaderLength
= sizeof(SRB_IO_CONTROL
);
249 AtaCtl
->hdr
.Length
= data_len
+ offsetof(UNIATA_CTL
, RawData
) - sizeof(AtaCtl
->hdr
);
251 AtaCtl
->hdr
.Length
= data_len
;
254 memcpy(&AtaCtl
->hdr
.Signature
, Signature
, 8);
256 AtaCtl
->hdr
.Timeout
= 10000;
257 AtaCtl
->hdr
.ControlCode
= Ioctl
;
258 AtaCtl
->hdr
.ReturnCode
= 0;
261 AtaCtl
->addr
= *addr
;
262 AtaCtl
->addr
.Length
= sizeof(AtaCtl
->addr
);
265 if(inBuffer
&& inBufferLength
) {
267 memcpy(&AtaCtl
->RawData
, inBuffer
, inBufferLength
);
269 memcpy(&AtaCtl
->addr
, inBuffer
, inBufferLength
);
273 status
= DeviceIoControl(h
,
282 if(outBuffer
&& outBufferLength
) {
284 memcpy(outBuffer
, &AtaCtl
->RawData
, outBufferLength
);
286 memcpy(outBuffer
, &AtaCtl
->addr
, outBufferLength
);
292 status
= GetLastError();
296 } // end ata_send_ioctl()
298 IO_SCSI_CAPABILITIES g_capabilities
;
299 UCHAR g_inquiry_buffer
[2048];
306 return (ident
->SataEnable
&& ident
->SataEnable
!= 0xffff);
310 ata_cur_mode_from_ident(
314 if(ata_is_sata(ident
)) {
318 if (ident
->UdmaModesValid
) {
319 if (ident
->UltraDMAActive
& 0x40)
321 if (ident
->UltraDMAActive
& 0x20)
323 if (ident
->UltraDMAActive
& 0x10)
325 if (ident
->UltraDMAActive
& 0x08)
327 if (ident
->UltraDMAActive
& 0x04)
329 if (ident
->UltraDMAActive
& 0x02)
331 if (ident
->UltraDMAActive
& 0x01)
335 if (ident
->MultiWordDMAActive
& 0x04)
337 if (ident
->MultiWordDMAActive
& 0x02)
339 if (ident
->MultiWordDMAActive
& 0x01)
342 if (ident
->SingleWordDMAActive
& 0x04)
344 if (ident
->SingleWordDMAActive
& 0x02)
346 if (ident
->SingleWordDMAActive
& 0x01)
349 if (ident
->PioTimingsValid
) {
350 if (ident
->AdvancedPIOModes
& AdvancedPIOModes_5
)
352 if (ident
->AdvancedPIOModes
& AdvancedPIOModes_4
)
354 if (ident
->AdvancedPIOModes
& AdvancedPIOModes_3
)
357 if (ident
->PioCycleTimingMode
== 2)
359 if (ident
->PioCycleTimingMode
== 1)
361 if (ident
->PioCycleTimingMode
== 0)
365 } // end ata_cur_mode_from_ident()
373 if(mode
== ATA_SA150
-1) {
374 sprintf(str
, "SATA");
376 if(mode
>= ATA_SA300
) {
377 sprintf(str
, "SATA-300");
379 if(mode
>= ATA_SA150
) {
380 sprintf(str
, "SATA-150");
382 if(mode
>= ATA_UDMA0
) {
383 sprintf(str
, "UDMA%d", mode
-ATA_UDMA0
);
385 if(mode
>= ATA_WDMA0
) {
386 sprintf(str
, "WDMA%d", mode
-ATA_WDMA0
);
388 if(mode
>= ATA_SDMA0
) {
389 sprintf(str
, "SDMA%d", mode
-ATA_SDMA0
);
391 if(mode
>= ATA_PIO0
) {
392 sprintf(str
, "PIO%d", mode
-ATA_PIO0
);
394 if(mode
== ATA_PIO_NRDY
) {
395 sprintf(str
, "PIO nRDY");
400 } // end ata_mode_to_str()
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))
416 if(!_stricmp(str
, "SATA"))
419 if(check_atamode_str(str
, 16))
421 if(check_atamode_str(str
, 25))
423 if(check_atamode_str(str
, 33))
425 if(check_atamode_str(str
, 44))
427 if(check_atamode_str(str
, 66))
429 if(check_atamode_str(str
, 100))
431 if(check_atamode_str(str
, 122))
436 if(len
>= 4 && !_memicmp(str
, "UDMA", 4)) {
442 if(mode
< 0 || mode
> 7)
444 return ATA_UDMA0
+mode
;
446 if(len
>= 4 && !_memicmp(str
, "WDMA", 4)) {
452 if(mode
< 0 || mode
> 2)
454 return ATA_WDMA0
+mode
;
456 if(len
>= 4 && !_memicmp(str
, "SDMA", 4)) {
462 if(mode
< 0 || mode
> 2)
464 return ATA_SDMA0
+mode
;
466 if(len
== 4 && !_memicmp(str
, "DMA", 4)) {
469 if(len
>= 3 && !_memicmp(str
, "PIO", 3)) {
475 if(mode
< 0 || mode
> 5)
477 return ATA_PIO0
+mode
;
481 } // end ata_str_to_mode()
494 for(i
=0, j
=0; i
<Length
; i
++, j
++) {
512 sprintf(Buffer
+j
, "%2.2x", a
);
520 } // end EncodeVendorStr()
524 IN PIDENTIFY_DATA ident
,
532 REGSAM access
= read_only
? KEY_READ
: KEY_ALL_ACCESS
;
534 Length
= EncodeVendorStr(DevSerial
, (PUCHAR
)ident
->ModelNumber
, sizeof(ident
->ModelNumber
), 0x01);
535 DevSerial
[Length
] = '-';
537 Length
+= EncodeVendorStr(DevSerial
+Length
, ident
->SerialNumber
, sizeof(ident
->SerialNumber
), 0x01);
539 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE
, "SYSTEM\\CurrentControlSet\\Services\\UniATA", NULL
, access
, &hKey
) != ERROR_SUCCESS
) {
543 if(RegOpenKey(hKey
, "Parameters", &hKey2
) != ERROR_SUCCESS
) {
545 if(read_only
|| (RegCreateKey(hKey
, "Parameters", &hKey2
) != ERROR_SUCCESS
)) {
551 if(RegOpenKey(hKey
, "Parameters\\BadBlocks", &hKey2
) != ERROR_SUCCESS
) {
553 if(read_only
|| (RegCreateKey(hKey
, "Parameters\\BadBlocks", &hKey2
) != ERROR_SUCCESS
)) {
564 } // end ata_get_bblist_regh()
566 IDENTIFY_DATA g_ident
;
570 HANDLE h
, // handle to ScsiXXX:
577 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
578 PSCSI_INQUIRY_DATA inquiryData
;
583 GETTRANSFERMODE IoMode
;
584 PSENDCMDOUTPARAMS pout
;
585 PIDENTIFY_DATA ident
;
586 char buff
[sizeof(SENDCMDOUTPARAMS
)+/*sizeof(IDENTIFY_DATA)*/2048];
588 ULONG bus_id
= (dev_id
>> 24) & 0xff;
589 BOOLEAN found
= FALSE
;
596 ULONGLONG max_lba
= -1;
600 dev_id
&= 0x00ffffff;
602 if(dev_id
== 0x007f7f7f) {
606 pout
= (PSENDCMDOUTPARAMS
)buff
;
607 ident
= (PIDENTIFY_DATA
)&(pout
->bBuffer
);
609 status
= DeviceIoControl(h
,
610 IOCTL_SCSI_GET_INQUIRY_DATA
,
614 sizeof(g_inquiry_buffer
),
619 printf("Can't get device info\n");
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
) {
629 if(dev_id/adapterInfo->BusData[i].NumberOfLogicalUnits ==
630 inquiryData->TargetId &&
631 dev_id%adapterInfo->BusData[i].NumberOfLogicalUnits ==
633 printf(" %d %d %3d %s %.28s ",
635 inquiryData->TargetId,
637 (inquiryData->DeviceClaimed) ? "Y" : "N",
638 &inquiryData->InquiryData[8]);
640 l_dev_id
= (i
<< 16) | ((ULONG
)(inquiryData
->TargetId
) << 8) | inquiryData
->Lun
;
642 if(l_dev_id
== dev_id
|| dev_id
== -1) {
644 if(!memcmp(&inquiryData
->InquiryData
[8], UNIATA_COMM_PORT_VENDOR_STR
, 24)) {
645 // skip communication port
651 if(inquiryData
->Lun
) {
652 sprintf(lun_str
, ":l%d", inquiryData
->Lun
);
654 sprintf(lun_str
, " ", inquiryData
->Lun
);
659 for (j = 0; j < 8; j++) {
660 printf("%02X ", inquiryData->InquiryData[j]);
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
,
671 &IoMode
, sizeof(IoMode
),
674 //io_mode = min(IoMode.CurrentMode, IoMode.MaxMode);
675 io_mode
= min(max(IoMode
.CurrentMode
,IoMode
.OrigMode
),IoMode
.MaxMode
);
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
;
687 status
= ata_send_ioctl(h
, NULL
, "SCSIDISK",
688 IOCTL_SCSI_MINIPORT_IDENTIFY
,
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
;
701 status
= ata_send_ioctl(h
, NULL
, "SCSIDISK",
702 IOCTL_SCSI_MINIPORT_IDENTIFY
,
711 printf(" b%d:d%d%s %24.24s %4.4s ",
713 inquiryData
->TargetId
,
715 /*(inquiryData->DeviceClaimed) ? "Y" : "N",*/
716 (g_extended
? (PUCHAR
)"" : &inquiryData
->InquiryData
[8]),
717 (g_extended
? (PUCHAR
)"" : &inquiryData
->InquiryData
[8+24])
720 printf(" b%d:d%d%s ",
722 inquiryData
->TargetId
,
727 io_mode
= ata_cur_mode_from_ident(ident
);
734 ata_mode_to_str(mode_str
, io_mode
);
736 if(!g_extended
|| !status
) {
738 printf(" %24.24s %4.4s ",
739 (&inquiryData
->InquiryData
[8]),
740 (&inquiryData
->InquiryData
[8+24])
744 printf(" %.12s ", mode_str
);
749 if(status
&& g_extended
) {
751 BOOLEAN BlockMode_valid
= TRUE
;
752 BOOLEAN print_geom
= FALSE
;
754 switch(ident
->DeviceType
) {
755 case ATAPI_TYPE_DIRECT
:
756 if(ident
->Removable
) {
759 printf(" Hard Drive ");
762 case ATAPI_TYPE_TAPE
:
763 printf(" Tape Drive ");
765 case ATAPI_TYPE_CDROM
:
766 printf(" CD/DVD Drive ");
767 BlockMode_valid
= FALSE
;
769 case ATAPI_TYPE_OPTICAL
:
770 printf(" Optical Drive ");
771 BlockMode_valid
= FALSE
;
774 printf(" Hard Drive ");
776 //MOV_DD_SWP(max_lba, ident->UserAddressableSectors);
777 max_lba
= ident
->UserAddressableSectors
;
778 if(ident
->FeaturesSupport
.Address48
) {
779 max_lba
= ident
->UserAddressableSectors48
;
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
;
789 printf(" %.12s\n", mode_str
);
791 for (j
= 0; j
< 40; j
+= 2) {
792 MOV_DW_SWP(SerNum
[j
], ((PUCHAR
)ident
->ModelNumber
)[j
]);
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
]);
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
]);
802 printf(" S/N: %20.20s\n", SerNum
);
804 if(BlockMode_valid
) {
805 if(ident
->MaximumBlockTransfer
) {
806 printf(" Multi-block mode: %d block%s\n", ident
->MaximumBlockTransfer
, ident
->MaximumBlockTransfer
== 1 ? "" : "s");
808 printf(" Multi-block mode: N/A\n");
812 printf(" C/H/S: %d/%d/%d \n", chs
[0], chs
[1], chs
[2]);
813 printf(" LBA: %d \n", max_lba
);
815 printf(" Size: %d kb\n", max_lba
/2);
817 if(max_lba
< 2*1024*1024) {
818 printf(" Size: %d Mb\n", max_lba
/2048);
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)
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)
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");
841 memcpy(&g_ident
, ident
, sizeof(IDENTIFY_DATA
));
844 if (inquiryData
->NextInquiryDataOffset
== 0) {
848 inquiryData
= (PSCSI_INQUIRY_DATA
) (g_inquiry_buffer
+
849 inquiryData
->NextInquiryDataOffset
);
853 printf(" No device(s) found.\n");
858 } // end ata_check_unit()
868 ADAPTERINFO AdapterInfo
;
872 PCI_SLOT_NUMBER slotData
;
874 sprintf(dev_name
, "\\\\.\\Scsi%d:", bus_id
);
875 h
= ata_open_dev(dev_name
);
878 addr
.PortNumber
= bus_id
;
880 memset(&AdapterInfo
, 0, sizeof(AdapterInfo
));
882 status
= ata_send_ioctl(h
, &addr
, "-UNIATA-",
883 IOCTL_SCSI_MINIPORT_UNIATA_ADAPTER_INFO
,
884 &AdapterInfo
, sizeof(AdapterInfo
),
885 &AdapterInfo
, sizeof(AdapterInfo
),
887 printf("Scsi%d: %s\n", bus_id
, status
? "[UniATA]" : "");
890 printf("Can't get adapter info\n");
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
);
902 if(AdapterInfo
.AdapterInterfaceType
== Isa
) {
903 printf(" ISA Bus\n");
905 printf(" IRQ: %d\n", AdapterInfo
.BusInterruptLevel
);
909 return status
? TRUE
: FALSE
;
910 } // end ata_adapter_info()
913 ata_check_controller(
914 HANDLE h
, // handle to ScsiXXX:
915 PIO_SCSI_CAPABILITIES capabilities
921 status
= DeviceIoControl(h
,
922 IOCTL_SCSI_GET_CAPABILITIES
,
926 sizeof(IO_SCSI_CAPABILITIES
),
930 } // end ata_check_controller()
940 BOOLEAN uniata_driven
;
943 for(bus_id
=0; TRUE
; bus_id
++) {
944 if(!ata_list(bus_id
, dev_id
))
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
);
955 ata_check_controller(h
, &g_capabilities
);
956 ata_check_unit(h
, -1);
960 ata_check_unit(h
, dev_id
| (bus_id
<< 24));
974 SETTRANSFERMODE IoMode
;
982 sprintf(dev_name
, "\\\\.\\Scsi%d:", bus_id
);
983 h
= ata_open_dev(dev_name
);
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
);
991 IoMode
.MaxMode
= mode
;
992 IoMode
.ApplyImmediately
= FALSE
;
993 // IoMode.ApplyImmediately = TRUE;
994 IoMode
.OrigMode
= mode
;
996 status
= ata_send_ioctl(h
, &addr
, "-UNIATA-",
997 IOCTL_SCSI_MINIPORT_UNIATA_SET_MAX_MODE
,
998 &IoMode
, sizeof(IoMode
),
1002 printf("Can't apply specified transfer mode\n");
1004 ata_mode_to_str(dev_name
, mode
);
1005 printf("Transfer rate switched to %s\n", dev_name
);
1008 return status
? TRUE
: FALSE
;
1026 sprintf(dev_name
, "\\\\.\\Scsi%d:", bus_id
);
1027 h
= ata_open_dev(dev_name
);
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
);
1035 if(addr
.TargetId
== 0x7f && addr
.Lun
== 0x7f) {
1036 addr
.TargetId
= (UCHAR
)0xff;
1038 printf("Resetting channel...\n");
1040 printf("Resetting device...\n");
1043 status
= ata_send_ioctl(h
, &addr
, "-UNIATA-",
1044 IOCTL_SCSI_MINIPORT_UNIATA_RESET_DEVICE
,
1049 printf("Reset failed\n");
1051 printf("Channel reset done\n");
1055 } // end ata_reset()
1076 lock
= DEFAULT_REMOVAL_LOCK_TIMEOUT
;
1078 sprintf(dev_name
, "\\\\.\\Scsi%d:", bus_id
);
1079 h
= ata_open_dev(dev_name
);
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
);
1087 to
.WaitForPhysicalLink
= lock
;
1088 to
.Flags
= persistent_hide
? UNIATA_REMOVE_FLAGS_HIDE
: 0;
1090 printf("Deleting device.\n");
1092 printf("ATTENTION: you have %d seconds to disconnect cable\n", lock
);
1094 status
= ata_send_ioctl(h
, &addr
, "-UNIATA-",
1095 IOCTL_SCSI_MINIPORT_UNIATA_DELETE_DEVICE
,
1122 lock
= DEFAULT_REMOVAL_LOCK_TIMEOUT
;
1124 sprintf(dev_name
, "\\\\.\\Scsi%d:", bus_id
);
1125 h
= ata_open_dev(dev_name
);
1129 if((UCHAR
)(dev_id
) != 0xff &&
1130 (UCHAR
)(dev_id
>> 8) != 0xff) {
1132 addr
.PortNumber
= bus_id
;
1133 addr
.PathId
= (UCHAR
)(dev_id
>> 16);
1137 to
.WaitForPhysicalLink
= lock
;
1138 to
.Flags
= unhide
? UNIATA_ADD_FLAGS_UNHIDE
: 0;
1140 printf("Scaning bus for new devices.\n");
1142 printf("You have %d seconds to connect device.\n", lock
);
1144 status
= ata_send_ioctl(h
, &addr
, "-UNIATA-",
1145 IOCTL_SCSI_MINIPORT_UNIATA_FIND_DEVICES
,
1150 status
= DeviceIoControl(h
,
1151 IOCTL_SCSI_RESCAN_BUS
,
1168 CHAR
*pointer
= string
;
1171 CHAR
*retval
= string
;
1179 if(!ReadFile(stream
, &ch
, 1, &read_bytes
, NULL
) ||
1182 if (pointer
== string
) {
1189 if ((*pointer
++ = (CHAR
)ch
) == '\n') {
1210 char DevSerial
[128];
1218 BOOLEAN retval
= FALSE
;
1220 char* bblist
= NULL
;
1221 LONGLONG tmp_bb_lba
;
1222 LONGLONG tmp_bb_len
;
1229 printf("\nERROR: Target device/bus ID must be specified\n\n");
1233 if((dev_id
>> 16) & 0xff == 0xff) {
1234 printf("\nERROR: Target device bus number (channel) must be specified with b:<bus id>\n\n");
1238 if((dev_id
>> 8) & 0xff == 0xff) {
1239 printf("\nERROR: Target device ID must be specified with d:<device id>\n\n");
1243 sprintf(dev_name
, "\\\\.\\Scsi%d:", bus_id
);
1244 h
= ata_open_dev(dev_name
);
1247 printf("Controller number must be specified\n");
1249 printf("Can't open Controller %d\n", bus_id
);
1255 hf
= ata_open_file(g_bb_list
, FALSE
);
1257 printf("Can't open bad block list file:\n %s\n", g_bb_list
);
1262 len
= GetFileSize(hf
, NULL
);
1263 if(!len
|| len
== -1)
1265 bblist
= (char*)GlobalAlloc(GMEM_FIXED
, len
*8);
1268 if(!ata_check_unit(h
, dev_id
| (bus_id
<< 24))) {
1272 hKey2
= ata_get_bblist_regh(&g_ident
, DevSerial
, list_bb
==1);
1274 printf("Can't open registry key:\n HKLM\\SYSTEM\\CurrentControlSet\\Services\\UniATA\\Parameters\\BadBlocks\n");
1279 if(RegDeleteValue(hKey2
, DevSerial
) != ERROR_SUCCESS
) {
1280 printf("Can't delete registry value:\n %s\n", DevSerial
);
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
);
1289 status
= ata_send_ioctl(h
, &addr
, "-UNIATA-",
1290 IOCTL_SCSI_MINIPORT_UNIATA_RESETBB
,
1295 printf("Bad block list shall be cleared after reboot.\n");
1297 printf("Bad block list cleared\n");
1301 LONGLONG
* pData
= ((LONGLONG
*)bblist
);
1308 while(_fgets(BB_Msg
, sizeof(BB_Msg
), hf
)) {
1310 BB_Msg
[sizeof(BB_Msg
)-1] = 0;
1312 while(a
= BB_Msg
[k
]) {
1313 if(a
== ' ' || a
== '\t' || a
== '\r') {
1319 if(!a
|| a
== ';' || a
== '#') {
1322 if(!strncmp(BB_Msg
+k
, "hex:", 4)) {
1326 if(!strncmp(BB_Msg
+k
, "dec:", 4)) {
1331 while(a
= BB_Msg
[k
]) {
1332 if(a
== ' ' || a
== '\t' || a
== '\r') {
1336 if(a
== ';' || a
== '#') {
1339 if(a
>= '0' && a
<= '9') {
1342 if(radix
== 16 && ((a
>= 'A' && a
<= 'F') || (a
>= 'a' && a
<= 'f'))) {
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
);
1355 b
= sscanf(BB_Msg
+k
, "%I64d\t%I64d", &tmp_bb_lba
, &tmp_bb_len
);
1357 b
= sscanf(BB_Msg
+k
, "%I64x\t%I64x", &tmp_bb_lba
, &tmp_bb_len
);
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
);
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
);
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
);
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
);
1384 (pData
[(i
-1)*2+1] == tmp_bb_lba
)) {
1385 pData
[(i
-1)*2+1]+=tmp_bb_len
;
1387 pData
[i
*2+0]=tmp_bb_lba
;
1388 pData
[i
*2+1]=tmp_bb_lba
+tmp_bb_len
;
1390 Length
+= sizeof(LONGLONG
)*2;
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
);
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);
1404 status = ata_send_ioctl(h, &addr, "-UNIATA-",
1405 IOCTL_SCSI_MINIPORT_UNIATA_SETBB,
1410 printf("Bad block list shall be applied after reboot\n");
1413 returned
= RegQueryValueEx(hKey2
, DevSerial
, NULL
, NULL
, NULL
, &len
);
1415 printf("No bad block list assigned\n");
1418 if(returned
!= ERROR_SUCCESS
) {
1419 printf("Can't get registry value:\n %s\n", DevSerial
);
1423 hf
= ata_open_file(g_bb_list
, TRUE
);
1425 printf("Can't create bad block list file:\n %s\n", g_bb_list
);
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
);
1435 for (j
= 0; j
< 20; j
+= 2) {
1436 MOV_DW_SWP(tmp
[j
], ((PUCHAR
)(&g_ident
.ModelNumber
))[j
]);
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
]);
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
]);
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
);
1457 b
= sprintf(BB_Msg
, "Starting LBA\tNum. of Blocks (HEX)\n");
1458 WriteFile(hf
, BB_Msg
, b
, &returned
, NULL
);
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
);
1467 len
-= sizeof(LONGLONG
)*2;
1487 if(a
>= '0' && a
<= '9')
1505 int b_dev
=-1, d_dev
=-1, l_dev
=0;
1508 int persistent_hide
=0;
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");
1514 for(i
=1; i
<argc
; i
++) {
1517 if((a
= argv
[i
][0]) != '-') {
1518 for(j
=0; a
= argv
[i
][j
]; j
++) {
1524 bus_id
= ata_num_to_x_dev(argv
[i
][j
]);
1528 b_dev
= ata_num_to_x_dev(argv
[i
][j
]);
1532 d_dev
= ata_num_to_x_dev(argv
[i
][j
]);
1536 l_dev
= ata_num_to_x_dev(argv
[i
][j
]);
1547 while(argv
[i
] && (a
= argv
[i
][j
]) && (a
!= ' ') && (a
!= '\t')) {
1562 persistent_hide
= 1;
1571 persistent_hide
= 1;
1588 mode
= ata_str_to_mode(argv
[i
]);
1592 j
= strlen(argv
[i
])-1;
1599 cmd
= CMD_ATA_RESET
;
1605 switch(argv
[i
][j
+1]) {
1622 if(cmd
!= CMD_ATA_BBLK
) {
1630 j
= strlen(argv
[i
])-1;
1633 if(cmd
&& cmd
!= CMD_ATA_FIND
&& cmd
!= CMD_ATA_HIDE
) {
1640 if(!sscanf(argv
[i
], "%d", &lock
)) {
1641 lock
= DEFAULT_REMOVAL_LOCK_TIMEOUT
;
1644 j
= strlen(argv
[i
])-1;
1647 if(cmd
!= CMD_ATA_BBLK
) {
1654 if(!strcmp(argv
[i
], "hex") ||
1655 !strcmp(argv
[i
], "16")) {
1658 if(!strcmp(argv
[i
], "dec") ||
1659 !strcmp(argv
[i
], "10")) {
1664 j
= strlen(argv
[i
])-1;
1674 if(g_adapter_info
&& !cmd
) {
1680 if(d_dev
== -1 && b_dev
!= -1) {
1685 if(d_dev
!= -1 && b_dev
!= -1) {
1686 dev_id
= (b_dev
<< 16) | (d_dev
<< 8) | l_dev
;
1688 if(cmd
== CMD_ATA_LIST
) {
1689 ata_list(bus_id
, dev_id
);
1691 if(cmd
== CMD_ATA_MODE
) {
1692 ata_mode(bus_id
, dev_id
, mode
);
1694 if(cmd
== CMD_ATA_RESET
) {
1695 ata_reset(bus_id
, dev_id
);
1697 if(cmd
== CMD_ATA_FIND
) {
1698 ata_scan(bus_id
, dev_id
, lock
, persistent_hide
);
1700 if(cmd
== CMD_ATA_HIDE
) {
1701 ata_hide(bus_id
, dev_id
, lock
, persistent_hide
);
1703 if(cmd
== CMD_ATA_BBLK
) {
1704 ata_bblk(bus_id
, dev_id
, list_bb
);