[ATACTL]
authorAmine Khaldi <amine.khaldi@reactos.org>
Tue, 31 Jul 2012 17:18:47 +0000 (17:18 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Tue, 31 Jul 2012 17:18:47 +0000 (17:18 +0000)
* Add atactl from the Uniata suite. It should be useful for troubleshooting uniata.

svn path=/trunk/; revision=57003

reactos/base/applications/CMakeLists.txt
reactos/base/applications/atactl/CMakeLists.txt [new file with mode: 0644]
reactos/base/applications/atactl/atactl.cpp [new file with mode: 0644]
reactos/base/applications/atactl/helper.h [new file with mode: 0644]

index a776a25..7f230cc 100644 (file)
@@ -1,4 +1,5 @@
 
+add_subdirectory(atactl)
 add_subdirectory(cacls)
 add_subdirectory(calc)
 add_subdirectory(charmap)
diff --git a/reactos/base/applications/atactl/CMakeLists.txt b/reactos/base/applications/atactl/CMakeLists.txt
new file mode 100644 (file)
index 0000000..80a3f6a
--- /dev/null
@@ -0,0 +1,16 @@
+
+add_definitions(-DUSER_MODE)
+include_directories(${REACTOS_SOURCE_DIR}/drivers/storage/ide/uniata)
+
+add_executable(atactl atactl.cpp)
+
+set_module_type(atactl win32cui)
+add_importlibs(atactl advapi32 msvcrt kernel32 ntdll)
+
+if(NOT MSVC)
+    # FIXME: http://www.cmake.org/Bug/view.php?id=12998
+    #allow_warnings(atactl)
+    set_source_files_properties(atactl.cpp PROPERTIES COMPILE_FLAGS "-Wno-error")
+    target_link_libraries(atactl gcc)
+endif()
+add_cd_file(TARGET atactl DESTINATION reactos/system32 FOR all)
\ No newline at end of file
diff --git a/reactos/base/applications/atactl/atactl.cpp b/reactos/base/applications/atactl/atactl.cpp
new file mode 100644 (file)
index 0000000..b8137b6
--- /dev/null
@@ -0,0 +1,1710 @@
+#include <windows.h>
+#include <WinIoCtl.h>
+#include <stdio.h>
+//#include <ntdddisk.h>
+//#include <ntddscsi.h>
+#include <ntddscsi.h>
+#include <atapi.h>
+#include <bm_devs.h>
+#include <uata_ctl.h>
+#include <tools.h>
+#include <uniata_ver.h>
+
+#include "helper.h"
+
+#define DEFAULT_REMOVAL_LOCK_TIMEOUT 20
+
+#define MOV_DW_SWP(a,b)                                                  \
+do                                                                       \
+{                                                                        \
+    *(unsigned short *)&(a) = _byteswap_ushort(*(unsigned short *)&(b)); \
+}                                                                        \
+while (0)
+
+#define MOV_DD_SWP(a,b)           \
+{                                 \
+    PFOUR_BYTE _from_, _to_;      \
+    _from_ = ((PFOUR_BYTE)&(b));  \
+    _to_ =   ((PFOUR_BYTE)&(a));  \
+    __asm mov ebx,_from_          \
+    __asm mov eax,[ebx]           \
+    __asm bswap eax               \
+    __asm mov ebx,_to_            \
+    __asm mov [ebx],eax           \
+}
+
+int g_extended = 0;
+int g_adapter_info = 0;
+char* g_bb_list = NULL;
+int gRadix = 16;
+
+void print_help() {
+    printf("Usage:\n"
+           "  atactl -<switches> c|s<controller id>:b<bus id>:d<device id>[:l<lun>]\n"
+           "Switches:\n"
+           "  l         (L)ist devices on SCSI and ATA controllers bus(es)\n"
+           "              Note: ATA Pri/Sec controller are usually represented\n"
+           "              as Scsi0/Scsi1 under NT-family OSes\n"
+           "  x         show e(X)tended info\n"
+           "  a         show (A)dapter info\n"
+           "  s         (S)can for new devices on ATA/SATA bus(es) (experimental)\n"
+           "  S         (S)can for new devices on ATA/SATA bus(es) (experimental)\n"
+           "              device, hidden with 'H' can be redetected\n"
+           "  h         (H)ide device on ATA/SATA bus for removal (experimental)\n"
+           "              device can be redetected\n"
+           "  H         (H)ide device on ATA/SATA bus (experimental)\n"
+           "              device can not be redetected until 'h' or 'S' is issued\n"
+           "  m [MODE]  set i/o (M)ode for device or revert to default\n"
+           "              available MODEs are PIO, PIO0-PIO5, DMA, WDMA0-WDMA2,\n"
+           "              UDMA33/44/66/100/133, UDMA0-UDMA5\n"
+           "  d [XXX]   lock ATA/SATA bus for device removal for XXX seconds or\n"
+           "              for %d seconds if no lock timeout specified.\n"
+           "              can be used with -h, -m or standalone.\n"
+           "  r         (R)eset device\n"
+           "  ba        (A)ssign (B)ad-block list\n"
+           "  bl        get assigned (B)ad-block (L)ist\n"
+           "  br        (R)eset assigned (B)ad-block list\n"
+           "  f         specify (F)ile for bad-block list\n"
+           "  n XXX     block (n)ubmering radix. XXX can be hex or dec\n"
+           "------\n"
+           "Examples:\n"
+           "  atactl -l\n"
+           "    will list all scsi buses and all connected devices\n"
+           "  atactl -m udma0 s2:b1:d1\n"
+           "    will switch device at Scsi2, bus 1, taget_id 1 to UDMA0 mode\n"
+           "  atactl -h -d 30 c1:b0:d0:l0 \n"
+           "    will hide Master (d0:l0) device on secondary (c1:b0) IDE channel\n"
+           "    and lock i/o on this channel for 30 seconds to ensure safity\n"
+           "    of removal process"
+           "------\n"
+           "Device address format:\n"
+           "\n"
+           "s<controller id> number of controller in system. Is assigned during hardware\n"
+           "                   detection. Usually s0/s1 are ATA Pri/Sec.\n"
+           "                   Note, due do NT internal desing ATA controllers are represented\n"
+           "                   as SCSI controllers.\n"
+           "b<bus id>        For ATA controllers it is channel number.\n"
+           "                   Note, usually onboard controller is represented as 2 legacy\n"
+           "                   ISA-compatible single-channel controllers (Scsi9/Scsi1). Additional\n"
+           "                   ATA, ATA-RAID and some specific onboard controllers are represented\n"
+           "                   as multichannel controllers.\n"
+           "d<device id>     For ATA controllers d0 is Master, d1 is Slave.\n"
+           "l<lun>           Not used in ATA controller drivers, alway 0\n"
+           "------\n"
+           "Bad-block list format:\n"
+           "\n"
+           "# Comment\n"
+           "; Still one comment\n"
+           "hex: switch to hexadecimal mode\n"
+           "<Bad Area 1 Start LBA, e.g. FD50> <Block count 1, e.g. 60>\n"
+           "<Bad Area 2 Start LBA> <Block count 2>\n"
+           "...\n"
+           "dec: switch to decimal mode\n"
+           "<Bad Area N Start LBA, e.g. 16384> <Block count N, e.g. 48>\n"
+           "...\n"
+           "------\n"
+           "",
+           DEFAULT_REMOVAL_LOCK_TIMEOUT
+           );
+    exit(0);
+}
+
+#define CMD_ATA_LIST  0x01
+#define CMD_ATA_FIND  0x02
+#define CMD_ATA_HIDE  0x03
+#define CMD_ATA_MODE  0x04
+#define CMD_ATA_RESET 0x05
+#define CMD_ATA_BBLK  0x06
+
+HANDLE
+ata_open_dev(
+    char* Name
+    )
+{
+    ULONG i;
+    HANDLE h;
+
+    for(i=0; i<4; i++) {
+        h = CreateFile(Name,
+                       READ_CONTROL | GENERIC_READ | GENERIC_WRITE ,
+                       ((i & 1) ? 0 : FILE_SHARE_READ) | ((i & 2) ? 0 : FILE_SHARE_WRITE),
+                       NULL,
+                       OPEN_EXISTING,
+                       FILE_ATTRIBUTE_NORMAL,
+                       NULL);
+        if(h && (h != ((HANDLE)(-1))) ) {
+            return h;
+        }
+    }
+
+    for(i=0; i<4; i++) {
+        h = CreateFile(Name,
+                       GENERIC_READ | GENERIC_WRITE ,
+                       ((i & 1) ? 0 : FILE_SHARE_READ) | ((i & 2) ? 0 : FILE_SHARE_WRITE),
+                       NULL,
+                       OPEN_EXISTING,
+                       FILE_ATTRIBUTE_NORMAL,
+                       NULL);
+        if(h && (h != ((HANDLE)(-1))) ) {
+            return h;
+        }
+    }
+
+    for(i=0; i<4; i++) {
+        h = CreateFile(Name,
+                          GENERIC_READ,
+                          ((i & 1) ? 0 : FILE_SHARE_READ) | ((i & 2) ? 0 : FILE_SHARE_WRITE),
+                       NULL,
+                       OPEN_EXISTING,
+                       FILE_ATTRIBUTE_NORMAL,
+                       NULL);
+        if(h && (h != ((HANDLE)(-1))) ) {
+            return h;
+        }
+    }
+
+    for(i=0; i<4; i++) {
+        h = CreateFile(Name,
+                       READ_CONTROL,
+                       ((i & 1) ? 0 : FILE_SHARE_READ) | ((i & 2) ? 0 : FILE_SHARE_WRITE),
+                       NULL,
+                       OPEN_EXISTING,
+                       FILE_ATTRIBUTE_NORMAL,
+                       NULL);
+        if(h && (h != ((HANDLE)(-1))) ) {
+            return h;
+        }
+    }
+
+    return NULL;
+} // end ata_open_dev()
+
+HANDLE
+ata_open_file(
+    char* Name,
+    BOOLEAN create
+    )
+{
+    ULONG i;
+    HANDLE h;
+
+    if(!Name) {
+        if(create) {
+            return GetStdHandle(STD_OUTPUT_HANDLE);
+        } else {
+            return GetStdHandle(STD_INPUT_HANDLE);
+        }
+    }
+
+    for(i=0; i<4; i++) {
+        h = CreateFile(Name,
+                       create ? GENERIC_WRITE : GENERIC_READ ,
+                       ((i & 1) ? 0 : FILE_SHARE_READ) | ((i & 2) ? 0 : FILE_SHARE_WRITE),
+                       NULL,
+                       create ? CREATE_NEW : OPEN_EXISTING,
+                       FILE_ATTRIBUTE_NORMAL,
+                       NULL);
+        if(h && (h != ((HANDLE)(-1))) ) {
+            return h;
+        }
+    }
+
+    return NULL;
+} // end ata_open_file()
+
+void
+ata_close_dev(
+    HANDLE h
+    )
+{
+    CloseHandle(h);
+} // end ata_close_dev()
+
+int
+ata_send_ioctl(
+    HANDLE h,
+    PSCSI_ADDRESS addr,
+    PCHAR  Signature,
+    ULONG  Ioctl,
+    PVOID  inBuffer,
+    ULONG  inBufferLength,
+    PVOID  outBuffer,
+    ULONG  outBufferLength,
+    PULONG returned
+    )
+{
+    ULONG status;
+    PUNIATA_CTL AtaCtl;
+    ULONG data_len = max(inBufferLength, outBufferLength);
+    ULONG len;
+
+    if(addr) {
+        len = data_len + offsetof(UNIATA_CTL, RawData);
+    } else {
+        len = data_len + sizeof(AtaCtl->hdr);
+    }
+    AtaCtl = (PUNIATA_CTL)GlobalAlloc(GMEM_FIXED, len);
+    AtaCtl->hdr.HeaderLength = sizeof(SRB_IO_CONTROL);
+    if(addr) {
+        AtaCtl->hdr.Length = data_len + offsetof(UNIATA_CTL, RawData) - sizeof(AtaCtl->hdr);
+    } else {
+        AtaCtl->hdr.Length = data_len;
+    }
+
+    memcpy(&AtaCtl->hdr.Signature, Signature, 8);
+
+    AtaCtl->hdr.Timeout = 10000;
+    AtaCtl->hdr.ControlCode = Ioctl;
+    AtaCtl->hdr.ReturnCode = 0;
+    
+    if(addr) {
+        AtaCtl->addr = *addr;
+        AtaCtl->addr.Length = sizeof(AtaCtl->addr);
+    }
+
+    if(inBuffer && inBufferLength) {
+        if(addr) {
+            memcpy(&AtaCtl->RawData, inBuffer, inBufferLength);
+        } else {
+            memcpy(&AtaCtl->addr, inBuffer, inBufferLength);
+        }
+    }
+
+    status = DeviceIoControl(h,
+                             IOCTL_SCSI_MINIPORT,
+                             AtaCtl,
+                             len,
+                             AtaCtl,
+                             len,
+                             returned,
+                             FALSE);
+
+    if(outBuffer && outBufferLength) {
+        if(addr) {
+            memcpy(outBuffer, &AtaCtl->RawData, outBufferLength);
+        } else {
+            memcpy(outBuffer, &AtaCtl->addr, outBufferLength);
+        }
+    }
+    GlobalFree(AtaCtl);
+
+    if(!status) {
+        status = GetLastError();
+        return FALSE;
+    }
+    return TRUE;
+} // end ata_send_ioctl()
+
+IO_SCSI_CAPABILITIES g_capabilities;
+UCHAR g_inquiry_buffer[2048];
+
+int
+ata_is_sata(
+    PIDENTIFY_DATA ident
+    )
+{
+    return (ident->SataEnable && ident->SataEnable != 0xffff);
+}
+
+int
+ata_cur_mode_from_ident(
+    PIDENTIFY_DATA ident
+    )
+{
+    if(ata_is_sata(ident)) {
+        return ATA_SA150-1;
+    }
+
+    if (ident->UdmaModesValid) {
+        if (ident->UltraDMAActive & 0x40)
+            return ATA_UDMA0+6;
+        if (ident->UltraDMAActive & 0x20)
+            return ATA_UDMA0+5;
+        if (ident->UltraDMAActive & 0x10)
+            return ATA_UDMA0+4;
+        if (ident->UltraDMAActive & 0x08)
+            return ATA_UDMA0+3;
+        if (ident->UltraDMAActive & 0x04)
+            return ATA_UDMA0+2;
+        if (ident->UltraDMAActive & 0x02)
+            return ATA_UDMA0+1;
+        if (ident->UltraDMAActive & 0x01)
+            return ATA_UDMA0+0;
+    }
+
+    if (ident->MultiWordDMAActive & 0x04)
+        return ATA_WDMA0+2;
+    if (ident->MultiWordDMAActive & 0x02)
+        return ATA_WDMA0+1;
+    if (ident->MultiWordDMAActive & 0x01)
+        return ATA_WDMA0+0;
+
+    if (ident->SingleWordDMAActive & 0x04)
+        return ATA_SDMA0+2;
+    if (ident->SingleWordDMAActive & 0x02)
+        return ATA_SDMA0+1;
+    if (ident->SingleWordDMAActive & 0x01)
+        return ATA_SDMA0+0;
+
+    if (ident->PioTimingsValid) {
+        if (ident->AdvancedPIOModes & AdvancedPIOModes_5)
+            return ATA_PIO0+5;
+        if (ident->AdvancedPIOModes & AdvancedPIOModes_4)
+            return ATA_PIO0+4;
+        if (ident->AdvancedPIOModes & AdvancedPIOModes_3) 
+            return ATA_PIO0+3;
+    }        
+    if (ident->PioCycleTimingMode == 2)
+        return ATA_PIO0+2;
+    if (ident->PioCycleTimingMode == 1)
+        return ATA_PIO0+1;
+    if (ident->PioCycleTimingMode == 0)
+        return ATA_PIO0+0;
+
+    return ATA_PIO;
+} // end ata_cur_mode_from_ident()
+
+void
+ata_mode_to_str(
+    char* str,
+    int mode
+    )
+{
+    if(mode == ATA_SA150-1) {
+        sprintf(str, "SATA");
+    } else
+    if(mode >= ATA_SA300) {
+        sprintf(str, "SATA-300");
+    } else
+    if(mode >= ATA_SA150) {
+        sprintf(str, "SATA-150");
+    } else
+    if(mode >= ATA_UDMA0) {
+        sprintf(str, "UDMA%d", mode-ATA_UDMA0);
+    } else
+    if(mode >= ATA_WDMA0) {
+        sprintf(str, "WDMA%d", mode-ATA_WDMA0);
+    } else
+    if(mode >= ATA_SDMA0) {
+        sprintf(str, "SDMA%d", mode-ATA_SDMA0);
+    } else
+    if(mode >= ATA_PIO0) {
+        sprintf(str, "PIO%d", mode-ATA_PIO0);
+    } else
+    if(mode == ATA_PIO_NRDY) {
+        sprintf(str, "PIO nRDY");
+    } else
+    {
+        sprintf(str, "PIO");
+    }
+} // end ata_mode_to_str()
+
+#define check_atamode_str(str, mode) \
+   (!_stricmp(str, "UDMA" #mode) || \
+    !_stricmp(str, "UDMA-" #mode) || \
+    !_stricmp(str, "ATA-" #mode) || \
+    !_stricmp(str, "ATA#" #mode))
+
+int
+ata_str_to_mode(
+    char* str
+    )
+{
+    int mode;
+    int len;
+
+    if(!_stricmp(str, "SATA"))
+        return ATA_SA150;
+
+    if(check_atamode_str(str, 16))
+        return ATA_UDMA0;
+    if(check_atamode_str(str, 25))
+        return ATA_UDMA1;
+    if(check_atamode_str(str, 33))
+        return ATA_UDMA2;
+    if(check_atamode_str(str, 44))
+        return ATA_UDMA3;
+    if(check_atamode_str(str, 66))
+        return ATA_UDMA4;
+    if(check_atamode_str(str, 100))
+        return ATA_UDMA5;
+    if(check_atamode_str(str, 122))
+        return ATA_UDMA6;
+
+    len = strlen(str);
+
+    if(len >= 4 && !_memicmp(str, "UDMA", 4)) {
+        if(len == 4)
+            return ATA_UDMA0;
+        if(len > 5)
+            return -1;
+        mode = str[4] - '0';
+        if(mode < 0 || mode > 7)
+            return -1;
+        return ATA_UDMA0+mode;
+    }
+    if(len >= 4 && !_memicmp(str, "WDMA", 4)) {
+        if(len == 4)
+            return ATA_WDMA0;
+        if(len > 5)
+            return -1;
+        mode = str[4] - '0';
+        if(mode < 0 || mode > 2)
+            return -1;
+        return ATA_WDMA0+mode;
+    }
+    if(len >= 4 && !_memicmp(str, "SDMA", 4)) {
+        if(len == 4)
+            return ATA_SDMA0;
+        if(len > 5)
+            return -1;
+        mode = str[4] - '0';
+        if(mode < 0 || mode > 2)
+            return -1;
+        return ATA_SDMA0+mode;
+    }
+    if(len == 4 && !_memicmp(str, "DMA", 4)) {
+        return ATA_SDMA0;
+    }
+    if(len >= 3 && !_memicmp(str, "PIO", 3)) {
+        if(len == 3)
+            return ATA_PIO;
+        if(len > 4)
+            return -1;
+        mode = str[3] - '0';
+        if(mode < 0 || mode > 5)
+            return -1;
+        return ATA_PIO0+mode;
+    }
+
+    return -1;
+} // end ata_str_to_mode()
+
+ULONG
+EncodeVendorStr(
+   OUT char*  Buffer,
+    IN PUCHAR Str,
+    IN ULONG  Length,
+    IN ULONG  Xorer
+    )
+{
+    ULONG i,j;
+    UCHAR a;
+
+    for(i=0, j=0; i<Length; i++, j++) {
+        a = Str[i ^ Xorer];
+        if(!a) {
+            Buffer[j] = 0;
+            return j;
+        } else
+        if(a == ' ') {
+            Buffer[j] = '_';
+        } else
+        if((a == '_') ||
+           (a == '#') ||
+           (a == '\\') ||
+           (a == '\"') ||
+           (a == '\'') ||
+           (a <  ' ') ||
+           (a >= 127)) {
+            Buffer[j] = '#';
+            j++;
+            sprintf(Buffer+j, "%2.2x", a);
+            j++;
+        } else {
+            Buffer[j] = a;
+        }
+    }
+    Buffer[j] = 0;
+    return j;
+} // end EncodeVendorStr()
+
+HKEY
+ata_get_bblist_regh(
+    IN PIDENTIFY_DATA ident,
+    OUT char* DevSerial,
+    BOOLEAN read_only
+    )
+{
+    HKEY hKey = NULL;
+    HKEY hKey2 = NULL;
+    ULONG Length;
+    REGSAM access = read_only ? KEY_READ : KEY_ALL_ACCESS;
+
+    Length = EncodeVendorStr(DevSerial, (PUCHAR)ident->ModelNumber, sizeof(ident->ModelNumber), 0x01);
+    DevSerial[Length] = '-';
+    Length++;
+    Length += EncodeVendorStr(DevSerial+Length, ident->SerialNumber, sizeof(ident->SerialNumber), 0x01);
+
+    if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\UniATA", NULL, access, &hKey) != ERROR_SUCCESS) {
+        hKey = NULL;
+        goto exit;
+    }
+    if(RegOpenKey(hKey, "Parameters", &hKey2) != ERROR_SUCCESS) {
+        hKey2 = NULL;
+        if(read_only || (RegCreateKey(hKey, "Parameters", &hKey2) != ERROR_SUCCESS)) {
+            hKey2 = NULL;
+            goto exit;
+        }
+    }
+    RegCloseKey(hKey2);
+    if(RegOpenKey(hKey, "Parameters\\BadBlocks", &hKey2) != ERROR_SUCCESS) {
+        hKey2 = NULL;
+        if(read_only || (RegCreateKey(hKey, "Parameters\\BadBlocks", &hKey2) != ERROR_SUCCESS)) {
+            hKey2 = NULL;
+            goto exit;
+        }
+    }
+
+exit:
+    if(hKey)
+        RegCloseKey(hKey);
+
+    return hKey2;
+} // end ata_get_bblist_regh()
+
+IDENTIFY_DATA   g_ident;
+
+int
+ata_check_unit(
+    HANDLE h,    // handle to ScsiXXX:
+    int dev_id
+    )
+{
+    ULONG status;
+    ULONG returned;
+
+    PSCSI_ADAPTER_BUS_INFO  adapterInfo;
+    PSCSI_INQUIRY_DATA inquiryData;
+    SCSI_ADDRESS addr;
+    ULONG i, j;
+    int l_dev_id;
+    ULONG len;
+    GETTRANSFERMODE IoMode;
+    PSENDCMDOUTPARAMS pout;
+    PIDENTIFY_DATA   ident;
+    char buff[sizeof(SENDCMDOUTPARAMS)+/*sizeof(IDENTIFY_DATA)*/2048];
+    char mode_str[12];
+    ULONG bus_id = (dev_id >> 24) & 0xff;
+    BOOLEAN found = FALSE;
+    SENDCMDINPARAMS pin;
+    int io_mode = -1;
+    char SerNum[128];
+    char DevSerial[128];
+    char lun_str[10];
+    HKEY hKey2;
+    ULONGLONG max_lba = -1;
+    USHORT chs[3];
+
+    if(dev_id != -1) {
+        dev_id &= 0x00ffffff;
+    }
+    if(dev_id == 0x007f7f7f) {
+        return TRUE;
+    }
+
+    pout = (PSENDCMDOUTPARAMS)buff;
+    ident = (PIDENTIFY_DATA)&(pout->bBuffer);
+
+    status = DeviceIoControl(h,
+                             IOCTL_SCSI_GET_INQUIRY_DATA,
+                             NULL,
+                             0,
+                             g_inquiry_buffer,
+                             sizeof(g_inquiry_buffer),
+                             &returned,
+                             FALSE);
+
+    if(!status) {
+        printf("Can't get device info\n");
+        return FALSE;
+    }
+
+    adapterInfo = (PSCSI_ADAPTER_BUS_INFO)g_inquiry_buffer;
+    for (i = 0; i < adapterInfo->NumberOfBuses; i++) {
+        inquiryData = (PSCSI_INQUIRY_DATA) (g_inquiry_buffer +
+            adapterInfo->BusData[i].InquiryDataOffset);
+        while (adapterInfo->BusData[i].InquiryDataOffset) {
+            /*
+            if(dev_id/adapterInfo->BusData[i].NumberOfLogicalUnits ==
+               inquiryData->TargetId &&
+               dev_id%adapterInfo->BusData[i].NumberOfLogicalUnits ==
+               inquiryData->Lun) {
+                printf(" %d   %d  %3d    %s    %.28s ",
+                i,
+                inquiryData->TargetId,
+                inquiryData->Lun,
+                (inquiryData->DeviceClaimed) ? "Y" : "N",
+                &inquiryData->InquiryData[8]);
+            }*/
+            l_dev_id = (i << 16) | ((ULONG)(inquiryData->TargetId) << 8) | inquiryData->Lun;
+            
+            if(l_dev_id == dev_id || dev_id == -1) {
+
+                if(!memcmp(&inquiryData->InquiryData[8], UNIATA_COMM_PORT_VENDOR_STR, 24)) {
+                    // skip communication port
+                    goto next_dev;
+                }
+
+                found = TRUE;
+
+                if(inquiryData->Lun) {
+                    sprintf(lun_str, ":l%d", inquiryData->Lun);
+                } else {
+                    sprintf(lun_str, "  ", inquiryData->Lun);
+                }
+
+
+                /*
+                for (j = 0; j < 8; j++) {
+                    printf("%02X ", inquiryData->InquiryData[j]);
+                }
+                */
+
+                addr.PortNumber = -1;
+                addr.PathId   = inquiryData->PathId;
+                addr.TargetId = inquiryData->TargetId;
+                addr.Lun      = inquiryData->Lun;
+                status = ata_send_ioctl(h, &addr, "-UNIATA-",
+                                        IOCTL_SCSI_MINIPORT_UNIATA_GET_MODE,
+                                        NULL, 0,
+                                        &IoMode, sizeof(IoMode),
+                                        &returned);
+                if(status) {
+                    //io_mode = min(IoMode.CurrentMode, IoMode.MaxMode);
+                    io_mode = min(max(IoMode.CurrentMode,IoMode.OrigMode),IoMode.MaxMode);
+                } else {
+                    io_mode = -1;
+                }
+    
+                memset(&pin, 0, sizeof(pin));
+                memset(buff, 0, sizeof(buff));
+                pin.irDriveRegs.bCommandReg = ID_CMD;
+                // this is valid for IDE/ATA, where only 2 devices can be attached to the bus.
+                // probably, we shall change this in future to support SATA splitters
+                pin.bDriveNumber = inquiryData->PathId*2+inquiryData->TargetId;
+
+                status = ata_send_ioctl(h, NULL, "SCSIDISK",
+                                        IOCTL_SCSI_MINIPORT_IDENTIFY,
+                                        &pin, sizeof(pin),
+                                        buff, sizeof(buff),
+                                        &returned);
+
+                if(!status) {
+                    memset(&pin, 0, sizeof(pin));
+                    memset(buff, 0, sizeof(buff));
+                    pin.irDriveRegs.bCommandReg = ATAPI_ID_CMD;
+                    // this is valid for IDE/ATA, where only 2 devices can be attached to the bus.
+                    // probably, we shall change this in future to support SATA splitters
+                    pin.bDriveNumber = inquiryData->PathId*2+inquiryData->TargetId;
+
+                    status = ata_send_ioctl(h, NULL, "SCSIDISK",
+                                            IOCTL_SCSI_MINIPORT_IDENTIFY,
+                                            &pin, sizeof(pin),
+                                            buff, sizeof(buff),
+                                            &returned);
+
+                }
+
+                if(status) {
+                    if(!g_extended) {
+                        printf("  b%d:d%d%s    %24.24s %4.4s ",
+                            i,
+                            inquiryData->TargetId,
+                            lun_str,
+                            /*(inquiryData->DeviceClaimed) ? "Y" : "N",*/
+                            (g_extended ? (PUCHAR)"" : &inquiryData->InquiryData[8]),
+                            (g_extended ? (PUCHAR)"" : &inquiryData->InquiryData[8+24])
+                            );
+                    } else {
+                        printf("  b%d:d%d%s ",
+                            i,
+                            inquiryData->TargetId,
+                            lun_str
+                            );
+                    }
+                    if(io_mode == -1) {
+                        io_mode = ata_cur_mode_from_ident(ident);
+                    }
+                } else {
+                    goto next_dev;
+
+                }
+                if(io_mode != -1) {
+                    ata_mode_to_str(mode_str, io_mode);
+                }
+                if(!g_extended || !status) {
+                    if(g_extended) {
+                        printf("   %24.24s %4.4s ",
+                            (&inquiryData->InquiryData[8]),
+                            (&inquiryData->InquiryData[8+24])
+                            );
+                    }
+                    if(io_mode != -1) {
+                        printf(" %.12s ", mode_str);
+                    }
+                }
+                printf("\n");
+
+                if(status && g_extended) {
+
+                    BOOLEAN BlockMode_valid = TRUE;
+                    BOOLEAN print_geom = FALSE;
+
+                    switch(ident->DeviceType) {
+                    case ATAPI_TYPE_DIRECT:
+                        if(ident->Removable) {
+                            printf("    Floppy        ");
+                        } else {
+                            printf("    Hard Drive    ");
+                        }
+                        break;
+                    case ATAPI_TYPE_TAPE:
+                        printf("    Tape Drive    ");
+                        break;
+                    case ATAPI_TYPE_CDROM:
+                        printf("    CD/DVD Drive  ");
+                        BlockMode_valid = FALSE;
+                        break;
+                    case ATAPI_TYPE_OPTICAL:
+                        printf("    Optical Drive ");
+                        BlockMode_valid = FALSE;
+                        break;
+                    default:
+                        printf("    Hard Drive    ");
+                        print_geom = 1;
+                        //MOV_DD_SWP(max_lba, ident->UserAddressableSectors);
+                        max_lba = ident->UserAddressableSectors;
+                        if(ident->FeaturesSupport.Address48) {
+                           max_lba = ident->UserAddressableSectors48;
+                        }
+                        //MOV_DW_SWP(chs[0], ident->NumberOfCylinders);
+                        //MOV_DW_SWP(chs[1], ident->NumberOfHeads);
+                        //MOV_DW_SWP(chs[2], ident->SectorsPerTrack);
+                        chs[0] = ident->NumberOfCylinders;
+                        chs[1] = ident->NumberOfHeads;
+                        chs[2] = ident->SectorsPerTrack;
+                    }
+                    if(io_mode != -1) {
+                        printf("           %.12s\n", mode_str);
+                    }
+                    for (j = 0; j < 40; j += 2) {
+                        MOV_DW_SWP(SerNum[j], ((PUCHAR)ident->ModelNumber)[j]);
+                    }
+                    printf("    Mod: %40.40s\n", SerNum);
+                    for (j = 0; j < 8; j += 2) {
+                        MOV_DW_SWP(SerNum[j], ((PUCHAR)ident->FirmwareRevision)[j]);
+                    }
+                    printf("    Rev: %8.8s\n", SerNum);
+                    for (j = 0; j < 20; j += 2) {
+                        MOV_DW_SWP(SerNum[j], ((PUCHAR)ident->SerialNumber)[j]);
+                    }
+                    printf("    S/N: %20.20s\n", SerNum);
+
+                    if(BlockMode_valid) {
+                        if(ident->MaximumBlockTransfer) {
+                            printf("    Multi-block mode:        %d block%s\n", ident->MaximumBlockTransfer, ident->MaximumBlockTransfer == 1 ? "" : "s");
+                        } else {
+                            printf("    Multi-block mode:        N/A\n");
+                        }
+                    }
+                    if(print_geom) {
+                        printf("    C/H/S:                   %d/%d/%d \n", chs[0], chs[1], chs[2]);
+                        printf("    LBA:                     %d \n", max_lba);
+                        if(max_lba < 2) {
+                            printf("    Size:                    %d kb\n", max_lba/2);
+                        } else
+                        if(max_lba < 2*1024*1024) {
+                            printf("    Size:                    %d Mb\n", max_lba/2048);
+                        } else
+                        if(max_lba < (ULONG)2*1024*1024*1024) {
+                            printf("    Size:                    %d.%d (%d) Gb\n", (ULONG)(max_lba/2048/1024),
+                                                                              (ULONG)(((max_lba/2048)%1024)/10),
+                                                                              (ULONG)(max_lba*512/1000/1000/1000)
+                            );
+                        } else {
+                            printf("    Size:                    %d.%d (%d) Tb\n", (ULONG)(max_lba/2048/1024/1024),
+                                                                              (ULONG)((max_lba/2048/1024)%1024)/10,
+                                                                              (ULONG)(max_lba*512/1000/1000/1000)
+                            );
+                        }
+                    }
+                    len = 0;
+                    if(hKey2 = ata_get_bblist_regh(ident, DevSerial, TRUE)) {
+                        if(RegQueryValueEx(hKey2, DevSerial, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
+                            printf("    !!! Assigned bad-block list !!!\n");
+                        }
+                        RegCloseKey(hKey2);
+                    }
+
+                }
+                memcpy(&g_ident, ident, sizeof(IDENTIFY_DATA));
+            }
+next_dev:
+            if (inquiryData->NextInquiryDataOffset == 0) {
+                break;
+            }
+            
+            inquiryData = (PSCSI_INQUIRY_DATA) (g_inquiry_buffer +
+                inquiryData->NextInquiryDataOffset);
+        }
+    }
+    if(!found) {
+        printf("  No device(s) found.\n");
+        return FALSE;
+    }
+
+    return TRUE;
+} // end ata_check_unit()
+
+BOOLEAN
+ata_adapter_info(
+    int bus_id,
+    int print_info
+    )
+{
+    char dev_name[64];
+    HANDLE h;
+    ADAPTERINFO AdapterInfo;
+    ULONG status;
+    ULONG returned;
+    SCSI_ADDRESS addr;
+    PCI_SLOT_NUMBER       slotData;
+
+    sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
+    h = ata_open_dev(dev_name);
+    if(!h)
+        return FALSE;
+    addr.PortNumber = bus_id;
+
+    memset(&AdapterInfo, 0, sizeof(AdapterInfo));
+
+    status = ata_send_ioctl(h, &addr, "-UNIATA-",
+                            IOCTL_SCSI_MINIPORT_UNIATA_ADAPTER_INFO,
+                            &AdapterInfo, sizeof(AdapterInfo),
+                            &AdapterInfo, sizeof(AdapterInfo),
+                            &returned);
+    printf("Scsi%d: %s\n", bus_id, status ? "[UniATA]" : "");
+    if(print_info) {
+        if(!status) {
+            printf("Can't get adapter info\n");
+        } else {
+            if(AdapterInfo.AdapterInterfaceType == PCIBus) {
+                slotData.u.AsULONG = AdapterInfo.slotNumber;
+                printf("  PCI Bus/Dev/Func:   %d/%d/%d%s\n",
+                    AdapterInfo.SystemIoBusNumber, slotData.u.bits.DeviceNumber, slotData.u.bits.FunctionNumber,
+                    AdapterInfo.AdapterInterfaceType == AdapterInfo.OrigAdapterInterfaceType ? "" : " (ISA-Bridged)");
+                printf("  VendorId/DevId/Rev: %#04x/%#04x/%#02x\n", AdapterInfo.DevID >> 16, AdapterInfo.DevID & 0xffff, AdapterInfo.RevID);
+                if(AdapterInfo.DeviceName[0]) {
+                    printf("  Name:               %s\n", AdapterInfo.DeviceName);
+                }
+            } else
+            if(AdapterInfo.AdapterInterfaceType == Isa) {
+                printf("  ISA Bus\n");
+            }
+            printf("  IRQ: %d\n", AdapterInfo.BusInterruptLevel);
+        }
+    }
+    ata_close_dev(h);
+    return status ? TRUE : FALSE;
+} // end ata_adapter_info()
+
+int
+ata_check_controller(
+    HANDLE h,    // handle to ScsiXXX:
+    PIO_SCSI_CAPABILITIES capabilities
+    )
+{
+    ULONG status;
+    ULONG returned;
+
+    status = DeviceIoControl(h,
+                             IOCTL_SCSI_GET_CAPABILITIES,
+                             NULL,
+                             0,
+                             capabilities,
+                             sizeof(IO_SCSI_CAPABILITIES),
+                             &returned,
+                             FALSE);
+    return status;
+} // end ata_check_controller()
+
+BOOLEAN
+ata_list(
+    int bus_id,
+    int dev_id
+    )
+{
+    char dev_name[64];
+    HANDLE h;
+    BOOLEAN uniata_driven;
+
+    if(bus_id == -1) {
+        for(bus_id=0; TRUE; bus_id++) {
+            if(!ata_list(bus_id, dev_id))
+                break;
+        }
+        return TRUE;
+    }
+    uniata_driven = ata_adapter_info(bus_id, g_adapter_info);
+    sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
+    h = ata_open_dev(dev_name);
+    if(!h)
+        return FALSE;
+    if(dev_id == -1) {
+        ata_check_controller(h, &g_capabilities);
+        ata_check_unit(h, -1);
+        ata_close_dev(h);
+        return TRUE;
+    }
+    ata_check_unit(h, dev_id | (bus_id << 24));
+    ata_close_dev(h);
+    return TRUE;
+} // end ata_list()
+
+BOOLEAN
+ata_mode(
+    int bus_id,
+    int dev_id,
+    int mode
+    )
+{
+    char dev_name[64];
+    HANDLE h;
+    SETTRANSFERMODE IoMode;
+    ULONG status;
+    ULONG returned;
+    SCSI_ADDRESS addr;
+
+    if(dev_id == -1) {
+        return FALSE;
+    }
+    sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
+    h = ata_open_dev(dev_name);
+    if(!h)
+        return FALSE;
+    addr.PortNumber = bus_id;
+    addr.PathId   = (UCHAR)(dev_id >> 16);
+    addr.TargetId = (UCHAR)(dev_id >> 8);
+    addr.Lun      = (UCHAR)(dev_id);
+
+    IoMode.MaxMode = mode;
+    IoMode.ApplyImmediately = FALSE;
+//    IoMode.ApplyImmediately = TRUE;
+    IoMode.OrigMode = mode;
+
+    status = ata_send_ioctl(h, &addr, "-UNIATA-",
+                            IOCTL_SCSI_MINIPORT_UNIATA_SET_MAX_MODE,
+                            &IoMode, sizeof(IoMode),
+                            NULL, 0,
+                            &returned);
+    if(!status) {
+        printf("Can't apply specified transfer mode\n");
+    } else {
+        ata_mode_to_str(dev_name, mode);
+        printf("Transfer rate switched to %s\n", dev_name);
+    }
+    ata_close_dev(h);
+    return status ? TRUE : FALSE;
+} // end ata_mode()
+
+BOOLEAN
+ata_reset(
+    int bus_id,
+    int dev_id
+    )
+{
+    char dev_name[64];
+    HANDLE h;
+    ULONG status;
+    ULONG returned;
+    SCSI_ADDRESS addr;
+
+    if(dev_id == -1) {
+        return FALSE;
+    }
+    sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
+    h = ata_open_dev(dev_name);
+    if(!h)
+        return FALSE;
+    addr.PortNumber = bus_id;
+    addr.PathId   = (UCHAR)(dev_id >> 16);
+    addr.TargetId = (UCHAR)(dev_id >> 8);
+    addr.Lun      = (UCHAR)(dev_id);
+
+    if(addr.TargetId == 0x7f && addr.Lun == 0x7f) {
+        addr.TargetId = (UCHAR)0xff;
+        addr.Lun      = 0;
+        printf("Resetting channel...\n");
+    } else {
+        printf("Resetting device...\n");
+    }
+
+    status = ata_send_ioctl(h, &addr, "-UNIATA-",
+                            IOCTL_SCSI_MINIPORT_UNIATA_RESET_DEVICE,
+                            NULL, 0,
+                            NULL, 0,
+                            &returned);
+    if(!status) {
+        printf("Reset failed\n");
+    } else {
+        printf("Channel reset done\n");
+    }
+    ata_close_dev(h);
+    return TRUE;
+} // end ata_reset()
+
+BOOLEAN
+ata_hide(
+    int bus_id,
+    int dev_id,
+    int lock,
+    int persistent_hide
+    )
+{
+    char dev_name[64];
+    HANDLE h;
+    ULONG status;
+    ULONG returned;
+    SCSI_ADDRESS addr;
+    ADDREMOVEDEV to;
+
+    if(dev_id == -1) {
+        return FALSE;
+    }
+    if(lock < 0) {
+        lock = DEFAULT_REMOVAL_LOCK_TIMEOUT;
+    }
+    sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
+    h = ata_open_dev(dev_name);
+    if(!h)
+        return FALSE;
+    addr.PortNumber = bus_id;
+    addr.PathId   = (UCHAR)(dev_id >> 16);
+    addr.TargetId = (UCHAR)(dev_id >> 8);
+    addr.Lun      = (UCHAR)(dev_id);
+
+    to.WaitForPhysicalLink = lock;
+    to.Flags = persistent_hide ? UNIATA_REMOVE_FLAGS_HIDE : 0;
+
+    printf("Deleting device.\n");
+    if(lock) {
+        printf("ATTENTION: you have %d seconds to disconnect cable\n", lock);
+    }
+    status = ata_send_ioctl(h, &addr, "-UNIATA-",
+                            IOCTL_SCSI_MINIPORT_UNIATA_DELETE_DEVICE,
+                            &to, sizeof(to),
+                            NULL, 0,
+                            &returned);
+    ata_close_dev(h);
+    return TRUE;
+} // end ata_hide()
+
+BOOLEAN
+ata_scan(
+    int bus_id,
+    int dev_id,
+    int lock,
+    int unhide
+    )
+{
+    char dev_name[64];
+    HANDLE h;
+    ULONG status;
+    ULONG returned;
+    SCSI_ADDRESS addr;
+    ADDREMOVEDEV to;
+
+    if(dev_id == -1) {
+        return FALSE;
+    }
+    if(lock < 0) {
+        lock = DEFAULT_REMOVAL_LOCK_TIMEOUT;
+    }
+    sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
+    h = ata_open_dev(dev_name);
+    if(!h)
+        return FALSE;
+
+    if((UCHAR)(dev_id) != 0xff &&
+       (UCHAR)(dev_id >> 8) != 0xff) {
+
+        addr.PortNumber = bus_id;
+        addr.PathId   = (UCHAR)(dev_id >> 16);
+        addr.TargetId = 0;
+        addr.Lun      = 0;
+
+        to.WaitForPhysicalLink = lock;
+        to.Flags = unhide ? UNIATA_ADD_FLAGS_UNHIDE : 0;
+
+        printf("Scaning bus for new devices.\n");
+        if(lock) {
+            printf("You have %d seconds to connect device.\n", lock);
+        }
+        status = ata_send_ioctl(h, &addr, "-UNIATA-",
+                                IOCTL_SCSI_MINIPORT_UNIATA_FIND_DEVICES,
+                                &to, sizeof(to),
+                                NULL, 0,
+                                &returned);
+    } else {
+        status = DeviceIoControl(h,
+                                 IOCTL_SCSI_RESCAN_BUS,
+                                 NULL, 0,
+                                 NULL, 0,
+                                 &returned,
+                                 FALSE);
+    }
+    ata_close_dev(h);
+    return TRUE;
+} // end ata_scan()
+
+CHAR*
+_fgets(
+    CHAR *string,
+    int count,
+    HANDLE stream
+    )
+{
+    CHAR *pointer = string;
+    ULONG read_bytes;
+
+    CHAR *retval = string;
+    int ch = 0;
+
+    if (count <= 0)
+        return(NULL);
+
+    while (--count)
+    {
+        if(!ReadFile(stream, &ch, 1, &read_bytes, NULL) ||
+           !read_bytes)
+        {
+            if (pointer == string) {
+                retval=NULL;
+                goto done;
+            }
+            break;
+        }
+
+        if ((*pointer++ = (CHAR)ch) == '\n') {
+            break;
+        }
+    }
+
+    *pointer = '\0';
+
+/* Common return */
+done:
+    return(retval);
+} // end _fgets()
+
+BOOLEAN
+ata_bblk(
+    int bus_id,
+    int dev_id,
+    int list_bb
+    )
+{
+    char dev_name[64];
+    char tmp[64];
+    char DevSerial[128];
+    HANDLE h = NULL;
+    HANDLE hf = NULL;
+    ULONG status;
+    ULONG returned;
+    SCSI_ADDRESS addr;
+    ULONG len;
+    ULONG Length;
+    BOOLEAN retval = FALSE;
+    HKEY hKey2 = NULL;
+    char* bblist = NULL;
+    LONGLONG tmp_bb_lba;
+    LONGLONG tmp_bb_len;
+    char BB_Msg[256];
+    int radix=gRadix;
+    int i, j;
+    ULONG b;
+
+    if(dev_id == -1) {
+        printf("\nERROR: Target device/bus ID must be specified\n\n");
+        print_help();
+        return FALSE;
+    }
+    if((dev_id >> 16) & 0xff == 0xff) {
+        printf("\nERROR: Target device bus number (channel) must be specified with b:<bus id>\n\n");
+        print_help();
+        return FALSE;
+    }
+    if((dev_id >> 8) & 0xff == 0xff) {
+        printf("\nERROR: Target device ID must be specified with d:<device id>\n\n");
+        print_help();
+        return FALSE;
+    }
+    sprintf(dev_name, "\\\\.\\Scsi%d:", bus_id);
+    h = ata_open_dev(dev_name);
+    if(!h) {
+        if(bus_id == -1) {
+            printf("Controller number must be specified\n");
+        } else {
+            printf("Can't open Controller %d\n", bus_id);
+        }
+        return FALSE;
+    }
+
+    if(list_bb == 0) {
+        hf = ata_open_file(g_bb_list, FALSE);
+        if(!hf) {
+            printf("Can't open bad block list file:\n  %s\n", g_bb_list);
+            ata_close_dev(h);
+            return FALSE;
+        }
+
+        len = GetFileSize(hf, NULL);
+        if(!len || len == -1)
+            goto exit;
+        bblist = (char*)GlobalAlloc(GMEM_FIXED, len*8);
+    }
+
+    if(!ata_check_unit(h, dev_id | (bus_id << 24))) {
+        goto exit;
+    }
+
+    hKey2 = ata_get_bblist_regh(&g_ident, DevSerial, list_bb==1);
+    if(!hKey2) {
+        printf("Can't open registry key:\n  HKLM\\SYSTEM\\CurrentControlSet\\Services\\UniATA\\Parameters\\BadBlocks\n");
+        goto exit;
+    }
+
+    if(list_bb == -1) {
+        if(RegDeleteValue(hKey2, DevSerial) != ERROR_SUCCESS) {
+            printf("Can't delete registry value:\n  %s\n", DevSerial);
+            goto exit;
+        }
+
+        addr.PortNumber = bus_id;
+        addr.PathId   = (UCHAR)(dev_id >> 16);
+        addr.TargetId = (UCHAR)(dev_id >> 8);
+        addr.Lun      = (UCHAR)(dev_id);
+
+        status = ata_send_ioctl(h, &addr, "-UNIATA-",
+                                IOCTL_SCSI_MINIPORT_UNIATA_RESETBB,
+                                NULL, 0,
+                                NULL, 0,
+                                &returned);
+        if(!status) {
+            printf("Bad block list shall be cleared after reboot.\n");
+        } else {
+            printf("Bad block list cleared\n");
+        }
+    } else
+    if(list_bb == 0) {
+        LONGLONG* pData = ((LONGLONG*)bblist);
+        char a;
+        int k, k0;
+        Length=0;
+        i=0;
+        j=0;
+        k=0;
+        while(_fgets(BB_Msg, sizeof(BB_Msg), hf)) {
+            j++;
+            BB_Msg[sizeof(BB_Msg)-1] = 0;
+            k=0;
+            while(a = BB_Msg[k]) {
+                if(a == ' ' || a == '\t' || a == '\r') {
+                    k++;
+                    continue;
+                }
+                break;
+            }
+            if(!a || a == ';' || a == '#') {
+                continue;
+            }
+            if(!strncmp(BB_Msg+k, "hex:", 4)) {
+                radix=16;
+                continue;
+            }
+            if(!strncmp(BB_Msg+k, "dec:", 4)) {
+                radix=10;
+                continue;
+            }
+            k0 = k;
+            while(a = BB_Msg[k]) {
+                if(a == ' ' || a == '\t' || a == '\r') {
+                    BB_Msg[k] = '\t';
+                }
+                k++;
+                if(a == ';' || a == '#') {
+                    break;
+                }
+                if(a >= '0' && a <= '9') {
+                    continue;
+                }
+                if(radix == 16 && ((a >= 'A' && a <= 'F') || (a >= 'a' && a <= 'f'))) {
+                    continue;
+                }
+                printf("Bad input BB list file:\n  %s\n", g_bb_list);
+                printf("Illegal character '%1.1s' in line %d:\n%s\n", BB_Msg+k-1, j, BB_Msg);
+                k0=-1;
+                break;
+            }
+            if(k0 == -1) {
+                continue;
+            }
+            k = k0;
+            if(radix == 10) {
+                b = sscanf(BB_Msg+k, "%I64d\t%I64d", &tmp_bb_lba, &tmp_bb_len);
+            } else {
+                b = sscanf(BB_Msg+k, "%I64x\t%I64x", &tmp_bb_lba, &tmp_bb_len);
+            }
+            if(b == 1) {
+                tmp_bb_len = 1;
+            } else
+            if(b != 2) {
+                printf("Bad input BB list file:\n  %s\n", g_bb_list);
+                printf("Can't parse line %d:\n%s\n", j, BB_Msg);
+                continue;
+            } 
+            if(!tmp_bb_len) {
+                printf("Bad input BB list file:\n  %s\n", g_bb_list);
+                printf("BlockCount evaluated to 0 in line %d:\n%s\n", j, BB_Msg);
+                continue;
+            }
+            if(tmp_bb_lba < 0) {
+                printf("Bad input BB list file:\n  %s\n", g_bb_list);
+                printf("Start LBA evaluated to negative in line %d:\n%s\n", j, BB_Msg);
+                continue;
+            }
+            if(tmp_bb_len < 0) {
+                printf("Bad input BB list file:\n  %s\n", g_bb_list);
+                printf("BlockCount evaluated to negative in line %d:\n%s\n", j, BB_Msg);
+                continue;
+            }
+
+            if(i &&
+                (pData[(i-1)*2+1] == tmp_bb_lba)) {
+                pData[(i-1)*2+1]+=tmp_bb_len;
+            } else {
+                pData[i*2+0]=tmp_bb_lba;
+                pData[i*2+1]=tmp_bb_lba+tmp_bb_len;
+                i++;
+                Length += sizeof(LONGLONG)*2;
+            }
+        }
+
+        if(RegSetValueEx(hKey2, DevSerial, NULL, REG_BINARY, (const UCHAR*)bblist, Length) != ERROR_SUCCESS) {
+            printf("Can't set registry value:\n  %s\n", DevSerial);
+            goto exit;
+        }
+/*
+        addr.PortNumber = bus_id;
+        addr.PathId   = (UCHAR)(dev_id >> 16);
+        addr.TargetId = (UCHAR)(dev_id >> 8);
+        addr.Lun      = (UCHAR)(dev_id);
+
+        status = ata_send_ioctl(h, &addr, "-UNIATA-",
+                                IOCTL_SCSI_MINIPORT_UNIATA_SETBB,
+                                NULL, 0,
+                                NULL, 0,
+                                &returned);
+*/
+        printf("Bad block list shall be applied after reboot\n");
+    } else {
+        len = 0;
+        returned = RegQueryValueEx(hKey2, DevSerial, NULL, NULL, NULL, &len);
+        if(returned == 2) {
+            printf("No bad block list assigned\n");
+            goto exit;
+        } else
+        if(returned != ERROR_SUCCESS) {
+            printf("Can't get registry value:\n  %s\n", DevSerial);
+            goto exit;
+        }
+
+        hf = ata_open_file(g_bb_list, TRUE);
+        if(!hf) {
+            printf("Can't create bad block list file:\n  %s\n", g_bb_list);
+            goto exit;
+        }
+
+        bblist = (char*)GlobalAlloc(GMEM_FIXED, len);
+        if(RegQueryValueEx(hKey2, DevSerial, NULL, NULL, (UCHAR*)bblist, &len) != ERROR_SUCCESS) {
+            printf("Can't get registry value:\n  %s\n", DevSerial);
+            goto exit;
+        }
+        if(g_bb_list) {
+            for (j = 0; j < 20; j += 2) {
+                MOV_DW_SWP(tmp[j], ((PUCHAR)(&g_ident.ModelNumber))[j]);
+            }
+            b = sprintf(BB_Msg, "#model: %20.20s\n", tmp);
+            WriteFile(hf, BB_Msg, b, &returned, NULL);
+            for (j = 0; j < 4; j += 2) {
+                MOV_DW_SWP(tmp[j], ((PUCHAR)(&g_ident.FirmwareRevision))[j]);
+            }
+            b = sprintf(BB_Msg, "#rev:   %4.4s\n",   tmp);
+            WriteFile(hf, BB_Msg, b, &returned, NULL);
+            for (j = 0; j < 20; j += 2) {
+                MOV_DW_SWP(tmp[j], ((PUCHAR)(&g_ident.SerialNumber))[j]);
+            }
+            b = sprintf(BB_Msg, "#s/n:   %20.20s\n", tmp);
+            WriteFile(hf, BB_Msg, b, &returned, NULL);
+            b = sprintf(BB_Msg, "#%s\n", DevSerial);
+            WriteFile(hf, BB_Msg, b, &returned, NULL);
+            b = sprintf(BB_Msg, "#Starting LBA\tNum. of Blocks\n");
+            WriteFile(hf, BB_Msg, b, &returned, NULL);
+            b = sprintf(BB_Msg, "hex:\n");
+            WriteFile(hf, BB_Msg, b, &returned, NULL);
+        } else {
+            b = sprintf(BB_Msg, "Starting LBA\tNum. of Blocks (HEX)\n");
+            WriteFile(hf, BB_Msg, b, &returned, NULL);
+        }
+        i = 0;
+        while(len >= sizeof(LONGLONG)*2) {
+            tmp_bb_lba = ((LONGLONG*)bblist)[i*2+0];
+            tmp_bb_len = ((LONGLONG*)bblist)[i*2+1] - tmp_bb_lba;
+            b = sprintf(BB_Msg, "%I64x\t%I64x\n", tmp_bb_lba, tmp_bb_len);
+            WriteFile(hf, BB_Msg, b, &returned, NULL);
+            i++;
+            len -= sizeof(LONGLONG)*2;
+        }
+    }
+    retval = TRUE;
+exit:
+    if(hKey2)
+        RegCloseKey(hKey2);
+    if(bblist) {
+        GlobalFree(bblist);
+    }
+    ata_close_dev(hf);
+    ata_close_dev(h);
+    return retval;
+} // end ata_bblk()
+
+int
+ata_num_to_x_dev(
+    char a
+    )
+{
+    if(a >= '0' && a <= '9')
+        return a-'0';
+    return -1;
+}
+
+int
+main (
+    int argc,
+    char* argv[]
+    )
+{
+    ULONG Flags = 0;
+    int i, j;
+    char a;
+    int bus_id = -1;
+    int dev_id = -1;
+    int cmd = 0;
+    int lock = -1;
+    int b_dev=-1, d_dev=-1, l_dev=0;
+    int mode=-1;
+    int list_bb=0;
+    int persistent_hide=0;
+
+    printf("Console ATA control utility for Windows NT3.51/NT4/2000/XP/2003\n"
+           "Version 0." UNIATA_VER_STR ", Copyright (c) Alexander A. Telyatnikov, 2003-2008\n"
+           "Home site: http://alter.org.ua\n");
+
+    for(i=1; i<argc; i++) {
+        if(!argv[i])
+            continue;
+        if((a = argv[i][0]) != '-') {
+            for(j=0; a = argv[i][j]; j++) {
+                switch(a) {
+                case 'a' :
+                case 's' :
+                case 'c' :
+                    j++;
+                    bus_id = ata_num_to_x_dev(argv[i][j]);
+                    break;
+                case 'b' :
+                    j++;
+                    b_dev = ata_num_to_x_dev(argv[i][j]);
+                    break;
+                case 'd' :
+                    j++;
+                    d_dev = ata_num_to_x_dev(argv[i][j]);
+                    break;
+                case 'l' :
+                    j++;
+                    l_dev = ata_num_to_x_dev(argv[i][j]);
+                    break;
+                case ':' :
+                    break;
+                default:
+                    print_help();
+                }
+            }
+            continue;
+        }
+        j=1;
+        while(argv[i] && (a = argv[i][j]) && (a != ' ') && (a != '\t')) {
+            switch(a) {
+            case 'l' :
+                if(cmd || lock>0) {
+                    print_help();
+                }
+                cmd = CMD_ATA_LIST;
+                break;
+            case 'x' :
+                g_extended = 1;
+                break;
+            case 'a' :
+                g_adapter_info = 1;
+                break;
+            case 'S' :
+                persistent_hide = 1;
+            case 's' :
+                if(cmd || lock>0) {
+                    print_help();
+                }
+                cmd = CMD_ATA_FIND;
+                d_dev = 0;
+                break;
+            case 'H' :
+                persistent_hide = 1;
+            case 'h' :
+                if(cmd) {
+                    print_help();
+                }
+                cmd = CMD_ATA_HIDE;
+                d_dev = 0;
+                break;
+            case 'm' :
+                if(cmd) {
+                    print_help();
+                }
+                cmd = CMD_ATA_MODE;
+                i++;
+                if(!argv[i]) {
+                    print_help();
+                }
+                mode = ata_str_to_mode(argv[i]);
+                if(mode == -1) {
+                    i--;
+                } else {
+                    j = strlen(argv[i])-1;
+                }
+                break;
+            case 'r' :
+                if(cmd) {
+                    print_help();
+                }
+                cmd = CMD_ATA_RESET;
+                break;
+            case 'b' :
+                if(cmd) {
+                    print_help();
+                }
+                switch(argv[i][j+1]) {
+                case 'l':
+                    list_bb = 1;
+                    break;
+                case 'a':
+                    list_bb = 0;
+                    break;
+                case 'r':
+                    list_bb = -1;
+                    break;
+                default:
+                    j--;
+                }
+                j++;
+                cmd = CMD_ATA_BBLK;
+                break;
+            case 'f' :
+                if(cmd != CMD_ATA_BBLK) {
+                    print_help();
+                }
+                i++;
+                if(!argv[i]) {
+                    print_help();
+                }
+                g_bb_list=argv[i];
+                j = strlen(argv[i])-1;
+                break;
+            case 'd' :
+                if(cmd && cmd != CMD_ATA_FIND && cmd != CMD_ATA_HIDE) {
+                    print_help();
+                }
+                i++;
+                if(!argv[i]) {
+                    print_help();
+                }
+                if(!sscanf(argv[i], "%d", &lock)) {
+                    lock = DEFAULT_REMOVAL_LOCK_TIMEOUT;
+                    i--;
+                }
+                j = strlen(argv[i])-1;
+                break;
+            case 'n' :
+                if(cmd != CMD_ATA_BBLK) {
+                    print_help();
+                }
+                i++;
+                if(!argv[i]) {
+                    print_help();
+                }
+                if(!strcmp(argv[i], "hex") ||
+                   !strcmp(argv[i], "16")) {
+                    gRadix = 16;
+                } else
+                if(!strcmp(argv[i], "dec") ||
+                   !strcmp(argv[i], "10")) {
+                    gRadix = 10;
+                } else {
+                    print_help();
+                }
+                j = strlen(argv[i])-1;
+                break;
+            case '?' :
+            default:
+                print_help();
+            }
+            j++;
+        }
+    }
+
+    if(g_adapter_info && !cmd) {
+        cmd = CMD_ATA_LIST;
+        b_dev = 127;
+        d_dev = 127;
+        l_dev = 127;
+    } else
+    if(d_dev == -1 && b_dev != -1) {
+        d_dev = 127;
+        l_dev = 127;
+    }
+
+    if(d_dev != -1 && b_dev != -1) {
+        dev_id = (b_dev << 16) | (d_dev << 8) | l_dev;
+    }
+    if(cmd == CMD_ATA_LIST) {
+        ata_list(bus_id, dev_id);
+    } else
+    if(cmd == CMD_ATA_MODE) {
+        ata_mode(bus_id, dev_id, mode);
+    } else
+    if(cmd == CMD_ATA_RESET) {
+        ata_reset(bus_id, dev_id);
+    } else
+    if(cmd == CMD_ATA_FIND) {
+        ata_scan(bus_id, dev_id, lock, persistent_hide);
+    } else
+    if(cmd == CMD_ATA_HIDE) {
+        ata_hide(bus_id, dev_id, lock, persistent_hide);
+    } else
+    if(cmd == CMD_ATA_BBLK) {
+        ata_bblk(bus_id, dev_id, list_bb);
+    } else {
+        print_help();
+    }
+    exit(0);
+}
+
diff --git a/reactos/base/applications/atactl/helper.h b/reactos/base/applications/atactl/helper.h
new file mode 100644 (file)
index 0000000..700bc7c
--- /dev/null
@@ -0,0 +1,38 @@
+typedef struct _DRIVERSTATUS {
+       UCHAR  bDriverError;
+       UCHAR  bIDEError;
+       UCHAR  bReserved[2];
+       ULONG  dwReserved[2];
+} DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS;
+
+typedef struct _IDEREGS {
+       UCHAR  bFeaturesReg;
+       UCHAR  bSectorCountReg;
+       UCHAR  bSectorNumberReg;
+       UCHAR  bCylLowReg;
+       UCHAR  bCylHighReg;
+       UCHAR  bDriveHeadReg;
+       UCHAR  bCommandReg;
+       UCHAR  bReserved;
+} IDEREGS, *PIDEREGS, *LPIDEREGS;
+
+#define ATAPI_ID_CMD                      0xA1
+#define ID_CMD                            0xEC
+#define SMART_CMD                         0xB0
+
+#include <pshpack1.h>
+typedef struct _SENDCMDOUTPARAMS {
+       ULONG  cBufferSize;
+       DRIVERSTATUS  DriverStatus;
+       UCHAR  bBuffer[1];
+} SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS;
+
+typedef struct _SENDCMDINPARAMS {
+       ULONG  cBufferSize;
+       IDEREGS  irDriveRegs;
+       UCHAR  bDriveNumber;
+       UCHAR  bReserved[3];
+       ULONG  dwReserved[4];
+       UCHAR  bBuffer[1];
+} SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS;
+#include <poppack.h>
\ No newline at end of file