* Reapply r57265 now that the testbot issues are solved.
authorAmine Khaldi <amine.khaldi@reactos.org>
Thu, 13 Sep 2012 21:07:44 +0000 (21:07 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Thu, 13 Sep 2012 21:07:44 +0000 (21:07 +0000)
[UNIATA]: Sync to 0.43f5.
[ATACTL]: Sync to 0.43f5.
CORE-6563 #comment Committed the 0.43f5 sync.

svn path=/trunk/; revision=57292

15 files changed:
reactos/base/applications/atactl/atactl.cpp
reactos/drivers/storage/ide/uniata/atapi.h
reactos/drivers/storage/ide/uniata/bm_devs.h
reactos/drivers/storage/ide/uniata/bsmaster.h
reactos/drivers/storage/ide/uniata/id_ata.cpp
reactos/drivers/storage/ide/uniata/id_dma.cpp
reactos/drivers/storage/ide/uniata/id_init.cpp
reactos/drivers/storage/ide/uniata/id_probe.cpp
reactos/drivers/storage/ide/uniata/id_sata.cpp
reactos/drivers/storage/ide/uniata/id_sata.h
reactos/drivers/storage/ide/uniata/inc/misc.h
reactos/drivers/storage/ide/uniata/scsi.h
reactos/drivers/storage/ide/uniata/todo.txt
reactos/drivers/storage/ide/uniata/uata_ctl.h
reactos/drivers/storage/ide/uniata/uniata_ver.h

index 69ea2f9..63a0416 100644 (file)
@@ -39,6 +39,13 @@ char* g_bb_list = NULL;
 int gRadix = 16;
 PADAPTERINFO g_AdapterInfo = NULL;
 
+BOOLEAN
+ata_power_mode(
+    int bus_id,
+    int dev_id,
+    int power_mode
+    );
+
 void print_help() {
     printf("Usage:\n"
            "  atactl -<switches> c|s<controller id>:b<bus id>:d<device id>[:l<lun>]\n"
@@ -61,6 +68,12 @@ void print_help() {
            "  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"
+           "  D [XXX]   disable device (turn into sleep mode) and lock ATA/SATA bus \n"
+           "              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"
+           "  pX        change power state to X, where X is\n"
+           "              0 - active, 1 - idle, 2 - standby, 3 - sleep\n"
            "  r         (R)eset device\n"
            "  ba        (A)ssign (B)ad-block list\n"
            "  bl        get assigned (B)ad-block (L)ist\n"
@@ -116,6 +129,7 @@ void print_help() {
 #define CMD_ATA_MODE  0x04
 #define CMD_ATA_RESET 0x05
 #define CMD_ATA_BBLK  0x06
+#define CMD_ATA_POWER 0x07
 
 HANDLE
 ata_open_dev(
@@ -304,6 +318,76 @@ ata_send_ioctl(
     return TRUE;
 } // end ata_send_ioctl()
 
+int
+ata_send_scsi(
+    HANDLE h,
+    PSCSI_ADDRESS addr,
+    PCDB   cdb,
+    UCHAR  cdbLength,
+    PVOID  Buffer,
+    ULONG  BufferLength,
+    BOOLEAN DataIn,
+    PSENSE_DATA senseData,
+    PULONG returned
+    )
+{
+    ULONG status;
+    PSCSI_PASS_THROUGH_WITH_BUFFERS sptwb;
+    ULONG data_len = BufferLength;
+    ULONG len;
+
+    len = BufferLength + offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf);
+
+    sptwb = (PSCSI_PASS_THROUGH_WITH_BUFFERS)GlobalAlloc(GMEM_FIXED, len);
+    if(!sptwb) {
+        return FALSE;
+    }
+    memset(sptwb, 0, offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf));
+
+    sptwb->spt.Length = sizeof(SCSI_PASS_THROUGH);
+    sptwb->spt.PathId   = addr->PathId;
+    sptwb->spt.TargetId = addr->TargetId;
+    sptwb->spt.Lun      = addr->Lun;
+    sptwb->spt.CdbLength = cdbLength;
+    sptwb->spt.SenseInfoLength = 24;
+    sptwb->spt.DataIn = Buffer ? (DataIn ? SCSI_IOCTL_DATA_IN : SCSI_IOCTL_DATA_OUT) : 0;
+    sptwb->spt.DataTransferLength = BufferLength;
+    sptwb->spt.TimeOutValue = 10;
+    sptwb->spt.DataBufferOffset =
+       offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf);
+    sptwb->spt.SenseInfoOffset = 
+       offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucSenseBuf);
+    memcpy(&sptwb->spt.Cdb, cdb, cdbLength);
+
+    if(Buffer && !DataIn) {
+        memcpy(&sptwb->ucSenseBuf, Buffer, BufferLength);
+    }
+
+    status = DeviceIoControl(h,
+                             IOCTL_SCSI_PASS_THROUGH,
+                             sptwb,
+                             (Buffer && !DataIn) ? len : sizeof(SCSI_PASS_THROUGH),
+                             sptwb,
+                             (Buffer && DataIn) ? len : offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf),
+                             returned,
+                             FALSE);
+
+    if(Buffer && DataIn) {
+        memcpy(Buffer, &sptwb->ucDataBuf, BufferLength);
+    }
+    if(senseData) {
+        memcpy(senseData, &sptwb->ucSenseBuf, sizeof(sptwb->ucSenseBuf));
+    }
+
+    GlobalFree(sptwb);
+
+    if(!status) {
+        status = GetLastError();
+        return FALSE;
+    }
+    return TRUE;
+} // end ata_send_scsi()
+
 IO_SCSI_CAPABILITIES g_capabilities;
 UCHAR g_inquiry_buffer[2048];
 
@@ -535,9 +619,10 @@ ata_check_unit(
     GETTRANSFERMODE IoMode;
     PSENDCMDOUTPARAMS pout;
     PIDENTIFY_DATA   ident;
+    PINQUIRYDATA     scsi_ident;
     char buff[sizeof(SENDCMDOUTPARAMS)+/*sizeof(IDENTIFY_DATA)*/2048];
     char mode_str[12];
-    ULONG bus_id = (dev_id >> 24) & 0xff;
+    //ULONG bus_id = (dev_id >> 24) & 0xff;
     BOOLEAN found = FALSE;
     SENDCMDINPARAMS pin;
     int io_mode = -1;
@@ -546,7 +631,7 @@ ata_check_unit(
     char lun_str[10];
     HKEY hKey2;
     ULONGLONG max_lba = -1;
-    USHORT chs[3];
+    USHORT chs[3] = { 0 };
 
     if(dev_id != -1) {
         dev_id &= 0x00ffffff;
@@ -594,7 +679,7 @@ ata_check_unit(
             } else {
                 mode_str[0] = 0;
             }
-            printf(" b%u [%s]\n",
+            printf(" b%lu [%s]\n",
                 i,
                 mode_str
                 );
@@ -617,7 +702,8 @@ ata_check_unit(
             
             if(l_dev_id == dev_id || dev_id == -1) {
 
-                if(!memcmp(&(inquiryData->InquiryData[8]), UNIATA_COMM_PORT_VENDOR_STR, 24)) {
+                scsi_ident = (PINQUIRYDATA)&(inquiryData->InquiryData);
+                if(!memcmp(&(scsi_ident->VendorId[0]), UNIATA_COMM_PORT_VENDOR_STR, 24)) {
                     // skip communication port
                     goto next_dev;
                 }
@@ -685,29 +771,27 @@ ata_check_unit(
 
                 }
 
+                if(!g_extended) {
+                    printf("  b%lu:d%d%s    %24.24s %4.4s ",
+                        i,
+                        inquiryData->TargetId,
+                        lun_str,
+                        /*(inquiryData->DeviceClaimed) ? "Y" : "N",*/
+                        (g_extended ? (PUCHAR)"" : &scsi_ident->VendorId[0]),
+                        (g_extended ? (PUCHAR)"" : &scsi_ident->ProductRevisionLevel[0])
+                        );
+                } else {
+                    printf("  b%lu:d%d%s ",
+                        i,
+                        inquiryData->TargetId,
+                        lun_str
+                        );
+                }
+
                 if(status) {
-                    if(!g_extended) {
-                        printf("  b%u: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%u:d%d%s ",
-                            i,
-                            inquiryData->TargetId,
-                            lun_str
-                            );
-                    }
                     if(io_mode == -1) {
-                        io_mode = ata_cur_mode_from_ident(ident);
+                        io_mode = ata_cur_mode_from_ident(ident, IDENT_MODE_ACTIVE);
                     }
-                } else {
-                    goto next_dev;
-
                 }
                 if(io_mode != -1) {
                     ata_mode_to_str(mode_str, io_mode);
@@ -725,100 +809,139 @@ ata_check_unit(
                 }
                 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 {
+                if(g_extended) {
+                    if(status) {
+
+                        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 = TRUE;
+                            //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(!max_lba) {
+                                max_lba = (ULONG)(chs[0])*(ULONG)(chs[1])*(ULONG)(chs[2]);
+                            }
                         }
-                        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;
+                        if(io_mode != -1) {
+                            printf("           %.12s\n", mode_str);
                         }
-                        //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(!max_lba) {
-                            max_lba = (ULONG)(chs[0])*(ULONG)(chs[1])*(ULONG)(chs[2]);
+                        for (j = 0; j < 40; j += 2) {
+                            MOV_DW_SWP(SerNum[j], ((PUCHAR)ident->ModelNumber)[j]);
                         }
-                    }
-                    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:        %u block%s\n", ident->MaximumBlockTransfer, ident->MaximumBlockTransfer == 1 ? "" : "s");
-                        } else {
-                            printf("    Multi-block mode:        N/A\n");
+                        printf("    Mod: %40.40s\n", SerNum);
+                        for (j = 0; j < 8; j += 2) {
+                            MOV_DW_SWP(SerNum[j], ((PUCHAR)ident->FirmwareRevision)[j]);
                         }
-                    }
-                    if(print_geom) {
-                        printf("    C/H/S:                   %u/%u/%u \n", chs[0], chs[1], chs[2]);
-                        printf("    LBA:                     %I64u \n", max_lba);
-                        if(max_lba < 2) {
-                            printf("    Size:                    %u kb\n", max_lba/2);
-                        } else
-                        if(max_lba < 2*1024*1024) {
-                            printf("    Size:                    %u Mb\n", max_lba/2048);
-                        } else
-                        if(max_lba < (ULONG)2*1024*1024*1024) {
-                            printf("    Size:                    %u.%u (%u) Gb\n", (ULONG)(max_lba/2048/1024),
-                                                                              (ULONG)(((max_lba/2048)%1024)/10),
-                                                                              (ULONG)(max_lba*512/1000/1000/1000)
-                            );
-                        } else {
-                            printf("    Size:                    %u.%u (%u) Tb\n", (ULONG)(max_lba/2048/1024/1024),
-                                                                              (ULONG)((max_lba/2048/1024)%1024)/10,
-                                                                              (ULONG)(max_lba*512/1000/1000/1000)
-                            );
+                        printf("    Rev: %8.8s\n", SerNum);
+                        for (j = 0; j < 20; j += 2) {
+                            MOV_DW_SWP(SerNum[j], ((PUCHAR)ident->SerialNumber)[j]);
                         }
-                    }
-                    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");
+                        printf("    S/N: %20.20s\n", SerNum);
+
+                        if(BlockMode_valid) {
+                            if(ident->MaximumBlockTransfer) {
+                                printf("    Multi-block mode:        %u block%s\n", ident->MaximumBlockTransfer, ident->MaximumBlockTransfer == 1 ? "" : "s");
+                            } else {
+                                printf("    Multi-block mode:        N/A\n");
+                            }
+                        }
+                        if(print_geom) {
+                            printf("    C/H/S:                   %u/%u/%u \n", chs[0], chs[1], chs[2]);
+                            printf("    LBA:                     %I64u \n", max_lba);
+                            if(max_lba < 2) {
+                                printf("    Size:                    %lu kb\n", (ULONG)(max_lba/2));
+                            } else
+                            if(max_lba < 2*1024*1024) {
+                                printf("    Size:                    %lu Mb\n", (ULONG)(max_lba/2048));
+                            } else
+                            if(max_lba < (ULONG)2*1024*1024*1024) {
+                                printf("    Size:                    %lu.%lu (%lu) Gb\n", (ULONG)(max_lba/2048/1024),
+                                                                                  (ULONG)(((max_lba/2048)%1024)/10),
+                                                                                  (ULONG)(max_lba*512/1000/1000/1000)
+                                );
+                            } else {
+                                printf("    Size:                    %lu.%lu (%lu) Tb\n", (ULONG)(max_lba/2048/1024/1024),
+                                                                                  (ULONG)((max_lba/2048/1024)%1024)/10,
+                                                                                  (ULONG)(max_lba*512/1000/1000/1000)
+                                );
+                            }
                         }
-                        RegCloseKey(hKey2);
+                        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);
+                        }
+                    } else {
+                        switch(scsi_ident->DeviceType) {
+                        case DIRECT_ACCESS_DEVICE:
+                            if(scsi_ident->RemovableMedia) {
+                                printf("    Floppy        ");
+                            } else {
+                                printf("    Hard Drive    ");
+                            }
+                            break;
+                        case SEQUENTIAL_ACCESS_DEVICE:
+                            printf("    Tape Drive    ");
+                            break;
+                        case PRINTER_DEVICE:
+                            printf("    Printer       ");
+                            break;
+                        case PROCESSOR_DEVICE:
+                            printf("    Processor     ");
+                            break;
+                        case WRITE_ONCE_READ_MULTIPLE_DEVICE:
+                            printf("    WORM Drive    ");
+                            break;
+                        case READ_ONLY_DIRECT_ACCESS_DEVICE:
+                            printf("    CDROM Drive   ");
+                            break;
+                        case SCANNER_DEVICE:
+                            printf("    Scanner       ");
+                            break;
+                        case OPTICAL_DEVICE:
+                            printf("    Optical Drive ");
+                            break;
+                        case MEDIUM_CHANGER:
+                            printf("    Changer       ");
+                            break;
+                        case COMMUNICATION_DEVICE:
+                            printf("    Comm. device  ");
+                            break;
+                        }
+                        printf("\n");
                     }
-
                 }
                 memcpy(&g_ident, ident, sizeof(IDENTIFY_DATA));
             }
@@ -887,7 +1010,7 @@ ata_adapter_info(
         } else {
             if(AdapterInfo->AdapterInterfaceType == PCIBus) {
                 slotData.u.AsULONG = AdapterInfo->slotNumber;
-                printf("  PCI Bus/Dev/Func:   %u/%u/%u%s\n",
+                printf("  PCI Bus/Dev/Func:   %lu/%lu/%lu%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",
@@ -901,7 +1024,7 @@ ata_adapter_info(
             if(AdapterInfo->AdapterInterfaceType == Isa) {
                 printf("  ISA Bus\n");
             }
-            printf("  IRQ: %d\n", AdapterInfo->BusInterruptLevel);
+            printf("  IRQ: %ld\n", AdapterInfo->BusInterruptLevel);
         }
     }
     ata_close_dev(h);
@@ -1060,7 +1183,8 @@ ata_hide(
     int bus_id,
     int dev_id,
     int lock,
-    int persistent_hide
+    int persistent_hide,
+    int power_mode
     )
 {
     char dev_name[64];
@@ -1073,6 +1197,11 @@ ata_hide(
     if(dev_id == -1) {
         return FALSE;
     }
+
+    if(power_mode) {
+        ata_power_mode(bus_id, dev_id, power_mode);
+    }
+
     if(lock < 0) {
         lock = DEFAULT_REMOVAL_LOCK_TIMEOUT;
     }
@@ -1261,7 +1390,7 @@ ata_bblk(
         }
 
         len = GetFileSize(hf, NULL);
-        if(!len || len == -1)
+        if(!len || len == INVALID_FILE_SIZE)
             goto exit;
         bblist = (char*)GlobalAlloc(GMEM_FIXED, len*8);
     }
@@ -1310,7 +1439,7 @@ ata_bblk(
             j++;
             BB_Msg[sizeof(BB_Msg)-1] = 0;
             k=0;
-            while(a = BB_Msg[k]) {
+            while((a = BB_Msg[k])) {
                 if(a == ' ' || a == '\t' || a == '\r') {
                     k++;
                     continue;
@@ -1329,7 +1458,7 @@ ata_bblk(
                 continue;
             }
             k0 = k;
-            while(a = BB_Msg[k]) {
+            while((a = BB_Msg[k])) {
                 if(a == ' ' || a == '\t' || a == '\r') {
                     BB_Msg[k] = '\t';
                 }
@@ -1480,6 +1609,52 @@ exit:
     return retval;
 } // end ata_bblk()
 
+BOOLEAN
+ata_power_mode(
+    int bus_id,
+    int dev_id,
+    int power_mode
+    )
+{
+    char dev_name[64];
+    HANDLE h;
+    ULONG status;
+    ULONG returned;
+    SCSI_ADDRESS addr;
+    CDB cdb;
+    SENSE_DATA senseData;
+
+    if(dev_id == -1) {
+        return FALSE;
+    }
+    if(!power_mode) {
+        return TRUE;
+    }
+
+    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);
+
+    memset(&cdb, 0, sizeof(cdb));
+    cdb.START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
+    cdb.START_STOP.Immediate = 1;
+    cdb.START_STOP.PowerConditions = power_mode;
+    cdb.START_STOP.Start = (power_mode != StartStop_Power_Sleep);
+
+    printf("Changing power state to ...\n");
+
+    status = ata_send_scsi(h, &addr, &cdb, 6,
+                            NULL, 0, FALSE,
+                            &senseData, &returned);
+    ata_close_dev(h);
+    return TRUE;
+} // end ata_power_mode()
+
 int
 ata_num_to_x_dev(
     char a
@@ -1496,7 +1671,7 @@ main (
     char* argv[]
     )
 {
-    ULONG Flags = 0;
+    //ULONG Flags = 0;
     int i, j;
     char a;
     int bus_id = -1;
@@ -1507,6 +1682,7 @@ main (
     int mode=-1;
     int list_bb=0;
     int persistent_hide=0;
+    int power_mode=StartStop_Power_NoChg;
 
     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-2012\n"
@@ -1516,7 +1692,7 @@ main (
         if(!argv[i])
             continue;
         if((a = argv[i][0]) != '-') {
-            for(j=0; a = argv[i][j]; j++) {
+            for(j=0; (a = argv[i][j]); j++) {
                 switch(a) {
                 case 'a' :
                 case 's' :
@@ -1630,10 +1806,47 @@ main (
                 g_bb_list=argv[i];
                 j = strlen(argv[i])-1;
                 break;
-            case 'd' :
+            case 'p' :
                 if(cmd && (cmd != CMD_ATA_FIND) && (cmd != CMD_ATA_HIDE)) {
                     print_help();
                 }
+                switch(argv[i][j+1]) {
+                case '0':
+                case 'a':
+                    // do nothing
+                    break;
+                case '1':
+                case 'i':
+                    power_mode = StartStop_Power_Idle;
+                    break;
+                case '2':
+                case 's':
+                    power_mode = StartStop_Power_Standby;
+                    break;
+                case '3':
+                case 'p':
+                    power_mode = StartStop_Power_Sleep;
+                    break;
+                default:
+                    j--;
+                }
+                j++;
+                if(power_mode && !cmd) {
+                    cmd = CMD_ATA_POWER;
+                }
+                break;
+            case 'D' :
+                power_mode = StartStop_Power_Sleep;
+                if(cmd && (cmd != CMD_ATA_HIDE)) {
+                    print_help();
+                }
+            case 'd' :
+                if(cmd && (cmd != CMD_ATA_FIND) && (cmd != CMD_ATA_HIDE) && (cmd != CMD_ATA_POWER)) {
+                    print_help();
+                }
+                if(!cmd) {
+                    cmd = CMD_ATA_HIDE;
+                }
                 i++;
                 if(!argv[i]) {
                     print_help();
@@ -1699,10 +1912,13 @@ main (
         ata_scan(bus_id, dev_id, lock, persistent_hide);
     } else
     if(cmd == CMD_ATA_HIDE) {
-        ata_hide(bus_id, dev_id, lock, persistent_hide);
+        ata_hide(bus_id, dev_id, lock, persistent_hide, power_mode);
     } else
     if(cmd == CMD_ATA_BBLK) {
         ata_bblk(bus_id, dev_id, list_bb);
+    } else
+    if(cmd == CMD_ATA_POWER) {
+        ata_power_mode(bus_id, dev_id, power_mode);
     } else {
         print_help();
     }
index 7eec3d5..f191a78 100644 (file)
@@ -387,7 +387,9 @@ typedef struct _MODE_PARAMETER_HEADER_10 {
 #define IDE_COMMAND_DOOR_LOCK        0xDE
 #define IDE_COMMAND_DOOR_UNLOCK      0xDF
 #define IDE_COMMAND_STANDBY_IMMED    0xE0 // flush and spin down
+#define IDE_COMMAND_IDLE_IMMED       0xE1
 #define IDE_COMMAND_STANDBY          0xE2 // flush and spin down and enable autopowerdown timer
+#define IDE_COMMAND_IDLE             0xE3
 #define IDE_COMMAND_READ_PM          0xE4 // SATA PM
 #define IDE_COMMAND_SLEEP            0xE6 // flush, spin down and deactivate interface
 #define IDE_COMMAND_FLUSH_CACHE      0xE7
@@ -559,6 +561,25 @@ typedef union _ATAPI_REGISTERS_2 {
 #define         ATA_C_F_ENAB_MEDIASTAT  0x95    /* enable media status */
 #define         ATA_C_F_DIS_MEDIASTAT   0x31    /* disable media status */
 
+#define         ATA_C_F_ENAB_APM        0x05    /* enable advanced power management */
+#define         ATA_C_F_DIS_APM         0x85    /* disable advanced power management */
+#define           ATA_C_F_APM_CNT_MAX_PERF        0xfe    /* maximum performance */
+#define           ATA_C_F_APM_CNT_MIN_NO_STANDBY  0x80    /* min. power w/o standby */
+#define           ATA_C_F_APM_CNT_MIN_STANDBY     0x01    /* min. power with standby */
+
+#define         ATA_C_F_ENAB_ACOUSTIC   0x42    /* enable acoustic management */
+#define         ATA_C_F_DIS_ACOUSTIC    0xc2    /* disable acoustic management */
+#define           ATA_C_F_AAM_CNT_MAX_PERF        0xfe    /* maximum performance */
+#define           ATA_C_F_AAM_CNT_MAX_POWER_SAVE  0x80    /* min. power */
+
+// New SMART Feature definitions
+#ifndef READ_LOG_SECTOR
+#define READ_LOG_SECTOR     0xD5
+#define WRITE_LOG_SECTOR    0xD6
+#define WRITE_THRESHOLDS    0xD7
+#define AUTO_OFFLINE        0xDB
+#endif // READ_LOG_SECTOR
+
 //
 // ATAPI interrupt reasons
 //
@@ -920,6 +941,7 @@ typedef struct _IDENTIFY_DATA {
     union {
         USHORT Integrity;                       // 255
         struct {
+#define ATA_ChecksumValid    0xA5
             USHORT ChecksumValid:8;
             USHORT Checksum:8;
         };
@@ -1538,12 +1560,17 @@ ata_is_sata(
     return (ident->SataCapabilities && ident->SataCapabilities != 0xffff);
 } // end ata_is_sata()
 
+#define IDENT_MODE_MAX     FALSE
+#define IDENT_MODE_ACTIVE  TRUE
+
 __inline
 LONG
 ata_cur_mode_from_ident(
-    PIDENTIFY_DATA ident
+    PIDENTIFY_DATA ident,
+    BOOLEAN Active
     )
 {
+    USHORT mode;
     if(ata_is_sata(ident)) {
         if(ident->SataCapabilities & ATA_SATA_GEN3) {
             return ATA_SA600;
@@ -1558,22 +1585,24 @@ ata_cur_mode_from_ident(
     }
 
     if (ident->UdmaModesValid) {
-        if (ident->UltraDMAActive & 0x40)
+        mode = Active ? ident->UltraDMAActive : ident->UltraDMASupport;
+        if (mode & 0x40)
             return ATA_UDMA0+6;
-        if (ident->UltraDMAActive & 0x20)
+        if (mode & 0x20)
             return ATA_UDMA0+5;
-        if (ident->UltraDMAActive & 0x10)
+        if (mode & 0x10)
             return ATA_UDMA0+4;
-        if (ident->UltraDMAActive & 0x08)
+        if (mode & 0x08)
             return ATA_UDMA0+3;
-        if (ident->UltraDMAActive & 0x04)
+        if (mode & 0x04)
             return ATA_UDMA0+2;
-        if (ident->UltraDMAActive & 0x02)
+        if (mode & 0x02)
             return ATA_UDMA0+1;
-        if (ident->UltraDMAActive & 0x01)
+        if (mode & 0x01)
             return ATA_UDMA0+0;
     }
 
+    mode = Active ? ident->MultiWordDMAActive : ident->MultiWordDMASupport;
     if (ident->MultiWordDMAActive & 0x04)
         return ATA_WDMA0+2;
     if (ident->MultiWordDMAActive & 0x02)
@@ -1581,6 +1610,7 @@ ata_cur_mode_from_ident(
     if (ident->MultiWordDMAActive & 0x01)
         return ATA_WDMA0+0;
 
+    mode = Active ? ident->SingleWordDMAActive : ident->SingleWordDMASupport;
     if (ident->SingleWordDMAActive & 0x04)
         return ATA_SDMA0+2;
     if (ident->SingleWordDMAActive & 0x02)
@@ -1589,13 +1619,15 @@ ata_cur_mode_from_ident(
         return ATA_SDMA0+0;
 
     if (ident->PioTimingsValid) {
-        if (ident->AdvancedPIOModes & AdvancedPIOModes_5)
+        mode = ident->AdvancedPIOModes;
+        if (mode & AdvancedPIOModes_5)
             return ATA_PIO0+5;
-        if (ident->AdvancedPIOModes & AdvancedPIOModes_4)
+        if (mode & AdvancedPIOModes_4)
             return ATA_PIO0+4;
-        if (ident->AdvancedPIOModes & AdvancedPIOModes_3) 
+        if (mode & AdvancedPIOModes_3) 
             return ATA_PIO0+3;
-    }        
+    }
+    mode = ident->PioCycleTimingMode;
     if (ident->PioCycleTimingMode == 2)
         return ATA_PIO0+2;
     if (ident->PioCycleTimingMode == 1)
index 039f111..7abe0ad 100644 (file)
@@ -50,11 +50,12 @@ Revision History:
 #ifndef __IDE_BUSMASTER_DEVICES_H__
 #define __IDE_BUSMASTER_DEVICES_H__
 
-#ifdef USER_MODE
+/*#ifdef USER_MODE
 #define PVEN_STR    PCSTR
 #else // USER_MODE
 #define PVEN_STR    PCHAR
-#endif // USER_MODE
+#endif // USER_MODE*/
+#define PVEN_STR    PCSTR
 
 typedef struct _BUSMASTER_CONTROLLER_INFORMATION {
     PVEN_STR VendorId;
@@ -76,15 +77,18 @@ typedef struct _BUSMASTER_CONTROLLER_INFORMATION {
     CHAR    MasterDev;
     BOOLEAN Known;
 #ifndef USER_MODE
-    CHAR    ChanInitOk;             // 0x01 - primary,  0x02 - secondary
+    UCHAR   ChanInitOk;             // 0x01 - primary,  0x02 - secondary, 0x80 - PciIde claimed
     BOOLEAN Isr2Enable;
-    PDEVICE_OBJECT Isr2DevObj;
+    union {
+        PDEVICE_OBJECT Isr2DevObj;
+        PDEVICE_OBJECT PciIdeDevObj;
+    };
     KIRQL      Isr2Irql;
     KAFFINITY  Isr2Affinity;
     ULONG      Isr2Vector;
     PKINTERRUPT Isr2InterruptObject;
     CHAR    AltInitMasterDev;       // 0xff - uninitialized,  0x00 - normal,  0x01 - change ISA to PCI
-       CHAR    NeedAltInit;            // 0x01 - try change ISA to PCI
+    CHAR    NeedAltInit;            // 0x01 - try change ISA to PCI
 #endif
 
 }BUSMASTER_CONTROLLER_INFORMATION, *PBUSMASTER_CONTROLLER_INFORMATION;
@@ -634,7 +638,8 @@ typedef struct _BUSMASTER_CONTROLLER_INFORMATION {
 #define ICH5            0x0200
 #define I6CH            0x0400
 #define I6CH2           0x0800
-#define I1CH            0x1000
+//#define I1CH            0x1000  // obsolete
+#define ICH7            0x1000
 
 #define NV4OFF          0x0100
 #define NVQ             0x0200
@@ -717,7 +722,7 @@ BUSMASTER_CONTROLLER_INFORMATION const BusMasterAdapters[] = {
 
     PCI_DEV_HW_SPEC_BM( 1230, 8086, 0x00, ATA_WDMA2, "Intel PIIX"       , 0                                       ),
     PCI_DEV_HW_SPEC_BM( 7010, 8086, 0x00, ATA_WDMA2, "Intel PIIX3"      , 0                                       ),
-    PCI_DEV_HW_SPEC_BM( 7111, 8086, 0x00, ATA_UDMA3, "Intel PIIX4"      , 0                                       ),
+    PCI_DEV_HW_SPEC_BM( 7111, 8086, 0x00, ATA_UDMA2, "Intel PIIX3"      , 0                                       ),
     PCI_DEV_HW_SPEC_BM( 7199, 8086, 0x00, ATA_UDMA2, "Intel PIIX4"      , 0                                       ),
     PCI_DEV_HW_SPEC_BM( 84ca, 8086, 0x00, ATA_UDMA2, "Intel PIIX4"      , 0                                       ),
     PCI_DEV_HW_SPEC_BM( 7601, 8086, 0x00, ATA_UDMA2, "Intel ICH0"       , 0                                       ),
@@ -747,15 +752,15 @@ BUSMASTER_CONTROLLER_INFORMATION const BusMasterAdapters[] = {
     PCI_DEV_HW_SPEC_BM( 2652, 8086, 0x00, ATA_SA150, "Intel ICH6"       , UNIATA_SATA | UNIATA_AHCI               ),
     PCI_DEV_HW_SPEC_BM( 2653, 8086, 0x00, ATA_SA150, "Intel ICH6M"      , UNIATA_SATA | UNIATA_AHCI               ),
 
-    PCI_DEV_HW_SPEC_BM( 27df, 8086, 0x00, ATA_UDMA5, "Intel ICH7"       , I1CH                                    ),
-    PCI_DEV_HW_SPEC_BM( 27c0, 8086, 0x00, ATA_SA300, "Intel ICH7 S1"    , UNIATA_SATA                             ),
+    PCI_DEV_HW_SPEC_BM( 27df, 8086, 0x00, ATA_UDMA5, "Intel ICH7"       , 0                                       ),
+    PCI_DEV_HW_SPEC_BM( 27c0, 8086, 0x00, ATA_SA300, "Intel ICH7 S1"    , ICH7 | UNIATA_SATA                      ),
     PCI_DEV_HW_SPEC_BM( 27c1, 8086, 0x00, ATA_SA300, "Intel ICH7"       , UNIATA_SATA | UNIATA_AHCI               ),
     PCI_DEV_HW_SPEC_BM( 27c3, 8086, 0x00, ATA_SA300, "Intel ICH7"       , UNIATA_SATA                             ),
-    PCI_DEV_HW_SPEC_BM( 27c4, 8086, 0x00, ATA_SA150, "Intel ICH7M R1"   , UNIATA_SATA                             ),
+    PCI_DEV_HW_SPEC_BM( 27c4, 8086, 0x00, ATA_SA150, "Intel ICH7M R1"   , ICH7 | UNIATA_SATA                      ),
     PCI_DEV_HW_SPEC_BM( 27c5, 8086, 0x00, ATA_SA150, "Intel ICH7M"      , UNIATA_SATA | UNIATA_AHCI               ),
     PCI_DEV_HW_SPEC_BM( 27c6, 8086, 0x00, ATA_SA150, "Intel ICH7M"      , UNIATA_SATA                             ),
 
-    PCI_DEV_HW_SPEC_BM( 269e, 8086, 0x00, ATA_UDMA5, "Intel 63XXESB2"   , I1CH                                    ),
+    PCI_DEV_HW_SPEC_BM( 269e, 8086, 0x00, ATA_UDMA5, "Intel 63XXESB2"   , 0                                       ),
     PCI_DEV_HW_SPEC_BM( 2680, 8086, 0x00, ATA_SA300, "Intel 63XXESB2"   , UNIATA_SATA                             ),
     PCI_DEV_HW_SPEC_BM( 2681, 8086, 0x00, ATA_SA300, "Intel 63XXESB2"   , UNIATA_SATA | UNIATA_AHCI               ),
     PCI_DEV_HW_SPEC_BM( 2682, 8086, 0x00, ATA_SA300, "Intel 63XXESB2"   , UNIATA_SATA | UNIATA_AHCI               ),
@@ -769,7 +774,7 @@ BUSMASTER_CONTROLLER_INFORMATION const BusMasterAdapters[] = {
     PCI_DEV_HW_SPEC_BM( 2828, 8086, 0x00, ATA_SA300, "Intel ICH8M"      , I6CH | UNIATA_SATA                      ),
     PCI_DEV_HW_SPEC_BM( 2829, 8086, 0x00, ATA_SA300, "Intel ICH8M"      , UNIATA_SATA | UNIATA_AHCI               ),
     PCI_DEV_HW_SPEC_BM( 282a, 8086, 0x00, ATA_SA300, "Intel ICH8M"      , UNIATA_SATA | UNIATA_AHCI               ),
-    PCI_DEV_HW_SPEC_BM( 2850, 8086, 0x00, ATA_UDMA5, "Intel ICH8M"      , I1CH                                    ),
+    PCI_DEV_HW_SPEC_BM( 2850, 8086, 0x00, ATA_UDMA5, "Intel ICH8M"      , 0                                       ),
 
     PCI_DEV_HW_SPEC_BM( 2920, 8086, 0x00, ATA_SA300, "Intel ICH9"       , I6CH | UNIATA_SATA                      ),
     PCI_DEV_HW_SPEC_BM( 2926, 8086, 0x00, ATA_SA300, "Intel ICH9"       , I6CH2 | UNIATA_SATA                     ),
@@ -779,10 +784,10 @@ BUSMASTER_CONTROLLER_INFORMATION const BusMasterAdapters[] = {
     PCI_DEV_HW_SPEC_BM( 2923, 8086, 0x00, ATA_SA300, "Intel ICH9"       , UNIATA_SATA | UNIATA_AHCI               ),
     PCI_DEV_HW_SPEC_BM( 2925, 8086, 0x00, ATA_SA300, "Intel ICH9"       , UNIATA_SATA | UNIATA_AHCI               ),
 
-    PCI_DEV_HW_SPEC_BM( 2928, 8086, 0x00, ATA_SA300, "Intel ICH9M"       , I6CH2 | UNIATA_SATA                     ),
-    PCI_DEV_HW_SPEC_BM( 2929, 8086, 0x00, ATA_SA300, "Intel ICH9M"       , UNIATA_SATA | UNIATA_AHCI               ),
-    PCI_DEV_HW_SPEC_BM( 292a, 8086, 0x00, ATA_SA300, "Intel ICH9M"       , UNIATA_SATA | UNIATA_AHCI               ),
-    PCI_DEV_HW_SPEC_BM( 292d, 8086, 0x00, ATA_SA300, "Intel ICH9M"       , I6CH2 | UNIATA_SATA                     ),
+    PCI_DEV_HW_SPEC_BM( 2928, 8086, 0x00, ATA_SA300, "Intel ICH9M"      , I6CH2 | UNIATA_SATA                     ),
+    PCI_DEV_HW_SPEC_BM( 2929, 8086, 0x00, ATA_SA300, "Intel ICH9M"      , UNIATA_SATA | UNIATA_AHCI               ),
+    PCI_DEV_HW_SPEC_BM( 292a, 8086, 0x00, ATA_SA300, "Intel ICH9M"      , UNIATA_SATA | UNIATA_AHCI               ),
+    PCI_DEV_HW_SPEC_BM( 292d, 8086, 0x00, ATA_SA300, "Intel ICH9M"      , I6CH2 | UNIATA_SATA                     ),
     
     PCI_DEV_HW_SPEC_BM( 3a20, 8086, 0x00, ATA_SA300, "Intel ICH10"      , I6CH | UNIATA_SATA                      ),
     PCI_DEV_HW_SPEC_BM( 3a26, 8086, 0x00, ATA_SA300, "Intel ICH10"      , I6CH2 | UNIATA_SATA                     ),
@@ -842,7 +847,7 @@ BUSMASTER_CONTROLLER_INFORMATION const BusMasterAdapters[] = {
     PCI_DEV_HW_SPEC_BM( 1e0f, 8086, 0x00, ATA_SA300, "Intel Panther Point" , UNIATA_SATA | UNIATA_AHCI               ),
 
 //    PCI_DEV_HW_SPEC_BM( 3200, 8086, 0x00, ATA_SA150, "Intel 31244"      , UNIATA_SATA                             ),
-    PCI_DEV_HW_SPEC_BM( 811a, 8086, 0x00, ATA_UDMA5, "Intel SCH"        , I1CH                                       ),
+    PCI_DEV_HW_SPEC_BM( 811a, 8086, 0x00, ATA_UDMA5, "Intel SCH"        , 0                                       ),
     PCI_DEV_HW_SPEC_BM( 2323, 8086, 0x00, ATA_SA300, "Intel DH98xxCC"   , UNIATA_SATA | UNIATA_AHCI                  ),
 
     PCI_DEV_HW_SPEC_BM( 2360, 197b, 0x00, ATA_SA300, "JMB360"           , UNIATA_SATA | UNIATA_AHCI               ),
index 864f7ea..ca6f963 100644 (file)
@@ -562,9 +562,9 @@ typedef struct _IDE_AHCI_PORT_REGISTERS {
         ULONG Reg;           // signature
         struct {
             UCHAR SectorCount;
-            UCHAR LbaLow;
-            UCHAR LbaMid;
-            UCHAR LbaHigh;
+            UCHAR LbaLow;       // IDX_IO1_i_BlockNumber
+            UCHAR LbaMid;       // IDX_IO1_i_CylinderLow
+            UCHAR LbaHigh;      // IDX_IO1_i_CylinderHigh
         };
     } SIG;  // 0x100 + 0x80*c + 0x0024
     union {
@@ -1060,6 +1060,7 @@ typedef struct _HW_CHANNEL {
 #define CTRFLAGS_DSC_BSY                0x0080
 #define CTRFLAGS_NO_SLAVE               0x0100
 //#define CTRFLAGS_PATA                   0x0200
+//#define CTRFLAGS_NOT_PRESENT            0x0200
 #define CTRFLAGS_AHCI_PM                0x0400
 #define CTRFLAGS_AHCI_PM2               0x0800
 
@@ -1086,7 +1087,7 @@ typedef struct _HW_LU_EXTENSION {
     BOOLEAN        DWordIO;        // Indicates use of 32-bit PIO
     UCHAR          ReturningMediaStatus;
     UCHAR          MaximumBlockXfer;
-    UCHAR          Padding0[1];    // padding
+    UCHAR          PowerState;
 
     UCHAR          TransferMode;          // current transfer mode
     UCHAR          LimitedTransferMode;   // user-defined or IDE cable limitation
@@ -1117,8 +1118,10 @@ typedef struct _HW_LU_EXTENSION {
     BOOLEAN        opt_ReadCacheEnable;
     BOOLEAN        opt_WriteCacheEnable;
     UCHAR          opt_ReadOnly;
-    // padding
-    BOOLEAN        opt_reserved[1];
+    UCHAR          opt_AdvPowerMode;
+    UCHAR          opt_AcousticMode;
+    UCHAR          opt_StandbyTimer;
+    UCHAR          opt_Padding[2]; // padding
 
     struct _SBadBlockListItem* bbListDescr;
     struct _SBadBlockRange* arrBadBlocks;
@@ -1216,6 +1219,9 @@ typedef struct _HW_DEVICE_EXTENSION {
     BOOLEAN MasterDev;
     BOOLEAN Host64;
     BOOLEAN DWordIO;         // Indicates use of 32-bit PIO
+/*    // Indicates, that HW Initialized is already called for this controller
+    // 0 bit for Primary, 1 - for Secondary. Is used to manage AltInit under w2k+
+    UCHAR   Initialized;     */
     UCHAR   Reserved1[2];
 
     LONG  ReCheckIntr;
@@ -1238,6 +1244,7 @@ typedef struct _HW_DEVICE_EXTENSION {
     IORES          BaseIoAHCI_0;
     //PIDE_AHCI_PORT_REGISTERS  BaseIoAHCIPort[AHCI_MAX_PORT];
     ULONG          AHCI_CAP;
+    ULONG          AHCI_PI;
     PATA_REQ       AhciInternalAtaReq0;
     PSCSI_REQUEST_BLOCK AhciInternalSrb0;
 
@@ -1260,6 +1267,9 @@ typedef struct _ISR2_DEVICE_EXTENSION {
     ULONG DevIndex;
 } ISR2_DEVICE_EXTENSION, *PISR2_DEVICE_EXTENSION;
 
+typedef ISR2_DEVICE_EXTENSION   PCIIDE_DEVICE_EXTENSION;
+typedef PISR2_DEVICE_EXTENSION  PPCIIDE_DEVICE_EXTENSION;
+
 #define HBAFLAGS_DMA_DISABLED           0x01
 #define HBAFLAGS_DMA_DISABLED_LBA48     0x02
 
@@ -1268,6 +1278,7 @@ extern PBUSMASTER_CONTROLLER_INFORMATION BMList;
 extern ULONG         BMListLen;
 extern ULONG         IsaCount;
 extern ULONG         MCACount;
+extern UNICODE_STRING SavedRegPath;
 
 //extern const CHAR retry_Wdma[MAX_RETRIES+1];
 //extern const CHAR retry_Udma[MAX_RETRIES+1];
@@ -1322,14 +1333,10 @@ UniataFindBusMasterController(
     OUT PBOOLEAN Again
     );
 
-extern ULONG NTAPI
-UniataFindFakeBusMasterController(
-    IN PVOID HwDeviceExtension,
-    IN PVOID Context,
-    IN PVOID BusInformation,
-    IN PCHAR ArgumentString,
-    IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
-    OUT PBOOLEAN Again
+extern NTSTATUS
+NTAPI
+UniataClaimLegacyPCIIDE(
+    ULONG i
     );
 
 extern NTSTATUS
@@ -1508,6 +1515,14 @@ AtapiGetIoRange(
     IN ULONG length //range id
     );
 
+extern USHORT
+NTAPI
+UniataEnableIoPCI(
+    IN  ULONG                  busNumber,
+    IN  ULONG                  slotNumber,
+ IN OUT PPCI_COMMON_CONFIG     pciData
+    );
+
 /****************** 1 *****************/
 #define GetPciConfig1(offs, op) {                                \
     ScsiPortGetBusDataByOffset(HwDeviceExtension,                \
index 0893379..852bd24 100644 (file)
@@ -47,7 +47,7 @@ Revision History:
     5. W2k support (binary compatibility)
     6. HDD hot swap under NT4
     7. XP support (binary compatibility)
-    8. Serial ATA (SATA/SATA2) support
+    8. Serial ATA (SATA/SATA2/SATA3) support
     9. NT 3.51 support (binary compatibility)
 
     etc. (See todo.txt)
@@ -121,6 +121,14 @@ AtapiHwInitialize__(
     IN ULONG lChannel
     );
 
+VOID
+NTAPI
+UniataUserDeviceReset(
+    PHW_DEVICE_EXTENSION deviceExtension,
+    PHW_LU_EXTENSION LunExt,
+    ULONG lChannel
+    );
+
 #define RESET_COMPLETE_CURRENT  0x00
 #define RESET_COMPLETE_ALL      0x01
 #define RESET_COMPLETE_NONE     0x02
@@ -482,6 +490,7 @@ AtapiSuckPort2(
     UCHAR statusByte;
     ULONG i;
 
+    // Assume, proper drive is already seleted
     WaitOnBusyLong(chan);
     for (i = 0; i < 0x10000; i++) {
 
@@ -1270,6 +1279,42 @@ UniataDumpATARegs(
 } // end UniataDumpATARegs()
 #endif
 
+VOID
+NTAPI
+UniataSnapAtaRegs(
+    IN PHW_CHANNEL chan,
+    IN ULONG DeviceNumber,
+ IN OUT PIDEREGS_EX regs
+    )
+{
+    if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
+        // AHCI
+        UniataAhciSnapAtaRegs(chan, DeviceNumber, regs);
+    } else {
+        // SATA/PATA, assume drive is selected
+        ULONG                j;
+        UCHAR                statusByteAlt;
+
+        if((regs->bOpFlags & ATA_FLAGS_48BIT_COMMAND) == 0) {
+            for(j=IDX_IO1_i_Error; j<=IDX_IO1_i_Status; j++) {
+                statusByteAlt = AtapiReadPort1(chan, IDX_IO1+j);
+                ((PUCHAR)regs)[j-1] = statusByteAlt;
+            }
+            regs->bOpFlags = 0;
+        } else {
+            regs->bDriveHeadReg    = AtapiReadPort1(chan, IDX_IO1_i_DriveSelect);
+            for(j=IDX_IO1_i_Error; j<IDX_IO1_i_DriveSelect; j++) {
+                statusByteAlt = AtapiReadPort1(chan, IDX_IO1+j);
+                ((PUCHAR)regs)[j-1] = statusByteAlt;
+                statusByteAlt = AtapiReadPort1(chan, IDX_IO1+j);
+                ((PUCHAR)regs)[j+8-1] = statusByteAlt;
+            }
+            regs->bCommandReg      = AtapiReadPort1(chan, IDX_IO1_i_Status);
+        }
+    }
+    return;
+} // end UniataSnapAtaRegs()
+
 /*++
 
 Routine Description:
@@ -1491,7 +1536,7 @@ IssueIdentify(
                     break;
                 }
             }
-            // Device didn't respond correctly. It will be given one more chances.
+            // Device didn't respond correctly. It will be given one more chance.
             KdPrint2((PRINT_PREFIX "IssueIdentify: DRQ never asserted (%#x). Error reg (%#x)\n",
                         statusByte, AtapiReadPort1(chan, IDX_IO1_i_Error)));
             GetBaseStatus(chan, statusByte);
@@ -1542,33 +1587,13 @@ IssueIdentify(
         if (atapiDev || !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/) {
 
             KdPrint2((PRINT_PREFIX "  use 16bit IO\n"));
-#if 0
-            USHORT w;
-            ULONG i;
+
             // ATI/SII chipsets with memory-mapped IO hangs when
             // I call ReadBuffer(), probably due to PCI burst/prefetch enabled
-            // Unfortunately, I don't know yet how to workaround it except the way you see below.
-            KdPrint2((PRINT_PREFIX 
-                       "  IO_%#x (%#x), %s:\n",
-                       IDX_IO1_i_Data,
-                       chan->RegTranslation[IDX_IO1_i_Data].Addr,
-                       chan->RegTranslation[IDX_IO1_i_Data].MemIo ? "Mem" : "IO"));
-            for(i=0; i<256; i++) {
-    /*
-                KdPrint2((PRINT_PREFIX 
-                           "  IO_%#x (%#x):\n",
-                           IDX_IO1_i_Data,
-                           chan->RegTranslation[IDX_IO1_i_Data].Addr));
-    */
-                w = AtapiReadPort2(chan, IDX_IO1_i_Data);
-                KdPrint2((PRINT_PREFIX 
-                           "    %x\n", w));
-                AtapiStallExecution(1);
-                ((PUSHORT)&deviceExtension->FullIdentifyData)[i] = w;
-            }
-#else
+            // Unfortunately, I don't know yet how to workaround it except
+            // spacifying manual delay in the way you see below.
             ReadBuffer(chan, (PUSHORT)&deviceExtension->FullIdentifyData, 256, PIO0_TIMING);
-#endif
+
             // Work around for some IDE and one model Atapi that will present more than
             // 256 bytes for the Identify data.
             KdPrint2((PRINT_PREFIX "IssueIdentify: suck data port\n", statusByte));
@@ -1600,7 +1625,7 @@ IssueIdentify(
     KdPrint2((PRINT_PREFIX "SWDMA: %x\n", deviceExtension->FullIdentifyData.SingleWordDMAActive));
     KdPrint2((PRINT_PREFIX "MWDMA: %x\n", deviceExtension->FullIdentifyData.MultiWordDMAActive));
     if(deviceExtension->FullIdentifyData.UdmaModesValid) {
-        KdPrint2((PRINT_PREFIX "UDMA:  %x\n", deviceExtension->FullIdentifyData.UltraDMAActive));
+        KdPrint2((PRINT_PREFIX "UDMA:  %x/%x\n", deviceExtension->FullIdentifyData.UltraDMAActive, deviceExtension->FullIdentifyData.UltraDMASupport));
     }
     KdPrint2((PRINT_PREFIX "SATA:  %x\n", deviceExtension->FullIdentifyData.SataEnable));
     KdPrint2((PRINT_PREFIX "SATA support: %x, CAPs %#x\n",
@@ -1609,9 +1634,18 @@ IssueIdentify(
 
     LunExt->LimitedTransferMode =
     LunExt->OrigTransferMode =
-        (UCHAR)ata_cur_mode_from_ident(&(deviceExtension->FullIdentifyData));
-
-    KdPrint2((PRINT_PREFIX "OrigTransferMode: %x\n", LunExt->OrigTransferMode));
+        (UCHAR)ata_cur_mode_from_ident(&(deviceExtension->FullIdentifyData), IDENT_MODE_MAX);
+    LunExt->TransferMode =
+        (UCHAR)ata_cur_mode_from_ident(&(deviceExtension->FullIdentifyData), IDENT_MODE_ACTIVE);
+
+    KdPrint2((PRINT_PREFIX "OrigTransferMode: %x, Active: %x\n", LunExt->OrigTransferMode, LunExt->TransferMode));
+    KdPrint2((PRINT_PREFIX "Accoustic %d, cur %d\n",
+        deviceExtension->FullIdentifyData.VendorAcoustic,
+        deviceExtension->FullIdentifyData.CurrentAcoustic
+        ));
+    KdPrint2((PRINT_PREFIX "AdvPowerMode %d, cur %d\n",
+        deviceExtension->FullIdentifyData.CfAdvPowerMode
+        ));
 
     // Check out a few capabilities / limitations of the device.
     if (deviceExtension->FullIdentifyData.RemovableStatus & 1) {
@@ -1841,7 +1875,6 @@ IssueIdentify(
                 }
             }
         }
-        KdPrint2((PRINT_PREFIX "final LunExt->opt_GeomType=%x\n", LunExt->opt_GeomType));
 
         if(LunExt->opt_GeomType == GEOM_STD) {
             deviceExtension->FullIdentifyData.CurrentSectorsPerTrack =
@@ -2025,6 +2058,7 @@ UniataForgetDevice(
     PHW_LU_EXTENSION   LunExt
     )
 {
+    // keep only DFLAGS_HIDDEN flag
     LunExt->DeviceFlags &= DFLAGS_HIDDEN;
     LunExt->AtapiReadyWaitDelay = 0;
 } // end UniataForgetDevice()
@@ -2034,6 +2068,7 @@ UniataForgetDevice(
 
 Routine Description:
     Reset IDE controller and/or Atapi device.
+    ->HwResetBus
 
 Arguments:
     HwDeviceExtension - HBA miniport driver's adapter data storage
@@ -2054,7 +2089,6 @@ AtapiResetController(
     return AtapiResetController__(HwDeviceExtension, PathId, RESET_COMPLETE_ALL);
 } // end AtapiResetController()
 
-
 BOOLEAN
 NTAPI
 AtapiResetController__(
@@ -2188,14 +2222,21 @@ AtapiResetController__(
         InterlockedExchange(&(chan->CheckIntr),
                                       CHECK_INTR_IDLE);
         
+        for (i = 0; i < MaxLuns; i++) {
+            chan->lun[i]->PowerState = 0;
+        }
         // Reset controller
         if(ChipFlags & UNIATA_AHCI) {
             KdPrint2((PRINT_PREFIX "  AHCI path\n"));
+            if(UniataAhciChanImplemented(deviceExtension, j)) {
 #if DBG
-            UniataDumpAhciPortRegs(chan);
+                UniataDumpAhciPortRegs(chan);
 #endif
-            AtapiDisableInterrupts(deviceExtension, j);
-            UniataAhciReset(HwDeviceExtension, j);
+                AtapiDisableInterrupts(deviceExtension, j);
+                UniataAhciReset(HwDeviceExtension, j);
+            } else {
+                KdPrint2((PRINT_PREFIX "  skip not implemented\n"));
+            }
         } else {
             KdPrint2((PRINT_PREFIX "  ATA path, chan %#x\n", chan));
             KdPrint2((PRINT_PREFIX "  disable intr (0)\n"));
@@ -2843,6 +2884,7 @@ Routine Description:
 
 Arguments:
     HwDeviceExtension - HBA miniport driver's adapter data storage
+    ->HwInitialize
 
 Return Value:
     TRUE - if initialization successful.
@@ -2864,6 +2906,11 @@ AtapiHwInitialize(
     if(WinVer_WDM_Model) {
         AtapiResetController__(HwDeviceExtension, CHAN_NOT_SPECIFIED, RESET_COMPLETE_ALL);
     }
+    if(deviceExtension->MasterDev) {
+        KdPrint2((PRINT_PREFIX "  mark chan %d of master controller [%x] as inited\n",
+            deviceExtension->Channel, deviceExtension->DevIndex));
+        BMList[deviceExtension->DevIndex].ChanInitOk |= 0x01 << deviceExtension->Channel;
+    }
 
     /* do extra chipset specific setups */
     AtapiChipInit(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, CHAN_NOT_SPECIFIED);
@@ -2894,6 +2941,11 @@ AtapiHwInitialize__(
 //    ULONG tmp32;
     ULONG PreferedMode = 0xffffffff;
 
+    if((deviceExtension->HwFlags & UNIATA_AHCI) &&
+       !UniataAhciChanImplemented(deviceExtension, lChannel)) {
+        return;
+    }
+
     AtapiChipInit(deviceExtension, DEVNUM_NOT_SPECIFIED, lChannel);
     FindDevices(deviceExtension, 0, lChannel);
 
@@ -2998,9 +3050,65 @@ AtapiHwInitialize__(
                     KdPrint2((PRINT_PREFIX "  Disable Write Cache\n"));
                     statusByte = AtaCommand(deviceExtension, i, lChannel,
                                         IDE_COMMAND_SET_FEATURES, 0, 0, 0,
-                                        0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_BASE_READY);
+                                        0, ATA_C_F_DIS_WCACHE, ATA_WAIT_BASE_READY);
                     LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
                 }
+
+                if(LunExt->IdentifyData.FeaturesSupport.PowerMngt ||
+                   LunExt->IdentifyData.FeaturesSupport.APM) {
+
+                    if(LunExt->opt_AdvPowerMode) {
+                        KdPrint2((PRINT_PREFIX "  Try Enable Adv. Power Mgmt\n"));
+                        // setup APM
+                        statusByte = AtaCommand(deviceExtension, i, lChannel,
+                                            IDE_COMMAND_SET_FEATURES, 0, 0, 0,
+                                            LunExt->opt_AdvPowerMode, ATA_C_F_ENAB_APM, ATA_WAIT_BASE_READY);
+                        // Check for errors.
+                        if (statusByte & IDE_STATUS_ERROR) {
+                            KdPrint2((PRINT_PREFIX 
+                                        "AtapiHwInitialize: Enable APM on Device %d failed\n",
+                                        i));
+                        }
+                    } else {
+                        KdPrint2((PRINT_PREFIX "  Disable Adv. Power Mgmt\n"));
+                        statusByte = AtaCommand(deviceExtension, i, lChannel,
+                                            IDE_COMMAND_SET_FEATURES, 0, 0, 0,
+                                            0, ATA_C_F_DIS_APM, ATA_WAIT_BASE_READY);
+                    }
+                }
+                if(LunExt->IdentifyData.FeaturesSupport.AutoAcoustic) {
+                    if(LunExt->opt_AcousticMode) {
+                        KdPrint2((PRINT_PREFIX "  Try Enable Acoustic Mgmt\n"));
+                        // setup acoustic mgmt
+                        statusByte = AtaCommand(deviceExtension, i, lChannel,
+                                            IDE_COMMAND_SET_FEATURES, 0, 0, 0,
+                                            LunExt->opt_AcousticMode, ATA_C_F_ENAB_ACOUSTIC, ATA_WAIT_BASE_READY);
+                        // Check for errors.
+                        if (statusByte & IDE_STATUS_ERROR) {
+                            KdPrint2((PRINT_PREFIX 
+                                        "AtapiHwInitialize: Enable Acoustic Mgmt on Device %d failed\n",
+                                        i));
+                        }
+                    } else {
+                        KdPrint2((PRINT_PREFIX "  Disable Acoustic Mgmt\n"));
+                        statusByte = AtaCommand(deviceExtension, i, lChannel,
+                                            IDE_COMMAND_SET_FEATURES, 0, 0, 0,
+                                            0, ATA_C_F_DIS_ACOUSTIC, ATA_WAIT_BASE_READY);
+                    }
+                }
+                if(LunExt->IdentifyData.FeaturesSupport.Standby) {
+                    KdPrint2((PRINT_PREFIX "  Try init standby timer: %d\n"));
+                    // setup standby timer
+                    statusByte = AtaCommand(deviceExtension, i, lChannel,
+                                        IDE_COMMAND_IDLE, 0, 0, 0,
+                                        LunExt->opt_StandbyTimer, 0, ATA_WAIT_BASE_READY);
+                    // Check for errors.
+                    if (statusByte & IDE_STATUS_ERROR) {
+                        KdPrint2((PRINT_PREFIX 
+                                    "AtapiHwInitialize: standby timer on Device %d failed\n",
+                                    i));
+                    }
+                }
             }
 
         } else if (!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED)){
@@ -3498,7 +3606,10 @@ AtapiInterrupt(
         if(!hIS) {
             return FALSE;
         }
-        checked = ~hIS; // assume all non-interrupted ports to be already checked
+        // assume all non-interrupted ports to be already checked
+        checked = ~hIS;
+        // assume all not implemented ports to be already checked
+        checked |= ~deviceExtension->AHCI_PI;
     } else {
         checked = 0; // assume all ports are not checked
     }
@@ -3661,7 +3772,11 @@ AtapiInterrupt2(
         if(!hIS) {
             return FALSE;
         }
-        checked = ~hIS; // assume all non-interrupted ports to be already checked
+        // assume all non-interrupted ports to be already checked
+        checked = ~hIS; 
+        // assume all not implemented ports to be already checked
+        checked |= ~deviceExtension->AHCI_PI;
+
     } else {
         checked = 0; // assume all ports are not checked
     }
@@ -3844,6 +3959,12 @@ AtapiEnableInterrupts(
         KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts_%d: WRONG CHANNEL\n",c));
         return;
     }
+    if((deviceExtension->HwFlags & UNIATA_AHCI) &&
+       !UniataAhciChanImplemented(deviceExtension, c)) {
+        KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts_%d: not imp. CHANNEL\n",c));
+        return;
+    }
+
     chan = &(deviceExtension->chan[c]);
     KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts_%d: %d\n",c, chan->DisableIntr));
     if(!InterlockedDecrement(&chan->DisableIntr)) {
@@ -3977,6 +4098,11 @@ AtapiCheckInterrupt__(
 
     if((ChipFlags & UNIATA_AHCI) &&
         UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
+
+        if(!UniataAhciChanImplemented(deviceExtension, lChannel)) {
+            return OurInterrupt;
+        }
+
         OurInterrupt = UniataAhciStatus(HwDeviceExtension, lChannel, DEVNUM_NOT_SPECIFIED);
         if((OurInterrupt == INTERRUPT_REASON_UNEXPECTED) &&
            (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE)) {
@@ -4929,27 +5055,27 @@ continue_err:
         KdPrint2((PRINT_PREFIX "Some higher mode doesn't work right :((\n"));
         KdPrint2((PRINT_PREFIX "Recovery stats[%d]: %d vs %d\n",
               AtaReq->retry,
-              chan->lun[DeviceNumber]->RecoverCount[AtaReq->retry],
-              chan->lun[DeviceNumber]->BlockIoCount
+              LunExt->RecoverCount[AtaReq->retry],
+              LunExt->BlockIoCount
               ));
-        chan->lun[DeviceNumber]->RecoverCount[AtaReq->retry]++;
-        if(chan->lun[DeviceNumber]->RecoverCount[AtaReq->retry] >= chan->lun[DeviceNumber]->BlockIoCount/3 ||
+        LunExt->RecoverCount[AtaReq->retry]++;
+        if(LunExt->RecoverCount[AtaReq->retry] >= chan->lun[DeviceNumber]->BlockIoCount/3 ||
            (deviceExtension->HwFlags & UNIATA_NO80CHK)
            ) {
 #else
         if(deviceExtension->HwFlags & UNIATA_NO80CHK) {
 #endif //IO_STATISTICS
-            KdPrint2((PRINT_PREFIX "Limit transfer rate to %x\n", deviceExtension->lun[DeviceNumber].TransferMode));
-            deviceExtension->lun[DeviceNumber].LimitedTransferMode =
-                deviceExtension->lun[DeviceNumber].TransferMode;
+            KdPrint2((PRINT_PREFIX "Limit transfer rate to %x\n", LunExt->TransferMode));
+            LunExt->LimitedTransferMode =
+                LunExt->TransferMode;
         }
     }
 #ifdef IO_STATISTICS
     if(AtaReq->bcount) {
         // we need stats for Read/Write operations
-        chan->lun[DeviceNumber]->BlockIoCount++;
+        LunExt->BlockIoCount++;
     }
-    chan->lun[DeviceNumber]->IoCount++;
+    LunExt->IoCount++;
 #endif //IO_STATISTICS
 
 continue_PIO:
@@ -5063,9 +5189,9 @@ IntrPrepareResetController:
         } else {
             AtaReq->WordsLeft -= AtaReq->WordsTransfered;
         }
-        if(AtaReq->WordsLeft && (status == SRB_STATUS_SUCCESS)) {
-            status = SRB_STATUS_DATA_OVERRUN;
-        }
+        //if(AtaReq->WordsLeft && (status == SRB_STATUS_SUCCESS)) {
+        //    status = SRB_STATUS_DATA_OVERRUN;
+        //}
         status = SRB_STATUS_SUCCESS;
         chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
         goto CompleteRequest;
@@ -5074,7 +5200,9 @@ IntrPrepareResetController:
         // Write the packet.
         KdPrint3((PRINT_PREFIX "AtapiInterrupt: Writing Atapi packet.\n"));
         // Send CDB to device.
-        WriteBuffer(chan, (PUSHORT)srb->Cdb, 6, 0);
+        WriteBuffer(chan, (PUSHORT)srb->Cdb, 
+                          LunExt->IdentifyData.AtapiCmdSize ? 8 : 6,
+                          0);
         AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
 
         if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) {
@@ -5457,7 +5585,7 @@ CompleteRequest:
         // Check and see if we are processing our secret (mechanism status/request sense) srb
 
         if(AtaReq->WordsLeft && (status == SRB_STATUS_SUCCESS)) {
-            KdPrint2((PRINT_PREFIX "WordsLeft %#x -> SRB_STATUS_SUCCESS\n", AtaReq->WordsLeft));
+            KdPrint2((PRINT_PREFIX "WordsLeft %#x -> SRB_STATUS_DATA_OVERRUN\n", AtaReq->WordsLeft));
             status = SRB_STATUS_DATA_OVERRUN;
         }
 
@@ -5785,31 +5913,35 @@ IntrCompleteReq:
             } else {
 
                 KdPrint2((PRINT_PREFIX "AtapiInterrupt: IOCTL completion\n"));
-                PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
 
                 if (status != SRB_STATUS_SUCCESS) {
                     error = AtapiReadPort1(chan, IDX_IO1_i_Error);
                     KdPrint2((PRINT_PREFIX "AtapiInterrupt: error %#x\n", error));
                 }
 
-                // Build the SMART status block depending upon the completion status.
-                cmdOutParameters->cBufferSize = wordCount;
-                cmdOutParameters->DriverStatus.bDriverError = (error) ? SMART_IDE_ERROR : 0;
-                cmdOutParameters->DriverStatus.bIDEError = error;
+                if(!AtapiStringCmp( (PCHAR)(((PSRB_IO_CONTROL)(srb->DataBuffer))->Signature),"SCSIDISK",sizeof("SCSIDISK")-1)) {
 
-                // If the sub-command is return smart status, jam the value from cylinder low and high, into the
-                // data buffer.
-                if (chan->SmartCommand == RETURN_SMART_STATUS) {
-                    cmdOutParameters->bBuffer[0] = RETURN_SMART_STATUS;
-                    cmdOutParameters->bBuffer[1] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason);
-                    cmdOutParameters->bBuffer[2] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_Unused1);
-                    cmdOutParameters->bBuffer[3] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow);
-                    cmdOutParameters->bBuffer[4] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh);
-                    cmdOutParameters->bBuffer[5] = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_DriveSelect);
-                    cmdOutParameters->bBuffer[6] = SMART_CMD;
-                    cmdOutParameters->cBufferSize = 8;
-                }
+                    PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
+                    // Build the SMART status block depending upon the completion status.
+                    cmdOutParameters->cBufferSize = wordCount;
+                    cmdOutParameters->DriverStatus.bDriverError = (error) ? SMART_IDE_ERROR : 0;
+                    cmdOutParameters->DriverStatus.bIDEError = error;
 
+                    // If the sub-command is return smart status, jam the value from cylinder low and high, into the
+                    // data buffer.
+                    if (chan->SmartCommand == RETURN_SMART_STATUS) {
+                        PIDEREGS_EX regs = (PIDEREGS_EX)&(cmdOutParameters->bBuffer);
+
+                        regs->bOpFlags = 0;
+                        UniataSnapAtaRegs(chan, 0, regs);
+
+                        regs->bCommandReg = SMART_CMD;
+                        regs->bFeaturesReg = RETURN_SMART_STATUS;
+
+                        cmdOutParameters->cBufferSize = 8;
+                    }
+                    chan->SmartCommand = 0; // cleanup after execution
+                }
                 // Indicate command complete.
                 goto IntrCompleteReq;
             }
@@ -5971,19 +6103,20 @@ ULONG
 NTAPI
 IdeSendSmartCommand(
     IN PVOID HwDeviceExtension,
-    IN PSCSI_REQUEST_BLOCK Srb
+    IN PSCSI_REQUEST_BLOCK Srb,
+    IN ULONG targetId // assume it is always valid
     )
 {
     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
-    ULONG                c               = GET_CHANNEL(Srb);
-    PHW_CHANNEL          chan            = &(deviceExtension->chan[c]);
+    ULONG                c               ; // = GET_CHANNEL(Srb); may be invalid
+    PHW_CHANNEL          chan            ; // = &(deviceExtension->chan[c]);
     PATA_REQ             AtaReq          = (PATA_REQ)(Srb->SrbExtension);
     PSENDCMDOUTPARAMS    cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
     SENDCMDINPARAMS      cmdInParameters = *(PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
     PIDEREGS             regs            = &cmdInParameters.irDriveRegs;
 //    ULONG                i;
-    UCHAR                statusByte,targetId;
-
+    UCHAR                statusByte;
+    ULONG DeviceNumber;
 
     if (regs->bCommandReg != SMART_CMD) {
         KdPrint2((PRINT_PREFIX 
@@ -5991,14 +6124,11 @@ IdeSendSmartCommand(
         return SRB_STATUS_INVALID_REQUEST;
     }
 
-    targetId = cmdInParameters.bDriveNumber;
+    c = targetId / deviceExtension->NumberLuns;
+    DeviceNumber = targetId % deviceExtension->NumberLuns;
+    KdPrint2((PRINT_PREFIX "  c %d, dev %d\n", c, DeviceNumber));
 
-    //TODO optimize this check
-    if ((!(deviceExtension->lun[targetId].DeviceFlags & DFLAGS_DEVICE_PRESENT)) ||
-         (deviceExtension->lun[targetId].DeviceFlags & DFLAGS_ATAPI_DEVICE)) {
-
-        return SRB_STATUS_SELECTION_TIMEOUT;
-    }
+    chan = &(deviceExtension->chan[c]);
 
     chan->SmartCommand = regs->bFeaturesReg;
 
@@ -6006,6 +6136,14 @@ IdeSendSmartCommand(
     switch(regs->bFeaturesReg) {
     case READ_ATTRIBUTES:
     case READ_THRESHOLDS:
+    case READ_LOG_SECTOR:
+    case WRITE_LOG_SECTOR:
+
+        if(Srb->DataTransferLength < sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDOUTPARAMS) + READ_ATTRIBUTE_BUFFER_SIZE - 1) {
+            KdPrint2((PRINT_PREFIX 
+                        "IdeSendSmartCommand: wrong buffer size\n"));
+            return SRB_STATUS_DATA_OVERRUN;
+        }
 
         statusByte = WaitOnBusy(chan);
 
@@ -6022,7 +6160,7 @@ IdeSendSmartCommand(
         AtaReq->DataBuffer = (PUSHORT)cmdOutParameters->bBuffer;
         AtaReq->WordsLeft = READ_ATTRIBUTE_BUFFER_SIZE / 2;
 
-        statusByte = AtaCommand(deviceExtension, targetId & 0x1, c,
+        statusByte = AtaCommand(deviceExtension, DeviceNumber, c,
                    regs->bCommandReg,
                    (USHORT)(regs->bCylLowReg) | (((USHORT)(regs->bCylHighReg)) << 8),
                    0,
@@ -6043,6 +6181,7 @@ IdeSendSmartCommand(
     case ENABLE_DISABLE_AUTOSAVE:
     case EXECUTE_OFFLINE_DIAGS:
     case SAVE_ATTRIBUTE_VALUES:
+    case AUTO_OFFLINE:
 
         statusByte = WaitOnBusy(chan);
 
@@ -6059,7 +6198,7 @@ IdeSendSmartCommand(
         AtaReq->DataBuffer = (PUSHORT)cmdOutParameters->bBuffer;
         AtaReq->WordsLeft = 0;
 
-        statusByte = AtaCommand(deviceExtension, targetId & 0x1, c,
+        statusByte = AtaCommand(deviceExtension, DeviceNumber, c,
                    regs->bCommandReg,
                    (USHORT)(regs->bCylLowReg) | (((USHORT)(regs->bCylHighReg)) << 8),
                    0,
@@ -6070,6 +6209,7 @@ IdeSendSmartCommand(
 
         if(!(statusByte & IDE_STATUS_ERROR)) {
             // Wait for interrupt.
+            UniataExpectChannelInterrupt(chan, TRUE); // device may interrupt
             return SRB_STATUS_PENDING;
         }
         return SRB_STATUS_ERROR;
@@ -6615,7 +6755,6 @@ AtapiSendCommand(
     PHW_LU_EXTENSION     LunExt;
     //ULONG                ldev = GET_LDEV(Srb);
     ULONG                DeviceNumber = GET_CDEV(Srb);
-    ULONG i;
     ULONG flags;
     UCHAR statusByte,byteCountLow,byteCountHigh;
     BOOLEAN use_dma = FALSE;
@@ -6709,6 +6848,7 @@ AtapiSendCommand(
 
     if(CmdAction == CMD_ACTION_PREPARE) {
         KdPrint2((PRINT_PREFIX "AtapiSendCommand: CMD_ACTION_PREPARE, Cdb %x\n", &(Srb->Cdb)));
+
         switch (Srb->Cdb[0]) {
         case SCSIOP_RECEIVE:
         case SCSIOP_SEND:
@@ -6775,6 +6915,13 @@ AtapiSendCommand(
        (AtaReq->ReqState != REQ_STATE_READY_TO_TRANSFER)) {
 
         KdPrint2((PRINT_PREFIX "AtapiSendCommand: prepare..., ATAPI CMD %x (Cdb %x)\n", Srb->Cdb[0], &(Srb->Cdb)));
+
+        if(!LunExt->IdentifyData.AtapiCmdSize &&
+            (Srb->CdbLength > 12)) {
+            KdPrint2((PRINT_PREFIX "Cdb16 not supported\n"));
+            return SRB_STATUS_INVALID_REQUEST;
+        }
+
         // Set data buffer pointer and words left.
         AtaReq->DataBuffer = (PUSHORT)Srb->DataBuffer;
         AtaReq->WordsLeft = Srb->DataTransferLength / 2;
@@ -7110,6 +7257,8 @@ retry:
         // Try to drain the data that one preliminary device thinks that it has
         // to transfer. Hopefully this random assertion of DRQ will not be present
         // in production devices.
+        statusByte = AtapiSuckPort2(chan);
+/*
         for (i = 0; i < 0x10000; i++) {
             GetStatus(chan, statusByte);
             if(statusByte & IDE_STATUS_DRQ) {
@@ -7118,8 +7267,8 @@ retry:
                 break;
             }
         }
-
-        if (i == 0x10000) {
+*/
+        if (statusByte & IDE_STATUS_DRQ) {
 make_reset:
             KdPrint3((PRINT_PREFIX "AtapiSendCommand: DRQ still asserted.Status (%#x)\n", statusByte));
 
@@ -7282,7 +7431,7 @@ make_reset:
 
     WriteBuffer(chan,
                 (PUSHORT)Srb->Cdb,
-                6,
+                LunExt->IdentifyData.AtapiCmdSize ? 8 : 6,
                 0);
 
     if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) {
@@ -7342,13 +7491,15 @@ IdeSendCommand(
     SetCheckPoint(4);
 
     UCHAR statusByte,errorByte;
-    ULONG status;
+    ULONG status = SRB_STATUS_INVALID_REQUEST;
     ULONG i;
     ULONGLONG lba;
     PMODE_PARAMETER_HEADER   modeData;
     //ULONG ldev;
     ULONG DeviceNumber;
     PATA_REQ AtaReq;
+    UCHAR command;
+
     SetCheckPoint(5);
     //ULONG __ebp__ = 0;
 
@@ -7510,21 +7661,61 @@ default_no_prep:
 
         break;
 
+    case SCSIOP_REPORT_LUNS: {
+
+        ULONG alen;
+        PREPORT_LUNS_INFO_HDR LunInfo;
+        
+        KdPrint2((PRINT_PREFIX 
+                   "IdeSendCommand: SCSIOP_REPORT_LUNS PATH:LUN:TID = %#x:%#x:%#x\n",
+                   Srb->PathId, Srb->Lun, Srb->TargetId));
+
+        MOV_DD_SWP(alen, cdb->REPORT_LUNS.AllocationLength);
+
+        if(alen < 16) {
+            goto invalid_cdb;
+        }
+        alen = 8;
+
+        LunInfo = (PREPORT_LUNS_INFO_HDR)(Srb->DataBuffer);
+        RtlZeroMemory(LunInfo, 16);
+
+        MOV_DD_SWP( LunInfo->ListLength, alen );
+        Srb->DataTransferLength = 16;
+        status = SRB_STATUS_SUCCESS;
+
+        break; }
+
     case SCSIOP_MODE_SENSE:
 
         KdPrint2((PRINT_PREFIX 
                    "IdeSendCommand: SCSIOP_MODE_SENSE PATH:LUN:TID = %#x:%#x:%#x\n",
                    Srb->PathId, Srb->Lun, Srb->TargetId));
-        // This is used to determine if the media is write-protected.
-        // Since IDE does not support mode sense then we will modify just the portion we need
-        // so the higher level driver can determine if media is protected.
+        
+        if(cdb->MODE_SENSE.PageCode == MODE_PAGE_POWER_CONDITION) {
+            PMODE_POWER_CONDITION_PAGE modeData;
+
+            KdPrint2((PRINT_PREFIX "MODE_PAGE_POWER_CONDITION\n"));
+            modeData = (PMODE_POWER_CONDITION_PAGE)(Srb->DataBuffer);
+            if(cdb->MODE_SENSE.AllocationLength < sizeof(MODE_POWER_CONDITION_PAGE)) {
+                status = SRB_STATUS_DATA_OVERRUN;
+            } else {
+                RtlZeroMemory(modeData, sizeof(MODE_POWER_CONDITION_PAGE));
+                modeData->PageCode = MODE_PAGE_POWER_CONDITION;
+                modeData->PageLength = sizeof(MODE_PAGE_POWER_CONDITION)-sizeof(MODE_PARAMETER_HEADER);
+                modeData->Byte3.Fields.Idle = LunExt->PowerState <= StartStop_Power_Idle;
+                modeData->Byte3.Fields.Standby = LunExt->PowerState == StartStop_Power_Standby;
+                Srb->DataTransferLength = sizeof(MODE_POWER_CONDITION_PAGE);
+                status = SRB_STATUS_SUCCESS;
+            }
+        } else
         if(cdb->MODE_SENSE.PageCode == MODE_PAGE_CACHING) {
             PMODE_CACHING_PAGE modeData;
 
             KdPrint2((PRINT_PREFIX "MODE_PAGE_CACHING\n"));
-            modeData = (PMODE_CACHING_PAGE)Srb->DataBuffer;
+            modeData = (PMODE_CACHING_PAGE)(Srb->DataBuffer);
             if(cdb->MODE_SENSE.AllocationLength < sizeof(MODE_CACHING_PAGE)) {
-                status = STATUS_BUFFER_TOO_SMALL;
+                status = SRB_STATUS_DATA_OVERRUN;
             } else {
                 RtlZeroMemory(modeData, sizeof(MODE_CACHING_PAGE));
                 modeData->PageCode = MODE_PAGE_CACHING;
@@ -7537,6 +7728,10 @@ default_no_prep:
         } else
         if (LunExt->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
 
+            // This is used to determine if the media is write-protected.
+            // Since IDE does not support mode sense then we will modify just the portion we need
+            // so the higher level driver can determine if media is protected.
+
             //SelectDrive(chan, DeviceNumber);
             //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_GET_MEDIA_STATUS);
             //statusByte = WaitOnBusy(chan);
@@ -7726,21 +7921,98 @@ default_no_prep:
     case SCSIOP_START_STOP_UNIT:
 
         KdPrint2((PRINT_PREFIX 
-                   "IdeSendCommand: SCSIOP_START_STOP_UNIT PATH:LUN:TID = %#x:%#x:%#x\n",
-                   Srb->PathId, Srb->Lun, Srb->TargetId));
+                   "IdeSendCommand: SCSIOP_START_STOP_UNIT immed %d PATH:LUN:TID = %#x:%#x:%#x\n",
+                   cdb->START_STOP.Immediate, Srb->PathId, Srb->Lun, Srb->TargetId));
         //Determine what type of operation we should perform
-        cdb = (PCDB)Srb->Cdb;
 
-        if (cdb->START_STOP.LoadEject == 1){
+        command = 0;
 
-            statusByte = WaitOnBaseBusy(chan);
+        if(cdb->START_STOP.FL ||
+           cdb->START_STOP.FormatLayerNumber ||
+           cdb->START_STOP.Reserved2 ||
+           cdb->START_STOP.Reserved2_2 ||
+           cdb->START_STOP.Reserved3 ||
+           FALSE) {
+            goto invalid_cdb;
+        }
+
+        if (cdb->START_STOP.PowerConditions) {
+            KdPrint2((PRINT_PREFIX "START_STOP Power %d\n", cdb->START_STOP.PowerConditions));
+            switch(cdb->START_STOP.PowerConditions) {
+            case StartStop_Power_Idle:
+                command = IDE_COMMAND_IDLE_IMMED;
+                break;
+            case StartStop_Power_Standby:
+                command = IDE_COMMAND_STANDBY_IMMED;
+                break;
+            case StartStop_Power_Sleep:
+                // TODO: we should save power state in order to know
+                // that RESET sould be issued to revert device into
+                // operable state
+
+                command = IDE_COMMAND_SLEEP;
+                break;
+            default:
+                goto invalid_cdb;
+            }
+            LunExt->PowerState = cdb->START_STOP.PowerConditions;
+        } else
+        if (cdb->START_STOP.LoadEject == 1) {
+            KdPrint2((PRINT_PREFIX "START_STOP eject\n"));
             // Eject media,
             // first select device 0 or 1.
             //SelectDrive(chan, DeviceNumber);
             //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_MEDIA_EJECT);
-            statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_MEDIA_EJECT, 0, 0, 0, 0, 0, ATA_IMMEDIATE);
+            command = IDE_COMMAND_MEDIA_EJECT;
+        } else
+        if (cdb->START_STOP.Start == 0) {
+            KdPrint2((PRINT_PREFIX "START_STOP standby\n"));
+            command = IDE_COMMAND_STANDBY_IMMED;
+        } else {
+            // TODO: we may need to perform hard reset (after sleep) or
+            // issue IDE_COMMAND_IDLE_IMMED in order to activate device
+            KdPrint2((PRINT_PREFIX "START_STOP activate\n"));
+
+            if(LunExt->PowerState == StartStop_Power_Sleep) {
+                UniataUserDeviceReset(deviceExtension, LunExt, lChannel);
+                status = SRB_STATUS_SUCCESS;
+                break;
+            } else
+            if(LunExt->PowerState > StartStop_Power_Idle) {
+                KdPrint2((PRINT_PREFIX "  issue IDLE\n"));
+                command = IDE_COMMAND_IDLE_IMMED;
+            } else {
+                KdPrint2((PRINT_PREFIX "  do nothing\n"));
+                status = SRB_STATUS_SUCCESS;
+                break;
+            }
+        }
+        if(command) {
+            statusByte = WaitOnBaseBusy(chan);
+            statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, command, 0, 0, 0, 0, 0, 
+                cdb->START_STOP.Immediate ? ATA_IMMEDIATE : ATA_WAIT_READY);
+            status = (statusByte & IDE_STATUS_ERROR) ? SRB_STATUS_ERROR : SRB_STATUS_SUCCESS;
+            //UniataExpectChannelInterrupt(chan, TRUE); // device may interrupt
+
+        } else {
+invalid_cdb:
+            KdPrint2((PRINT_PREFIX "START_STOP invalid\n"));
+            if (Srb->SenseInfoBuffer) {
+
+                PSENSE_DATA  senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
+
+                senseBuffer->ErrorCode = 0x70;
+                senseBuffer->Valid     = 1;
+                senseBuffer->AdditionalSenseLength = 0xb;
+                senseBuffer->SenseKey = SCSI_SENSE_ILLEGAL_REQUEST;
+                senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_INVALID_CDB;
+                senseBuffer->AdditionalSenseCodeQualifier = 0;
+
+                Srb->SrbStatus = SRB_STATUS_AUTOSENSE_VALID;
+                Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
+            }
+            status = SRB_STATUS_ERROR;
         }
-        status = SRB_STATUS_SUCCESS;
         break;
 
     case SCSIOP_MEDIUM_REMOVAL:
@@ -7802,25 +8074,59 @@ default_no_prep:
         
         regs = (PIDEREGS_EX) &(Srb->Cdb[2]);
 
-        lChannel = Srb->TargetId >> 1;
-
-        regs->bDriveHeadReg &= 0x0f;
-        regs->bDriveHeadReg |= (UCHAR) (((Srb->TargetId & 0x1) << 4) | 0xA0);
+        if(chan->DeviceExtension->HwFlags & UNIATA_SATA) {
+            //lChannel = Srb->TargetId >> 1;
+        } else {
+            DeviceNumber = max(DeviceNumber, 1);
+            regs->bDriveHeadReg &= 0x0f;
+            regs->bDriveHeadReg |= (UCHAR) (((DeviceNumber & 0x1) << 4) | 0xA0);
+        }
 
         if((regs->bOpFlags & 1) == 0) {      // execute ATA command
 
             KdPrint2((PRINT_PREFIX 
-                       "IdeSendCommand: SCSIOP_START_STOP_UNIT PATH:LUN:TID = %#x:%#x:%#x\n",
+                       "IdeSendCommand: SCSIOP_ATA_PASSTHROUGH (exec) PATH:LUN:TID = %#x:%#x:%#x\n",
                        Srb->PathId, Srb->Lun, Srb->TargetId));
 
+            if((regs->bOpFlags & UNIATA_SPTI_EX_SPEC_TO) == UNIATA_SPTI_EX_SPEC_TO) {
+                to_lim = Srb->TimeOutValue;
+            } else {
+                if(Srb->TimeOutValue <= 2) {
+                    to_lim = Srb->TimeOutValue*900;
+                } else {
+                    to_lim = (Srb->TimeOutValue*999) - 500;
+                }
+            }
 
             AtapiDisableInterrupts(deviceExtension, lChannel);
 
+            if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
+                // AHCI
+                statusByte = UniataAhciSendPIOCommandDirect(
+                        deviceExtension,
+                        lChannel,
+                        DeviceNumber,
+                        Srb,
+                        regs,
+                        ATA_WAIT_INTR,
+                        to_lim
+                        );
+                if(statusByte == IDE_STATUS_WRONG) {
+                    goto passthrough_err;
+                }
+                if(statusByte & (IDE_STATUS_BUSY | IDE_STATUS_ERROR)) {
+                    UniataAhciAbortOperation(chan);
+                    goto passthrough_err;
+                }
+                goto passthrough_done;
+            }
+
+            // SATA/PATA
             if((AtaCommandFlags[regs->bCommandReg] & ATA_CMD_FLAG_DMA) || (regs->bOpFlags & UNIATA_SPTI_EX_USE_DMA)) {
-                if((chan->lun[Srb->TargetId & 0x1]->LimitedTransferMode >= ATA_DMA)) {
+                if((chan->lun[DeviceNumber]->LimitedTransferMode >= ATA_DMA)) {
                     use_dma = TRUE;
                     // this will set REQ_FLAG_DMA_OPERATION in AtaReq->Flags on success
-                    if(!AtapiDmaSetup(HwDeviceExtension, Srb->TargetId & 0x1, lChannel, Srb,
+                    if(!AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb,
                                   (PUCHAR)(Srb->DataBuffer),
                                   ((Srb->DataTransferLength + DEV_BSIZE-1) & ~(DEV_BSIZE-1)))) {
                         use_dma = FALSE;
@@ -7828,7 +8134,7 @@ default_no_prep:
                 }
             }
 
-            AtapiWritePort1(chan, IDX_IO1_o_DriveSelect,  regs->bDriveHeadReg);
+            AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, regs->bDriveHeadReg);
             AtapiStallExecution(10);
 
             if((regs->bOpFlags & ATA_FLAGS_48BIT_COMMAND) == 0) {      // execute ATA command
@@ -7856,20 +8162,11 @@ default_no_prep:
                 if(statusByte & IDE_STATUS_ERROR) {
                     goto passthrough_err;
                 }
-                AtapiDmaStart(HwDeviceExtension, (Srb->TargetId & 0x1), lChannel, Srb);
+                AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
             }
 
             ScsiPortStallExecution(1);                  // wait for busy to be set
 
-            if(regs->bOpFlags & UNIATA_SPTI_EX_SPEC_TO) {
-                to_lim = Srb->TimeOutValue;
-            } else {
-                if(Srb->TimeOutValue <= 2) {
-                    to_lim = Srb->TimeOutValue*900;
-                } else {
-                    to_lim = (Srb->TimeOutValue*999) - 500;
-                }
-            }
             for(i=0; i<to_lim;i+=2) {      // 2 msec from WaitOnBaseBusy()
                 statusByte = WaitOnBaseBusy(chan);      // wait for busy to be clear, up to 2 msec
                 GetBaseStatus(chan, statusByte);
@@ -7890,7 +8187,7 @@ default_no_prep:
             if(use_dma) {
                 AtapiCheckInterrupt__(deviceExtension, (UCHAR)lChannel);
             }
-            AtapiDmaDone(deviceExtension, (Srb->TargetId & 0x1), lChannel, NULL);
+            AtapiDmaDone(deviceExtension, DeviceNumber, lChannel, NULL);
             GetBaseStatus(chan, statusByte);
 
             if(statusByte & (IDE_STATUS_BUSY | IDE_STATUS_ERROR)) {
@@ -7930,34 +8227,33 @@ passthrough_err:
                 }
                 status = SRB_STATUS_SUCCESS;
             }
-
+passthrough_done:;
             AtapiEnableInterrupts(deviceExtension, lChannel);
 
         } else { // read task register
 
+            BOOLEAN use48;
             regs = (PIDEREGS_EX) Srb->DataBuffer;
 
-            regs->bDriveHeadReg    = AtapiReadPort1(chan, IDX_IO1_i_DriveSelect);
+            KdPrint2((PRINT_PREFIX 
+                       "IdeSendCommand: SCSIOP_ATA_PASSTHROUGH (snap) PATH:LUN:TID = %#x:%#x:%#x\n",
+                       Srb->PathId, Srb->Lun, Srb->TargetId));
 
-            if((regs->bOpFlags & ATA_FLAGS_48BIT_COMMAND) == 0) {      // execute ATA command
-                regs->bFeaturesReg     = AtapiReadPort1(chan, IDX_IO1_i_Error);
-                regs->bSectorCountReg  = AtapiReadPort1(chan, IDX_IO1_i_BlockCount);
-                regs->bSectorNumberReg = AtapiReadPort1(chan, IDX_IO1_i_BlockNumber);
-                regs->bCylLowReg       = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
-                regs->bCylHighReg      = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
+            if((Srb->DataTransferLength >= sizeof(IDEREGS_EX)) &&
+               (regs->bOpFlags & ATA_FLAGS_48BIT_COMMAND)) {
+                use48 = TRUE;
+            } else
+            if(Srb->DataTransferLength >= sizeof(IDEREGS)) {
+                use48 = FALSE;
             } else {
-                regs->bFeaturesReg     = AtapiReadPort1(chan, IDX_IO1_i_Error);
-                regs->bFeaturesRegH    = AtapiReadPort1(chan, IDX_IO1_i_Error);
-                regs->bSectorCountReg  = AtapiReadPort1(chan, IDX_IO1_i_BlockCount);
-                regs->bSectorCountRegH = AtapiReadPort1(chan, IDX_IO1_i_BlockCount);
-                regs->bSectorNumberReg = AtapiReadPort1(chan, IDX_IO1_i_BlockNumber);
-                regs->bSectorNumberRegH= AtapiReadPort1(chan, IDX_IO1_i_BlockNumber);
-                regs->bCylLowReg       = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
-                regs->bCylLowRegH      = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
-                regs->bCylHighReg      = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
-                regs->bCylHighRegH     = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
+                KdPrint2((PRINT_PREFIX " buffer too small \n"));
+                status = SRB_STATUS_DATA_OVERRUN;
+                break;
             }
-            regs->bCommandReg      = AtapiReadPort1(chan, IDX_IO1_i_Status);
+            RtlZeroMemory(regs, use48 ? sizeof(IDEREGS_EX) : sizeof(IDEREGS));
+            regs->bOpFlags = use48 ? ATA_FLAGS_48BIT_COMMAND : 0;
+            UniataSnapAtaRegs(chan, 0, regs);
+
             status = SRB_STATUS_SUCCESS;
         }
         break;
@@ -8132,23 +8428,24 @@ NTAPI
 UniataUserDeviceReset(
     PHW_DEVICE_EXTENSION deviceExtension,
     PHW_LU_EXTENSION LunExt,
-    ULONG PathId
+    ULONG lChannel
     )
 {
     ULONG i;
-    AtapiDisableInterrupts(deviceExtension, PathId);
-    if (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
+    AtapiDisableInterrupts(deviceExtension, lChannel);
+    if ((LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) &&
+        (LunExt->PowerState != StartStop_Power_Sleep)) {
         KdPrint2((PRINT_PREFIX "UniataUserDeviceReset: Reset ATAPI\n"));
-        AtapiSoftReset(&(deviceExtension->chan[PathId]), LunExt->Lun);
+        AtapiSoftReset(&(deviceExtension->chan[lChannel]), LunExt->Lun);
     } else {
         KdPrint2((PRINT_PREFIX "UniataUserDeviceReset: Reset IDE -> reset entire channel\n"));
-        AtapiResetController__(deviceExtension, PathId, RESET_COMPLETE_NONE);
+        AtapiResetController__(deviceExtension, lChannel, RESET_COMPLETE_NONE);
         for(i=0; i<deviceExtension->NumberLuns; i++) {
-            deviceExtension->chan[PathId].lun[i]->DeviceFlags |= DFLAGS_REINIT_DMA;
+            deviceExtension->chan[lChannel].lun[i]->DeviceFlags |= DFLAGS_REINIT_DMA;
         }
     }
     LunExt->DeviceFlags |= DFLAGS_REINIT_DMA;  // force PIO/DMA reinit
-    AtapiEnableInterrupts(deviceExtension, PathId);
+    AtapiEnableInterrupts(deviceExtension, lChannel);
     return;
 } // end UniataUserDeviceReset()
 
@@ -8194,6 +8491,7 @@ Routine Description:
 
     This routine is called from the SCSI port driver synchronized
     with the kernel to start an IO request.
+    ->HwStartIo
 
 Arguments:
 
@@ -8257,13 +8555,14 @@ AtapiStartIo__(
         UniAtaClearAtaReq(Srb->SrbExtension);
     }
 
-    do {
+    do { // fetch all queued commands for the channel (if valid)
 
         lChannel = GET_CHANNEL(Srb);
         //ldev = GET_LDEV(Srb);
         chan = NULL;
         LunExt = NULL;
         DeviceNumber = GET_CDEV(Srb);
+        commPort = FALSE;
 
         //ASSERT(deviceExtension);
         //ASSERT(chan);
@@ -8283,6 +8582,14 @@ AtapiStartIo__(
                        "AtapiStartIo: Communication port\n"));
             if(Srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
 
+                if(Srb->DataTransferLength < sizeof(PINQUIRYDATA)) {
+                    KdPrint2((PRINT_PREFIX "AtapiStartIo: Buffer too small: %#x < %#x\n", Srb->DataTransferLength,
+                        sizeof(PINQUIRYDATA) ));
+wrong_buffer_size:
+                    status = SRB_STATUS_DATA_OVERRUN;
+                    goto complete_req;
+                }
+
                 PINQUIRYDATA    inquiryData  = (PINQUIRYDATA)(Srb->DataBuffer);
 
                 KdPrint2((PRINT_PREFIX 
@@ -8302,22 +8609,26 @@ AtapiStartIo__(
             /* Pass IOCTL request down */
         } else
         if(lChannel >= deviceExtension->NumberChannels ||
-           Srb->TargetId /*DeviceNumber*/ >= deviceExtension->NumberLuns ||
-           Srb->Lun) {
+            Srb->TargetId /*DeviceNumber*/ >= deviceExtension->NumberLuns ||
+            Srb->Lun) {
 
-           if(lChannel >= deviceExtension->NumberChannels) {
-               chan = NULL;
-           }
+            if(lChannel >= deviceExtension->NumberChannels) {
+                chan = NULL;
+            }
 
 reject_srb:
             //if(!CheckDevice(HwDeviceExtension, lChannel, DeviceNumber, FALSE)) {
-                KdPrint3((PRINT_PREFIX 
+            KdPrint3((PRINT_PREFIX 
                            "AtapiStartIo: SRB rejected\n"));
-                // Indicate no device found at this address.
-                KdPrint2((PRINT_PREFIX "SRB_STATUS_SELECTION_TIMEOUT\n"));
-                status = SRB_STATUS_SELECTION_TIMEOUT;
-                goto complete_req;
+            // Indicate no device found at this address.
+            KdPrint2((PRINT_PREFIX "SRB_STATUS_SELECTION_TIMEOUT\n"));
+            status = SRB_STATUS_SELECTION_TIMEOUT;
+            goto complete_req;
             //}
+        } else
+        if((deviceExtension->HwFlags & UNIATA_AHCI) &&
+           !UniataAhciChanImplemented(deviceExtension, lChannel)) {
+            chan = NULL;
         }
 
         if(!commPort) {
@@ -8426,6 +8737,7 @@ reject_srb:
                 KdPrint2((PRINT_PREFIX "AtapiStartIo: Already have %d request(s)!\n", chan->queue_depth));
 
             } else {
+
                 // Send command to device.
                 KdPrint2((PRINT_PREFIX "Send to device %x\n", Srb->Cdb[0]));
                 if(TopLevel) {
@@ -8465,7 +8777,8 @@ reject_srb:
 #endif //NAVO_TEST
 
                 if(atapiDev &&
-                   (Srb->Cdb[0] != SCSIOP_ATA_PASSTHROUGH)) {
+                   (Srb->Cdb[0] != SCSIOP_ATA_PASSTHROUGH)/* &&
+                   (Srb->Cdb[0] != SCSIOP_REPORT_LUNS)*/) {
                     KdPrint3((PRINT_PREFIX "Try ATAPI send %x\n", Srb->Cdb[0]));
                     status = AtapiSendCommand(HwDeviceExtension, Srb, CMD_ACTION_ALL);
                 } else {
@@ -8660,44 +8973,122 @@ do_bus_reset:
 
             if(!AtapiStringCmp( (PCHAR)(((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature),"SCSIDISK",sizeof("SCSIDISK")-1)) {
 
+                ULONG targetId = (ULONG)(-1);
+
+                if(len < sizeof(SRB_IO_CONTROL)) {
+                    goto wrong_buffer_size;
+                }
+
+                // extract bogus bus address
                 switch (((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode) {
                 case IOCTL_SCSI_MINIPORT_SMART_VERSION: {
-
                     PGETVERSIONINPARAMS versionParameters = (PGETVERSIONINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
-                    UCHAR deviceNumber;
 
-                    KdPrint2((PRINT_PREFIX "AtapiStartIo: IOCTL_SCSI_MINIPORT_SMART_VERSION\n"));
+                    if(len < sizeof(SRB_IO_CONTROL)+sizeof(GETVERSIONINPARAMS)) {
+                        goto wrong_buffer_size;
+                    }
 
-                    // Version and revision per SMART 1.03
+                    targetId = versionParameters->bIDEDeviceMap;
+                    KdPrint2((PRINT_PREFIX "targetId (smart ver) %d\n", targetId));
+                    break; }
+                case IOCTL_SCSI_MINIPORT_IDENTIFY:
+                case IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS:
+                case IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS:
+                case IOCTL_SCSI_MINIPORT_ENABLE_SMART:
+                case IOCTL_SCSI_MINIPORT_DISABLE_SMART:
+                case IOCTL_SCSI_MINIPORT_RETURN_STATUS:
+                case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE:
+                case IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES:
+                case IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS:
+                case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE:
+                case IOCTL_SCSI_MINIPORT_READ_SMART_LOG:
+                case IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG:
+                    {
+                    PSENDCMDINPARAMS   cmdInParameters = (PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
+
+                    if(len < sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDINPARAMS) - 1) {
+                        goto wrong_buffer_size;
+                    }
 
-                    versionParameters->bVersion = 1;
-                    versionParameters->bRevision = 1;
-                    versionParameters->bReserved = 0;
+                    targetId = cmdInParameters->bDriveNumber;
+                    KdPrint2((PRINT_PREFIX "targetId (smart/ident) %d\n", targetId));
+                    break; }
+                default:
+invalid_request:
+                    KdPrint2((PRINT_PREFIX "AtapiStartIo: invalid IoControl %#x for SCSIDISK signature\n",
+                                ((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode ));
+                    status = SRB_STATUS_INVALID_REQUEST;
+                    goto complete_req;
+                } // end switch()
 
-                    // Indicate that support for IDE IDENTIFY, ATAPI IDENTIFY and SMART commands.
-                    versionParameters->fCapabilities = (CAP_ATA_ID_CMD | CAP_ATAPI_ID_CMD | CAP_SMART_CMD);
+                // adjust (if necessary) bus address
+                if(targetId != (ULONG)(-1)) {
 
                     // This is done because of how the IOCTL_SCSI_MINIPORT
                     // determines 'targetid's'. Disk.sys places the real target id value
                     // in the DeviceMap field. Once we do some parameter checking, the value passed
                     // back to the application will be determined.
 
-                    deviceNumber = versionParameters->bIDEDeviceMap;
-
+                    if (deviceExtension->NumberChannels == 1) {
+                        // do this for legacy controllers and legacy callers
+                        KdPrint2((PRINT_PREFIX "AtapiStartIo: legacy call\n"));
+                        DeviceNumber = (targetId & 0x01);
+                        lChannel = 0;
+                    } else
                     if(commPort) {
+                        // do this for smartmontools, sending IOCTLs to PhysicalDrive%d
+                        // due to DISK.SYS design bug, we have invalid SCSI address in SRB
+                        KdPrint2((PRINT_PREFIX "AtapiStartIo: legacy call (2)\n"));
+                        if(deviceExtension->HwFlags & UNIATA_AHCI) {
+                            lChannel = (UCHAR)targetId / 2;
+                            DeviceNumber = 0;
+                        } else {
+                            lChannel = (UCHAR)(targetId / 2);
+                            DeviceNumber = targetId & 0x01;
+                        }
+                    } else {
+                        // otherwise assume lChannel and DeviceNumber from Srb are ok
+                    }
+                    if(lChannel >= deviceExtension->NumberChannels ||
+                        DeviceNumber >= deviceExtension->NumberLuns) {
                         KdPrint2((PRINT_PREFIX 
-                                   "AtapiStartIo: SCSIDISK IOCTL for commPort -> EXECUTE_SCSI rejected (2)\n"));
+                                   "AtapiStartIo: SCSIDISK IOCTL for non-exestent drive %d -> EXECUTE_SCSI rejected (2)\n",
+                                       targetId));
                         // Indicate no device found at this address.
-                        KdPrint2((PRINT_PREFIX "SRB_STATUS_SELECTION_TIMEOUT\n"));
-                        status = SRB_STATUS_SELECTION_TIMEOUT;
-                        break;
+                        goto reject_srb;
                     }
-                    
-                    if (!(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT) ||
-                        atapiDev) {
+                    targetId = lChannel*deviceExtension->NumberLuns+DeviceNumber;
+                    chan = &(deviceExtension->chan[lChannel]);
+                    LunExt = chan->lun[DeviceNumber];
+                    if(!LunExt) {
+                        goto reject_srb;
+                    }
+                    atapiDev = (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) ? TRUE : FALSE;
 
-                        status = SRB_STATUS_SELECTION_TIMEOUT;
-                        break;
+                    if (!(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
+                        goto reject_srb;
+                    }
+                }
+
+                switch (((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode) {
+                case IOCTL_SCSI_MINIPORT_SMART_VERSION: {
+
+                    PGETVERSIONINPARAMS versionParameters = (PGETVERSIONINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
+                    UCHAR deviceNumberMap;
+
+                    KdPrint2((PRINT_PREFIX "AtapiStartIo: IOCTL_SCSI_MINIPORT_SMART_VERSION\n"));
+
+                    // Version and revision per SMART 1.03
+
+                    versionParameters->bVersion = 1;
+                    versionParameters->bRevision = 1;
+                    versionParameters->bReserved = 0;
+
+                    // Indicate that support for IDE IDENTIFY, ATAPI IDENTIFY and SMART commands.
+                    versionParameters->fCapabilities = (CAP_ATA_ID_CMD | CAP_ATAPI_ID_CMD | CAP_SMART_CMD);
+
+                    if (atapiDev) {
+                        goto invalid_request;
                     }
 
                     // NOTE: This will only set the bit
@@ -8709,19 +9100,20 @@ do_bus_reset:
                     //     3 2 1 0
 
                     if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
-                        deviceNumber = 1 << lChannel;
+                        deviceNumberMap = 1 << lChannel;
+                        DeviceNumber = 0;
                     } else
                     if (deviceExtension->NumberChannels == 1) {
                         if (chan->PrimaryAddress) {
-                            deviceNumber = 1 << DeviceNumber;
+                            deviceNumberMap = 1 << DeviceNumber;
                         } else {
-                            deviceNumber = 4 << DeviceNumber;
+                            deviceNumberMap = 4 << DeviceNumber;
                         }
                     } else {
-                        deviceNumber = 1 << (DeviceNumber+lChannel*2);
+                        deviceNumberMap = 1 << (DeviceNumber+lChannel*2);
                     }
 
-                    versionParameters->bIDEDeviceMap = deviceNumber;
+                    versionParameters->bIDEDeviceMap = deviceNumberMap;
 
                     status = SRB_STATUS_SUCCESS;
                     break;
@@ -8731,41 +9123,24 @@ do_bus_reset:
 
                     PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
                     SENDCMDINPARAMS   cmdInParameters = *(PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
-                    UCHAR             targetId;
 
                     KdPrint2((PRINT_PREFIX "AtapiStartIo: IOCTL_SCSI_MINIPORT_IDENTIFY\n"));
                     // Extract the target.
-                    targetId = cmdInParameters.bDriveNumber;
                     KdPrint2((PRINT_PREFIX "targetId %d\n", targetId));
-                    if(deviceExtension->HwFlags & UNIATA_AHCI) {
-                        // cheat code for AHCI :)
-                        // upper layer assumes that we have 2 devices per channel
-                        // TODO: we should invent something to handle PM here
-                        targetId /= 2;
-                    }
-
-                    if((targetId >= deviceExtension->NumberChannels*deviceExtension->NumberLuns) ||
-                       !(deviceExtension->lun[targetId].DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
-                        KdPrint2((PRINT_PREFIX "Error: xxx_ID_CMD for non-existant device\n"));
-                        status = SRB_STATUS_SELECTION_TIMEOUT;
-                        break;
-                    }
 
                     switch(cmdInParameters.irDriveRegs.bCommandReg) {
                     case ID_CMD:
-                        if((deviceExtension->lun[targetId].DeviceFlags & DFLAGS_ATAPI_DEVICE)) {
+                        if(atapiDev) {
                             KdPrint2((PRINT_PREFIX "Error: ID_CMD for ATAPI\n"));
-                            status = SRB_STATUS_INVALID_REQUEST;
-                            break;
+                            goto invalid_request;
                         }
                         /* FALL THROUGH */
                     case ATAPI_ID_CMD:
 
-                        if(!(deviceExtension->lun[targetId].DeviceFlags & DFLAGS_ATAPI_DEVICE) &&
+                        if(!atapiDev &&
                            (cmdInParameters.irDriveRegs.bCommandReg == ATAPI_ID_CMD)) {
                             KdPrint2((PRINT_PREFIX "Error: ATAPI_ID_CMD for non-ATAPI\n"));
-                            status = SRB_STATUS_INVALID_REQUEST;
-                            break;
+                            goto invalid_request;
                         }
 
                         len = min(len, sizeof(SENDCMDOUTPARAMS) - 1 + IDENTIFY_BUFFER_SIZE);
@@ -8781,9 +9156,21 @@ do_bus_reset:
                         cmdOutParameters->DriverStatus.bIDEError = 0;
 
                         // Extract the identify data from the device extension.
-                        ScsiPortMoveMemory (cmdOutParameters->bBuffer, &deviceExtension->lun[targetId].IdentifyData,
+                        ScsiPortMoveMemory (cmdOutParameters->bBuffer, &(LunExt->IdentifyData),
                             cmdOutParameters->cBufferSize);
 
+                        if((cmdOutParameters->cBufferSize == IDENTIFY_BUFFER_SIZE) &&
+                           (LunExt->IdentifyData.ChecksumValid == ATA_ChecksumValid)) {
+                            // adjust checksum if it is possible
+                            CHAR csum = 0;
+                            ULONG i;
+
+                            for(i=0; i < IDENTIFY_BUFFER_SIZE-1; i++) {
+                                csum += (CHAR)(cmdOutParameters->bBuffer[i]);
+                            }
+                            cmdOutParameters->bBuffer[i] = -csum;
+                            KdPrint2((PRINT_PREFIX "AtapiStartIo: adjust checksum %d\n"));
+                        }
                         KdPrint2((PRINT_PREFIX "AtapiStartIo: IOCTL_SCSI_MINIPORT_IDENTIFY Ok\n"));
 
                         status = SRB_STATUS_SUCCESS;
@@ -8797,7 +9184,7 @@ do_bus_reset:
                     }
                     break;
                 }
-
+/*
                 case  IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS:
                 case  IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS:
                 case  IOCTL_SCSI_MINIPORT_ENABLE_SMART:
@@ -8806,14 +9193,15 @@ do_bus_reset:
                 case  IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE:
                 case  IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES:
                 case  IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS:
-
+*/
+                default:
+                    // *all* IOCTLs here are SMART
                     if(commPort) {
                         KdPrint2((PRINT_PREFIX 
                                    "AtapiStartIo: SCSIDISK Smart IOCTL for commPort -> EXECUTE_SCSI rejected (3)\n"));
-                        // Indicate no device found at this address.
-                        KdPrint2((PRINT_PREFIX "SRB_STATUS_SELECTION_TIMEOUT\n"));
-                        status = SRB_STATUS_SELECTION_TIMEOUT;
-                        break;
+                    }
+                    if (atapiDev) {
+                        goto invalid_request;
                     }
 
                     PostReq = UniataNeedQueueing(deviceExtension, chan, TopLevel);
@@ -8832,16 +9220,17 @@ do_bus_reset:
                         KdPrint2((PRINT_PREFIX "AtapiStartIo: Already have %d request(s)!\n", chan->queue_depth));
                     } else {
 
-                        status = IdeSendSmartCommand(HwDeviceExtension,Srb);
+                        status = IdeSendSmartCommand(HwDeviceExtension, Srb, targetId);
                     }
                     break;
 
-                default :
+                // we should not get here, checked above
+/*                default :
                     KdPrint2((PRINT_PREFIX "AtapiStartIo: invalid IoControl %#x for SCSIDISK signature\n",
                                 ((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode ));
                     status = SRB_STATUS_INVALID_REQUEST;
                     break;
-
+*/
                 }
             } else
             if(!AtapiStringCmp( (PCHAR)(((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature),"-UNIATA-", sizeof("-UNIATA-")-1)) {
@@ -8857,8 +9246,7 @@ do_bus_reset:
                 if(len < pos) {
                     KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
                         FIELD_OFFSET(UNIATA_CTL, RawData) ));
-                    status = SRB_STATUS_DATA_OVERRUN;
-                    break;
+                    goto wrong_buffer_size;
                 }
 
                 if(AtaCtl->addr.Lun ||
@@ -8927,8 +9315,7 @@ handle_bad_ldev:
                     if(len < pos+sizeof(AtaCtl->SetMode)) {
                         KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
                             pos+sizeof(AtaCtl->SetMode) ));
-                        status = SRB_STATUS_DATA_OVERRUN;
-                        goto complete_req;
+                        goto wrong_buffer_size;
                     }
                     if(!AtaCtl->SetMode.ApplyImmediately) {
                         break;
@@ -8963,8 +9350,7 @@ uata_ctl_queue:
                     if(len < pos+sizeof(AtaCtl->FindDelDev)) {
                         KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
                             pos+sizeof(AtaCtl->FindDelDev) ));
-                        status = SRB_STATUS_DATA_OVERRUN;
-                        goto complete_req;
+                        goto wrong_buffer_size;
                     }
                     if(AtaCtl->FindDelDev.Flags & UNIATA_ADD_FLAGS_UNHIDE) {
                         KdPrint2((PRINT_PREFIX "AtapiStartIo: unhide from further detection\n"));
@@ -8993,8 +9379,7 @@ uata_ctl_queue:
                     if(len < pos+sizeof(AtaCtl->FindDelDev)) {
                         KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
                             pos+sizeof(AtaCtl->FindDelDev) ));
-                        status = SRB_STATUS_DATA_OVERRUN;
-                        goto complete_req;
+                        goto wrong_buffer_size;
                     }
                     LunExt->DeviceFlags = 0;
                     if(AtaCtl->FindDelDev.Flags & UNIATA_REMOVE_FLAGS_HIDE) {
@@ -9017,8 +9402,7 @@ uata_ctl_queue:
                     if(len < pos+sizeof(AtaCtl->SetMode)) {
                         KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
                             pos+sizeof(AtaCtl->SetMode) ));
-                        status = SRB_STATUS_DATA_OVERRUN;
-                        goto complete_req;
+                        goto wrong_buffer_size;
                     }
                     if(AtaCtl->SetMode.OrigMode != IOMODE_NOT_SPECIFIED) {
                         LunExt->OrigTransferMode = (UCHAR)(AtaCtl->SetMode.OrigMode);
@@ -9050,8 +9434,7 @@ uata_ctl_queue:
                     if(len < pos+sizeof(AtaCtl->GetMode)) {
                         KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
                             pos+sizeof(AtaCtl->GetMode) ));
-                        status = SRB_STATUS_DATA_OVERRUN;
-                        goto complete_req;
+                        goto wrong_buffer_size;
                     }
                     AtaCtl->GetMode.OrigMode    = LunExt->OrigTransferMode;
                     AtaCtl->GetMode.MaxMode     = LunExt->LimitedTransferMode;
@@ -9068,8 +9451,7 @@ uata_ctl_queue:
                     if(len < pos+sizeof(AtaCtl->Version)) {
                         KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
                             pos+sizeof(AtaCtl->Version) ));
-                        status = SRB_STATUS_DATA_OVERRUN;
-                        goto complete_req;
+                        goto wrong_buffer_size;
                     }
                     AtaCtl->Version.Length      = sizeof(GETDRVVERSION);
                     AtaCtl->Version.VersionMj   = UNIATA_VER_MJ;
@@ -9087,8 +9469,7 @@ uata_ctl_queue:
                     if(len < pos+sizeof(AtaCtl->AdapterInfo)) {
                         KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
                             pos+sizeof(AtaCtl->AdapterInfo) ));
-                        status = SRB_STATUS_DATA_OVERRUN;
-                        goto complete_req;
+                        goto wrong_buffer_size;
                     }
                     AtaCtl->AdapterInfo.HeaderLength = sizeof(ADAPTERINFO);
 
@@ -9216,8 +9597,10 @@ complete_req:
             // Set status in SRB.
             Srb->SrbStatus = (UCHAR)status;
 
-            KdPrint2((PRINT_PREFIX "AtapiStartIo: AtapiDmaDBSync(%x, %x)\n", chan, Srb));
-            AtapiDmaDBSync(chan, Srb);
+            if(chan && Srb) {
+                KdPrint2((PRINT_PREFIX "AtapiStartIo: AtapiDmaDBSync(%x, %x)\n", chan, Srb));
+                AtapiDmaDBSync(chan, Srb);
+            }
             KdPrint2((PRINT_PREFIX "AtapiStartIo: UniataRemoveRequest(%x, %x)\n", chan, Srb));
             UniataRemoveRequest(chan, Srb);
             // Indicate command complete.
@@ -9652,6 +10035,15 @@ DriverEntry(
         if(GlobalConfig->AtDiskSecondaryAddressClaimed)
             SecondaryClaimed = TRUE;
 
+        if(!WinVer_WDM_Model && !PrimaryClaimed && !SecondaryClaimed &&
+            !(BMList[i].ChanInitOk & 0x80)) {
+            newStatus = UniataClaimLegacyPCIIDE(i);
+            if(newStatus != STATUS_SUCCESS) {
+                KdPrint2((PRINT_PREFIX "Can't acquire PCI part of BusMaster, try as pure ISA later.\n"));
+                break;
+            }
+        }
+
         if(g_opt_Verbose) {
             _PrintNtConsole("Init standard Dual-channel PCI ATA controller:");
         }
@@ -9710,7 +10102,15 @@ DriverEntry(
                     statusToReturn = newStatus;
                 }
                 if (newStatus == STATUS_SUCCESS) {
-                    BMList[i].ChanInitOk |= 0x01 << c;
+                    if(WinVer_Id() < WinVer_2k) {
+                        // This should be done in HwInitialize under w2k+ to ensure that 
+                        // channel is actually initialized
+                        BMList[i].ChanInitOk |= 0x01 << c;
+                    } else {
+                        if(BMList[i].ChanInitOk & (0x01 << c)) {
+                            KdPrint2((PRINT_PREFIX "HwInit passed\n"));
+                        }
+                    }
 /*
                     if(BMList[i].MasterDev && (WinVer_Id() > WinVer_NT)) {
                         c = 1; // this will break our for()
@@ -9719,43 +10119,28 @@ DriverEntry(
 */
                 }
             }
-            if(WinVer_Id() >= WinVer_2k) {
-                // the following doesn't work under higher OSes
+/*            if(WinVer_Id() >= WinVer_2k) {
+                // the following didn't work under higher OSes,
+                // until we move setting of FLAGS to HwInit
                 KdPrint2((PRINT_PREFIX "make still one attempt\n"));
                 continue;
-            }
+            }*/
             if(BMList[i].ChanInitOk & 0x03) {
-                // under NT we receive status immediately, so
-                // we can omit alternative init method id STATUS_SUCCESS returned
+                // Under NT we receive status immediately, so
+                // we can omit alternative init method if STATUS_SUCCESS returned.
+                // Under w2k+ we relay on flags, set in HwInitialize.
                 KdPrint2((PRINT_PREFIX "Ok, no more retries required\n"));
                 break;
+            } else
+            if(WinVer_Id() >= WinVer_2k) {
+                // try AltInit if HwInit was not called immediately under w2k+
+                KdPrint2((PRINT_PREFIX "make still one attempt w2k+\n"));
+            } else {
+                // if (WinVer_Id() == WinVer_NT) and some error occured
+                // try alternative init method
+                KdPrint2((PRINT_PREFIX "make still one attempt w2k+\n"));
             }
-            // if (WinVer_Id() == WinVer_NT) and some error occured
-            // try alternative init method
         } // for(alt...)
-#if 0
-        if(WinVer_WDM_Model) {
-            hwInitializationData.comm.HwFindAdapter = UniataFindFakeBusMasterController;
-            hwInitializationData.comm.NumberOfAccessRanges = 5;
-            hwInitializationData.comm.AdapterInterfaceType = PCIBus;
-
-            hwInitializationData.comm.VendorId             = BMList[i].VendorId;
-            hwInitializationData.comm.VendorIdLength       = (USHORT) BMList[i].VendorIdLength;
-            hwInitializationData.comm.DeviceId             = BMList[i].DeviceId;
-            hwInitializationData.comm.DeviceIdLength       = (USHORT) BMList[i].DeviceIdLength;
-
-            //BMList[i].channel = 0/*(UCHAR)c*/;
-
-            KdPrint2((PRINT_PREFIX "Try init fake: %4.4s %4.4s \n",
-                                   hwInitializationData.comm.VendorId,
-                                   hwInitializationData.comm.DeviceId));
-            newStatus = ScsiPortInitialize(DriverObject,
-                                           Argument2,
-                                           &hwInitializationData.comm,
-                                           (PVOID)i);
-            KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x\n", newStatus));
-        }
-#endif //0
         if(g_opt_Verbose) {
             if(BMList[i].ChanInitOk & 0x03) {
                 _PrintNtConsole("  OK\n");
@@ -9793,9 +10178,9 @@ DriverEntry(
         hwInitializationData.comm.NumberOfAccessRanges = 6;
         hwInitializationData.comm.AdapterInterfaceType = PCIBus;
 
-        hwInitializationData.comm.VendorId             = BMList[i].VendorId;
+        hwInitializationData.comm.VendorId             = (PVOID)BMList[i].VendorId;
         hwInitializationData.comm.VendorIdLength       = (USHORT) BMList[i].VendorIdLength;
-        hwInitializationData.comm.DeviceId             = BMList[i].DeviceId;
+        hwInitializationData.comm.DeviceId             = (PVOID)BMList[i].DeviceId;
         hwInitializationData.comm.DeviceIdLength       = (USHORT) BMList[i].DeviceIdLength;
 
         BMList[i].channel = 0/*(UCHAR)c*/;
index 208f07d..f27e2d9 100644 (file)
@@ -944,19 +944,19 @@ AtapiDmaInit(
     }
 
     // Limit transfer mode (controller limitation)
-    if((LONG)deviceExtension->MaxTransferMode >= ATA_UDMA) {
-        KdPrint2((PRINT_PREFIX "AtapiDmaInit: deviceExtension->MaxTransferMode >= ATA_UDMA\n"));
-        udmamode = min( udmamode, (CHAR)(deviceExtension->MaxTransferMode - ATA_UDMA));
+    if((LONG)chan->MaxTransferMode >= ATA_UDMA) {
+        KdPrint2((PRINT_PREFIX "AtapiDmaInit: chan->MaxTransferMode >= ATA_UDMA\n"));
+        udmamode = min( udmamode, (CHAR)(chan->MaxTransferMode - ATA_UDMA));
     } else
-    if((LONG)deviceExtension->MaxTransferMode >= ATA_WDMA) {
-        KdPrint2((PRINT_PREFIX "AtapiDmaInit: deviceExtension->MaxTransferMode >= ATA_WDMA\n"));
+    if((LONG)chan->MaxTransferMode >= ATA_WDMA) {
+        KdPrint2((PRINT_PREFIX "AtapiDmaInit: chan->MaxTransferMode >= ATA_WDMA\n"));
         udmamode = -1;
-        wdmamode = min( wdmamode, (CHAR)(deviceExtension->MaxTransferMode - ATA_WDMA));
+        wdmamode = min( wdmamode, (CHAR)(chan->MaxTransferMode - ATA_WDMA));
     } else
-    if((LONG)deviceExtension->MaxTransferMode >= ATA_PIO0) {
+    if((LONG)chan->MaxTransferMode >= ATA_PIO0) {
         KdPrint2((PRINT_PREFIX "AtapiDmaInit: NO DMA\n"));
         wdmamode = udmamode = -1;
-        apiomode = min( apiomode, (CHAR)(deviceExtension->MaxTransferMode - ATA_PIO0));
+        apiomode = min( apiomode, (CHAR)(chan->MaxTransferMode - ATA_PIO0));
     } else {
         KdPrint2((PRINT_PREFIX "AtapiDmaInit: PIO0\n"));
         wdmamode = udmamode = -1;
@@ -1003,14 +1003,16 @@ AtapiDmaInit(
         }
     //}
 
-    if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
+    if(UniataIsSATARangeAvailable(deviceExtension, lChannel) ||
+        (ChipFlags & UNIATA_AHCI) || (chan->MaxTransferMode >= ATA_SA150)
+       ) {
     //if(ChipFlags & (UNIATA_SATA | UNIATA_AHCI)) {
         /****************/
         /* SATA Generic */
         /****************/
 
         KdPrint2((PRINT_PREFIX "SATA Generic\n"));
-        if((udmamode >= 5) || (ChipFlags & UNIATA_AHCI) || chan->MaxTransferMode >= ATA_SA150) {
+        if((udmamode >= 5) || (ChipFlags & UNIATA_AHCI) || (chan->MaxTransferMode >= ATA_SA150)) {
             /* some drives report UDMA6, some UDMA5 */
             /* ATAPI may not have SataCapabilities set in IDENTIFY DATA */
             if(ata_is_sata(&(LunExt->IdentifyData))) {
@@ -1024,7 +1026,7 @@ AtapiDmaInit(
 
             } else {
                 KdPrint2((PRINT_PREFIX "SATA -> PATA adapter ?\n"));
-                if (udmamode > 2 && (!LunExt->IdentifyData.HwResCableId || (LunExt->IdentifyData.HwResValid != IDENTIFY_CABLE_ID_VALID) )) {
+                if (udmamode > 2 && (!LunExt->IdentifyData.HwResCableId && (LunExt->IdentifyData.HwResValid == IDENTIFY_CABLE_ID_VALID) )) {
                     KdPrint2((PRINT_PREFIX "AtapiDmaInit: DMA limited to UDMA33, non-ATA66 compliant cable\n"));
                     udmamode = 2;
                     apiomode = min( apiomode, (CHAR)(LunExt->LimitedTransferMode - ATA_PIO0));
@@ -1054,7 +1056,7 @@ AtapiDmaInit(
         goto try_generic_dma;
     }
 
-    if(udmamode > 2 && (!LunExt->IdentifyData.HwResCableId || (LunExt->IdentifyData.HwResValid != IDENTIFY_CABLE_ID_VALID)) ) {
+    if(udmamode > 2 && (!LunExt->IdentifyData.HwResCableId && (LunExt->IdentifyData.HwResValid == IDENTIFY_CABLE_ID_VALID)) ) {
         if(ata_is_sata(&(LunExt->IdentifyData))) {
             KdPrint2((PRINT_PREFIX "AtapiDmaInit: SATA beyond adapter or Controller compat mode\n"));
         } else {
@@ -1384,6 +1386,7 @@ set_new_acard:
         UCHAR  new44  = 0;
         UCHAR  intel_timings[] = { 0x00, 0x00, 0x10, 0x21, 0x23, 0x10, 0x21, 0x23,
                                   0x23, 0x23, 0x23, 0x23, 0x23, 0x23 };
+        UCHAR  intel_utimings[] = { 0x00, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02 };
 
         if(deviceExtension->DevID == ATA_I82371FB) {
             if (wdmamode >= 2 && apiomode >= 4) {
@@ -1466,17 +1469,24 @@ set_new_acard:
         for(i=udmamode; i>=0; i--) {
             if(AtaSetTransferMode(deviceExtension, DeviceNumber, lChannel, LunExt, ATA_UDMA0 + i)) {
 
-               /* Set UDMA reference clock (33/66/133MHz). */
+               /* Set UDMA reference clock (33 MHz or more). */
                 SetPciConfig1(0x48, reg48 | (0x0001 << dev));
                 if(!(ChipFlags & ICH4_FIX)) {
-                    SetPciConfig2(0x4a, (reg4a & ~(0x3 << (dev<<2))) |
-                                        (0x01 + !(i & 0x01))  );
+                    if(deviceExtension->MaxTransferMode == ATA_UDMA3) {
+                        // Special case (undocumented overclock !) for PIIX4e
+                        SetPciConfig2(0x4a, (reg4a | (0x03 << (dev<<2)) ) );
+                    } else {
+                        SetPciConfig2(0x4a, (reg4a & ~(0x03 << (dev<<2))) |
+                                                      (((USHORT)(intel_utimings[i])) << (dev<<2) )  );
+                    }
                 }
-                if(i >= 2) {
+               /* Set UDMA reference clock (66 MHz or more). */
+                if(i > 2) {
                     reg54 |= (0x1 << dev);
                 } else {
                     reg54 &= ~(0x1 << dev);
                 }
+               /* Set UDMA reference clock (133 MHz). */
                 if(i >= 5) {
                     reg54 |= (0x1000 << dev);
                 } else {
index bc844ca..94ee5ab 100644 (file)
@@ -178,6 +178,7 @@ UniataChipDetectChannels(
             KdPrint2((PRINT_PREFIX "New ITE PATA 1 chan\n"));
         }
         break;
+#if 0
     case ATA_INTEL_ID:
         /* New Intel PATA controllers */
         if(g_opt_VirtualMachine != VM_VBOX &&
@@ -193,6 +194,7 @@ UniataChipDetectChannels(
             KdPrint2((PRINT_PREFIX "New Intel PATA 1 chan\n"));
         }
         break;
+#endif // this code is removed from newer FreeBSD
     case ATA_JMICRON_ID:
         /* New JMicron PATA controllers */
         if(deviceExtension->DevID == ATA_JMB361 ||
@@ -1418,6 +1420,11 @@ generic_cable80(
     ULONG slotNumber = deviceExtension->slotNumber;
     ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber;
 
+    if(deviceExtension->MaxTransferMode <= ATA_UDMA2) {
+        KdPrint2((PRINT_PREFIX "generic_cable80(%d, %#x, %d) <= UDMA2\n", channel, pci_reg, bit_offs));
+        return FALSE;
+    }
+
     //ULONG ChipType  = deviceExtension->HwFlags & CHIPTYPE_MASK;
     PHW_CHANNEL chan;
     ULONG  c; // logical channel (for Compatible Mode controllers)
@@ -1468,6 +1475,27 @@ UniAtaReadLunConfig(
     tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"PreferedTransferMode", 0xffffffff);
     LunExt->opt_PreferedTransferMode = tmp32;
 
+    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"AdvancedPowerMode", ATA_C_F_APM_CNT_MIN_NO_STANDBY);
+    if(tmp32 > 0xfe) {
+        tmp32 = 0xfe; // max. performance
+    }
+    LunExt->opt_AdvPowerMode = (UCHAR)tmp32;
+
+    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"AcousticMgmt", ATA_C_F_AAM_CNT_MAX_POWER_SAVE);
+    if(tmp32 > 0xfe) {
+        tmp32 = 0xfe; // max. performance
+    } else
+    if(tmp32 < 0x80) {
+        tmp32 = 0x0; // disable feature
+    }
+    LunExt->opt_AcousticMode = (UCHAR)tmp32;
+
+    tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"StandbyTimer", 0);
+    if(tmp32 == 0xfe) {
+        tmp32 = 0xff;
+    }
+    LunExt->opt_StandbyTimer = (UCHAR)tmp32;
+
     tmp32 = AtapiRegCheckDevValue(deviceExtension, channel, DeviceNumber, L"ReadOnly", 0);
     if(tmp32 <= 2) {
         LunExt->opt_ReadOnly = (UCHAR)tmp32;
@@ -1623,6 +1651,7 @@ AtapiChipInit(
     ULONG  tmp32;
     ULONG  c; // logical channel (for Compatible Mode controllers)
     BOOLEAN CheckCable = FALSE;
+    BOOLEAN GlobalInit = FALSE;
     //ULONG BaseIoAddress;
 
     switch(channel) {
@@ -1631,6 +1660,7 @@ AtapiChipInit(
         /* FALLTHROUGH */
     case CHAN_NOT_SPECIFIED:
         c = CHAN_NOT_SPECIFIED;
+        GlobalInit = TRUE;
         break;
     default:
         //c = channel - deviceExtension->Channel; // logical channel (for Compatible Mode controllers)
@@ -1669,6 +1699,27 @@ AtapiChipInit(
         }
     }
 
+    if((WinVer_Id() > WinVer_NT) &&
+       GlobalInit &&
+       deviceExtension->MasterDev) {
+        PCI_COMMON_CONFIG pciData;
+        ULONG busDataRead;
+
+        KdPrint2((PRINT_PREFIX "  re-enable IO resources of MasterDev\n" ));
+
+        busDataRead = HalGetBusData
+                      //ScsiPortGetBusData
+                                   (
+                                    //HwDeviceExtension,
+                                    PCIConfiguration, SystemIoBusNumber, slotNumber,
+                                    &pciData, PCI_COMMON_HDR_LENGTH);
+        if(busDataRead == PCI_COMMON_HDR_LENGTH) {
+            UniataEnableIoPCI(SystemIoBusNumber, slotNumber, &pciData);
+        } else {
+            KdPrint2((PRINT_PREFIX "  re-enable IO resources of MasterDev FAILED\n" ));
+        }
+    }
+
     switch(VendorID) {
 //  case ATA_ACARD_ID:
 //      break;
@@ -1778,8 +1829,16 @@ AtapiChipInit(
                 KdPrint2((PRINT_PREFIX "Base init\n"));
                 /* force all ports active "the legacy way" */
                 ChangePciConfig2(0x92, (a | 0x0f));
+
+                if(deviceExtension->BaseIoAddressSATA_0.Addr && (ChipFlags & ICH7)) {
+                    /* Set SCRAE bit to enable registers access. */
+                    ChangePciConfig4(0x94, (a | (1 << 9)));
+                    /* Set Ports Implemented register bits. */
+                    AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x0c,
+                         AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x0c) | 0xff);
+                }
                 /* enable PCI interrupt */
-                ChangePciConfig2(/*PCIR_COMMAND*/0x04, (a & ~0x0400));
+                ChangePciConfig2(offsetof(PCI_COMMON_CONFIG, Command), (a & ~0x0400));
 
             } else {
 
@@ -1867,7 +1926,7 @@ AtapiChipInit(
 
             break;
         }
-        if(deviceExtension->MaxTransferMode < ATA_UDMA2)
+        if(deviceExtension->MaxTransferMode <= ATA_UDMA2)
             break;
         // check 80-pin cable
         if(c == CHAN_NOT_SPECIFIED) {
@@ -1875,7 +1934,12 @@ AtapiChipInit(
         } else {
             chan = &deviceExtension->chan[c];
             GetPciConfig2(0x54, reg54);
-            if( ((reg54 >> (channel*2)) & 30) != 30) {
+            KdPrint2((PRINT_PREFIX " intel 80-pin check (reg54=%x)\n", reg54));
+            if(reg54 == 0x0000 || reg54 == 0xffff) {
+                KdPrint2((PRINT_PREFIX " check failed (not supported)\n"));
+            } else
+            if( ((reg54 >> (channel*2)) & 30) == 0) {
+                KdPrint2((PRINT_PREFIX " intel 40-pin\n"));
                 chan->MaxTransferMode = min(deviceExtension->MaxTransferMode, ATA_UDMA2);
             }
         }
@@ -2179,7 +2243,7 @@ AtapiChipInit(
             // no init for SATA
             if(ChipFlags & (UNIATA_SATA | VIASATA)) {
                 /* enable PCI interrupt */
-                ChangePciConfig2(/*PCIR_COMMAND*/0x04, (a & ~0x0400));
+                ChangePciConfig2(offsetof(PCI_COMMON_CONFIG, Command), (a & ~0x0400));
 
                /*
                 * vt6420/1 has problems talking to some drives.  The following
@@ -2238,6 +2302,8 @@ AtapiChipInit(
             // no init for SATA
             if(ChipFlags & (UNIATA_SATA | VIASATA)) {
                 if((ChipFlags & VIABAR) && (c >= 2)) {
+                    // this is PATA channel
+                    chan->MaxTransferMode = ATA_UDMA5;
                     break;
                 }
                 UniataSataWritePort4(chan, IDX_SATA_SError, 0xffffffff, 0);
index 5a4336f..1c01a29 100644 (file)
@@ -83,6 +83,50 @@ AtapiDoNothing(VOID)
 
 #endif //UNIATA_CORE
 
+USHORT
+NTAPI
+UniataEnableIoPCI(
+    IN  ULONG                  busNumber,
+    IN  ULONG                  slotNumber,
+ IN OUT PPCI_COMMON_CONFIG     pciData
+    )
+{
+    ULONG i;
+    ULONG busDataRead;
+
+    // Enable Busmastering, IO-space and Mem-space
+    KdPrint2((PRINT_PREFIX "Enabling Mem/Io spaces and busmastering...\n"));
+    KdPrint2((PRINT_PREFIX "Initial pciData.Command = %#x\n", pciData->Command));
+    for(i=0; i<3; i++) {
+        switch(i) {
+        case 0:
+            KdPrint2((PRINT_PREFIX "PCI_ENABLE_IO_SPACE\n"));
+            pciData->Command |= PCI_ENABLE_IO_SPACE;
+            break;
+        case 1:
+            KdPrint2((PRINT_PREFIX "PCI_ENABLE_MEMORY_SPACE\n"));
+            pciData->Command |= PCI_ENABLE_MEMORY_SPACE;
+            break;
+        case 2:
+            KdPrint2((PRINT_PREFIX "PCI_ENABLE_BUS_MASTER\n"));
+            pciData->Command |= PCI_ENABLE_BUS_MASTER;
+            break;
+        }
+        HalSetBusDataByOffset(  PCIConfiguration, busNumber, slotNumber,
+                                &(pciData->Command),
+                                offsetof(PCI_COMMON_CONFIG, Command),
+                                sizeof(pciData->Command));
+        KdPrint2((PRINT_PREFIX "InterruptLine = %#x\n", pciData->u.type0.InterruptLine));
+
+        // reread config space
+        busDataRead = HalGetBusData(PCIConfiguration, busNumber, slotNumber,
+                                    pciData, PCI_COMMON_HDR_LENGTH);
+        KdPrint2((PRINT_PREFIX "New pciData.Command = %#x\n", pciData->Command));
+    }
+    KdPrint2((PRINT_PREFIX "Final pciData.Command = %#x\n", pciData->Command));
+    return pciData->Command;
+} // end UniataEnableIoPCI()
+
 /*
     Get PCI address by ConfigInfo and RID
 */
@@ -329,7 +373,6 @@ UniataEnumBusMasterController__(
                 SubVendorID = pciData.u.type0.SubVendorID;
                 SubSystemID = pciData.u.type0.SubSystemID;
 
-
                 //KdPrint2((PRINT_PREFIX "DevId = %8.8X Class = %4.4X/%4.4X\n", dev_id, BaseClass, SubClass ));
 
                 // check for (g_opt_VirtualMachine == VM_AUTO) is performed inside each
@@ -367,6 +410,14 @@ UniataEnumBusMasterController__(
                 found = FALSE;
                 known = FALSE;
 
+                if(pciData.u.type0.InterruptPin == 14 ||
+                   pciData.u.type0.InterruptPin == 15 ||
+                   pciData.u.type0.InterruptLine == 14 ||
+                   pciData.u.type0.InterruptLine == 15) {
+                    KdPrint2((PRINT_PREFIX "(!) InterruptPin = %#x\n", pciData.u.type0.InterruptPin));
+                    KdPrint2((PRINT_PREFIX "(!) InterruptLine = %#x\n", pciData.u.type0.InterruptLine));
+                }
+
                 if(deviceExtension) {
                     deviceExtension->slotNumber = slotData.u.AsULONG;
                     deviceExtension->SystemIoBusNumber = busNumber;
@@ -426,36 +477,7 @@ UniataEnumBusMasterController__(
                     KdPrint2((PRINT_PREFIX "InterruptLine = %#x\n", pciData.u.type0.InterruptLine));
 
                     if(!pass && known) {
-                        // Enable Busmastering, IO-space and Mem-space
-                        KdPrint2((PRINT_PREFIX "Enabling Mem/Io spaces and busmastering...\n"));
-                        KdPrint2((PRINT_PREFIX "Initial pciData.Command = %#x\n", pciData.Command));
-                        for(i=0; i<3; i++) {
-                            switch(i) {
-                            case 0:
-                                KdPrint2((PRINT_PREFIX "PCI_ENABLE_IO_SPACE\n"));
-                                pciData.Command |= PCI_ENABLE_IO_SPACE;
-                                break;
-                            case 1:
-                                KdPrint2((PRINT_PREFIX "PCI_ENABLE_MEMORY_SPACE\n"));
-                                pciData.Command |= PCI_ENABLE_MEMORY_SPACE;
-                                break;
-                            case 2:
-                                KdPrint2((PRINT_PREFIX "PCI_ENABLE_BUS_MASTER\n"));
-                                pciData.Command |= PCI_ENABLE_BUS_MASTER;
-                                break;
-                            }
-                            HalSetBusDataByOffset(  PCIConfiguration, busNumber, slotData.u.AsULONG,
-                                                    &(pciData.Command),
-                                                    offsetof(PCI_COMMON_CONFIG, Command),
-                                                    sizeof(pciData.Command));
-                            KdPrint2((PRINT_PREFIX "InterruptLine = %#x\n", pciData.u.type0.InterruptLine));
-
-                            // reread config space
-                            busDataRead = HalGetBusData(PCIConfiguration, busNumber, slotData.u.AsULONG,
-                                                        &pciData, PCI_COMMON_HDR_LENGTH);
-                            KdPrint2((PRINT_PREFIX "New pciData.Command = %#x\n", pciData.Command));
-                        }
-                        KdPrint2((PRINT_PREFIX "Final pciData.Command = %#x\n", pciData.Command));
+                        UniataEnableIoPCI(busNumber, slotData.u.AsULONG, &pciData);
                     }
                     // validate Mem/Io ranges
                     no_ranges = TRUE;
@@ -1175,37 +1197,7 @@ UniataFindBusMasterController(
         deviceExtension->BusMaster = DMA_MODE_NONE;
 
         if(WinVer_WDM_Model && !deviceExtension->UnknownDev) {
-            ULONG i;
-            // Enable Busmastering, IO-space and Mem-space
-            KdPrint2((PRINT_PREFIX "Enabling Mem/Io spaces and busmastering...\n"));
-            KdPrint2((PRINT_PREFIX "Initial pciData.Command = %#x\n", pciData.Command));
-            for(i=0; i<3; i++) {
-                switch(i) {
-                case 0:
-                    KdPrint2((PRINT_PREFIX "PCI_ENABLE_IO_SPACE\n"));
-                    pciData.Command |= PCI_ENABLE_IO_SPACE;
-                    break;
-                case 1:
-                    KdPrint2((PRINT_PREFIX "PCI_ENABLE_MEMORY_SPACE\n"));
-                    pciData.Command |= PCI_ENABLE_MEMORY_SPACE;
-                    break;
-                case 2:
-                    KdPrint2((PRINT_PREFIX "PCI_ENABLE_BUS_MASTER\n"));
-                    pciData.Command |= PCI_ENABLE_BUS_MASTER;
-                    break;
-                }
-                HalSetBusDataByOffset(  PCIConfiguration, SystemIoBusNumber, slotData.u.AsULONG, 
-                                        &(pciData.Command),
-                                        offsetof(PCI_COMMON_CONFIG, Command),
-                                        sizeof(pciData.Command));
-                KdPrint2((PRINT_PREFIX "InterruptLine = %#x\n", pciData.u.type0.InterruptLine));
-
-                // reread config space
-                busDataRead = HalGetBusData(PCIConfiguration, SystemIoBusNumber, slotData.u.AsULONG, 
-                                            &pciData, PCI_COMMON_HDR_LENGTH);
-                KdPrint2((PRINT_PREFIX "New pciData.Command = %#x\n", pciData.Command));
-            }
-            KdPrint2((PRINT_PREFIX "Final pciData.Command = %#x\n", pciData.Command));
+            UniataEnableIoPCI(ConfigInfo->SystemIoBusNumber, slotData.u.AsULONG, &pciData);
         }
         // validate Mem/Io ranges
         //no_ranges = TRUE;
@@ -1364,6 +1356,7 @@ UniataFindBusMasterController(
         KdPrint2((PRINT_PREFIX "!MasterDev\n"));
         ConfigInfo->SlotNumber = slotNumber;
         ConfigInfo->SystemIoBusNumber = SystemIoBusNumber;
+        ConfigInfo->InterruptMode = LevelSensitive;
 
         /* primary and secondary channels share the same interrupt */
         if(!ConfigInfo->BusInterruptVector ||
@@ -1394,8 +1387,13 @@ UniataFindBusMasterController(
     }
     if((WinVer_Id() > WinVer_2k) ||
        (ConfigInfo->Length >= sizeof(_ConfigInfo->comm) + sizeof(_ConfigInfo->nt4) + sizeof(_ConfigInfo->w2k))) {
-        KdPrint2((PRINT_PREFIX "update ConfigInfo->w2k\n"));
-        _ConfigInfo->w2k.Dma64BitAddresses           = 0;
+        KdPrint2((PRINT_PREFIX "update ConfigInfo->w2k: 64bit %d\n",
+            deviceExtension->Host64));
+#ifdef USE_OWN_DMA
+        // We need not set Dma64BitAddresses since we perform address translation manually.
+#else
+        _ConfigInfo->w2k.Dma64BitAddresses           = deviceExtension->Host64;
+#endif //USE_OWN_DMA
         _ConfigInfo->w2k.ResetTargetSupported        = TRUE;
         _ConfigInfo->w2k.MaximumNumberOfLogicalUnits = (UCHAR)deviceExtension->NumberLuns;
     }
@@ -1411,20 +1409,32 @@ UniataFindBusMasterController(
     deviceExtension->AlignmentMask      = ConfigInfo->AlignmentMask;
     deviceExtension->AdapterInterfaceType = PCIBus;
 
+    KdPrint2((PRINT_PREFIX "chan[%d] InterruptMode: %d, Level %d, Level2 %d, Vector %d, Vector2 %d\n",
+        channel,
+        ConfigInfo->InterruptMode,
+        ConfigInfo->BusInterruptLevel,
+        ConfigInfo->BusInterruptLevel2,
+        ConfigInfo->BusInterruptVector,
+        ConfigInfo->BusInterruptVector2
+        ));
+
     found = FALSE;
 
     if(deviceExtension->BusMaster) {
 
         KdPrint2((PRINT_PREFIX "Reconstruct ConfigInfo\n"));
-        ConfigInfo->MapBuffers = TRUE;
 #ifdef USE_OWN_DMA
         ConfigInfo->NeedPhysicalAddresses = FALSE;
 #else
         ConfigInfo->NeedPhysicalAddresses = TRUE;
 #endif //USE_OWN_DMA
         if(!MasterDev) {
+//#ifdef USE_OWN_DMA
+//            KdPrint2((PRINT_PREFIX "!MasterDev, own DMA\n"));
+//#else
             KdPrint2((PRINT_PREFIX "set Dma32BitAddresses\n"));
             ConfigInfo->Dma32BitAddresses = TRUE;
+//#endif //USE_OWN_DMA
         }
 
         // thanks to Vitaliy Vorobyov aka deathsoft@yandex.ru for
@@ -1451,9 +1461,10 @@ UniataFindBusMasterController(
         ConfigInfo->Master        = TRUE;
         ConfigInfo->DmaWidth      = Width16Bits;
 #endif //USE_OWN_DMA
-        ConfigInfo->CachesData    = TRUE;
         ConfigInfo->ScatterGather = TRUE;
     }
+    ConfigInfo->MapBuffers = TRUE; // Need for PIO and OWN_DMA
+    ConfigInfo->CachesData = TRUE;
 
     KdPrint2((PRINT_PREFIX "BMList[i].channel %#x, NumberChannels %#x, channel %#x\n",BMList[i].channel, deviceExtension->NumberChannels, channel));
 
@@ -1486,14 +1497,6 @@ UniataFindBusMasterController(
                 (*ConfigInfo->AccessRanges)[channel * 2 + 1].RangeStart =
                     ScsiPortConvertUlongToPhysicalAddress((channel ? IO_WD2 : IO_WD1) + ATA_ALTOFFSET);
                 (*ConfigInfo->AccessRanges)[channel * 2 + 1].RangeLength = ATA_ALTIOSIZE;
-
-                // do not claim 2nd BM io-range for Secondary channel of
-                // Compatible-mode controllers
-                if(/*(WinVer_Id() <= WinVer_NT) &&*/ !c && channel == 1) {
-                    KdPrint2((PRINT_PREFIX "cheat ScsiPort for 2nd channel, BM io-range\n"));
-                    (*ConfigInfo->AccessRanges)[4].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0);
-                    (*ConfigInfo->AccessRanges)[4].RangeLength = 0;
-                }
             } else
             if(AltInit &&
                !(*ConfigInfo->AccessRanges)[channel * 2 + 0].RangeStart.QuadPart &&
@@ -1552,8 +1555,8 @@ UniataFindBusMasterController(
 
             // Get the system physical address for this IO range.
             ioSpace = (PUCHAR)ScsiPortGetDeviceBase(HwDeviceExtension,
-                                            PCIBus /*ConfigInfo->AdapterInterfaceType*/,
-                                            SystemIoBusNumber /*ConfigInfo->SystemIoBusNumber*/,
+                                            MasterDev ? ConfigInfo->AdapterInterfaceType : PCIBus /*ConfigInfo->AdapterInterfaceType*/,
+                                            MasterDev ? ConfigInfo->SystemIoBusNumber : SystemIoBusNumber /*ConfigInfo->SystemIoBusNumber*/,
                                             IoBasePort1,
                                             ATA_IOSIZE,
                                             TRUE);
@@ -1577,8 +1580,8 @@ UniataFindBusMasterController(
 
             // Get the system physical address for the second IO range.
             ioSpace = (PUCHAR)ScsiPortGetDeviceBase(HwDeviceExtension,
-                                            PCIBus /*ConfigInfo->AdapterInterfaceType*/,
-                                            SystemIoBusNumber /*ConfigInfo->SystemIoBusNumber*/,
+                                            MasterDev ? ConfigInfo->AdapterInterfaceType : PCIBus /*ConfigInfo->AdapterInterfaceType*/,
+                                            MasterDev ? ConfigInfo->SystemIoBusNumber : SystemIoBusNumber /*ConfigInfo->SystemIoBusNumber*/,
                                             IoBasePort2,
                                             ATA_ALTIOSIZE,
                                             TRUE);
@@ -1744,12 +1747,12 @@ exit_findbm:
         KdPrint2((PRINT_PREFIX "MasterDev=%#x, NumberChannels=%#x, Isr2DevObj=%#x\n",
             MasterDev, deviceExtension->NumberChannels, BMList[i].Isr2DevObj));
 
-        if(WinVer_WDM_Model && MasterDev) {
-            KdPrint2((PRINT_PREFIX "do not tell system, that we know about this:\n"));
-            if(BaseIoAddressBM_0) {
+        if(/*WinVer_WDM_Model &&*/ MasterDev) {
+            KdPrint2((PRINT_PREFIX "do not tell system, that we know about PCI IO ranges\n"));
+/*            if(BaseIoAddressBM_0) {
                 ScsiPortFreeDeviceBase(HwDeviceExtension,
                                        BaseIoAddressBM_0);
-            }
+            }*/
             (*ConfigInfo->AccessRanges)[4].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0);
             (*ConfigInfo->AccessRanges)[4].RangeLength = 0;
             (*ConfigInfo->AccessRanges)[5].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0);
@@ -1761,6 +1764,17 @@ exit_findbm:
             found = FALSE;
             goto exit_findbm;
         }
+
+        KdPrint2((PRINT_PREFIX "final chan[%d] InterruptMode: %d, Level %d, Level2 %d, Vector %d, Vector2 %d\n",
+            channel,
+            ConfigInfo->InterruptMode,
+            ConfigInfo->BusInterruptLevel,
+            ConfigInfo->BusInterruptLevel2,
+            ConfigInfo->BusInterruptVector,
+            ConfigInfo->BusInterruptVector2
+            ));
+
+
     }
 #endif //UNIATA_CORE
 
@@ -1790,331 +1804,78 @@ exit_notfound:
 /*
    This is for claiming PCI Busmaster in compatible mode under WDM OSes
 */
-ULONG
+NTSTATUS
 NTAPI
-UniataFindFakeBusMasterController(
-    IN PVOID HwDeviceExtension,
-    IN PVOID Context,
-    IN PVOID BusInformation,
-    IN PCHAR ArgumentString,
-    IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
-    OUT PBOOLEAN Again
+UniataClaimLegacyPCIIDE(
+    ULONG i
     )
 {
-    PHW_DEVICE_EXTENSION  deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
-    //PHW_CHANNEL           chan = NULL;
-    // this buffer must be global for UNIATA_CORE build
-    PCI_COMMON_CONFIG     pciData;
-
-    ULONG                 slotNumber;
-    ULONG                 busDataRead;
-    ULONG                 SystemIoBusNumber;
-
-    UCHAR                 vendorString[5];
-    UCHAR                 deviceString[5];
-    PUCHAR                vendorStrPtr;
-    PUCHAR                deviceStrPtr;
-
-    UCHAR   BaseClass;
-    UCHAR   SubClass;
-    ULONG   VendorID;
-    ULONG   DeviceID;
-    ULONG   RevID;
-    ULONG   dev_id;
-    PCI_SLOT_NUMBER       slotData;
-
-    ULONG   i;
-//    PUCHAR  ioSpace;
-//    UCHAR   statusByte;
-
-//    UCHAR   tmp8;
-//    ULONG   irq;
-
-    BOOLEAN found = FALSE;
-    BOOLEAN MasterDev;
-    BOOLEAN simplexOnly = FALSE;
-    //BOOLEAN skip_find_dev = FALSE;
-    //BOOLEAN AltInit = FALSE;
-
-    PIDE_BUSMASTER_REGISTERS BaseIoAddressBM_0 = NULL;
-
     NTSTATUS status;
-    PPORT_CONFIGURATION_INFORMATION_COMMON _ConfigInfo =
-        (PPORT_CONFIGURATION_INFORMATION_COMMON)ConfigInfo;
-
-    *Again = FALSE;
-
-    if(InDriverEntry) {
-        i = (ULONG)Context;
-    } else {
-        for(i=0; i<BMListLen; i++) {
-            if(BMList[i].slotNumber == ConfigInfo->SlotNumber &&
-               BMList[i].busNumber  == ConfigInfo->SystemIoBusNumber) {
-                break;
-            }
-        }
-        if(i >= BMListLen) {
-            KdPrint2((PRINT_PREFIX "unexpected device arrival => SP_RETURN_NOT_FOUND\n"));
-            goto exit_notfound;
-        }
-    }
-
-    KdPrint2((PRINT_PREFIX "UniataFindFakeBusMasterController (WDM)\n"));
-
-    if (!deviceExtension) {
-        KdPrint2((PRINT_PREFIX "!deviceExtension => SP_RETURN_ERROR\n"));
-        return SP_RETURN_ERROR;
-    }
-    RtlZeroMemory(deviceExtension, sizeof(HW_DEVICE_EXTENSION));
-
-    vendorStrPtr = vendorString;
-    deviceStrPtr = deviceString;
-
-    slotNumber = BMList[i].slotNumber;
-    SystemIoBusNumber = BMList[i].busNumber;
-
-    KdPrint2((PRINT_PREFIX "AdapterInterfaceType=%#x\n",ConfigInfo->AdapterInterfaceType));
-    KdPrint2((PRINT_PREFIX "IoBusNumber=%#x\n",ConfigInfo->SystemIoBusNumber));
-    KdPrint2((PRINT_PREFIX "slotNumber=%#x\n",slotNumber));
-
-    // this buffer must be global and already filled for UNIATA_CORE build
-    busDataRead = HalGetBusData(
-        //busDataRead = ScsiPortGetBusData(HwDeviceExtension,
-                                     PCIConfiguration,
-                                     SystemIoBusNumber,
-                                     slotNumber,
-                                     &pciData,
-                                     PCI_COMMON_HDR_LENGTH);
-
-    if (busDataRead < PCI_COMMON_HDR_LENGTH) {
-        KdPrint2((PRINT_PREFIX "busDataRead < PCI_COMMON_HDR_LENGTH => SP_RETURN_ERROR\n"));
-        goto exit_error;
-    }
-
-    KdPrint2((PRINT_PREFIX "busDataRead\n"));
-    if (pciData.VendorID == PCI_INVALID_VENDORID) {
-        KdPrint2((PRINT_PREFIX "PCI_INVALID_VENDORID\n"));
-        goto exit_error;
-    }
-
-    VendorID  = pciData.VendorID;
-    DeviceID  = pciData.DeviceID;
-    BaseClass = pciData.BaseClass;
-    SubClass  = pciData.SubClass;
-    RevID     = pciData.RevisionID;
-    dev_id = VendorID | (DeviceID << 16);
-    slotData.u.AsULONG = slotNumber;
-    KdPrint2((PRINT_PREFIX "DevId = %8.8X Class = %4.4X/%4.4X\n", dev_id, BaseClass, SubClass ));
-
-    deviceExtension->slotNumber = slotNumber;
-    deviceExtension->SystemIoBusNumber = SystemIoBusNumber;
-    deviceExtension->DevID = dev_id;
-    deviceExtension->RevID = RevID;
-    deviceExtension->NumberChannels = IDE_DEFAULT_MAX_CHAN; // default
-    deviceExtension->NumberLuns = IDE_MAX_LUN_PER_CHAN; // default
-    deviceExtension->DevIndex = i;
-
-    _snprintf(deviceExtension->Signature, sizeof(deviceExtension->Signature),
-              "UATA%8.8x/%1.1x@%8.8x", dev_id, 0xff, slotNumber);
-
-    if(BaseClass != PCI_DEV_CLASS_STORAGE) {
-        KdPrint2((PRINT_PREFIX "BaseClass != PCI_DEV_CLASS_STORAGE => SP_RETURN_NOT_FOUND\n"));
-        goto exit_notfound;
-    }
-
-    KdPrint2((PRINT_PREFIX "Storage Class\n"));
-
-    // look for known chipsets
-    if(VendorID != BMList[i].nVendorId ||
-       DeviceID != BMList[i].nDeviceId) {
-        KdPrint2((PRINT_PREFIX "device not suitable\n"));
-        goto exit_notfound;
-    }
-
-    if((BMList[i].RaidFlags & UNIATA_RAID_CONTROLLER) &&
-        SkipRaids) {
-        KdPrint2((PRINT_PREFIX "RAID support disabled\n"));
-        goto exit_notfound;
-    }
-
-    if(!UniataCheckPCISubclass(FALSE, BMList[i].RaidFlags, SubClass)) {
-        KdPrint2((PRINT_PREFIX "Subclass not supported\n"));
-        goto exit_notfound;
-    }
-
-    ConfigInfo->AlignmentMask = 0x00000003;
-
-    status = UniataChipDetect(HwDeviceExtension, &pciData, i, ConfigInfo, &simplexOnly);
-    switch(status) {
-    case STATUS_SUCCESS:
-        found = TRUE;
-        break;
-    case STATUS_NOT_FOUND:
-        found = FALSE;
-        break;
-    default:
-        KdPrint2((PRINT_PREFIX "FAILED => SP_RETURN_ERROR\n"));
-        goto exit_error;
-    }
-    KdPrint2((PRINT_PREFIX "ForceSimplex = %d\n", simplexOnly));
-    KdPrint2((PRINT_PREFIX "HwFlags = %x\n (0)", deviceExtension->HwFlags));
-    switch(dev_id) {
-    /* additional checks for some supported chipsets */
-    case 0xc6931080:
-        if (SubClass != PCI_DEV_SUBCLASS_IDE) {
-            KdPrint2((PRINT_PREFIX "0xc6931080, SubClass != PCI_DEV_SUBCLASS_IDE => found = FALSE\n"));
-            found = FALSE;
-        } else {
-            found = FALSE;
-        }
-        break;
+    PCM_RESOURCE_LIST resourceList;
+    UNICODE_STRING devname;
 
-    /* unknown chipsets, try generic DMA if it seems possible */
-    default:
-        if (found)
-            break;
-        KdPrint2((PRINT_PREFIX "Default device\n"));
-        if(Ata_is_supported_dev(&pciData)) {
-            KdPrint2((PRINT_PREFIX "Ata_is_supported_dev\n"));
-            found = TRUE;
-        } else {
-            KdPrint2((PRINT_PREFIX "!Ata_is_supported_dev => found = FALSE\n"));
-            found = FALSE;
-        }
-        deviceExtension->UnknownDev = TRUE;
-        break;
-    }
+    KdPrint2((PRINT_PREFIX "UniataClaimLegacyPCIIDE:\n"));
 
-    KdPrint2((PRINT_PREFIX "HwFlags = %x\n (1)", deviceExtension->HwFlags));
-    if(!found) {
-        KdPrint2((PRINT_PREFIX "!found => SP_RETURN_NOT_FOUND\n"));
-        goto exit_notfound;
+    if(BMList[i].PciIdeDevObj) {
+        KdPrint2((PRINT_PREFIX "Already initialized\n"));
+        return STATUS_UNSUCCESSFUL;
     }
 
-    KdPrint2((PRINT_PREFIX "HwFlags = %x\n (2)", deviceExtension->HwFlags));
-    KdPrint2((PRINT_PREFIX "found suitable device\n"));
-
-    /***********************************************************/
-    /***********************************************************/
-    /***********************************************************/
+    RtlInitUnicodeString(&devname, L"\\Device\\uniata_PCIIDE");
+    status = IoCreateDevice(SavedDriverObject, sizeof(PCIIDE_DEVICE_EXTENSION),
+                            /*NULL*/ &devname, FILE_DEVICE_UNKNOWN,
+                            0, FALSE, &(BMList[i].PciIdeDevObj));
 
-    deviceExtension->UseDpc = TRUE;
-    KdPrint2((PRINT_PREFIX "HwFlags = %x\n (3)", deviceExtension->HwFlags));
-    if(deviceExtension->HwFlags & UNIATA_NO_DPC) {
-        /* CMD 649, ROSB SWK33, ICH4 */
-        KdPrint2((PRINT_PREFIX "UniataFindBusMasterController: UNIATA_NO_DPC (0)\n"));
-        deviceExtension->UseDpc = FALSE;
+    if(!NT_SUCCESS(status)) {
+        KdPrint2((PRINT_PREFIX "IoCreateDevice failed %#x\n", status));
+        return status;
     }
 
-    MasterDev = IsMasterDev(&pciData);
+    resourceList = (PCM_RESOURCE_LIST) ExAllocatePool(PagedPool,
+                                sizeof(CM_RESOURCE_LIST));
 
-    if(MasterDev) {
-        KdPrint2((PRINT_PREFIX "MasterDev\n"));
-        deviceExtension->MasterDev = TRUE;
-        deviceExtension->NumberChannels = 1;
-    } else {
-        KdPrint2((PRINT_PREFIX "!MasterDev => SP_RETURN_NOT_FOUND\n"));
-        goto exit_notfound;
+    if (!resourceList) {
+        KdPrint2((PRINT_PREFIX "!resourceList\n"));
+        status = STATUS_INSUFFICIENT_RESOURCES;
+del_do:
+        IoDeleteDevice(BMList[i].PciIdeDevObj);
+        BMList[i].PciIdeDevObj          = NULL;
+        return status;
     }
 
-    if(deviceExtension->AltRegMap) {
-        KdPrint2((PRINT_PREFIX "  Non-standard registers layout => SP_RETURN_NOT_FOUND\n"));
-        goto exit_notfound;
-    }
-    if(IsBusMaster(&pciData)) {
-        KdPrint2((PRINT_PREFIX "  !BusMaster => SP_RETURN_NOT_FOUND\n"));
-        goto exit_notfound;
-    }
+    RtlZeroMemory(
+        resourceList,
+        sizeof(CM_RESOURCE_LIST));
 
-    KdPrint2((PRINT_PREFIX "IsBusMaster == TRUE\n"));
-    BaseIoAddressBM_0 = (PIDE_BUSMASTER_REGISTERS)
-        (AtapiGetIoRange(HwDeviceExtension, ConfigInfo, &pciData, SystemIoBusNumber,
-                        4, 0, 0x10/*ATA_BMIOSIZE*/)/* - bm_offset*/); //range id
-    if(BaseIoAddressBM_0) {
-        UniataInitMapBM(deviceExtension,
-                        BaseIoAddressBM_0,
-                        (*ConfigInfo->AccessRanges)[4].RangeInMemory ? TRUE : FALSE);
-        deviceExtension->BusMaster = DMA_MODE_BM;
-        deviceExtension->BaseIoAddressBM_0.Addr  = (ULONGIO_PTR)BaseIoAddressBM_0;
-        if((*ConfigInfo->AccessRanges)[4].RangeInMemory) {
-            deviceExtension->BaseIoAddressBM_0.MemIo = TRUE;
-        }
-    }
-    KdPrint2((PRINT_PREFIX "  BusMasterAddress (base): %#x\n", BaseIoAddressBM_0));
+    // IoReportDetectedDevice() should be used for WDM OSes
 
-    /*
-     * the Cypress chip is a mess, it contains two ATA functions, but 
-     * both channels are visible on the first one.
-     * simply ignore the second function for now, as the right
-     * solution (ignoring the second channel on the first function)
-     * doesn't work with the crappy ATA interrupt setup on the alpha.
-     */
-    if (dev_id == 0xc6931080 && slotData.u.bits.FunctionNumber > 1) {
-        KdPrint2((PRINT_PREFIX "dev_id == 0xc6931080 && FunctionNumber > 1 => exit_findbm\n"));
-        goto exit_findbm;
-    }
+    resourceList->Count = 1;
+    resourceList->List[0].InterfaceType = PCIBus;
+    resourceList->List[0].BusNumber = BMList[i].busNumber;
+    // we do not report IO ranges since they are used/claimed by ISA part(s)
+    resourceList->List[0].PartialResourceList.Count = 0;
 
-    // Indicate number of buses.
-    ConfigInfo->NumberOfBuses = 0;
-    if(!ConfigInfo->InitiatorBusId[0]) {
-        ConfigInfo->InitiatorBusId[0] = (CHAR)(IoGetConfigurationInformation()->ScsiPortCount);
-        KdPrint2((PRINT_PREFIX "set ConfigInfo->InitiatorBusId[0] = %#x\n", ConfigInfo->InitiatorBusId[0]));
-    }
-    // Indicate four devices can be attached to the adapter
-    ConfigInfo->MaximumNumberOfTargets = 0;
+    RtlInitUnicodeString(&devname, L"PCIIDE");
+    status = HalAssignSlotResources(&SavedRegPath,
+                                    &devname,
+                                    SavedDriverObject,
+                                    BMList[i].PciIdeDevObj,
+                                    PCIBus,
+                                    BMList[i].busNumber,
+                                    BMList[i].slotNumber,
+                                    &resourceList);
 
-    ConfigInfo->MultipleRequestPerLu = FALSE;
-    ConfigInfo->AutoRequestSense     = FALSE;
-    ConfigInfo->TaggedQueuing        = FALSE;
-
-    if((WinVer_Id() >= WinVer_NT) ||
-       (ConfigInfo->Length >= sizeof(_ConfigInfo->comm) + sizeof(_ConfigInfo->nt4))) {
-        _ConfigInfo->nt4.DeviceExtensionSize         = sizeof(HW_DEVICE_EXTENSION);
-        _ConfigInfo->nt4.SpecificLuExtensionSize     = sizeof(HW_LU_EXTENSION);    
-        _ConfigInfo->nt4.SrbExtensionSize            = sizeof(ATA_REQ);            
-    }
-    if((WinVer_Id() > WinVer_2k) ||
-       (ConfigInfo->Length >= sizeof(_ConfigInfo->comm) + sizeof(_ConfigInfo->nt4) + sizeof(_ConfigInfo->w2k))) {
-        _ConfigInfo->w2k.Dma64BitAddresses           = 0;
-        _ConfigInfo->w2k.ResetTargetSupported        = FALSE;
-        _ConfigInfo->w2k.MaximumNumberOfLogicalUnits = 0;
+    if (!NT_SUCCESS(status)) {
+        KdPrint2((PRINT_PREFIX "HalAssignSlotResources failed %#x\n", status));
+        ExFreePool(resourceList);
+        goto del_do;
     }
 
-    // Save the Interrupe Mode for later use
-    deviceExtension->InterruptMode      = ConfigInfo->InterruptMode;
-    deviceExtension->BusInterruptLevel  = ConfigInfo->BusInterruptLevel;
-    deviceExtension->BusInterruptVector = ConfigInfo->BusInterruptVector;
-    deviceExtension->Channel            = 0;
-    deviceExtension->DevIndex           = i;
-    deviceExtension->OrigAdapterInterfaceType
-                                        = ConfigInfo->AdapterInterfaceType;
-    deviceExtension->AlignmentMask      = ConfigInfo->AlignmentMask;
-    deviceExtension->AdapterInterfaceType = PCIBus;
-
-    KdPrint2((PRINT_PREFIX "Reconstruct ConfigInfo\n"));
-    ConfigInfo->MapBuffers = TRUE;
-#ifdef USE_OWN_DMA
-    ConfigInfo->NeedPhysicalAddresses = FALSE;
-#else
-    ConfigInfo->NeedPhysicalAddresses = TRUE;
-#endif //USE_OWN_DMA
-
-exit_findbm:
-
-    KdPrint2((PRINT_PREFIX "return SP_RETURN_FOUND\n"));
-    //PrintNtConsole("return SP_RETURN_FOUND, de %#x, c0.lun0 %#x\n", deviceExtension, deviceExtension->chan[0].lun[0]);
-
-    return SP_RETURN_FOUND;
-    
-exit_error:
-    UniataFreeLunExt(deviceExtension);
-    return SP_RETURN_ERROR;
-    
-exit_notfound:
-    UniataFreeLunExt(deviceExtension);
-    return SP_RETURN_NOT_FOUND;
+    KdPrint2((PRINT_PREFIX "ok %#x\n", status));
+    BMList[i].ChanInitOk |= 0x80;
 
-} // end UniataFindFakeBusMasterController()
+    return status;
+} // end UniataClaimLegacyPCIIDE()
 
 
 /*++
@@ -2148,11 +1909,6 @@ UniataConnectIntr2(
 
     KdPrint2((PRINT_PREFIX "Init ISR:\n"));
 
-    if(BMList[i].Isr2DevObj) {
-        KdPrint2((PRINT_PREFIX "Already initialized %#x\n", BMList[i].Isr2DevObj));
-        return STATUS_SUCCESS;
-    }
-
     if(!deviceExtension->MasterDev && (deviceExtension->NumberChannels > 1) &&   // do not touch MasterDev
        !deviceExtension->simplexOnly && /*                        // this is unnecessary on simplex controllers
        !BMList[i].Isr2DevObj*/                                    // handle re-init under w2k+
@@ -2172,6 +1928,11 @@ UniataConnectIntr2(
         return STATUS_SUCCESS;
     }
 
+    if(BMList[i].Isr2DevObj) {
+        KdPrint2((PRINT_PREFIX "Already initialized [%d] %#x\n", i, BMList[i].Isr2DevObj));
+        return STATUS_SUCCESS;
+    }
+
     KdPrint2((PRINT_PREFIX "Create DO\n"));
 
     devname.Length = 
@@ -2188,7 +1949,7 @@ UniataConnectIntr2(
                             0, FALSE, &(BMList[i].Isr2DevObj));
 
     if(!NT_SUCCESS(status)) {
-        KdPrint2((PRINT_PREFIX "IoCreateDevice failed %#x\n"));
+        KdPrint2((PRINT_PREFIX "IoCreateDevice failed %#x\n", status));
         return status;
     }
 
@@ -2907,6 +2668,10 @@ CheckDevice(
     }
     LunExt = chan->lun[deviceNumber];
 
+    if(ResetDev) {
+        LunExt->PowerState = 0;
+    }
+
     if(ResetDev && (deviceExtension->HwFlags & UNIATA_AHCI)) {
         KdPrint2((PRINT_PREFIX "CheckDevice: reset AHCI dev\n"));
         if(UniataAhciSoftReset(HwDeviceExtension, chan->lChannel, deviceNumber) == (ULONG)(-1)) {
index 6f6c8ac..188019b 100644 (file)
@@ -619,7 +619,26 @@ UniataAhciInit(
     UniataDumpAhciRegs(deviceExtension);
 #endif //DBG
 
-    /* reset AHCI controller */
+    /* disable AHCI interrupts, for MSI compatibility issue
+       see http://www.intel.com/Assets/PDF/specupdate/307014.pdf
+       26. AHCI Reset and MSI Request
+    */
+
+    KdPrint2((PRINT_PREFIX "  get GHC\n"));
+    /* enable AHCI mode */
+    GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC);
+    if(!(GHC & AHCI_GHC_AE)) {
+        KdPrint2((PRINT_PREFIX "  enable AHCI mode, disable intr, GHC %#x\n", GHC));
+        UniataAhciWriteHostPort4(deviceExtension, IDX_AHCI_GHC,
+            (GHC | AHCI_GHC_AE) & ~AHCI_GHC_IE);
+    } else {
+        KdPrint2((PRINT_PREFIX "  disable intr, GHC %#x\n", GHC));
+        UniataAhciWriteHostPort4(deviceExtension, IDX_AHCI_GHC,
+            GHC & ~AHCI_GHC_IE);
+    }
+    AtapiStallExecution(100);
+
+    /* read GHC again and reset AHCI controller */
     GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC);
     KdPrint2((PRINT_PREFIX "  reset AHCI controller, GHC %#x\n", GHC));
     UniataAhciWriteHostPort4(deviceExtension, IDX_AHCI_GHC,
@@ -638,12 +657,14 @@ UniataAhciInit(
         return FALSE;
     }
 
-    /* enable AHCI mode */
-    GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC);
-    KdPrint2((PRINT_PREFIX "  enable AHCI mode, GHC %#x\n", GHC));
-    UniataAhciWriteHostPort4(deviceExtension, IDX_AHCI_GHC,
-        GHC | AHCI_GHC_AE);
+    /* re-enable AHCI mode */
     GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC);
+    if(!(GHC & AHCI_GHC_AE)) {
+        KdPrint2((PRINT_PREFIX "  re-enable AHCI mode, GHC %#x\n", GHC));
+        UniataAhciWriteHostPort4(deviceExtension, IDX_AHCI_GHC,
+            GHC | AHCI_GHC_AE);
+        GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC);
+    }
     KdPrint2((PRINT_PREFIX "  AHCI GHC %#x\n", GHC));
     if(!(GHC & AHCI_GHC_AE)) {
         KdPrint2((PRINT_PREFIX "  Can't enable AHCI mode\n"));
@@ -652,7 +673,6 @@ UniataAhciInit(
 
     deviceExtension->AHCI_CAP =
       CAP = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_CAP);
-    PI = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_PI);
     KdPrint2((PRINT_PREFIX "  AHCI CAP %#x\n", CAP));
     if(CAP & AHCI_CAP_S64A) {
         KdPrint2((PRINT_PREFIX "  AHCI 64bit\n"));
@@ -689,6 +709,8 @@ UniataAhciInit(
 
         KdPrint2((PRINT_PREFIX "  chan %d, offs %#x\n", c, offs));
 
+        chan->MaxTransferMode = deviceExtension->MaxTransferMode;
+
         AtapiSetupLunPtrs(chan, deviceExtension, c);
 
         chan->BaseIoAHCI_Port = deviceExtension->BaseIoAHCI_0;
@@ -719,6 +741,11 @@ UniataAhciInit(
 
         AtapiDmaAlloc(HwDeviceExtension, NULL, c);
 
+        if(!UniataAhciChanImplemented(deviceExtension, c)) {
+            KdPrint2((PRINT_PREFIX "  chan %d not implemented\n", c));
+            continue;
+        }
+
         UniataAhciResume(chan);
 
         chan->ChannelCtrlFlags |= CTRFLAGS_NO_SLAVE;
@@ -727,6 +754,35 @@ UniataAhciInit(
     return TRUE;
 } // end UniataAhciInit()
 
+BOOLEAN
+NTAPI
+UniAtaAhciValidateVersion(
+    IN PHW_DEVICE_EXTENSION deviceExtension,
+    IN ULONG version,
+    IN BOOLEAN Strict
+    )
+{
+    switch(version) {
+    case 0x00000000:
+    case 0xffffffff:
+        KdPrint(("  wrong AHCI revision %#x\n", version));
+        return FALSE;
+    case 0x00000905:
+    case 0x00010000:
+    case 0x00010100:
+    case 0x00010200:
+    case 0x00010300:
+        break;
+    default:
+        KdPrint2((PRINT_PREFIX "  Unknown AHCI revision\n"));
+        if(AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"CheckAhciRevision", Strict)) {
+            KdPrint(("  AHCI revision excluded\n"));
+            return FALSE;
+        }
+    }
+    return TRUE;
+} // end UniAtaAhciValidateVersion()
+
 BOOLEAN
 NTAPI
 UniataAhciDetect(
@@ -743,12 +799,13 @@ UniataAhciDetect(
     ULONG PI;
     ULONG CAP;
     ULONG CAP2;
-    ULONG GHC;
+    ULONG GHC, GHC0;
     ULONG BOHC;
     ULONG NumberChannels;
     ULONG v_Mn, v_Mj;
     ULONG BaseMemAddress;
-    BOOLEAN MemIo;
+    BOOLEAN MemIo = FALSE;
+    BOOLEAN found = FALSE;
 
     KdPrint2((PRINT_PREFIX "  UniataAhciDetect:\n"));
 
@@ -762,7 +819,7 @@ UniataAhciDetect(
         KdPrint2((PRINT_PREFIX "  AHCI init failed - no IoRange\n"));
         return FALSE;
     }
-    if(BaseMemAddress && (*ConfigInfo->AccessRanges)[5].RangeInMemory) {
+    if((*ConfigInfo->AccessRanges)[5].RangeInMemory) {
         KdPrint2((PRINT_PREFIX "MemIo\n"));
         MemIo = TRUE;
     }
@@ -779,12 +836,29 @@ UniataAhciDetect(
         return FALSE;
     }
 
-    /* enable AHCI mode */
+    /* check AHCI mode. Save state and try enable */
+    GHC0 = 
     GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC);
     KdPrint2((PRINT_PREFIX "  check AHCI mode, GHC %#x\n", GHC));
+
+    version = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_VS);
+
     if(!(GHC & AHCI_GHC_AE)) {
-        KdPrint2((PRINT_PREFIX "  Non-AHCI GHC (!AE)\n"));
-        return FALSE;
+        KdPrint2((PRINT_PREFIX "  Non-AHCI GHC (!AE), check revision %#x\n", version));
+        if(!UniAtaAhciValidateVersion(deviceExtension, version, FALSE)) {
+            KdPrint2((PRINT_PREFIX "  Non-AHCI\n"));
+            goto exit_detect;
+        }
+        KdPrint2((PRINT_PREFIX "  try enable\n"));
+        UniataAhciWriteHostPort4(deviceExtension, IDX_AHCI_GHC,
+            (GHC | AHCI_GHC_AE) & ~AHCI_GHC_IE);
+        GHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_GHC);
+
+        KdPrint2((PRINT_PREFIX "  re-check AHCI mode, GHC %#x\n", GHC));
+        if(!(GHC & AHCI_GHC_AE)) {
+            KdPrint2((PRINT_PREFIX "  Non-AHCI GHC (!AE)\n"));
+            goto exit_detect;
+        }
     }
 
     CAP = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_CAP);
@@ -792,7 +866,7 @@ UniataAhciDetect(
     KdPrint2((PRINT_PREFIX "  AHCI CAP %#x, CAP2 %#x\n", CAP, CAP2));
     if(CAP & AHCI_CAP_S64A) {
         KdPrint2((PRINT_PREFIX "  64bit"));
-        //deviceExtension->Host64 = TRUE;
+        //deviceExtension->Host64 = TRUE; // this is just DETECT, do not update anything
     }
     if(CAP2 & AHCI_CAP2_BOH) {
         BOHC = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_BOHC);
@@ -811,6 +885,7 @@ UniataAhciDetect(
 
     /* get the number of HW channels */
     PI = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_PI);
+    deviceExtension->AHCI_PI = PI;
     KdPrint2((PRINT_PREFIX "  AHCI PI %#x\n", PI));
     for(i=PI, n=0; i; n++, i=i>>1);
     NumberChannels =
@@ -834,10 +909,10 @@ UniataAhciDetect(
 
     if(!NumberChannels) {
         KdPrint2((PRINT_PREFIX "  Non-AHCI - NumberChannels=0\n"));
-        return FALSE;
+        found = FALSE;
+        goto exit_detect;
     }
 
-    version = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_VS);
     v_Mj = ((version >> 20) & 0xf0) + ((version >> 16) & 0x0f);
     v_Mn = ((version >> 4) & 0xf0) + (version & 0x0f);
 
@@ -862,19 +937,8 @@ UniataAhciDetect(
         deviceExtension->NumberLuns = 1;
     }
 
-    switch(version) {
-    case 0x00000905:
-    case 0x00010000:
-    case 0x00010100:
-    case 0x00010200:
-    case 0x00010300:
-        break;
-    default:
-        KdPrint2((PRINT_PREFIX "  Unknown AHCI revision\n"));
-        if(AtapiRegCheckDevValue(deviceExtension, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"CheckAhciRevision", 1)) {
-            KdPrint(("  AHCI revision excluded\n"));
-            return FALSE;
-        }
+    if(!UniAtaAhciValidateVersion(deviceExtension, version, TRUE)) {
+        goto exit_detect;
     }
 
     deviceExtension->HwFlags |= UNIATA_SATA | UNIATA_AHCI;
@@ -887,7 +951,13 @@ UniataAhciDetect(
     deviceExtension->BusMaster = DMA_MODE_AHCI;
     deviceExtension->MaxTransferMode = max(deviceExtension->MaxTransferMode, ATA_SA150+(((CAP & AHCI_CAP_ISS_MASK) >> 20)-1) );
 
-    return TRUE;
+    found = TRUE;
+
+exit_detect:
+    UniataAhciWriteHostPort4(deviceExtension, IDX_AHCI_GHC, GHC0);
+    KdPrint(("  AHCI detect status %d\n", found));
+
+    return found;
 } // end UniataAhciDetect()
 
 UCHAR
@@ -974,6 +1044,31 @@ UniataAhciStatus(
 
 } // end UniataAhciStatus()
 
+VOID
+NTAPI
+UniataAhciSnapAtaRegs(
+    IN PHW_CHANNEL chan,
+    IN ULONG DeviceNumber,
+ IN OUT PIDEREGS_EX regs
+    )
+{
+    ULONG TFD, SIG;
+
+    regs->bDriveHeadReg    = IDE_DRIVE_SELECT_1;
+    TFD = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_TFD);
+    regs->bCommandReg = (UCHAR)(TFD & 0xff);
+    regs->bFeaturesReg = (UCHAR)((TFD >> 8) & 0xff);
+
+    SIG = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_SIG);
+    regs->bSectorCountReg  = (UCHAR)(SIG & 0xff);
+    regs->bSectorNumberReg = (UCHAR)((SIG >> 8) & 0xff);
+    regs->bCylLowReg       = (UCHAR)((SIG >> 16) & 0xff);
+    regs->bCylHighReg      = (UCHAR)((SIG >> 24) & 0xff);
+    regs->bOpFlags = 0;
+
+    return;
+} // end UniataAhciSnapAtaRegs()
+
 ULONG
 NTAPI
 UniataAhciSetupFIS_H2D(
@@ -1083,6 +1178,99 @@ UniataAhciSetupFIS_H2D(
     return 20;
 } // end UniataAhciSetupFIS_H2D()
 
+ULONG
+NTAPI
+UniataAhciSetupFIS_H2D_Direct(
+    IN PHW_DEVICE_EXTENSION deviceExtension,
+    IN ULONG DeviceNumber,
+    IN ULONG lChannel,
+   OUT PUCHAR fis,
+    IN PIDEREGS_EX regs
+    )
+{
+    //ULONG i;
+    //PUCHAR plba;
+    BOOLEAN need48;
+    PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
+    UCHAR command;
+
+    command = regs->bCommandReg;
+
+    KdPrint2((PRINT_PREFIX "  AHCI setup FIS Direct %x, ch %d, dev %d\n", fis, lChannel, DeviceNumber));
+    //i = 0;
+    //plba = (PUCHAR)&lba;
+
+    RtlZeroMemory(fis, 20);
+
+    fis[0] = AHCI_FIS_TYPE_ATA_H2D;  /* host to device */
+    fis[1] = 0x80 | ((UCHAR)DeviceNumber & 0x0f);  /* command FIS (note PM goes here) */
+    fis[IDX_AHCI_o_DriveSelect] = IDE_DRIVE_SELECT_1 |
+             ((AtaCommandFlags[command] & (ATA_CMD_FLAG_LBAIOsupp | ATA_CMD_FLAG_48)) ? IDE_USE_LBA : 0);
+    fis[IDX_AHCI_o_Control] = IDE_DC_A_4BIT;
+
+    // IDE_COMMAND_ATAPI_IDENTIFY should be processed as regular ATA command,
+    // the rest of ATAPI requests are processed via IDE_COMMAND_ATAPI_PACKET
+    if(/*(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_ATAPI_DEVICE) && 
+        */
+        command == IDE_COMMAND_ATAPI_PACKET) { 
+/*        fis[IDX_AHCI_o_Command] = IDE_COMMAND_ATAPI_PACKET;
+        if(feature & ATA_F_DMA) {
+            fis[IDX_AHCI_o_Feature] = (UCHAR)(feature & 0xff);
+        } else {
+            fis[IDX_AHCI_o_CylinderLow] = (UCHAR)(count & 0xff);
+            fis[IDX_AHCI_o_CylinderHigh] = (UCHAR)(count>>8) & 0xff;
+        }*/
+        return 0;
+        //fis[IDX_AHCI_o_Control] |= IDE_DC_A_4BIT;
+    } else {
+
+        need48 = (regs->bOpFlags & ATA_FLAGS_48BIT_COMMAND) &&
+            chan->lun[DeviceNumber]->IdentifyData.FeaturesSupport.Address48;
+
+        /* translate command into 48bit version */
+        if(need48) {
+            if(AtaCommandFlags[command] & ATA_CMD_FLAG_48supp) {
+                command = AtaCommands48[command];
+            } else {
+                KdPrint2((PRINT_PREFIX "  unhandled LBA48 command\n"));
+                return 0;
+            }
+        }
+
+        fis[IDX_AHCI_o_Command] = command;
+        fis[IDX_AHCI_o_Feature] = regs->bFeaturesReg;
+
+        fis[IDX_AHCI_o_BlockNumber]  = regs->bSectorNumberReg;
+        fis[IDX_AHCI_o_CylinderLow]  = regs->bCylLowReg;
+        fis[IDX_AHCI_o_CylinderHigh] = regs->bCylHighReg;
+
+        fis[IDX_AHCI_o_BlockCount]   = regs->bSectorCountReg;
+
+        if(need48) {
+            //i++;
+            fis[IDX_AHCI_o_Control] |= IDE_DC_USE_HOB;
+
+            fis[IDX_AHCI_o_BlockNumberExp]  = regs->bSectorNumberRegH;
+            fis[IDX_AHCI_o_CylinderLowExp]  = regs->bCylLowRegH;
+            fis[IDX_AHCI_o_CylinderHighExp] = regs->bCylHighRegH;
+
+            fis[IDX_AHCI_o_BlockCountExp]   = regs->bSectorCountRegH;
+
+            fis[IDX_AHCI_o_FeatureExp] = regs->bFeaturesRegH;
+
+            chan->ChannelCtrlFlags |= CTRFLAGS_LBA48;
+        } else {
+            //fis[IDX_AHCI_o_DriveSelect] |= /*IDE_DRIVE_1 |*/ (plba[3] & 0x0f);
+            chan->ChannelCtrlFlags &= ~CTRFLAGS_LBA48;
+        }
+        fis[IDX_AHCI_o_DriveSelect] |= regs->bDriveHeadReg & 0x0f;
+    }
+
+    KdDump(fis, 20);
+
+    return 20;
+} // end UniataAhciSetupFIS_H2D_Direct()
+
 UCHAR
 NTAPI
 UniataAhciWaitCommandReady(
@@ -1304,6 +1492,116 @@ UniataAhciSendPIOCommand(
 
 } // end UniataAhciSendPIOCommand()
 
+UCHAR
+NTAPI
+UniataAhciSendPIOCommandDirect(
+    IN PVOID HwDeviceExtension,
+    IN ULONG lChannel,
+    IN ULONG DeviceNumber,
+    IN PSCSI_REQUEST_BLOCK Srb,
+    IN PIDEREGS_EX regs,
+    IN ULONG wait_flags,
+    IN ULONG timeout
+    )
+{
+    PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
+    PHW_CHANNEL chan = &deviceExtension->chan[lChannel];
+    UCHAR statusByte;
+    PATA_REQ AtaReq;
+    ULONG fis_size;
+    //ULONG tag=0;
+    //PIDE_AHCI_CMD  AHCI_CMD = &(chan->AhciCtlBlock->cmd);
+    PIDE_AHCI_CMD  AHCI_CMD = NULL;
+    USHORT ahci_flags=0;
+//    USHORT bcount=0;
+
+    //PIDE_AHCI_CMD_LIST AHCI_CL = &(chan->AhciCtlBlock->cmd_list[tag]);
+
+    KdPrint2((PRINT_PREFIX "UniataAhciSendPIOCommand: cntrlr %#x:%#x dev %#x, buff %#x, len %#x, WF %#x \n",
+                 deviceExtension->DevIndex, lChannel, DeviceNumber, Srb->DataBuffer, Srb->DataTransferLength, wait_flags ));
+
+//    if(Srb->DataTransferLength/DEV_BSIZE != bcount) {
+//        KdPrint(("  length/DEV_BSIZE != bcount\n"));
+//    }
+
+#ifdef DBG
+    //UniataDumpAhciPortRegs(chan);
+#endif // DBG
+
+    if(!Srb) {
+        KdPrint(("  !Srb\n"));
+        return IDE_STATUS_WRONG;
+        //UniataAhciSetupCmdPtr(AtaReq); // must be called before DMA setup
+        //should be already called on init
+    }
+    AtaReq = (PATA_REQ)(Srb->SrbExtension);
+    //KdPrint(("  Srb %#x, AtaReq %#x\n", Srb, AtaReq));
+
+    AHCI_CMD = AtaReq->ahci.ahci_cmd_ptr;
+    if(!AHCI_CMD) {
+        KdPrint(("  !AHCI_CMD\n"));
+        return IDE_STATUS_WRONG;
+    }
+
+    if(Srb->DataTransferLength) {
+        if(Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
+            ahci_flags |= ATA_AHCI_CMD_WRITE;
+            AtaReq->Flags &= ~REQ_FLAG_READ;
+        } else {
+            AtaReq->Flags |= REQ_FLAG_READ;
+        }
+    }
+
+    fis_size = UniataAhciSetupFIS_H2D_Direct(deviceExtension, DeviceNumber, lChannel,
+           &(AHCI_CMD->cfis[0]),
+            regs);
+
+    if(!fis_size) {
+        KdPrint2(("!fis_size\n"));
+        return IDE_STATUS_WRONG;
+    }
+
+    //KdPrint2(("UniAtaAhciAdjustIoFlags(command, ahci_flags, fis_size, DeviceNumber)\n"));
+    ahci_flags = UniAtaAhciAdjustIoFlags(regs->bCommandReg, ahci_flags, fis_size, DeviceNumber);
+    KdPrint2(("ahci_flags %#x\n", ahci_flags));
+
+    if(Srb->DataTransferLength) {
+        if(!AtapiDmaSetup(HwDeviceExtension,
+                            DeviceNumber,
+                            lChannel,          // logical channel,
+                            Srb,
+                            (PUCHAR)(Srb->DataBuffer),
+                            Srb->DataTransferLength)) {
+            KdPrint2(("  can't setup buffer\n"));
+            return IDE_STATUS_WRONG;
+        }
+    }
+
+    AtaReq->ahci.io_cmd_flags = ahci_flags;
+
+#ifdef DBG
+    //UniataDumpAhciPortRegs(chan);
+#endif // DBG
+
+    UniataAhciBeginTransaction(HwDeviceExtension, lChannel, DeviceNumber, Srb);
+
+#ifdef DBG
+    //UniataDumpAhciPortRegs(chan);
+#endif // DBG
+
+    if(wait_flags == ATA_IMMEDIATE) {
+        statusByte = 0;
+        KdPrint2(("  return imemdiately\n"));
+    } else {
+        statusByte = UniataAhciWaitCommandReady(chan, timeout);
+        UniataAhciStatus(HwDeviceExtension, lChannel, DeviceNumber);
+        UniataAhciEndTransaction(HwDeviceExtension, lChannel, DeviceNumber, Srb);
+    }
+
+    return statusByte;
+
+} // end UniataAhciSendPIOCommandDirect()
+
 BOOLEAN
 NTAPI
 UniataAhciAbortOperation(
index 0d04f2a..aa66652 100644 (file)
@@ -147,6 +147,14 @@ UniataAhciStatus(
     IN ULONG DeviceNumber
     );
 
+VOID
+NTAPI
+UniataAhciSnapAtaRegs(
+    IN PHW_CHANNEL chan,
+    IN ULONG DeviceNumber,
+ IN OUT PIDEREGS_EX regs
+    );
+
 ULONG
 NTAPI
 UniataAhciSetupFIS_H2D(
@@ -195,6 +203,18 @@ UniataAhciSendPIOCommand(
     IN ULONG timeout
     );
 
+UCHAR
+NTAPI
+UniataAhciSendPIOCommandDirect(
+    IN PVOID HwDeviceExtension,
+    IN ULONG lChannel,
+    IN ULONG DeviceNumber,
+    IN PSCSI_REQUEST_BLOCK Srb,
+    IN PIDEREGS_EX regs,
+    IN ULONG wait_flags,
+    IN ULONG timeout
+    );
+
 BOOLEAN
 NTAPI
 UniataAhciAbortOperation(
@@ -387,4 +407,8 @@ BuildAhciInternalSrb (
     IN ULONG Length = 0
     );
 
+#define UniataAhciChanImplemented(deviceExtension, c) \
+    (((deviceExtension)->AHCI_PI) & (1 << c))
+
+
 #endif //__UNIATA_SATA__H__
index 0a99830..94f406b 100644 (file)
@@ -5,7 +5,7 @@
 
 /* The definitions look so crappy, because the code doesn't care 
    whether the source is an array or an integer */
-#define MOV_DD_SWP(a,b) ((a) = RtlUlongByteSwap(*(PULONG)&(b)))
+#define MOV_DD_SWP(a,b) ( ((PULONG)&(a))[0] = RtlUlongByteSwap(*(PULONG)&(b)))
 #define MOV_DW_SWP(a,b) ( ((PUSHORT)&(a))[0] = RtlUshortByteSwap(*(PUSHORT)&(b)))
 #define MOV_SWP_DW2DD(a,b) ((a) = RtlUshortByteSwap(*(PUSHORT)&(b)))
 #define MOV_QD_SWP(a,b) { ((PULONG)&(a))[0] = RtlUlongByteSwap( ((PULONG)&(b))[1]); ((PULONG)&(a))[1] = RtlUlongByteSwap( ((PULONG)&(b))[0]); }
index a93c1cb..3506cff 100644 (file)
@@ -392,13 +392,22 @@ typedef union _CDB {
         UCHAR Immediate: 1;
         UCHAR Reserved1 : 4;
         UCHAR Lun : 3;
-        UCHAR Reserved2[2];
+        UCHAR Reserved2;
+        UCHAR FormatLayerNumber : 2;
+        UCHAR Reserved2_2 : 6;
         UCHAR Start : 1;
         UCHAR LoadEject : 1;
-        UCHAR Reserved3 : 6;
+        UCHAR FL : 1;
+        UCHAR Reserved3 : 1;
+        UCHAR PowerConditions : 4;
         UCHAR Control;
     } START_STOP, *PSTART_STOP;
 
+#define StartStop_Power_NoChg    0x00
+#define StartStop_Power_Idle     0x02
+#define StartStop_Power_Standby  0x03
+#define StartStop_Power_Sleep    0x05
+
     struct _MEDIA_REMOVAL {
         UCHAR OperationCode;
         UCHAR Reserved1 : 5;
@@ -685,6 +694,14 @@ typedef union _CDB {
         UCHAR Control;
     } SET_READ_AHEAD, *PSET_READ_AHEAD;
 
+    struct _REPORT_LUNS {
+        UCHAR OperationCode;    // 0xA0 - SCSIOP_REPORT_LUNS
+        UCHAR Reserved1[5];
+        UCHAR AllocationLength[4];
+        UCHAR Reserved2[1];
+        UCHAR Control;
+    } REPORT_LUNS, *PREPORT_LUNS;
+
 #define SendOpc_DoOpc   0x01
 
     struct _SEND_OPC_INFO {
@@ -901,6 +918,7 @@ typedef union _CDB {
 
   #define SCSIOP_SA_READ_CAPACITY16     0x10
 
+#define SCSIOP_REPORT_LUNS          0xA0
 #define SCSIOP_BLANK                0xA1
 #define SCSIOP_SEND_KEY             0xA3
 #define SCSIOP_REPORT_KEY           0xA4
@@ -1393,6 +1411,9 @@ typedef struct _SENSE_DATA {
 #define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE ((FILE_DEVICE_SCSI << 16) + 0x0507)
 #define IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES   ((FILE_DEVICE_SCSI << 16) + 0x0508)
 #define IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS   ((FILE_DEVICE_SCSI << 16) + 0x0509)
+#define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE ((FILE_DEVICE_SCSI << 16) + 0x050a)
+#define IOCTL_SCSI_MINIPORT_READ_SMART_LOG              ((FILE_DEVICE_SCSI << 16) + 0x050b)
+#define IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG             ((FILE_DEVICE_SCSI << 16) + 0x050c)
 
 // Read Capacity Data - returned in Big Endian format
 
@@ -2902,6 +2923,12 @@ typedef struct _DVD_RPC_KEY {
     UCHAR Reserved2[1];
 } DVD_RPC_KEY, * PDVD_RPC_KEY;
 
+typedef struct _REPORT_LUNS_INFO_HDR {
+    UCHAR ListLength[4];
+    UCHAR Reserved[4];
+} REPORT_LUNS_INFO_HDR, *PREPORT_LUNS_INFO_HDR;
+
+
 #pragma pack(pop)
 
 #endif //__CDRW_DEVICE_H__
index 1674c2f..677b348 100644 (file)
 156.use http://www.winimage.com/readfi15.zip for performance checks
 157.use IOCTL_SCSI_MINIPORT_IDENTIFY in atactl.exe to determine         ...
     PIO/DMA when no uniata.sys is installed                            (+++)
-158.
+158.implement .INF generator
+159.fix bug with invalid INF section under XP+                         (43e2)
+160.add INF handler for SCSI\NET\VEN_UNIATA&PROD_MANAGEMENT_PORT
+161.
\ No newline at end of file
index 9a2ccce..c3e671e 100644 (file)
@@ -204,8 +204,14 @@ typedef struct _ATA_PASS_THROUGH_DIRECT {
   ULONG  TimeOutValue;
   ULONG  ReservedAsUlong;
   PVOID  DataBuffer;
-  UCHAR  PreviousTaskFile[8];
-  UCHAR  CurrentTaskFile[8];
+  union {
+      UCHAR  PreviousTaskFile[8];
+      IDEREGS Regs;
+  };
+  union {
+      UCHAR  CurrentTaskFile[8];
+      IDEREGS RegsH;
+  };
 } ATA_PASS_THROUGH_DIRECT, *PATA_PASS_THROUGH_DIRECT;
 
 #define    ATA_FLAGS_DRDY_REQUIRED 0x01 // Wait for DRDY status from the device before sending the command to the device.
@@ -214,6 +220,8 @@ typedef struct _ATA_PASS_THROUGH_DIRECT {
 #define    ATA_FLAGS_48BIT_COMMAND 0x08 // The ATA command to be send uses the 48 bit LBA feature set.
                                         //   When this flag is set, the contents of the PreviousTaskFile member in the
                                         //   ATA_PASS_THROUGH_DIRECT structure should be valid.
+#define    ATA_FLAGS_USE_DMA       0x10 // Set the transfer mode to DMA.
+#define    ATA_FLAGS_NO_MULTIPLE   0x20 // Read single sector only.
 
 #endif //ATA_FLAGS_DRDY_REQUIRED
 
@@ -221,13 +229,19 @@ typedef struct _ATA_PASS_THROUGH_DIRECT {
 
 #pragma pack(push, 1)
 typedef struct _IDEREGS_EX {
-        UCHAR    bFeaturesReg;           // Used for specifying SMART "commands".
+    union {
+        UCHAR    bFeaturesReg;           // Used for specifying SMART "commands" on input.
+        UCHAR    bErrorReg;              // Error on output.
+    };
         UCHAR    bSectorCountReg;        // IDE sector count register
         UCHAR    bSectorNumberReg;       // IDE sector number register
         UCHAR    bCylLowReg;             // IDE low order cylinder value
         UCHAR    bCylHighReg;            // IDE high order cylinder value
         UCHAR    bDriveHeadReg;          // IDE drive/head register
+    union {
         UCHAR    bCommandReg;            // Actual IDE command.
+        UCHAR    bStatusReg;             // Status register.
+    };
         UCHAR    bOpFlags;               // 00 - send
                                          // 01 - read regs
                                          // 08 - lba48
@@ -236,9 +250,12 @@ typedef struct _IDEREGS_EX {
 #define UNIATA_SPTI_EX_SND               0x00
 #define UNIATA_SPTI_EX_RCV               0x01
 #define UNIATA_SPTI_EX_LBA48             0x08
-#define UNIATA_SPTI_EX_SPEC_TO           0x10
+//#define UNIATA_SPTI_EX_SPEC_TO           0x10
 //#define UNIATA_SPTI_EX_FREEZE_TO         0x20 // do not reset device on timeout and keep interrupts disabled
-#define UNIATA_SPTI_EX_USE_DMA                  0x20 // Force DMA transfer mode
+#define UNIATA_SPTI_EX_USE_DMA                  0x10 // Force DMA transfer mode
+
+// use 'invalid' combination to specify special TO options
+#define UNIATA_SPTI_EX_SPEC_TO           (ATA_FLAGS_DATA_OUT | ATA_FLAGS_DATA_IN)
 
         UCHAR    bFeaturesRegH;          // feature (high part for LBA48 mode)
         UCHAR    bSectorCountRegH;       // IDE sector count register (high part for LBA48 mode)
@@ -288,6 +305,19 @@ typedef struct _UNIATA_CTL {
     };
 } UNIATA_CTL, *PUNIATA_CTL;
 
+typedef struct _SCSI_PASS_THROUGH_WITH_BUFFERS {
+    SCSI_PASS_THROUGH spt;
+    ULONG             Filler;      // realign buffers to double word boundary
+    UCHAR             ucSenseBuf[32];
+    UCHAR             ucDataBuf[512]; // recommended minimum
+} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS;
+
+typedef struct _SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER {
+    SCSI_PASS_THROUGH_DIRECT sptd;
+    ULONG             Filler;      // realign buffer to double word boundary
+    UCHAR             ucSenseBuf[32];
+} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
+
 #endif //UNIATA_CORE
 
 #ifdef __cplusplus
index 087b161..9c3b5b3 100644 (file)
@@ -1,10 +1,10 @@
-#define UNIATA_VER_STR         "42i2"
-#define UNIATA_VER_DOT         0.42.9.2
+#define UNIATA_VER_STR         "43f5"
+#define UNIATA_VER_DOT         0.43.6.5
 #define UNIATA_VER_MJ          0
-#define UNIATA_VER_MN          42
-#define UNIATA_VER_SUB_MJ      9
-#define UNIATA_VER_SUB_MN      2
-#define UNIATA_VER_DOT_COMMA   0,42,9,2
-#define UNIATA_VER_DOT_STR     "0.42.9.2"
+#define UNIATA_VER_MN          43
+#define UNIATA_VER_SUB_MJ      6
+#define UNIATA_VER_SUB_MN      5
+#define UNIATA_VER_DOT_COMMA   0,43,6,5
+#define UNIATA_VER_DOT_STR     "0.43.6.5"
 #define UNIATA_VER_YEAR        2012
 #define UNIATA_VER_YEAR_STR    "2012"