7 //#include <ntdddisk.h>
8 //#include <ntddscsi.h>
14 #include <uniata_ver.h>
18 #define DEFAULT_REMOVAL_LOCK_TIMEOUT 20
20 #define MOV_DW_SWP(a,b) \
23 *(unsigned short *)&(a) = _byteswap_ushort(*(unsigned short *)&(b)); \
27 #define MOV_DD_SWP(a,b) \
29 PFOUR_BYTE _from_, _to_; \
30 _from_ = ((PFOUR_BYTE)&(b)); \
31 _to_ = ((PFOUR_BYTE)&(a)); \
32 __asm mov ebx,_from_ \
40 int g_adapter_info
= 0;
41 char* g_bb_list
= NULL
;
43 PADAPTERINFO g_AdapterInfo
= NULL
;
54 " atactl -<switches> c|s<controller id>:b<bus id>:d<device id>[:l<lun>]\n"
56 " l (L)ist devices on SCSI and ATA controllers bus(es)\n"
57 " Note: ATA Pri/Sec controller are usually represented\n"
58 " as Scsi0/Scsi1 under NT-family OSes\n"
59 " x show e(X)tended info\n"
60 " a show (A)dapter info\n"
61 " s (S)can for new devices on ATA/SATA bus(es) (experimental)\n"
62 " S (S)can for new devices on ATA/SATA bus(es) (experimental)\n"
63 " device, hidden with 'H' can be redetected\n"
64 " h (H)ide device on ATA/SATA bus for removal (experimental)\n"
65 " device can be redetected\n"
66 " H (H)ide device on ATA/SATA bus (experimental)\n"
67 " device can not be redetected until 'h' or 'S' is issued\n"
68 " m [MODE] set i/o (M)ode for device or revert to default\n"
69 " available MODEs are PIO, PIO0-PIO5, DMA, WDMA0-WDMA2,\n"
70 " UDMA33/44/66/100/133, UDMA0-UDMA5\n"
71 " d [XXX] lock ATA/SATA bus for device removal for XXX seconds or\n"
72 " for %d seconds if no lock timeout specified.\n"
73 " can be used with -h, -m or standalone.\n"
74 " D [XXX] disable device (turn into sleep mode) and lock ATA/SATA bus \n"
75 " for device removal for XXX seconds or\n"
76 " for %d seconds if no lock timeout specified.\n"
77 " can be used with -h, -m or standalone.\n"
78 " pX change power state to X, where X is\n"
79 " 0 - active, 1 - idle, 2 - standby, 3 - sleep\n"
81 " ba (A)ssign (B)ad-block list\n"
82 " bl get assigned (B)ad-block (L)ist\n"
83 " br (R)eset assigned (B)ad-block list\n"
84 " f specify (F)ile for bad-block list\n"
85 " n XXX block (n)ubmering radix. XXX can be hex or dec\n"
89 " will list all scsi buses and all connected devices\n"
90 " atactl -m udma0 s2:b1:d1\n"
91 " will switch device at Scsi2, bus 1, taget_id 1 to UDMA0 mode\n"
92 " atactl -h -d 30 c1:b0:d0:l0 \n"
93 " will hide Master (d0:l0) device on secondary (c1:b0) IDE channel\n"
94 " and lock i/o on this channel for 30 seconds to ensure safety\n"
97 "Device address format:\n"
99 "s<controller id> number of controller in system. Is assigned during hardware\n"
100 " detection. Usually s0/s1 are ATA Pri/Sec.\n"
101 " Note, due do NT internal design ATA controllers are represented\n"
102 " as SCSI controllers.\n"
103 "b<bus id> For ATA controllers it is channel number.\n"
104 " Note, usually onboard controller is represented as 2 legacy\n"
105 " ISA-compatible single-channel controllers (Scsi9/Scsi1). Additional\n"
106 " ATA, ATA-RAID and some specific onboard controllers are represented\n"
107 " as multichannel controllers.\n"
108 "d<device id> For ATA controllers d0 is Master, d1 is Slave.\n"
109 "l<lun> Not used in ATA controller drivers, alway 0\n"
111 "Bad-block list format:\n"
114 "; Still one comment\n"
115 "hex: switch to hexadecimal mode\n"
116 "<Bad Area 1 Start LBA, e.g. FD50> <Block count 1, e.g. 60>\n"
117 "<Bad Area 2 Start LBA> <Block count 2>\n"
119 "dec: switch to decimal mode\n"
120 "<Bad Area N Start LBA, e.g. 16384> <Block count N, e.g. 48>\n"
124 DEFAULT_REMOVAL_LOCK_TIMEOUT
,
125 DEFAULT_REMOVAL_LOCK_TIMEOUT
130 #define CMD_ATA_LIST 0x01
131 #define CMD_ATA_FIND 0x02
132 #define CMD_ATA_HIDE 0x03
133 #define CMD_ATA_MODE 0x04
134 #define CMD_ATA_RESET 0x05
135 #define CMD_ATA_BBLK 0x06
136 #define CMD_ATA_POWER 0x07
148 READ_CONTROL
| GENERIC_READ
| GENERIC_WRITE
,
149 ((i
& 1) ? 0 : FILE_SHARE_READ
) | ((i
& 2) ? 0 : FILE_SHARE_WRITE
),
152 FILE_ATTRIBUTE_NORMAL
,
154 if(h
&& (h
!= ((HANDLE
)(-1))) ) {
161 GENERIC_READ
| GENERIC_WRITE
,
162 ((i
& 1) ? 0 : FILE_SHARE_READ
) | ((i
& 2) ? 0 : FILE_SHARE_WRITE
),
165 FILE_ATTRIBUTE_NORMAL
,
167 if(h
&& (h
!= ((HANDLE
)(-1))) ) {
175 ((i
& 1) ? 0 : FILE_SHARE_READ
) | ((i
& 2) ? 0 : FILE_SHARE_WRITE
),
178 FILE_ATTRIBUTE_NORMAL
,
180 if(h
&& (h
!= ((HANDLE
)(-1))) ) {
188 ((i
& 1) ? 0 : FILE_SHARE_READ
) | ((i
& 2) ? 0 : FILE_SHARE_WRITE
),
191 FILE_ATTRIBUTE_NORMAL
,
193 if(h
&& (h
!= ((HANDLE
)(-1))) ) {
199 } // end ata_open_dev()
212 return GetStdHandle(STD_OUTPUT_HANDLE
);
214 return GetStdHandle(STD_INPUT_HANDLE
);
220 create
? GENERIC_WRITE
: GENERIC_READ
,
221 ((i
& 1) ? 0 : FILE_SHARE_READ
) | ((i
& 2) ? 0 : FILE_SHARE_WRITE
),
223 create
? CREATE_NEW
: OPEN_EXISTING
,
224 FILE_ATTRIBUTE_NORMAL
,
226 if(h
&& (h
!= ((HANDLE
)(-1))) ) {
232 } // end ata_open_file()
240 } // end ata_close_dev()
249 ULONG inBufferLength
,
251 ULONG outBufferLength
,
257 ULONG data_len
= max(inBufferLength
, outBufferLength
);
261 len
= data_len
+ offsetof(UNIATA_CTL
, RawData
);
263 len
= data_len
+ sizeof(AtaCtl
->hdr
);
265 AtaCtl
= (PUNIATA_CTL
)GlobalAlloc(GMEM_FIXED
, len
);
266 AtaCtl
->hdr
.HeaderLength
= sizeof(SRB_IO_CONTROL
);
268 AtaCtl
->hdr
.Length
= data_len
+ offsetof(UNIATA_CTL
, RawData
) - sizeof(AtaCtl
->hdr
);
270 AtaCtl
->hdr
.Length
= data_len
;
273 memcpy(&AtaCtl
->hdr
.Signature
, Signature
, 8);
275 AtaCtl
->hdr
.Timeout
= 10000;
276 AtaCtl
->hdr
.ControlCode
= Ioctl
;
277 AtaCtl
->hdr
.ReturnCode
= 0;
280 AtaCtl
->addr
= *addr
;
281 AtaCtl
->addr
.Length
= sizeof(AtaCtl
->addr
);
284 if(outBufferLength
) {
286 memset(&AtaCtl
->RawData
, 0, outBufferLength
);
288 memset(&AtaCtl
->addr
, 0, outBufferLength
);
292 if(inBuffer
&& inBufferLength
) {
294 memcpy(&AtaCtl
->RawData
, inBuffer
, inBufferLength
);
296 memcpy(&AtaCtl
->addr
, inBuffer
, inBufferLength
);
300 status
= DeviceIoControl(h
,
309 if(outBuffer
&& outBufferLength
) {
311 memcpy(outBuffer
, &AtaCtl
->RawData
, outBufferLength
);
313 memcpy(outBuffer
, &AtaCtl
->addr
, outBufferLength
);
319 status
= GetLastError();
323 } // end ata_send_ioctl()
334 PSENSE_DATA senseData
,
339 PSCSI_PASS_THROUGH_WITH_BUFFERS sptwb
;
340 //ULONG data_len = BufferLength;
343 len
= BufferLength
+ offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS
, ucDataBuf
);
345 sptwb
= (PSCSI_PASS_THROUGH_WITH_BUFFERS
)GlobalAlloc(GMEM_FIXED
, len
);
349 memset(sptwb
, 0, offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS
, ucDataBuf
));
351 sptwb
->spt
.Length
= sizeof(SCSI_PASS_THROUGH
);
352 sptwb
->spt
.PathId
= addr
->PathId
;
353 sptwb
->spt
.TargetId
= addr
->TargetId
;
354 sptwb
->spt
.Lun
= addr
->Lun
;
355 sptwb
->spt
.CdbLength
= cdbLength
;
356 sptwb
->spt
.SenseInfoLength
= 24;
357 sptwb
->spt
.DataIn
= Buffer
? (DataIn
? SCSI_IOCTL_DATA_IN
: SCSI_IOCTL_DATA_OUT
) : 0;
358 sptwb
->spt
.DataTransferLength
= BufferLength
;
359 sptwb
->spt
.TimeOutValue
= 10;
360 sptwb
->spt
.DataBufferOffset
=
361 offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS
,ucDataBuf
);
362 sptwb
->spt
.SenseInfoOffset
=
363 offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS
,ucSenseBuf
);
364 memcpy(&sptwb
->spt
.Cdb
, cdb
, cdbLength
);
366 if(Buffer
&& !DataIn
) {
367 memcpy(&sptwb
->ucSenseBuf
, Buffer
, BufferLength
);
370 status
= DeviceIoControl(h
,
371 IOCTL_SCSI_PASS_THROUGH
,
373 (Buffer
&& !DataIn
) ? len
: sizeof(SCSI_PASS_THROUGH
),
375 (Buffer
&& DataIn
) ? len
: offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS
, ucDataBuf
),
379 if(Buffer
&& DataIn
) {
380 memcpy(Buffer
, &sptwb
->ucDataBuf
, BufferLength
);
383 memcpy(senseData
, &sptwb
->ucSenseBuf
, sizeof(sptwb
->ucSenseBuf
));
389 status
= GetLastError();
393 } // end ata_send_scsi()
395 IO_SCSI_CAPABILITIES g_capabilities
;
396 UCHAR g_inquiry_buffer
[2048];
404 if(mode
> ATA_SA600
) {
405 sprintf(str
, "SATA-600+");
407 if(mode
>= ATA_SA600
) {
408 sprintf(str
, "SATA-600");
410 if(mode
>= ATA_SA300
) {
411 sprintf(str
, "SATA-300");
413 if(mode
>= ATA_SA150
) {
414 sprintf(str
, "SATA-150");
416 if(mode
>= ATA_UDMA0
) {
417 sprintf(str
, "UDMA%d", mode
-ATA_UDMA0
);
419 if(mode
>= ATA_WDMA0
) {
420 sprintf(str
, "WDMA%d", mode
-ATA_WDMA0
);
422 if(mode
>= ATA_SDMA0
) {
423 sprintf(str
, "SDMA%d", mode
-ATA_SDMA0
);
425 if(mode
>= ATA_PIO0
) {
426 sprintf(str
, "PIO%d", mode
-ATA_PIO0
);
428 if(mode
== ATA_PIO_NRDY
) {
429 sprintf(str
, "PIO nRDY");
434 } // end ata_mode_to_str()
436 #define check_atamode_str(str, mode) \
437 (!_stricmp(str, "UDMA" #mode) || \
438 !_stricmp(str, "UDMA-" #mode) || \
439 !_stricmp(str, "ATA-" #mode) || \
440 !_stricmp(str, "ATA#" #mode))
450 if(!_stricmp(str
, "SATA600"))
452 if(!_stricmp(str
, "SATA300"))
454 if(!_stricmp(str
, "SATA150"))
456 if(!_stricmp(str
, "SATA"))
459 if(check_atamode_str(str
, 16))
461 if(check_atamode_str(str
, 25))
463 if(check_atamode_str(str
, 33))
465 if(check_atamode_str(str
, 44))
467 if(check_atamode_str(str
, 66))
469 if(check_atamode_str(str
, 100))
471 if(check_atamode_str(str
, 122))
476 if(len
>= 4 && !_memicmp(str
, "UDMA", 4)) {
482 if(mode
< 0 || mode
> 7)
484 return ATA_UDMA0
+mode
;
486 if(len
>= 4 && !_memicmp(str
, "WDMA", 4)) {
492 if(mode
< 0 || mode
> 2)
494 return ATA_WDMA0
+mode
;
496 if(len
>= 4 && !_memicmp(str
, "SDMA", 4)) {
502 if(mode
< 0 || mode
> 2)
504 return ATA_SDMA0
+mode
;
506 if(len
== 4 && !_memicmp(str
, "DMA", 4)) {
509 if(len
>= 3 && !_memicmp(str
, "PIO", 3)) {
515 if(mode
< 0 || mode
> 5)
517 return ATA_PIO0
+mode
;
521 } // end ata_str_to_mode()
534 for(i
=0, j
=0; i
<Length
; i
++, j
++) {
552 sprintf(Buffer
+j
, "%2.2x", a
);
560 } // end EncodeVendorStr()
564 IN PIDENTIFY_DATA ident
,
572 REGSAM access
= read_only
? KEY_READ
: KEY_ALL_ACCESS
;
574 Length
= EncodeVendorStr(DevSerial
, (PUCHAR
)ident
->ModelNumber
, sizeof(ident
->ModelNumber
), 0x01);
575 DevSerial
[Length
] = '-';
577 Length
+= EncodeVendorStr(DevSerial
+Length
, ident
->SerialNumber
, sizeof(ident
->SerialNumber
), 0x01);
579 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE
, "SYSTEM\\CurrentControlSet\\Services\\UniATA", NULL
, access
, &hKey
) != ERROR_SUCCESS
) {
583 if(RegOpenKey(hKey
, "Parameters", &hKey2
) != ERROR_SUCCESS
) {
585 if(read_only
|| (RegCreateKey(hKey
, "Parameters", &hKey2
) != ERROR_SUCCESS
)) {
591 if(RegOpenKey(hKey
, "Parameters\\BadBlocks", &hKey2
) != ERROR_SUCCESS
) {
593 if(read_only
|| (RegCreateKey(hKey
, "Parameters\\BadBlocks", &hKey2
) != ERROR_SUCCESS
)) {
604 } // end ata_get_bblist_regh()
606 IDENTIFY_DATA g_ident
;
610 HANDLE h
, // handle to ScsiXXX:
617 PSCSI_ADAPTER_BUS_INFO adapterInfo
;
618 PSCSI_INQUIRY_DATA inquiryData
;
623 GETTRANSFERMODE IoMode
;
624 PSENDCMDOUTPARAMS pout
;
625 PIDENTIFY_DATA ident
;
626 PINQUIRYDATA scsi_ident
;
627 char buff
[sizeof(SENDCMDOUTPARAMS
)+/*sizeof(IDENTIFY_DATA)*/2048];
629 //ULONG bus_id = (dev_id >> 24) & 0xff;
630 BOOLEAN found
= FALSE
;
637 ULONGLONG max_lba
= -1;
638 USHORT chs
[3] = { 0 };
641 dev_id
&= 0x00ffffff;
643 if(dev_id
== 0x007f7f7f) {
647 pout
= (PSENDCMDOUTPARAMS
)buff
;
648 ident
= (PIDENTIFY_DATA
)&(pout
->bBuffer
);
650 status
= DeviceIoControl(h
,
651 IOCTL_SCSI_GET_INQUIRY_DATA
,
655 sizeof(g_inquiry_buffer
),
660 printf("Can't get device info\n");
664 // Note: adapterInfo->NumberOfBuses is 1 greater than g_AdapterInfo->NumberChannels
665 // because of virtual communication port
666 adapterInfo
= (PSCSI_ADAPTER_BUS_INFO
)g_inquiry_buffer
;
667 for (i
= 0; i
+1 < adapterInfo
->NumberOfBuses
; i
++) {
668 inquiryData
= (PSCSI_INQUIRY_DATA
) (g_inquiry_buffer
+
669 adapterInfo
->BusData
[i
].InquiryDataOffset
);
671 if(g_extended
&& g_AdapterInfo
&& g_AdapterInfo
->ChanHeaderLengthValid
&&
672 g_AdapterInfo
->NumberChannels
< i
) {
675 ChanInfo
= (PCHANINFO
)
676 (((PCHAR
)g_AdapterInfo
)+
678 g_AdapterInfo
->ChanHeaderLength
*i
);
680 io_mode
= ChanInfo
->MaxTransferMode
;
682 ata_mode_to_str(mode_str
, io_mode
);
686 printf(" b%lu [%s]\n",
692 while (adapterInfo
->BusData
[i
].InquiryDataOffset
) {
694 if(dev_id/adapterInfo->BusData[i].NumberOfLogicalUnits ==
695 inquiryData->TargetId &&
696 dev_id%adapterInfo->BusData[i].NumberOfLogicalUnits ==
698 printf(" %d %d %3d %s %.28s ",
700 inquiryData->TargetId,
702 (inquiryData->DeviceClaimed) ? "Y" : "N",
703 &inquiryData->InquiryData[8]);
705 l_dev_id
= (i
<< 16) | ((ULONG
)(inquiryData
->TargetId
) << 8) | inquiryData
->Lun
;
707 if(l_dev_id
== dev_id
|| dev_id
== -1) {
709 scsi_ident
= (PINQUIRYDATA
)&(inquiryData
->InquiryData
);
710 if(!memcmp(&(scsi_ident
->VendorId
[0]), UNIATA_COMM_PORT_VENDOR_STR
, 24)) {
711 // skip communication port
717 if(inquiryData
->Lun
) {
718 sprintf(lun_str
, ":l%d", inquiryData
->Lun
);
720 sprintf(lun_str
, " ");
725 for (j = 0; j < 8; j++) {
726 printf("%02X ", inquiryData->InquiryData[j]);
730 addr
.Length
= sizeof(addr
);
731 addr
.PortNumber
= -1;
732 addr
.PathId
= inquiryData
->PathId
;
733 addr
.TargetId
= inquiryData
->TargetId
;
734 addr
.Lun
= inquiryData
->Lun
;
735 status
= ata_send_ioctl(h
, &addr
, "-UNIATA-",
736 IOCTL_SCSI_MINIPORT_UNIATA_GET_MODE
,
738 &IoMode
, sizeof(IoMode
),
741 //io_mode = min(IoMode.CurrentMode, IoMode.MaxMode);
742 io_mode
= IoMode
.PhyMode
;
744 io_mode
= min(max(IoMode
.CurrentMode
,IoMode
.OrigMode
),IoMode
.MaxMode
);
750 memset(&pin
, 0, sizeof(pin
));
751 memset(buff
, 0, sizeof(buff
));
752 pin
.irDriveRegs
.bCommandReg
= ID_CMD
;
753 // this is valid for IDE/ATA, where only 2 devices can be attached to the bus.
754 // probably, we shall change this in future to support SATA splitters
755 pin
.bDriveNumber
= inquiryData
->PathId
*2+inquiryData
->TargetId
;
757 status
= ata_send_ioctl(h
, NULL
, "SCSIDISK",
758 IOCTL_SCSI_MINIPORT_IDENTIFY
,
764 memset(&pin
, 0, sizeof(pin
));
765 memset(buff
, 0, sizeof(buff
));
766 pin
.irDriveRegs
.bCommandReg
= ATAPI_ID_CMD
;
767 // this is valid for IDE/ATA, where only 2 devices can be attached to the bus.
768 // probably, we shall change this in future to support SATA splitters
769 pin
.bDriveNumber
= inquiryData
->PathId
*2+inquiryData
->TargetId
;
771 status
= ata_send_ioctl(h
, NULL
, "SCSIDISK",
772 IOCTL_SCSI_MINIPORT_IDENTIFY
,
780 printf(" b%lu:d%d%s %24.24s %4.4s ",
782 inquiryData
->TargetId
,
784 /*(inquiryData->DeviceClaimed) ? "Y" : "N",*/
785 (g_extended
? (PUCHAR
)"" : &scsi_ident
->VendorId
[0]),
786 (g_extended
? (PUCHAR
)"" : &scsi_ident
->ProductRevisionLevel
[0])
789 printf(" b%lu:d%d%s ",
791 inquiryData
->TargetId
,
798 io_mode
= ata_cur_mode_from_ident(ident
, IDENT_MODE_ACTIVE
);
802 ata_mode_to_str(mode_str
, io_mode
);
804 if(!g_extended
|| !status
) {
806 printf(" %24.24s %4.4s ",
807 (&inquiryData
->InquiryData
[8]),
808 (&inquiryData
->InquiryData
[8+24])
812 printf(" %.12s ", mode_str
);
820 BOOLEAN BlockMode_valid
= TRUE
;
821 BOOLEAN print_geom
= FALSE
;
823 switch(ident
->DeviceType
) {
824 case ATAPI_TYPE_DIRECT
:
825 if(ident
->Removable
) {
828 printf(" Hard Drive ");
831 case ATAPI_TYPE_TAPE
:
832 printf(" Tape Drive ");
834 case ATAPI_TYPE_CDROM
:
835 printf(" CD/DVD Drive ");
836 BlockMode_valid
= FALSE
;
838 case ATAPI_TYPE_OPTICAL
:
839 printf(" Optical Drive ");
840 BlockMode_valid
= FALSE
;
843 printf(" Hard Drive ");
845 //MOV_DD_SWP(max_lba, ident->UserAddressableSectors);
846 max_lba
= ident
->UserAddressableSectors
;
847 if(ident
->FeaturesSupport
.Address48
) {
848 max_lba
= ident
->UserAddressableSectors48
;
850 //MOV_DW_SWP(chs[0], ident->NumberOfCylinders);
851 //MOV_DW_SWP(chs[1], ident->NumberOfHeads);
852 //MOV_DW_SWP(chs[2], ident->SectorsPerTrack);
853 chs
[0] = ident
->NumberOfCylinders
;
854 chs
[1] = ident
->NumberOfHeads
;
855 chs
[2] = ident
->SectorsPerTrack
;
857 max_lba
= (ULONG
)(chs
[0])*(ULONG
)(chs
[1])*(ULONG
)(chs
[2]);
861 printf(" %.12s\n", mode_str
);
863 for (j
= 0; j
< 40; j
+= 2) {
864 MOV_DW_SWP(SerNum
[j
], ((PUCHAR
)ident
->ModelNumber
)[j
]);
866 printf(" Mod: %40.40s\n", SerNum
);
867 for (j
= 0; j
< 8; j
+= 2) {
868 MOV_DW_SWP(SerNum
[j
], ((PUCHAR
)ident
->FirmwareRevision
)[j
]);
870 printf(" Rev: %8.8s\n", SerNum
);
871 for (j
= 0; j
< 20; j
+= 2) {
872 MOV_DW_SWP(SerNum
[j
], ((PUCHAR
)ident
->SerialNumber
)[j
]);
874 printf(" S/N: %20.20s\n", SerNum
);
876 if(BlockMode_valid
) {
877 if(ident
->MaximumBlockTransfer
) {
878 printf(" Multi-block mode: %u block%s\n", ident
->MaximumBlockTransfer
, ident
->MaximumBlockTransfer
== 1 ? "" : "s");
880 printf(" Multi-block mode: N/A\n");
884 printf(" C/H/S: %u/%u/%u \n", chs
[0], chs
[1], chs
[2]);
885 printf(" LBA: %I64u \n", max_lba
);
887 printf(" Size: %lu kb\n", (ULONG
)(max_lba
/2));
889 if(max_lba
< 2*1024*1024) {
890 printf(" Size: %lu Mb\n", (ULONG
)(max_lba
/2048));
892 if(max_lba
< (ULONG
)2*1024*1024*1024) {
893 printf(" Size: %lu.%lu (%lu) Gb\n", (ULONG
)(max_lba
/2048/1024),
894 (ULONG
)(((max_lba
/2048)%1024)/10),
895 (ULONG
)(max_lba
*512/1000/1000/1000)
898 printf(" Size: %lu.%lu (%lu) Tb\n", (ULONG
)(max_lba
/2048/1024/1024),
899 (ULONG
)((max_lba
/2048/1024)%1024)/10,
900 (ULONG
)(max_lba
*512/1000/1000/1000)
905 if((hKey2
= ata_get_bblist_regh(ident
, DevSerial
, TRUE
))) {
906 if(RegQueryValueEx(hKey2
, DevSerial
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
907 printf(" !!! Assigned bad-block list !!!\n");
912 switch(scsi_ident
->DeviceType
) {
913 case DIRECT_ACCESS_DEVICE
:
914 if(scsi_ident
->RemovableMedia
) {
917 printf(" Hard Drive ");
920 case SEQUENTIAL_ACCESS_DEVICE
:
921 printf(" Tape Drive ");
926 case PROCESSOR_DEVICE
:
927 printf(" Processor ");
929 case WRITE_ONCE_READ_MULTIPLE_DEVICE
:
930 printf(" WORM Drive ");
932 case READ_ONLY_DIRECT_ACCESS_DEVICE
:
933 printf(" CDROM Drive ");
939 printf(" Optical Drive ");
944 case COMMUNICATION_DEVICE
:
945 printf(" Comm. device ");
951 memcpy(&g_ident
, ident
, sizeof(IDENTIFY_DATA
));
954 if (inquiryData
->NextInquiryDataOffset
== 0) {
958 inquiryData
= (PSCSI_INQUIRY_DATA
) (g_inquiry_buffer
+
959 inquiryData
->NextInquiryDataOffset
);
963 printf(" No device(s) found.\n");
968 } // end ata_check_unit()
978 PADAPTERINFO AdapterInfo
;
982 PCI_SLOT_NUMBER slotData
;
986 sprintf(dev_name
, "\\\\.\\Scsi%d:", bus_id
);
987 h
= ata_open_dev(dev_name
);
990 addr
.Length
= sizeof(addr
);
991 addr
.PortNumber
= bus_id
;
993 len
= sizeof(ADAPTERINFO
)+sizeof(CHANINFO
)*AHCI_MAX_PORT
;
995 AdapterInfo
= (PADAPTERINFO
)GlobalAlloc(GMEM_FIXED
, len
);
1001 AdapterInfo
= g_AdapterInfo
;
1003 memset(AdapterInfo
, 0, len
);
1005 status
= ata_send_ioctl(h
, &addr
, "-UNIATA-",
1006 IOCTL_SCSI_MINIPORT_UNIATA_ADAPTER_INFO
,
1011 ata_mode_to_str(mode_str
, AdapterInfo
->MaxTransferMode
);
1013 printf("Scsi%d: %s %s\n", bus_id
, status
? "[UniATA]" : "", status
? mode_str
: "");
1016 printf("Can't get adapter info\n");
1018 if(AdapterInfo
->AdapterInterfaceType
== PCIBus
) {
1019 slotData
.u
.AsULONG
= AdapterInfo
->slotNumber
;
1020 printf(" PCI Bus/Dev/Func: %lu/%lu/%lu%s\n",
1021 AdapterInfo
->SystemIoBusNumber
, slotData
.u
.bits
.DeviceNumber
, slotData
.u
.bits
.FunctionNumber
,
1022 AdapterInfo
->AdapterInterfaceType
== AdapterInfo
->OrigAdapterInterfaceType
? "" : " (ISA-Bridged)");
1023 printf(" VendorId/DevId/Rev: %#04x/%#04x/%#02x\n",
1024 (USHORT
)(AdapterInfo
->DevID
>> 16),
1025 (USHORT
)(AdapterInfo
->DevID
& 0xffff),
1026 (UCHAR
)(AdapterInfo
->RevID
));
1027 if(AdapterInfo
->DeviceName
[0]) {
1028 printf(" Name: %s\n", AdapterInfo
->DeviceName
);
1031 if(AdapterInfo
->AdapterInterfaceType
== Isa
) {
1032 printf(" ISA Bus\n");
1034 printf(" IRQ: %ld\n", AdapterInfo
->BusInterruptLevel
);
1038 //GlobalFree(AdapterInfo);
1039 g_AdapterInfo
= AdapterInfo
;
1040 return status
? TRUE
: FALSE
;
1041 } // end ata_adapter_info()
1044 ata_check_controller(
1045 HANDLE h
, // handle to ScsiXXX:
1046 PIO_SCSI_CAPABILITIES capabilities
1052 status
= DeviceIoControl(h
,
1053 IOCTL_SCSI_GET_CAPABILITIES
,
1057 sizeof(IO_SCSI_CAPABILITIES
),
1061 } // end ata_check_controller()
1071 //BOOLEAN uniata_driven;
1074 for(bus_id
=0; TRUE
; bus_id
++) {
1075 if(!ata_list(bus_id
, dev_id
))
1080 /*uniata_driven =*/ ata_adapter_info(bus_id
, g_adapter_info
);
1081 sprintf(dev_name
, "\\\\.\\Scsi%d:", bus_id
);
1082 h
= ata_open_dev(dev_name
);
1086 ata_check_controller(h
, &g_capabilities
);
1087 ata_check_unit(h
, -1);
1091 ata_check_unit(h
, dev_id
| (bus_id
<< 24));
1105 SETTRANSFERMODE IoMode
;
1113 sprintf(dev_name
, "\\\\.\\Scsi%d:", bus_id
);
1114 h
= ata_open_dev(dev_name
);
1117 addr
.Length
= sizeof(addr
);
1118 addr
.PortNumber
= bus_id
;
1119 addr
.PathId
= (UCHAR
)(dev_id
>> 16);
1120 addr
.TargetId
= (UCHAR
)(dev_id
>> 8);
1121 addr
.Lun
= (UCHAR
)(dev_id
);
1123 IoMode
.MaxMode
= mode
;
1124 IoMode
.ApplyImmediately
= FALSE
;
1125 // IoMode.ApplyImmediately = TRUE;
1126 IoMode
.OrigMode
= mode
;
1128 status
= ata_send_ioctl(h
, &addr
, "-UNIATA-",
1129 IOCTL_SCSI_MINIPORT_UNIATA_SET_MAX_MODE
,
1130 &IoMode
, sizeof(IoMode
),
1134 printf("Can't apply specified transfer mode\n");
1136 ata_mode_to_str(dev_name
, mode
);
1137 printf("Transfer rate switched to %s\n", dev_name
);
1140 return status
? TRUE
: FALSE
;
1158 sprintf(dev_name
, "\\\\.\\Scsi%d:", bus_id
);
1159 h
= ata_open_dev(dev_name
);
1162 addr
.Length
= sizeof(addr
);
1163 addr
.PortNumber
= bus_id
;
1164 addr
.PathId
= (UCHAR
)(dev_id
>> 16);
1165 addr
.TargetId
= (UCHAR
)(dev_id
>> 8);
1166 addr
.Lun
= (UCHAR
)(dev_id
);
1168 if(addr
.TargetId
== 0x7f && addr
.Lun
== 0x7f) {
1169 addr
.TargetId
= (UCHAR
)0xff;
1171 printf("Resetting channel...\n");
1173 printf("Resetting device...\n");
1176 status
= ata_send_ioctl(h
, &addr
, "-UNIATA-",
1177 IOCTL_SCSI_MINIPORT_UNIATA_RESET_DEVICE
,
1182 printf("Reset failed\n");
1184 printf("Channel reset done\n");
1188 } // end ata_reset()
1195 int persistent_hide
,
1211 ata_power_mode(bus_id
, dev_id
, power_mode
);
1215 lock
= DEFAULT_REMOVAL_LOCK_TIMEOUT
;
1217 sprintf(dev_name
, "\\\\.\\Scsi%d:", bus_id
);
1218 h
= ata_open_dev(dev_name
);
1221 addr
.Length
= sizeof(addr
);
1222 addr
.PortNumber
= bus_id
;
1223 addr
.PathId
= (UCHAR
)(dev_id
>> 16);
1224 addr
.TargetId
= (UCHAR
)(dev_id
>> 8);
1225 addr
.Lun
= (UCHAR
)(dev_id
);
1227 to
.WaitForPhysicalLink
= lock
;
1228 to
.Flags
= persistent_hide
? UNIATA_REMOVE_FLAGS_HIDE
: 0;
1230 printf("Deleting device.\n");
1232 printf("ATTENTION: you have %d seconds to disconnect cable\n", lock
);
1234 status
= ata_send_ioctl(h
, &addr
, "-UNIATA-",
1235 IOCTL_SCSI_MINIPORT_UNIATA_DELETE_DEVICE
,
1240 printf("Delete failed\n");
1242 printf("Device is detached\n");
1245 return status
? TRUE
: FALSE
;
1267 lock
= DEFAULT_REMOVAL_LOCK_TIMEOUT
;
1269 sprintf(dev_name
, "\\\\.\\Scsi%d:", bus_id
);
1270 h
= ata_open_dev(dev_name
);
1274 if((UCHAR
)(dev_id
) != 0xff &&
1275 (UCHAR
)(dev_id
>> 8) != 0xff) {
1277 addr
.Length
= sizeof(addr
);
1278 addr
.PortNumber
= bus_id
;
1279 addr
.PathId
= (UCHAR
)(dev_id
>> 16);
1283 to
.WaitForPhysicalLink
= lock
;
1284 to
.Flags
= unhide
? UNIATA_ADD_FLAGS_UNHIDE
: 0;
1286 printf("Scanning bus for new devices.\n");
1288 printf("You have %d seconds to connect device.\n", lock
);
1290 status
= ata_send_ioctl(h
, &addr
, "-UNIATA-",
1291 IOCTL_SCSI_MINIPORT_UNIATA_FIND_DEVICES
,
1296 status
= DeviceIoControl(h
,
1297 IOCTL_SCSI_RESCAN_BUS
,
1304 return status
? TRUE
: FALSE
;
1314 CHAR
*pointer
= string
;
1317 CHAR
*retval
= string
;
1325 if(!ReadFile(stream
, &ch
, 1, &read_bytes
, NULL
) ||
1328 if (pointer
== string
) {
1335 if ((*pointer
++ = (CHAR
)ch
) == '\n') {
1356 char DevSerial
[128];
1364 BOOLEAN retval
= FALSE
;
1366 char* bblist
= NULL
;
1367 LONGLONG tmp_bb_lba
;
1368 LONGLONG tmp_bb_len
;
1375 printf("\nERROR: Target device/bus ID must be specified\n\n");
1379 if(((dev_id
>> 16) & 0xff) == 0xff) {
1380 printf("\nERROR: Target device bus number (channel) must be specified with b:<bus id>\n\n");
1384 if(((dev_id
>> 8) & 0xff) == 0xff) {
1385 printf("\nERROR: Target device ID must be specified with d:<device id>\n\n");
1389 sprintf(dev_name
, "\\\\.\\Scsi%d:", bus_id
);
1390 h
= ata_open_dev(dev_name
);
1393 printf("Controller number must be specified\n");
1395 printf("Can't open Controller %d\n", bus_id
);
1401 hf
= ata_open_file(g_bb_list
, FALSE
);
1403 printf("Can't open bad block list file:\n %s\n", g_bb_list
);
1408 len
= GetFileSize(hf
, NULL
);
1409 if(!len
|| len
== INVALID_FILE_SIZE
)
1411 bblist
= (char*)GlobalAlloc(GMEM_FIXED
, len
*8);
1414 if(!ata_check_unit(h
, dev_id
| (bus_id
<< 24))) {
1418 hKey2
= ata_get_bblist_regh(&g_ident
, DevSerial
, list_bb
==1);
1420 printf("Can't open registry key:\n HKLM\\SYSTEM\\CurrentControlSet\\Services\\UniATA\\Parameters\\BadBlocks\n");
1425 if(RegDeleteValue(hKey2
, DevSerial
) != ERROR_SUCCESS
) {
1426 printf("Can't delete registry value:\n %s\n", DevSerial
);
1430 addr
.PortNumber
= bus_id
;
1431 addr
.PathId
= (UCHAR
)(dev_id
>> 16);
1432 addr
.TargetId
= (UCHAR
)(dev_id
>> 8);
1433 addr
.Lun
= (UCHAR
)(dev_id
);
1435 status
= ata_send_ioctl(h
, &addr
, "-UNIATA-",
1436 IOCTL_SCSI_MINIPORT_UNIATA_RESETBB
,
1441 printf("Bad block list shall be cleared after reboot.\n");
1443 printf("Bad block list cleared\n");
1447 LONGLONG
* pData
= ((LONGLONG
*)bblist
);
1454 while(_fgets(BB_Msg
, sizeof(BB_Msg
), hf
)) {
1456 BB_Msg
[sizeof(BB_Msg
)-1] = 0;
1458 while((a
= BB_Msg
[k
])) {
1459 if(a
== ' ' || a
== '\t' || a
== '\r') {
1465 if(!a
|| a
== ';' || a
== '#') {
1468 if(!strncmp(BB_Msg
+k
, "hex:", 4)) {
1472 if(!strncmp(BB_Msg
+k
, "dec:", 4)) {
1477 while((a
= BB_Msg
[k
])) {
1478 if(a
== ' ' || a
== '\t' || a
== '\r') {
1482 if(a
== ';' || a
== '#') {
1485 if(a
>= '0' && a
<= '9') {
1488 if(radix
== 16 && ((a
>= 'A' && a
<= 'F') || (a
>= 'a' && a
<= 'f'))) {
1491 printf("Bad input BB list file:\n %s\n", g_bb_list
);
1492 printf("Illegal character '%1.1s' in line %d:\n%s\n", BB_Msg
+k
-1, j
, BB_Msg
);
1501 b
= sscanf(BB_Msg
+k
, "%I64u\t%I64u", &tmp_bb_lba
, &tmp_bb_len
);
1503 b
= sscanf(BB_Msg
+k
, "%I64x\t%I64x", &tmp_bb_lba
, &tmp_bb_len
);
1509 printf("Bad input BB list file:\n %s\n", g_bb_list
);
1510 printf("Can't parse line %d:\n%s\n", j
, BB_Msg
);
1514 printf("Bad input BB list file:\n %s\n", g_bb_list
);
1515 printf("BlockCount evaluated to 0 in line %d:\n%s\n", j
, BB_Msg
);
1518 if(tmp_bb_lba
< 0) {
1519 printf("Bad input BB list file:\n %s\n", g_bb_list
);
1520 printf("Start LBA evaluated to negative in line %d:\n%s\n", j
, BB_Msg
);
1523 if(tmp_bb_len
< 0) {
1524 printf("Bad input BB list file:\n %s\n", g_bb_list
);
1525 printf("BlockCount evaluated to negative in line %d:\n%s\n", j
, BB_Msg
);
1530 (pData
[(i
-1)*2+1] == tmp_bb_lba
)) {
1531 pData
[(i
-1)*2+1]+=tmp_bb_len
;
1533 pData
[i
*2+0]=tmp_bb_lba
;
1534 pData
[i
*2+1]=tmp_bb_lba
+tmp_bb_len
;
1536 Length
+= sizeof(LONGLONG
)*2;
1540 if(RegSetValueEx(hKey2
, DevSerial
, NULL
, REG_BINARY
, (const UCHAR
*)bblist
, Length
) != ERROR_SUCCESS
) {
1541 printf("Can't set registry value:\n %s\n", DevSerial
);
1545 addr.PortNumber = bus_id;
1546 addr.PathId = (UCHAR)(dev_id >> 16);
1547 addr.TargetId = (UCHAR)(dev_id >> 8);
1548 addr.Lun = (UCHAR)(dev_id);
1550 status = ata_send_ioctl(h, &addr, "-UNIATA-",
1551 IOCTL_SCSI_MINIPORT_UNIATA_SETBB,
1556 printf("Bad block list shall be applied after reboot\n");
1559 returned
= RegQueryValueEx(hKey2
, DevSerial
, NULL
, NULL
, NULL
, &len
);
1561 printf("No bad block list assigned\n");
1564 if(returned
!= ERROR_SUCCESS
) {
1565 printf("Can't get registry value:\n %s\n", DevSerial
);
1569 hf
= ata_open_file(g_bb_list
, TRUE
);
1571 printf("Can't create bad block list file:\n %s\n", g_bb_list
);
1575 bblist
= (char*)GlobalAlloc(GMEM_FIXED
, len
);
1576 if(RegQueryValueEx(hKey2
, DevSerial
, NULL
, NULL
, (UCHAR
*)bblist
, &len
) != ERROR_SUCCESS
) {
1577 printf("Can't get registry value:\n %s\n", DevSerial
);
1581 for (j
= 0; j
< 20; j
+= 2) {
1582 MOV_DW_SWP(tmp
[j
], ((PUCHAR
)(&g_ident
.ModelNumber
))[j
]);
1584 b
= sprintf(BB_Msg
, "#model: %20.20s\n", tmp
);
1585 WriteFile(hf
, BB_Msg
, b
, &returned
, NULL
);
1586 for (j
= 0; j
< 4; j
+= 2) {
1587 MOV_DW_SWP(tmp
[j
], ((PUCHAR
)(&g_ident
.FirmwareRevision
))[j
]);
1589 b
= sprintf(BB_Msg
, "#rev: %4.4s\n", tmp
);
1590 WriteFile(hf
, BB_Msg
, b
, &returned
, NULL
);
1591 for (j
= 0; j
< 20; j
+= 2) {
1592 MOV_DW_SWP(tmp
[j
], ((PUCHAR
)(&g_ident
.SerialNumber
))[j
]);
1594 b
= sprintf(BB_Msg
, "#s/n: %20.20s\n", tmp
);
1595 WriteFile(hf
, BB_Msg
, b
, &returned
, NULL
);
1596 b
= sprintf(BB_Msg
, "#%s\n", DevSerial
);
1597 WriteFile(hf
, BB_Msg
, b
, &returned
, NULL
);
1598 b
= sprintf(BB_Msg
, "#Starting LBA\tNum. of Blocks\n");
1599 WriteFile(hf
, BB_Msg
, b
, &returned
, NULL
);
1600 b
= sprintf(BB_Msg
, "hex:\n");
1601 WriteFile(hf
, BB_Msg
, b
, &returned
, NULL
);
1603 b
= sprintf(BB_Msg
, "Starting LBA\tNum. of Blocks (HEX)\n");
1604 WriteFile(hf
, BB_Msg
, b
, &returned
, NULL
);
1607 while(len
>= sizeof(LONGLONG
)*2) {
1608 tmp_bb_lba
= ((LONGLONG
*)bblist
)[i
*2+0];
1609 tmp_bb_len
= ((LONGLONG
*)bblist
)[i
*2+1] - tmp_bb_lba
;
1610 b
= sprintf(BB_Msg
, "%I64u\t%I64u\n", tmp_bb_lba
, tmp_bb_len
);
1611 WriteFile(hf
, BB_Msg
, b
, &returned
, NULL
);
1613 len
-= sizeof(LONGLONG
)*2;
1641 SENSE_DATA senseData
;
1650 sprintf(dev_name
, "\\\\.\\Scsi%d:", bus_id
);
1651 h
= ata_open_dev(dev_name
);
1654 addr
.PortNumber
= bus_id
;
1655 addr
.PathId
= (UCHAR
)(dev_id
>> 16);
1656 addr
.TargetId
= (UCHAR
)(dev_id
>> 8);
1657 addr
.Lun
= (UCHAR
)(dev_id
);
1659 memset(&cdb
, 0, sizeof(cdb
));
1660 cdb
.START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
1661 cdb
.START_STOP
.Immediate
= 1;
1662 cdb
.START_STOP
.PowerConditions
= power_mode
;
1663 cdb
.START_STOP
.Start
= (power_mode
!= StartStop_Power_Sleep
);
1665 printf("Changing power state to ...\n");
1667 status
= ata_send_scsi(h
, &addr
, &cdb
, 6,
1669 &senseData
, &returned
);
1671 return status
? TRUE
: FALSE
;
1672 } // end ata_power_mode()
1679 if(a
>= '0' && a
<= '9')
1697 int b_dev
=-1, d_dev
=-1, l_dev
=0;
1700 int persistent_hide
=0;
1701 int power_mode
=StartStop_Power_NoChg
;
1703 printf("Console ATA control utility for Windows NT3.51/NT4/2000/XP/2003\n"
1704 "Version 0." UNIATA_VER_STR
", Copyright (c) Alexander A. Telyatnikov, 2003-2012\n"
1705 "Home site: http://alter.org.ua\n");
1707 for(i
=1; i
<argc
; i
++) {
1710 if((a
= argv
[i
][0]) != '-') {
1711 for(j
=0; (a
= argv
[i
][j
]); j
++) {
1717 bus_id
= ata_num_to_x_dev(argv
[i
][j
]);
1721 b_dev
= ata_num_to_x_dev(argv
[i
][j
]);
1725 d_dev
= ata_num_to_x_dev(argv
[i
][j
]);
1729 l_dev
= ata_num_to_x_dev(argv
[i
][j
]);
1740 while(argv
[i
] && (a
= argv
[i
][j
]) && (a
!= ' ') && (a
!= '\t')) {
1755 persistent_hide
= 1;
1764 persistent_hide
= 1;
1781 mode
= ata_str_to_mode(argv
[i
]);
1785 j
= strlen(argv
[i
])-1;
1792 cmd
= CMD_ATA_RESET
;
1798 switch(argv
[i
][j
+1]) {
1815 if(cmd
!= CMD_ATA_BBLK
) {
1823 j
= strlen(argv
[i
])-1;
1826 if(cmd
&& (cmd
!= CMD_ATA_FIND
) && (cmd
!= CMD_ATA_HIDE
)) {
1829 switch(argv
[i
][j
+1]) {
1836 power_mode
= StartStop_Power_Idle
;
1840 power_mode
= StartStop_Power_Standby
;
1844 power_mode
= StartStop_Power_Sleep
;
1850 if(power_mode
&& !cmd
) {
1851 cmd
= CMD_ATA_POWER
;
1855 power_mode
= StartStop_Power_Sleep
;
1856 if(cmd
&& (cmd
!= CMD_ATA_HIDE
)) {
1860 if(cmd
&& (cmd
!= CMD_ATA_FIND
) && (cmd
!= CMD_ATA_HIDE
) && (cmd
!= CMD_ATA_POWER
)) {
1870 if(!sscanf(argv
[i
], "%d", &lock
)) {
1871 lock
= DEFAULT_REMOVAL_LOCK_TIMEOUT
;
1874 j
= strlen(argv
[i
])-1;
1877 if(cmd
!= CMD_ATA_BBLK
) {
1884 if(!strcmp(argv
[i
], "hex") ||
1885 !strcmp(argv
[i
], "16")) {
1888 if(!strcmp(argv
[i
], "dec") ||
1889 !strcmp(argv
[i
], "10")) {
1894 j
= strlen(argv
[i
])-1;
1904 if(g_adapter_info
&& !cmd
) {
1910 if((d_dev
== -1) && (b_dev
!= -1)) {
1915 if((d_dev
!= -1) && (b_dev
!= -1)) {
1916 dev_id
= (b_dev
<< 16) | (d_dev
<< 8) | l_dev
;
1918 if(cmd
== CMD_ATA_LIST
) {
1919 ata_list(bus_id
, dev_id
);
1921 if(cmd
== CMD_ATA_MODE
) {
1922 ata_mode(bus_id
, dev_id
, mode
);
1924 if(cmd
== CMD_ATA_RESET
) {
1925 ata_reset(bus_id
, dev_id
);
1927 if(cmd
== CMD_ATA_FIND
) {
1928 ata_scan(bus_id
, dev_id
, lock
, persistent_hide
);
1930 if(cmd
== CMD_ATA_HIDE
) {
1931 ata_hide(bus_id
, dev_id
, lock
, persistent_hide
, power_mode
);
1933 if(cmd
== CMD_ATA_BBLK
) {
1934 ata_bblk(bus_id
, dev_id
, list_bb
);
1936 if(cmd
== CMD_ATA_POWER
) {
1937 ata_power_mode(bus_id
, dev_id
, power_mode
);