xref: /reactos/drivers/storage/ide/uniata/id_ata.cpp (revision c8d07514)
1 /*++
2 
3 Copyright (c) 2002-2018 Alexandr A. Telyatnikov (Alter)
4 
5 Module Name:
6     id_ata.cpp
7 
8 Abstract:
9     This is the miniport driver for ATA/ATAPI IDE/SATA/AHCI controllers
10     with Busmaster DMA and Serial ATA support
11 
12 Author:
13     Alexander A. Telyatnikov (Alter)
14 
15 Environment:
16     kernel mode only
17 
18 Notes:
19 
20     THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 Revision History:
32 
33     The skeleton was taken from standard ATAPI.SYS from NT4 DDK by
34          Mike Glass (MGlass)
35          Chuck Park (ChuckP)
36 
37     Some parts of code were taken from FreeBSD 4.3-6.1 ATA driver by
38          S�ren Schmidt, Copyright (c) 1998-2007
39 
40     All parts of code are significantly changed/updated by
41          Alter, Copyright (c) 2002-2014:
42 
43     1. Internal command queueing/reordering
44     2. Drive identification
45     3. Support for 2 _independent_ channels in a single PCI device
46     4. Smart host<->drive transfer rate slowdown (for bad cable)
47     5. W2k support (binary compatibility)
48     6. HDD hot swap under NT4
49     7. XP support (binary compatibility)
50     8. Serial ATA (SATA/SATA2/SATA3) support
51     9. NT 3.51 support (binary compatibility)
52     10. AHCI support
53 
54     etc. (See todo.txt)
55 
56 Licence:
57     GPLv2
58 
59 --*/
60 
61 #include "stdafx.h"
62 
63 #ifndef UNIATA_CORE
64 
65 static const CHAR ver_string[] = "\n\nATAPI IDE MiniPort Driver (UniATA) v 0." UNIATA_VER_STR "\n";
66 
67 static const CHAR uniata_comm_name[] = UNIATA_COMM_PORT_VENDOR_STR "    \n";
68 
69 UNICODE_STRING SavedRegPath;
70 WCHAR SavedRegPathBuffer[256];
71 
72 #endif //UNIATA_CORE
73 
74 //UCHAR AtaCommands48[256];
75 //UCHAR AtaCommandFlags[256];
76 
77 ULONG  SkipRaids = 1;
78 ULONG  ForceSimplex = 0;
79 
80 LONGLONG g_Perf = 0;
81 ULONG    g_PerfDt = 0;
82 
83 #ifdef _DEBUG
84 ULONG  g_LogToDisplay = 0;
85 #endif //_DEBUG
86 
87 ULONG  g_WaitBusyInISR = 1;
88 
89 ULONG  g_opt_WaitBusyResetCount = 10000; // 20000
90 ULONG  g_opt_WaitBusyCount = 200; // 20000
91 ULONG  g_opt_WaitBusyDelay = 10;  // 150
92 ULONG  g_opt_WaitDrqDelay  = 10; // 100
93 ULONG  g_opt_WaitBusyLongCount = 2000; // 2000
94 ULONG  g_opt_WaitBusyLongDelay = 250;  // 250
95 ULONG  g_opt_MaxIsrWait = 40;
96 
97 ULONG  g_opt_DriveSelectNanoDelay = 0; // 400; // ns
98 
99 BOOLEAN g_opt_AtapiSendDisableIntr = 0; // 0
100 BOOLEAN g_opt_AtapiDmaRawRead = 1; // 0
101 BOOLEAN g_opt_AtapiNoDma = FALSE;
102 BOOLEAN g_opt_BochsDmaReadWorkaround = FALSE;
103 BOOLEAN hasPCI = FALSE;
104 
105 ULONG g_opt_VirtualMachine = 0; // Auto
106 
107 BOOLEAN InDriverEntry = TRUE;
108 BOOLEAN g_Dump = FALSE;
109 
110 BOOLEAN g_opt_Verbose = 0;
111 
112 BOOLEAN WinVer_WDM_Model = FALSE;
113 ULONG CPU_num = 1;
114 
115 //UCHAR EnableDma = FALSE;
116 //UCHAR EnableReorder = FALSE;
117 
118 UCHAR g_foo = 0;
119 
120 BOOLEAN
121 NTAPI
122 AtapiResetController__(
123     IN PVOID HwDeviceExtension,
124     IN ULONG PathId,
125     IN UCHAR CompleteType
126     );
127 
128 VOID
129 NTAPI
130 AtapiHwInitialize__(
131     IN PHW_DEVICE_EXTENSION deviceExtension,
132     IN ULONG lChannel
133     );
134 
135 VOID
136 NTAPI
137 UniataUserDeviceReset(
138     PHW_DEVICE_EXTENSION deviceExtension,
139     PHW_LU_EXTENSION LunExt,
140     ULONG lChannel
141     );
142 
143 #define RESET_COMPLETE_CURRENT  0x00
144 #define RESET_COMPLETE_ALL      0x01
145 #define RESET_COMPLETE_NONE     0x02
146 
147 #ifndef UNIATA_CORE
148 
149 VOID
150 NTAPI
151 AtapiCallBack_X(
152     IN PVOID HwDeviceExtension
153     );
154 
155 #ifdef UNIATA_USE_XXableInterrupts
156   #define RETTYPE_XXableInterrupts   BOOLEAN
157   #define RETVAL_XXableInterrupts    TRUE
158 #else
159   #define RETTYPE_XXableInterrupts   VOID
160   #define RETVAL_XXableInterrupts
161 #endif
162 
163 RETTYPE_XXableInterrupts
164 NTAPI
165 AtapiInterruptDpc(
166     IN PVOID HwDeviceExtension
167     );
168 
169 RETTYPE_XXableInterrupts
170 NTAPI
171 AtapiEnableInterrupts__(
172     IN PVOID HwDeviceExtension
173     );
174 
175 VOID
176 NTAPI
177 AtapiQueueTimerDpc(
178     IN PVOID HwDeviceExtension,
179     IN ULONG lChannel,
180     IN PHW_TIMER HwScsiTimer,
181     IN ULONG MiniportTimerValue
182     );
183 
184 SCSI_ADAPTER_CONTROL_STATUS
185 NTAPI
186 AtapiAdapterControl(
187     IN PVOID HwDeviceExtension,
188     IN SCSI_ADAPTER_CONTROL_TYPE ControlType,
189     IN PVOID Parameters
190     );
191 
192 #endif //UNIATA_CORE
193 
194 #ifndef UNIATA_CORE
195 
196 BOOLEAN
197 NTAPI
198 AtapiRegGetStringParameterValue(
199     IN PWSTR RegistryPath,
200     IN PWSTR Name,
201     IN PWCHAR Str,
202     IN ULONG MaxLen
203     )
204 {
205 #define ITEMS_TO_QUERY 2 // always 1 greater than what is searched
206     NTSTATUS          status;
207     RTL_QUERY_REGISTRY_TABLE parameters[ITEMS_TO_QUERY];
208     UNICODE_STRING ustr;
209 
210     ustr.Buffer = Str;
211     ustr.Length =
212     ustr.MaximumLength = (USHORT)MaxLen;
213     RtlZeroMemory(parameters, (sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY));
214 
215     parameters[0].Flags         = RTL_QUERY_REGISTRY_DIRECT;
216     parameters[0].Name          = Name;
217     parameters[0].EntryContext  = &ustr;
218     parameters[0].DefaultType   = REG_SZ;
219     parameters[0].DefaultData   = Str;
220     parameters[0].DefaultLength = MaxLen;
221 
222     status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE /*| RTL_REGISTRY_OPTIONAL*/,
223                                     RegistryPath, parameters, NULL, NULL);
224 
225     if(!NT_SUCCESS(status))
226         return FALSE;
227 
228     return TRUE;
229 
230 #undef ITEMS_TO_QUERY
231 } // end AtapiRegGetStringParameterValue()
232 
233 
234 #endif //UNIATA_CORE
235 
236 VOID
237 DDKFASTAPI
238 UniataNanoSleep(
239     ULONG nano
240     )
241 {
242     LONGLONG t;
243     LARGE_INTEGER t0;
244 
245 #ifdef NAVO_TEST
246     return;
247 #endif //NAVO_TEST
248 
249     if(!nano || !g_Perf || !g_PerfDt)
250         return;
251     t = (g_Perf * nano) / g_PerfDt / 1000;
252     if(!t) {
253         t = 1;
254     }
255     do {
256         KeQuerySystemTime(&t0);
257         t--;
258     } while(t);
259 } // end UniataNanoSleep()
260 
261 #define AtapiWritePortN_template(_type, _Type, sz) \
262 VOID \
263 DDKFASTAPI \
264 AtapiWritePort##sz( \
265     IN PHW_CHANNEL chan, \
266     IN ULONGIO_PTR _port, \
267     IN _type  data \
268     ) \
269 { \
270     PIORES res; \
271     if(_port >= IDX_MAX_REG) { \
272         res = (PIORES)(_port);  \
273     } else \
274     if(chan) { \
275         res = &chan->RegTranslation[_port];  \
276     } else {                                     \
277         KdPrint(("invalid io write request @ ch %x, res* %x\n", chan, _port)); \
278         return; \
279     } \
280     if(res->Proc) {             \
281         KdPrint(("PROC io write request @ ch %x, res* %x\n", chan, _port)); \
282         ASSERT(FALSE); /* We should never get here */ \
283     } \
284     if(!res->MemIo) {             \
285         ScsiPortWritePort##_Type((_type*)(ULONGIO_PTR)(res->Addr), data); \
286     } else {                                      \
287         /*KdPrint(("r_mem @ (%x) %x\n", _port, port));*/ \
288         ScsiPortWriteRegister##_Type((_type*)(ULONG_PTR)(res->Addr), data); \
289     }                                                        \
290     return;                                                  \
291 }
292 
293 AtapiWritePortN_template(ULONG,  Ulong,  4);
294 AtapiWritePortN_template(USHORT, Ushort, 2);
295 AtapiWritePortN_template(UCHAR,  Uchar,  1);
296 
297 #define AtapiWritePortExN_template(_type, _Type, sz) \
298 VOID \
299 DDKFASTAPI \
300 AtapiWritePortEx##sz( \
301     IN PHW_CHANNEL chan, \
302     IN ULONGIO_PTR _port, \
303     IN ULONG offs, \
304     IN _type  data \
305     ) \
306 { \
307     PIORES res; \
308     if(_port >= IDX_MAX_REG) { \
309         res = (PIORES)(_port);  \
310     } else \
311     if(chan) { \
312         res = &chan->RegTranslation[_port];  \
313     } else {                                     \
314         KdPrint(("invalid io write request @ ch %x, res* %x, offs %x\n", chan, _port, offs)); \
315         return; \
316     } \
317     if(res->Proc) {             \
318         KdPrint(("PROC io write request @ ch %x, res* %x, offs %x\n", chan, _port, offs)); \
319         ASSERT(FALSE); /* We should never get here */ \
320     } \
321     if(!res->MemIo) {             \
322         ScsiPortWritePort##_Type((_type*)(ULONGIO_PTR)(res->Addr+offs), data); \
323     } else {                                      \
324         /*KdPrint(("r_mem @ (%x) %x\n", _port, port));*/ \
325         ScsiPortWriteRegister##_Type((_type*)(ULONG_PTR)(res->Addr+offs), data); \
326     }                                                        \
327     return;                                                  \
328 }
329 
330 AtapiWritePortExN_template(ULONG,  Ulong,  4);
331 //AtapiWritePortExN_template(USHORT, Ushort, 2);
332 AtapiWritePortExN_template(UCHAR,  Uchar,  1);
333 
334 #define AtapiReadPortN_template(_type, _Type, sz) \
335 _type \
336 DDKFASTAPI \
337 AtapiReadPort##sz( \
338     IN PHW_CHANNEL chan, \
339     IN ULONGIO_PTR _port \
340     ) \
341 { \
342     PIORES res; \
343     if(_port >= IDX_MAX_REG) { \
344         res = (PIORES)(_port);  \
345     } else \
346     if(chan) { \
347         res = &chan->RegTranslation[_port];  \
348     } else {                                     \
349         KdPrint(("invalid io read request @ ch %x, res* %x\n", chan, _port)); \
350         return (_type)(-1); \
351     } \
352     if(res->Proc) {             \
353         KdPrint(("PROC io read request @ ch %x, res* %x\n", chan, _port)); \
354         ASSERT(FALSE); /* We should never get here */ \
355     } \
356     if(!res->MemIo) {             \
357         /*KdPrint(("r_io @ (%x) %x\n", _port, res->Addr));*/ \
358         return ScsiPortReadPort##_Type((_type*)(ULONGIO_PTR)(res->Addr)); \
359     } else {                                      \
360         /*KdPrint(("r_mem @ (%x) %x\n", _port, res->Addr));*/ \
361         return ScsiPortReadRegister##_Type((_type*)(ULONG_PTR)(res->Addr)); \
362     }                                                        \
363 }
364 
365 AtapiReadPortN_template(ULONG,  Ulong,  4);
366 AtapiReadPortN_template(USHORT, Ushort, 2);
367 AtapiReadPortN_template(UCHAR,  Uchar,  1);
368 
369 #define AtapiReadPortExN_template(_type, _Type, sz) \
370 _type \
371 DDKFASTAPI \
372 AtapiReadPortEx##sz( \
373     IN PHW_CHANNEL chan, \
374     IN ULONGIO_PTR _port, \
375     IN ULONG offs \
376     ) \
377 { \
378     PIORES res; \
379     if(_port >= IDX_MAX_REG) { \
380         res = (PIORES)(_port);  \
381     } else \
382     if(chan) { \
383         res = &chan->RegTranslation[_port];  \
384     } else {                                     \
385         KdPrint(("invalid io read request @ ch %x, res* %x, offs %x\n", chan, _port, offs)); \
386         return (_type)(-1); \
387     } \
388     if(res->Proc) {             \
389         KdPrint(("PROC io read request @ ch %x, res* %x, offs %x\n", chan, _port, offs)); \
390         ASSERT(FALSE); /* We should never get here */ \
391     } \
392     if(!res->MemIo) {             \
393         return ScsiPortReadPort##_Type((_type*)(ULONGIO_PTR)(res->Addr+offs)); \
394     } else {                                      \
395         /*KdPrint(("r_mem @ (%x) %x\n", _port, port));*/ \
396         return ScsiPortReadRegister##_Type((_type*)(ULONG_PTR)(res->Addr+offs)); \
397     }                                                        \
398 }
399 
400 AtapiReadPortExN_template(ULONG,  Ulong,  4);
401 //AtapiReadPortExN_template(USHORT, Ushort, 2);
402 AtapiReadPortExN_template(UCHAR,  Uchar,  1);
403 
404 #define AtapiReadPortBufferN_template(_type, _Type, sz) \
405 VOID \
406 DDKFASTAPI \
407 AtapiReadBuffer##sz( \
408     IN PHW_CHANNEL chan, \
409     IN ULONGIO_PTR _port, \
410     IN PVOID Buffer, \
411     IN ULONG Count,   \
412     IN ULONG Timing   \
413     ) \
414 { \
415     PIORES res; \
416                  \
417     if(Timing) { \
418         while(Count) { \
419             (*((_type*)Buffer)) = AtapiReadPort##sz(chan, _port); \
420             Count--; \
421             Buffer = ((_type*)Buffer)+1; \
422             UniataNanoSleep(Timing); \
423         } \
424         return; \
425     } \
426            \
427     if(_port >= IDX_MAX_REG) { \
428         res = (PIORES)(_port);  \
429     } else \
430     if(chan) { \
431         res = &chan->RegTranslation[_port];  \
432     } else {                                     \
433         KdPrint(("invalid io read request @ ch %x, res* %x\n", chan, _port)); \
434         return; \
435     } \
436     if(!res->MemIo) {             \
437         /*KdPrint(("r_io @ (%x) %x\n", _port, res->Addr));*/ \
438         ScsiPortReadPortBuffer##_Type((_type*)(ULONGIO_PTR)(res->Addr), (_type*)Buffer, Count); \
439         return; \
440     }                                                        \
441     while(Count) { \
442         (*((_type*)Buffer)) = ScsiPortReadRegister##_Type((_type*)(ULONG_PTR)(res->Addr)); \
443         Count--; \
444         Buffer = ((_type*)Buffer)+1; \
445     } \
446     return;                                                  \
447 }
448 
449 #define AtapiWritePortBufferN_template(_type, _Type, sz) \
450 VOID \
451 DDKFASTAPI \
452 AtapiWriteBuffer##sz( \
453     IN PHW_CHANNEL chan, \
454     IN ULONGIO_PTR _port, \
455     IN PVOID Buffer, \
456     IN ULONG Count,   \
457     IN ULONG Timing   \
458     ) \
459 { \
460     PIORES res; \
461                  \
462     if(Timing) { \
463         while(Count) { \
464             AtapiWritePort##sz(chan, _port, *((_type*)Buffer)); \
465             Buffer = ((_type*)Buffer)+1; \
466             Count--; \
467             UniataNanoSleep(Timing); \
468         } \
469         return;                                                  \
470     } \
471            \
472     if(_port >= IDX_MAX_REG) { \
473         res = (PIORES)(_port);  \
474     } else \
475     if(chan) { \
476         res = &chan->RegTranslation[_port];  \
477     } else {                                     \
478         KdPrint(("invalid io write request @ ch %x, res* %x\n", chan, _port)); \
479         return; \
480     } \
481     if(!res->MemIo) {             \
482         /*KdPrint(("r_io @ (%x) %x\n", _port, res->Addr));*/ \
483         ScsiPortWritePortBuffer##_Type((_type*)(ULONGIO_PTR)(res->Addr), (_type*)Buffer, Count); \
484         return; \
485     }                                                        \
486     while(Count) { \
487         ScsiPortWriteRegister##_Type((_type*)(ULONG_PTR)(res->Addr), *((_type*)Buffer)); \
488         Count--; \
489         Buffer = ((_type*)Buffer)+1; \
490     } \
491     return;                                                  \
492 }
493 
494 AtapiWritePortBufferN_template(ULONG,  Ulong,  4);
495 AtapiWritePortBufferN_template(USHORT, Ushort, 2);
496 
497 AtapiReadPortBufferN_template(ULONG,  Ulong,  4);
498 AtapiReadPortBufferN_template(USHORT, Ushort, 2);
499 
500 
501 UCHAR
502 DDKFASTAPI
503 AtapiSuckPort2(
504     IN PHW_CHANNEL chan
505     )
506 {
507     UCHAR statusByte;
508     ULONG i;
509 
510     // Assume, proper drive is already seleted
511     WaitOnBusyLong(chan);
512     for (i = 0; i < 0x10000; i++) {
513 
514         GetStatus(chan, statusByte);
515         if (statusByte & IDE_STATUS_DRQ) {
516             // Suck out any remaining bytes and throw away.
517             AtapiReadPort2(chan, IDX_IO1_i_Data);
518             UniataNanoSleep(PIO0_TIMING);
519         } else {
520             break;
521         }
522     }
523     if(i) {
524         KdPrint2((PRINT_PREFIX "AtapiSuckPort2: overrun detected (%#x words)\n", i ));
525     }
526     return statusByte;
527 } // AtapiSuckPort2()
528 
529 ULONG
530 DDKFASTAPI
531 AtapiSuckPortBuffer2(
532     IN PHW_CHANNEL chan,
533     IN PUSHORT Buffer,
534     IN ULONG Count
535     )
536 {
537     UCHAR statusByte;
538     ULONG i;
539     USHORT data;
540     BOOLEAN retry = FALSE;
541 
542     // Assume, proper drive is already seleted
543     WaitOnBusyLong(chan);
544     for (i = 0; i < Count; i++) {
545 
546         GetStatus(chan, statusByte);
547         if (statusByte & IDE_STATUS_DRQ) {
548             // Suck out any remaining bytes and throw away.
549             data = AtapiReadPort2(chan, IDX_IO1_i_Data);
550             (*Buffer) = data;
551             Count--;
552             Buffer++;
553             UniataNanoSleep(PIO0_TIMING);
554             retry = FALSE;
555         } else {
556             if(i<Count && !retry) {
557                 KdPrint2((PRINT_PREFIX "  wait...\n"));
558                 WaitForDrq(chan);
559                 retry = TRUE;
560             }
561             break;
562         }
563     }
564     if(i) {
565         KdPrint2((PRINT_PREFIX "AtapiSuckPortBuffer2: %#x words\n", i ));
566         if(i==Count) {
567             AtapiSuckPort2(chan);
568         }
569     }
570     return i;
571 } // AtapiSuckPortBuffer2()
572 
573 UCHAR
574 DDKFASTAPI
575 SelectDrive(
576     IN PHW_CHANNEL   chan,
577     IN ULONG         DeviceNumber
578     )
579 {
580     if(!chan) {
581         return 0;
582     }
583 /*
584     if(chan->lun[DeviceNumber] &&
585        (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_ATAPI_CHANGER)) {
586         KdPrint3(("  Select %d\n", DeviceNumber));
587     }
588 */
589     if(chan->last_devsel == DeviceNumber) {
590         //KdPrint3(("  Selected %d\n", DeviceNumber));
591         return 1;
592     }
593     AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, DeviceNumber ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1); \
594     chan->last_devsel = DeviceNumber ? 1 : 0;
595     if(!g_opt_DriveSelectNanoDelay) {
596         //KdPrint3(("  Select %d\n", DeviceNumber));
597         return 2;
598     }
599     //KdPrint3(("  Select %d (%d ns)\n", DeviceNumber, g_opt_DriveSelectNanoDelay));
600     UniataNanoSleep(g_opt_DriveSelectNanoDelay);
601     return 2;
602 } // end SelectDrive()
603 
604 UCHAR
605 DDKFASTAPI
606 WaitOnBusy(
607     IN PHW_CHANNEL   chan
608     )
609 {
610     ULONG i;
611     UCHAR Status;
612 
613     GetStatus(chan, Status);
614     for (i=0; i<g_opt_WaitBusyCount; i++) {
615         if (Status & IDE_STATUS_BUSY) {
616             AtapiStallExecution(g_opt_WaitBusyDelay);
617             GetStatus(chan, Status);
618             continue;
619         } else {
620             break;
621         }
622     }
623     return Status;
624 } // end WaitOnBusy()
625 
626 UCHAR
627 DDKFASTAPI
628 WaitOnBusyLong(
629     IN PHW_CHANNEL   chan
630     )
631 {
632     ULONG i;
633     UCHAR Status;
634 
635     Status = WaitOnBusy(chan);
636     if(!(Status & IDE_STATUS_BUSY))
637         return Status;
638     for (i=0; i<g_opt_WaitBusyLongCount; i++) {
639         GetStatus(chan, Status);
640         if (Status & IDE_STATUS_BUSY) {
641             AtapiStallExecution(g_opt_WaitBusyLongDelay);
642             continue;
643         } else {
644             break;
645         }
646     }
647     return Status;
648 } // end WaitOnBusyLong()
649 
650 UCHAR
651 DDKFASTAPI
652 WaitOnBaseBusy(
653     IN PHW_CHANNEL   chan
654     )
655 {
656     ULONG i;
657     UCHAR Status = IDE_STATUS_WRONG;
658     for (i=0; i<g_opt_WaitBusyCount; i++) {
659         GetBaseStatus(chan, Status);
660         if (Status & IDE_STATUS_BUSY) {
661             AtapiStallExecution(g_opt_WaitBusyDelay);
662             continue;
663         } else {
664             break;
665         }
666     }
667     return Status;
668 } // end WaitOnBaseBusy()
669 
670 UCHAR
671 DDKFASTAPI
672 WaitOnBaseBusyLong(
673     IN PHW_CHANNEL   chan
674     )
675 {
676     ULONG i;
677     UCHAR Status;
678 
679     Status = WaitOnBaseBusy(chan);
680     if(!(Status & IDE_STATUS_BUSY))
681         return Status;
682     for (i=0; i<2000; i++) {
683         GetBaseStatus(chan, Status);
684         if (Status & IDE_STATUS_BUSY) {
685             AtapiStallExecution(250);
686             continue;
687         } else {
688             break;
689         }
690     }
691     return Status;
692 } // end WaitOnBaseBusyLong()
693 
694 UCHAR
695 DDKFASTAPI
696 UniataIsIdle(
697     IN struct _HW_DEVICE_EXTENSION* deviceExtension,
698     IN UCHAR Status
699     )
700 {
701     UCHAR Status2;
702 
703     if(Status == IDE_STATUS_WRONG) {
704         return IDE_STATUS_WRONG;
705     }
706     if(Status & IDE_STATUS_BUSY) {
707         return Status;
708     }
709 //    if(deviceExtension->HwFlags & UNIATA_SATA) {
710     if(UniataIsSATARangeAvailable(deviceExtension, 0)) {
711         if(Status & (IDE_STATUS_BUSY | IDE_STATUS_ERROR)) {
712             return Status;
713         }
714     } else {
715         Status2 = Status & ~(IDE_STATUS_ERROR | IDE_STATUS_INDEX);
716         if ((Status & IDE_STATUS_BUSY) ||
717             (Status2 != IDE_STATUS_IDLE && Status2 != IDE_STATUS_DRDY)) {
718             return Status;
719         }
720     }
721     return IDE_STATUS_IDLE;
722 } // end UniataIsIdle()
723 
724 UCHAR
725 DDKFASTAPI
726 WaitForIdleLong(
727     IN PHW_CHANNEL   chan
728     )
729 {
730     ULONG i;
731     UCHAR Status;
732     UCHAR Status2;
733     for (i=0; i<20000; i++) {
734         GetStatus(chan, Status);
735         Status2 = UniataIsIdle(chan->DeviceExtension, Status);
736         if(Status2 == IDE_STATUS_WRONG) {
737             // no drive ?
738             break;
739         } else
740         if(Status2 & IDE_STATUS_BUSY) {
741             AtapiStallExecution(10);
742             continue;
743         } else {
744             break;
745         }
746     }
747     return Status;
748 } // end WaitForIdleLong()
749 
750 UCHAR
751 DDKFASTAPI
752 WaitForDrq(
753     IN PHW_CHANNEL   chan
754     )
755 {
756     ULONG i;
757     UCHAR Status;
758     for (i=0; i<1000; i++) {
759         GetStatus(chan, Status);
760         if (Status & IDE_STATUS_BUSY) {
761             AtapiStallExecution(g_opt_WaitDrqDelay);
762         } else if (Status & IDE_STATUS_DRQ) {
763             break;
764         } else {
765             AtapiStallExecution(g_opt_WaitDrqDelay*2);
766         }
767     }
768     return Status;
769 } // end WaitForDrq()
770 
771 UCHAR
772 DDKFASTAPI
773 WaitShortForDrq(
774     IN PHW_CHANNEL   chan
775     )
776 {
777     ULONG i;
778     UCHAR Status;
779     for (i=0; i<2; i++) {
780         GetStatus(chan, Status);
781         if (Status & IDE_STATUS_BUSY) {
782             AtapiStallExecution(g_opt_WaitDrqDelay);
783         } else if (Status & IDE_STATUS_DRQ) {
784             break;
785         } else {
786             AtapiStallExecution(g_opt_WaitDrqDelay);
787         }
788     }
789     return Status;
790 } // end WaitShortForDrq()
791 
792 VOID
793 DDKFASTAPI
794 AtapiSoftReset(
795     IN PHW_CHANNEL   chan,
796     IN ULONG         DeviceNumber
797     )
798 {
799     //ULONG c = chan->lChannel;
800     ULONG i = 30 * 1000;
801     UCHAR dma_status = 0;
802     KdPrint2((PRINT_PREFIX "AtapiSoftReset:\n"));
803     UCHAR statusByte0, statusByte2;
804 
805     if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
806         UniataAhciSoftReset(chan->DeviceExtension, chan->lChannel, DeviceNumber);
807         return;
808     }
809 
810     GetBaseStatus(chan, statusByte2);
811     KdPrint2((PRINT_PREFIX "  statusByte2 %x:\n", statusByte2));
812     SelectDrive(chan, DeviceNumber);
813     if(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_MANUAL_CHS) {
814         // For ESDI/MFM
815         KdPrint2((PRINT_PREFIX "  ESDI/MFM\n"));
816         AtapiStallExecution(10000);
817         for (i = 0; i < 1000; i++) {
818             AtapiStallExecution(999);
819         }
820 /*    } else
821     // Seems to be unnecessary, verified by KtP
822     if(!hasPCI) {
823         // original atapi.sys behavior for old ISA-only hardware
824         AtapiStallExecution(10000);
825         AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_RESET);
826         for (i = 0; i < 1000; i++) {
827             AtapiStallExecution(999);
828         } */
829     } else {
830         AtapiStallExecution(500);
831         GetBaseStatus(chan, statusByte2);
832         statusByte0 = statusByte2;
833         AtapiWritePort1(chan, IDX_IO1_o_Command, IDE_COMMAND_ATAPI_RESET);
834 
835         // Do not wait for BUSY assertion if it was initially set, jump to
836         // BUSY release wait loop
837         if(!(statusByte0 & IDE_STATUS_BUSY)) {
838             // Wait for BUSY assertion, in some cases delay may occure
839             // 100ms should be enough
840             if(g_opt_VirtualMachine == VM_BOCHS) {
841                 i = 100;
842             } else {
843                 i = 10*1000;
844             }
845             statusByte2 = AtapiReadPort1(chan, IDX_IO1_i_Status);
846             while (!(statusByte2 & IDE_STATUS_BUSY) &&
847                    i--)
848             {
849                 if(!(statusByte0 & IDE_STATUS_ERROR) && (statusByte2 & IDE_STATUS_ERROR)) {
850                     KdPrint2((PRINT_PREFIX "  Command aborted, statusByte2 %x:\n", statusByte2));
851                     break;
852                 }
853                 AtapiStallExecution(10);
854             }
855         }
856 
857         i = 30 * 1000;
858         // ReactOS modification: Already stop looping when we know that the drive has finished resetting.
859         // Not all controllers clear the IDE_STATUS_BUSY flag (e.g. not the VMware one), so ensure that
860         // the maximum waiting time (30 * i = 0.9 seconds) does not exceed the one of the original
861         // implementation. (which is around 1 second)
862         while ((AtapiReadPort1(chan, IDX_IO1_i_Status) & IDE_STATUS_BUSY) &&
863                i--)
864         {
865             AtapiStallExecution(30);
866         }
867         KdPrint2((PRINT_PREFIX " set DFLAGS_REINIT_DMA\n"));
868         chan->lun[DeviceNumber]->DeviceFlags |= DFLAGS_REINIT_DMA;
869     }
870 
871     chan->last_devsel = -1; // make sure proper drive would be selected
872     SelectDrive(chan, DeviceNumber);
873     WaitOnBusy(chan);
874     GetBaseStatus(chan, statusByte2);
875     AtapiStallExecution(500);
876 
877     GetBaseStatus(chan, statusByte2);
878     if(chan && chan->DeviceExtension) {
879         dma_status = GetDmaStatus(chan->DeviceExtension, chan->lChannel);
880         KdPrint2((PRINT_PREFIX "  DMA status %#x\n", dma_status));
881     } else {
882         KdPrint2((PRINT_PREFIX "  can't get DMA status\n"));
883     }
884     if(dma_status & BM_STATUS_INTR) {
885         // bullshit, we have DMA interrupt, but had never initiate DMA operation
886         KdPrint2((PRINT_PREFIX "  clear unexpected DMA intr on ATAPI reset\n"));
887         AtapiDmaDone(chan->DeviceExtension, DeviceNumber, chan->lChannel, NULL);
888         GetBaseStatus(chan, statusByte2);
889     }
890     if(chan->DeviceExtension->HwFlags & UNIATA_SATA) {
891         UniataSataClearErr(chan->DeviceExtension, chan->lChannel, UNIATA_SATA_IGNORE_CONNECT, DeviceNumber);
892 /*        if(!(chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE)) {
893             UniataSataClearErr(chan->DeviceExtension, chan->lChannel, UNIATA_SATA_IGNORE_CONNECT, 1);
894         }*/
895     }
896     return;
897 
898 } // end AtapiSoftReset()
899 
900 VOID
901 DDKFASTAPI
902 AtapiHardReset(
903     IN struct _HW_CHANNEL*   chan,
904     IN BOOLEAN               DisableInterrupts,
905     IN ULONG                 Delay
906     )
907 {
908     KdPrint2((PRINT_PREFIX "AtapiHardReset: %d, dis=%d\n", Delay, DisableInterrupts));
909     AtapiWritePort1(chan, IDX_IO2_o_Control, IDE_DC_RESET_CONTROLLER |
910                               (DisableInterrupts ? IDE_DC_DISABLE_INTERRUPTS : 0));
911     chan->last_devsel = -1;
912     AtapiStallExecution(Delay);
913     AtapiWritePort1(chan, IDX_IO2_o_Control, IDE_DC_REENABLE_CONTROLLER);
914 } // end AtapiHardReset()
915 
916 /*
917     Send command to device.
918     Translate to 48-Lba form if required
919 */
920 UCHAR
921 NTAPI
922 AtaCommand48(
923     IN PHW_DEVICE_EXTENSION deviceExtension,
924     IN ULONG DeviceNumber,
925     IN ULONG lChannel,
926     IN UCHAR command,
927     IN ULONGLONG lba,
928     IN USHORT count,
929     IN USHORT feature,
930     IN ULONG wait_flags
931     )
932 {
933     PHW_CHANNEL          chan = &(deviceExtension->chan[lChannel]);
934     UCHAR                statusByte;
935     ULONG i;
936     PUCHAR plba;
937 
938     KdPrint2((PRINT_PREFIX "AtaCommand48: cntrlr %#x:%#x dev %#x, cmd %#x, lba %#I64x count %#x feature %#x\n",
939                  deviceExtension->DevIndex, deviceExtension->Channel, DeviceNumber, command, lba, count, feature ));
940 
941     if(deviceExtension->HwFlags & UNIATA_AHCI) {
942         //PIDE_AHCI_CMD  AHCI_CMD = &(chan->AhciCtlBlock->cmd);
943 
944         KdPrint3(("  (ahci)\n"));
945 
946         statusByte = UniataAhciSendPIOCommand(deviceExtension, lChannel, DeviceNumber,
947             (PSCSI_REQUEST_BLOCK)NULL,
948             NULL,
949             0,
950             command,
951             lba, count,
952             feature,
953             0 /* ahci flags */ ,
954             wait_flags,
955             1000 /* timeout 1 sec */
956             );
957 
958         return statusByte;
959     }
960 
961     SelectDrive(chan, DeviceNumber);
962 
963     statusByte = WaitOnBusy(chan);
964 
965     /* ready to issue command ? */
966     if (statusByte & IDE_STATUS_BUSY) {
967         KdPrint2((PRINT_PREFIX "  Returning BUSY status\n"));
968         return statusByte;
969     }
970     // !!! We should not check ERROR condition here
971     // ERROR bit may be asserted durring previous operation
972     // and not cleared after SELECT
973 
974     //>>>>>> NV: 2006/08/03
975     if(((AtaCommandFlags[command] & (ATA_CMD_FLAG_LBAIOsupp|ATA_CMD_FLAG_FUA)) == ATA_CMD_FLAG_LBAIOsupp) &&
976        CheckIfBadBlock(chan->lun[DeviceNumber], lba, count)) {
977         KdPrint3((PRINT_PREFIX ": artificial bad block, lba %#I64x count %#x\n", lba, count));
978         return IDE_STATUS_ERROR;
979         //return SRB_STATUS_ERROR;
980     }
981     //<<<<<< NV:  2006/08/03
982 
983     /* only use 48bit addressing if needed because of the overhead */
984     if (UniAta_need_lba48(command, lba, count,
985         chan->lun[DeviceNumber]->IdentifyData.FeaturesSupport.Address48)) {
986 
987         KdPrint2((PRINT_PREFIX "  dev %#x USE_LBA_48\n", DeviceNumber ));
988         /* translate command into 48bit version */
989         if(AtaCommandFlags[command] & ATA_CMD_FLAG_48supp) {
990             command = AtaCommands48[command];
991         } else {
992             KdPrint2((PRINT_PREFIX "  unhandled LBA48 command\n"));
993 			return (UCHAR)-1;
994         }
995 
996         chan->ChannelCtrlFlags |= CTRFLAGS_LBA48;
997         plba = (PUCHAR)&lba;
998 
999         AtapiWritePort1(chan, IDX_IO1_o_Feature,      (UCHAR)(feature>>8));
1000         AtapiWritePort1(chan, IDX_IO1_o_Feature,      (UCHAR)feature);
1001         AtapiWritePort1(chan, IDX_IO1_o_BlockCount,   (UCHAR)(count>>8));
1002         AtapiWritePort1(chan, IDX_IO1_o_BlockCount,   (UCHAR)count);
1003         AtapiWritePort1(chan, IDX_IO1_o_BlockNumber,  (UCHAR)(plba[3]));
1004         AtapiWritePort1(chan, IDX_IO1_o_BlockNumber,  (UCHAR)(plba[0]));
1005         AtapiWritePort1(chan, IDX_IO1_o_CylinderLow,  (UCHAR)(plba[4]));
1006         AtapiWritePort1(chan, IDX_IO1_o_CylinderLow,  (UCHAR)(plba[1]));
1007         AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, (UCHAR)(plba[5]));
1008         AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, (UCHAR)(plba[2]));
1009 
1010         //KdPrint2((PRINT_PREFIX "AtaCommand48: dev %#x USE_LBA48 (2)\n", DeviceNumber ));
1011         AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, IDE_USE_LBA | (DeviceNumber ? IDE_DRIVE_2 : IDE_DRIVE_1) );
1012     } else {
1013 
1014         plba = (PUCHAR)&lba; //ktp
1015         chan->ChannelCtrlFlags &= ~CTRFLAGS_LBA48;
1016 
1017         //if(feature ||
1018         //   (chan->lun[DeviceNumber]->DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_TAPE_DEVICE | DFLAGS_LBA_ENABLED))) {
1019             AtapiWritePort1(chan, IDX_IO1_o_Feature,      (UCHAR)feature);
1020         //}
1021         AtapiWritePort1(chan, IDX_IO1_o_BlockCount,   (UCHAR)count);
1022         AtapiWritePort1(chan, IDX_IO1_o_BlockNumber,  (UCHAR)plba[0]);
1023         AtapiWritePort1(chan, IDX_IO1_o_CylinderLow,  (UCHAR)plba[1]);
1024         AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, (UCHAR)plba[2]);
1025         if(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_LBA_ENABLED) {
1026             //KdPrint2((PRINT_PREFIX "AtaCommand28: dev %#x USE_LBA\n", DeviceNumber ));
1027             AtapiWritePort1(chan, IDX_IO1_o_DriveSelect,  (UCHAR)(plba[3] & 0xf) | IDE_USE_LBA | (DeviceNumber ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1) );
1028         } else {
1029             //KdPrint2((PRINT_PREFIX "AtaCommand28: dev %#x USE_CHS\n", DeviceNumber ));
1030             AtapiWritePort1(chan, IDX_IO1_o_DriveSelect,  (UCHAR)(plba[3] & 0xf) | (DeviceNumber ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1) );
1031         }
1032     }
1033 
1034     // write command code to device
1035     AtapiWritePort1(chan, IDX_IO1_o_Command, command);
1036 
1037     switch (wait_flags) {
1038     case ATA_WAIT_INTR:
1039 
1040         // caller requested wait for interrupt
1041         for(i=0;i<4;i++) {
1042             WaitOnBusy(chan);
1043             statusByte = WaitForDrq(chan);
1044             if (statusByte & IDE_STATUS_DRQ)
1045                 break;
1046             AtapiStallExecution(500);
1047             KdPrint2((PRINT_PREFIX "  retry waiting DRQ, status %#x\n", statusByte));
1048         }
1049 
1050         return statusByte;
1051 
1052     case ATA_WAIT_IDLE:
1053 
1054         // caller requested wait for entering Wait state
1055         for (i=0; i<30 * 1000; i++) {
1056 
1057             GetStatus(chan, statusByte);
1058             statusByte = UniataIsIdle(deviceExtension, statusByte);
1059             if(statusByte == IDE_STATUS_WRONG) {
1060                 // no drive ?
1061                 break;
1062             } else
1063             if(statusByte & IDE_STATUS_ERROR) {
1064                 break;
1065             } else
1066             if(statusByte & IDE_STATUS_BUSY) {
1067                 AtapiStallExecution(100);
1068                 continue;
1069             } else
1070             if((statusByte & ~IDE_STATUS_INDEX) == IDE_STATUS_IDLE) {
1071                 break;
1072             } else {
1073                 //if(deviceExtension->HwFlags & UNIATA_SATA) {
1074                 if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
1075                     break;
1076                 }
1077                 AtapiStallExecution(100);
1078             }
1079         }
1080         //statusByte |= IDE_STATUS_BUSY;
1081         break;
1082 
1083     case ATA_WAIT_READY:
1084         statusByte = WaitOnBusyLong(chan);
1085         break;
1086     case ATA_WAIT_BASE_READY:
1087         statusByte = WaitOnBaseBusyLong(chan);
1088         break;
1089     case ATA_IMMEDIATE:
1090         GetStatus(chan, statusByte);
1091         if (statusByte & IDE_STATUS_ERROR) {
1092             KdPrint2((PRINT_PREFIX "  Warning: Immed Status %#x :(\n", statusByte));
1093             if(statusByte == (IDE_STATUS_IDLE | IDE_STATUS_ERROR)) {
1094                 break;
1095             }
1096             KdPrint2((PRINT_PREFIX "  try to continue\n"));
1097             statusByte &= ~IDE_STATUS_ERROR;
1098 
1099         } else {
1100             //KdPrint2((PRINT_PREFIX "  send Status %#x\n", statusByte));
1101         }
1102         UniataExpectChannelInterrupt(chan, TRUE);
1103         // !!!!!
1104         InterlockedExchange(&(chan->CheckIntr),
1105                                       CHECK_INTR_IDLE);
1106 
1107         statusByte = IDE_STATUS_SUCCESS;
1108         break;
1109     }
1110 
1111     //KdPrint2((PRINT_PREFIX "  Status %#x\n", statusByte));
1112 
1113     return statusByte;
1114 } // end AtaCommand48()
1115 
1116 /*
1117     Send command to device.
1118     This is simply wrapper for AtaCommand48()
1119 */
1120 UCHAR
1121 NTAPI
1122 AtaCommand(
1123     IN PHW_DEVICE_EXTENSION deviceExtension,
1124     IN ULONG DeviceNumber,
1125     IN ULONG lChannel,
1126     IN UCHAR command,
1127     IN USHORT cylinder,
1128     IN UCHAR head,
1129     IN UCHAR sector,
1130     IN UCHAR count,
1131     IN UCHAR feature,
1132     IN ULONG wait_flags
1133     )
1134 {
1135     if(!(deviceExtension->HwFlags & UNIATA_AHCI)) {
1136         return AtaCommand48(deviceExtension, DeviceNumber, lChannel,
1137                             command,
1138                             (ULONG)sector | ((ULONG)cylinder << 8) | ((ULONG)(head & 0x0f) << 24),
1139                             count, feature, wait_flags);
1140     } else {
1141         return UniataAhciSendPIOCommand(deviceExtension, lChannel, DeviceNumber,
1142             (PSCSI_REQUEST_BLOCK)NULL,
1143             NULL,
1144             0,
1145             command,
1146             (ULONG)sector | ((ULONG)cylinder << 8) | ((ULONG)(head & 0x0f) << 24),
1147             count,
1148             feature,
1149             0 /* ahci flags */ ,
1150             wait_flags,
1151             1000 /* timeout 1 sec */
1152             );
1153 
1154     }
1155 } // end AtaCommand()
1156 
1157 LONG
1158 NTAPI
1159 AtaPio2Mode(LONG pio)
1160 {
1161     switch (pio) {
1162     default: return ATA_PIO;
1163     case 0: return ATA_PIO0;
1164     case 1: return ATA_PIO1;
1165     case 2: return ATA_PIO2;
1166     case 3: return ATA_PIO3;
1167     case 4: return ATA_PIO4;
1168     case 5: return ATA_PIO5;
1169     }
1170 } // end AtaPio2Mode()
1171 
1172 LONG
1173 NTAPI
1174 AtaPioMode(PIDENTIFY_DATA2 ident)
1175 {
1176     if (ident->PioTimingsValid) {
1177         if (ident->AdvancedPIOModes & AdvancedPIOModes_5)
1178             return 5;
1179         if (ident->AdvancedPIOModes & AdvancedPIOModes_4)
1180             return 4;
1181         if (ident->AdvancedPIOModes & AdvancedPIOModes_3)
1182             return 3;
1183     }
1184     if (ident->PioCycleTimingMode == 2)
1185         return 2;
1186     if (ident->PioCycleTimingMode == 1)
1187         return 1;
1188     if (ident->PioCycleTimingMode == 0)
1189         return 0;
1190     return IOMODE_NOT_SPECIFIED;
1191 } // end AtaPioMode()
1192 
1193 LONG
1194 NTAPI
1195 AtaWmode(PIDENTIFY_DATA2 ident)
1196 {
1197     if (ident->MultiWordDMASupport & 0x04)
1198         return 2;
1199     if (ident->MultiWordDMASupport & 0x02)
1200         return 1;
1201     if (ident->MultiWordDMASupport & 0x01)
1202         return 0;
1203     return IOMODE_NOT_SPECIFIED;
1204 } // end AtaWmode()
1205 
1206 LONG
1207 NTAPI
1208 AtaUmode(PIDENTIFY_DATA2 ident)
1209 {
1210     if (!ident->UdmaModesValid)
1211         return IOMODE_NOT_SPECIFIED;
1212     if (ident->UltraDMASupport & 0x40)
1213         return 6;
1214     if (ident->UltraDMASupport & 0x20)
1215         return 5;
1216     if (ident->UltraDMASupport & 0x10)
1217         return 4;
1218     if (ident->UltraDMASupport & 0x08)
1219         return 3;
1220     if (ident->UltraDMASupport & 0x04)
1221         return 2;
1222     if (ident->UltraDMASupport & 0x02)
1223         return 1;
1224     if (ident->UltraDMASupport & 0x01)
1225         return 0;
1226     return IOMODE_NOT_SPECIFIED;
1227 } // end AtaUmode()
1228 
1229 LONG
1230 NTAPI
1231 AtaSAmode(PIDENTIFY_DATA2 ident) {
1232     if(!ident->SataCapabilities ||
1233        ident->SataCapabilities == 0xffff) {
1234         return IOMODE_NOT_SPECIFIED;
1235     }
1236     if(ident->SataCapabilities & ATA_SATA_GEN3) {
1237         return ATA_SA600;
1238     } else
1239     if(ident->SataCapabilities & ATA_SATA_GEN2) {
1240         return ATA_SA300;
1241     } else
1242     if(ident->SataCapabilities & ATA_SATA_GEN1) {
1243         return ATA_SA150;
1244     }
1245     return IOMODE_NOT_SPECIFIED;
1246 } // end AtaSAmode()
1247 
1248 #ifndef UNIATA_CORE
1249 
1250 VOID
1251 NTAPI
1252 AtapiTimerDpc(
1253     IN PVOID HwDeviceExtension
1254     )
1255 {
1256     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
1257     PHW_TIMER HwScsiTimer;
1258     LARGE_INTEGER time;
1259     ULONG MiniportTimerValue;
1260     BOOLEAN recall = FALSE;
1261     ULONG lChannel;
1262     PHW_CHANNEL chan;
1263 
1264     KdPrint2((PRINT_PREFIX "AtapiTimerDpc:\n"));
1265 
1266     lChannel = deviceExtension->ActiveDpcChan = deviceExtension->FirstDpcChan;
1267     if(lChannel == CHAN_NOT_SPECIFIED) {
1268         KdPrint2((PRINT_PREFIX "AtapiTimerDpc: no items\n"));
1269         return;
1270     }
1271     chan = &(deviceExtension->chan[lChannel]);
1272 
1273     while(TRUE) {
1274 
1275         HwScsiTimer = chan->HwScsiTimer;
1276         chan->HwScsiTimer = NULL;
1277 
1278         deviceExtension->FirstDpcChan = chan->NextDpcChan;
1279         if(deviceExtension->FirstDpcChan != CHAN_NOT_SPECIFIED) {
1280             recall = TRUE;
1281         }
1282 
1283         HwScsiTimer(HwDeviceExtension);
1284 
1285         chan->NextDpcChan = CHAN_NOT_SPECIFIED;
1286 
1287         lChannel = deviceExtension->ActiveDpcChan = deviceExtension->FirstDpcChan;
1288         if(lChannel == CHAN_NOT_SPECIFIED) {
1289             KdPrint2((PRINT_PREFIX "AtapiTimerDpc: no more items\n"));
1290             deviceExtension->FirstDpcChan =
1291             deviceExtension->ActiveDpcChan = CHAN_NOT_SPECIFIED;
1292             return;
1293         }
1294 
1295         KeQuerySystemTime(&time);
1296         KdPrint2((PRINT_PREFIX "AtapiTimerDpc: KeQuerySystemTime=%#x%#x\n", time.HighPart, time.LowPart));
1297 
1298         chan = &deviceExtension->chan[lChannel];
1299         if(time.QuadPart >= chan->DpcTime - 10) {
1300             // call now
1301             KdPrint2((PRINT_PREFIX "AtapiTimerDpc: get next DPC, DpcTime1=%#x%#x\n",
1302                          (ULONG)(chan->DpcTime >> 32), (ULONG)(chan->DpcTime)));
1303             continue;
1304         }
1305         break;
1306     }
1307 
1308     if(recall) {
1309         deviceExtension->ActiveDpcChan = CHAN_NOT_SPECIFIED;
1310         MiniportTimerValue = (ULONG)(time.QuadPart - chan->DpcTime)/10;
1311         if(!MiniportTimerValue)
1312             MiniportTimerValue = 1;
1313 
1314         KdPrint2((PRINT_PREFIX "AtapiTimerDpc: recall AtapiTimerDpc\n"));
1315         ScsiPortNotification(RequestTimerCall, HwDeviceExtension,
1316                              AtapiTimerDpc,
1317                              MiniportTimerValue
1318                              );
1319     }
1320     return;
1321 
1322 } // end AtapiTimerDpc()
1323 
1324 /*
1325     Wrapper for ScsiPort, that implements smart Dpc
1326     queueing. We need it to allow parallel functioning
1327     of IDE channels with shared interrupt. Standard Dpc mechanism
1328     cancels previous Dpc request (if any), but we need Dpc queue.
1329 */
1330 VOID
1331 NTAPI
1332 AtapiQueueTimerDpc(
1333     IN PVOID HwDeviceExtension,
1334     IN ULONG lChannel,
1335     IN PHW_TIMER HwScsiTimer,
1336     IN ULONG MiniportTimerValue
1337     )
1338 {
1339     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
1340     LARGE_INTEGER time;
1341     LARGE_INTEGER time2;
1342     ULONG i;
1343     PHW_CHANNEL prev_chan;
1344     PHW_CHANNEL chan;
1345 //    BOOLEAN UseRequestTimerCall = TRUE;
1346 
1347     KdPrint2((PRINT_PREFIX "AtapiQueueTimerDpc: dt=%d for lChn %#x\n", MiniportTimerValue, lChannel));
1348     KeQuerySystemTime(&time);
1349     time2 = time;
1350     KdPrint2((PRINT_PREFIX "AtapiQueueTimerDpc: KeQuerySystemTime=%#x%#x\n", time.HighPart, time.LowPart));
1351     time.QuadPart += MiniportTimerValue*10;
1352     KdPrint2((PRINT_PREFIX "AtapiQueueTimerDpc: KeQuerySystemTime2=%#x%#x\n", time.HighPart, time.LowPart));
1353 
1354     KdPrint2((PRINT_PREFIX "  ActiveDpcChan=%d, FirstDpcChan=%d\n", deviceExtension->ActiveDpcChan, deviceExtension->FirstDpcChan));
1355 
1356     i = deviceExtension->FirstDpcChan;
1357     chan = prev_chan = NULL;
1358     while(i != CHAN_NOT_SPECIFIED) {
1359         prev_chan = chan;
1360         chan = &(deviceExtension->chan[i]);
1361         if(chan->DpcTime > time.QuadPart) {
1362             break;
1363         }
1364         i = chan->NextDpcChan;
1365     }
1366     chan = &(deviceExtension->chan[lChannel]);
1367     if(!prev_chan) {
1368         deviceExtension->FirstDpcChan = lChannel;
1369     } else {
1370         prev_chan->NextDpcChan = lChannel;
1371     }
1372     chan->NextDpcChan = i;
1373     chan->HwScsiTimer = HwScsiTimer;
1374     chan->DpcTime     = time.QuadPart;
1375 
1376     KdPrint2((PRINT_PREFIX "AtapiQueueTimerDpc: KeQuerySystemTime3=%#x%#x\n", time2.HighPart, time2.LowPart));
1377     if(time.QuadPart <= time2.QuadPart) {
1378         MiniportTimerValue = 1;
1379     } else {
1380         MiniportTimerValue = (ULONG)((time.QuadPart - time2.QuadPart) / 10);
1381     }
1382 
1383     KdPrint2((PRINT_PREFIX "AtapiQueueTimerDpc: dt=%d for lChn %#x\n", MiniportTimerValue, lChannel));
1384     ScsiPortNotification(RequestTimerCall, HwDeviceExtension,
1385                          AtapiTimerDpc,
1386                          MiniportTimerValue);
1387 
1388 } // end AtapiQueueTimerDpc()
1389 
1390 #endif //UNIATA_CORE
1391 
1392 #ifdef _DEBUG
1393 VOID
1394 NTAPI
1395 UniataDumpATARegs(
1396     IN PHW_CHANNEL chan
1397     )
1398 {
1399     ULONG                j;
1400     UCHAR                statusByteAlt;
1401 
1402     GetStatus(chan, statusByteAlt);
1403     KdPrint2((PRINT_PREFIX "  AltStatus (%#x)\n", statusByteAlt));
1404 
1405     for(j=1; j<IDX_IO1_SZ; j++) {
1406         statusByteAlt = AtapiReadPort1(chan, IDX_IO1+j);
1407         KdPrint2((PRINT_PREFIX
1408                    "  Reg_%#x (%#x) = %#x\n",
1409                    j,
1410                    chan->RegTranslation[IDX_IO1+j].Addr,
1411                    statusByteAlt));
1412     }
1413     if(!chan->RegTranslation[IDX_BM_IO].Addr) {
1414         return;
1415     }
1416     for(j=0; j<IDX_BM_IO_SZ-1; j++) {
1417         statusByteAlt = AtapiReadPort1(chan, IDX_BM_IO+j);
1418         KdPrint2((PRINT_PREFIX
1419                    "  BM_%#x (%#x) = %#x\n",
1420                    j,
1421                    chan->RegTranslation[IDX_BM_IO+j].Addr,
1422                    statusByteAlt));
1423     }
1424     return;
1425 } // end UniataDumpATARegs()
1426 #endif //_DEBUG
1427 
1428 VOID
1429 NTAPI
1430 UniataSnapAtaRegs(
1431     IN PHW_CHANNEL chan,
1432     IN ULONG DeviceNumber,
1433  IN OUT PIDEREGS_EX regs
1434     )
1435 {
1436     if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
1437         // AHCI
1438         UniataAhciSnapAtaRegs(chan, DeviceNumber, regs);
1439     } else {
1440         // SATA/PATA, assume drive is selected
1441         ULONG                j;
1442         UCHAR                statusByteAlt;
1443 
1444         if((regs->bOpFlags & ATA_FLAGS_48BIT_COMMAND) == 0) {
1445             for(j=IDX_IO1_i_Error; j<=IDX_IO1_i_Status; j++) {
1446                 statusByteAlt = AtapiReadPort1(chan, IDX_IO1+j);
1447                 ((PUCHAR)regs)[j-1] = statusByteAlt;
1448             }
1449             regs->bOpFlags = 0;
1450         } else {
1451             regs->bDriveHeadReg    = AtapiReadPort1(chan, IDX_IO1_i_DriveSelect);
1452             for(j=IDX_IO1_i_Error; j<IDX_IO1_i_DriveSelect; j++) {
1453                 statusByteAlt = AtapiReadPort1(chan, IDX_IO1+j);
1454                 ((PUCHAR)regs)[j-1] = statusByteAlt;
1455                 statusByteAlt = AtapiReadPort1(chan, IDX_IO1+j);
1456                 ((PUCHAR)regs)[j+8-1] = statusByteAlt;
1457             }
1458             regs->bCommandReg      = AtapiReadPort1(chan, IDX_IO1_i_Status);
1459         }
1460     }
1461     return;
1462 } // end UniataSnapAtaRegs()
1463 
1464 /*++
1465 
1466 Routine Description:
1467 
1468     Issue IDENTIFY command to a device.
1469 
1470 Arguments:
1471 
1472     HwDeviceExtension - HBA miniport driver's adapter data storage
1473     DeviceNumber - Indicates which device.
1474     Command - Either the standard (EC) or the ATAPI packet (A1) IDENTIFY.
1475 
1476 Return Value:
1477 
1478     TRUE if all goes well.
1479 
1480 --*/
1481 BOOLEAN
1482 NTAPI
1483 IssueIdentify(
1484     IN PVOID HwDeviceExtension,
1485     IN ULONG DeviceNumber,
1486     IN ULONG lChannel,
1487     IN UCHAR Command,
1488     IN BOOLEAN NoSetup
1489     )
1490 {
1491     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
1492     PHW_CHANNEL          chan = &(deviceExtension->chan[lChannel]);
1493     ULONG                waitCount = 50000;
1494     ULONG                j;
1495     UCHAR                statusByte;
1496     //UCHAR                statusByte2;
1497     UCHAR                signatureLow,
1498                          signatureHigh;
1499     BOOLEAN              atapiDev = FALSE;
1500     BOOLEAN              use_ahci = FALSE;
1501     PHW_LU_EXTENSION     LunExt = chan->lun[DeviceNumber];
1502 
1503     use_ahci = UniataIsSATARangeAvailable(deviceExtension, lChannel) &&
1504         (deviceExtension->HwFlags & UNIATA_AHCI);
1505 
1506     if(chan->ChannelCtrlFlags & CTRFLAGS_AHCI_PM) {
1507         if(chan->PmLunMap & (1 << DeviceNumber)) {
1508             // OK
1509         } else {
1510             KdPrint2((PRINT_PREFIX "IssueIdentify: PM empty port\n"));
1511             return FALSE;
1512         }
1513     } else
1514     if(DeviceNumber && (chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE)) {
1515         KdPrint2((PRINT_PREFIX "IssueIdentify: NO SLAVE\n"));
1516         return FALSE;
1517     }
1518     if(LunExt->DeviceFlags & DFLAGS_HIDDEN) {
1519         KdPrint2((PRINT_PREFIX "IssueIdentify: HIDDEN\n"));
1520         return FALSE;
1521     }
1522 
1523     if(use_ahci) {
1524         statusByte = WaitOnBusyLong(chan);
1525 #ifdef _DEBUG
1526         if(!chan->AhciInternalAtaReq) {
1527             KdPrint2((PRINT_PREFIX "!AhciInternalAtaReq\n"));
1528         }
1529 #endif
1530     } else {
1531         SelectDrive(chan, DeviceNumber);
1532         AtapiStallExecution(10);
1533         statusByte = WaitOnBusyLong(chan);
1534         // Check that the status register makes sense.
1535         GetBaseStatus(chan, statusByte);
1536         /*
1537         // unnecessary
1538         if(!hasPCI) {
1539             // original atapi.sys behavior for old ISA-only hardware
1540             AtapiStallExecution(100);
1541         }
1542         */
1543     }
1544 
1545     if (Command == IDE_COMMAND_IDENTIFY) {
1546         // Mask status byte ERROR bits.
1547         statusByte = UniataIsIdle(deviceExtension, statusByte & ~(IDE_STATUS_ERROR | IDE_STATUS_INDEX));
1548         KdPrint2((PRINT_PREFIX "IssueIdentify: Checking for IDE. Status (%#x)\n", statusByte));
1549         // Check if register value is reasonable.
1550 
1551         if(statusByte != IDE_STATUS_IDLE) {
1552 
1553             // No reset here !!!
1554             KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte != IDE_STATUS_IDLE\n"));
1555 
1556             //if(!(deviceExtension->HwFlags & UNIATA_SATA)) {
1557             if(!UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
1558                 SelectDrive(chan, DeviceNumber);
1559                 WaitOnBusyLong(chan);
1560 
1561                 signatureLow = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
1562                 signatureHigh = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
1563 
1564                 if (signatureLow == ATAPI_MAGIC_LSB &&
1565                     signatureHigh == ATAPI_MAGIC_MSB) {
1566                     // Device is Atapi.
1567                     KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (dev %d)\n", DeviceNumber));
1568                     return FALSE;
1569                 }
1570 
1571                 // We really should wait up to 31 seconds
1572                 // The ATA spec. allows device 0 to come back from BUSY in 31 seconds!
1573                 // (30 seconds for device 1)
1574                 do {
1575                     // Wait for Busy to drop.
1576                     AtapiStallExecution(100);
1577                     GetStatus(chan, statusByte);
1578                     if(statusByte == IDE_STATUS_WRONG) {
1579                         KdPrint2((PRINT_PREFIX "IssueIdentify: IDE_STATUS_WRONG (dev %d)\n", DeviceNumber));
1580                         return FALSE;
1581                     }
1582 
1583                 } while ((statusByte & IDE_STATUS_BUSY) && waitCount--);
1584                 GetBaseStatus(chan, statusByte);
1585 
1586                 SelectDrive(chan, DeviceNumber);
1587             } else {
1588                 GetBaseStatus(chan, statusByte);
1589             }
1590             // Another check for signature, to deal with one model Atapi that doesn't assert signature after
1591             // a soft reset.
1592             signatureLow = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
1593             signatureHigh = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
1594 
1595             if (signatureLow == ATAPI_MAGIC_LSB &&
1596                 signatureHigh == ATAPI_MAGIC_MSB) {
1597                 KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (2) (dev %d)\n", DeviceNumber));
1598                 // Device is Atapi.
1599                 return FALSE;
1600             }
1601 
1602             statusByte = UniataIsIdle(deviceExtension, statusByte) & ~IDE_STATUS_INDEX;
1603             if (statusByte != IDE_STATUS_IDLE) {
1604                 // Give up on this.
1605                 KdPrint2((PRINT_PREFIX "IssueIdentify: no dev (dev %d)\n", DeviceNumber));
1606                 return FALSE;
1607             }
1608         }
1609     } else {
1610         KdPrint2((PRINT_PREFIX "IssueIdentify: Checking for ATAPI. Status (%#x)\n", statusByte));
1611         if(statusByte == IDE_STATUS_WRONG) {
1612             return FALSE;
1613         }
1614         //if(!(deviceExtension->HwFlags & UNIATA_SATA)) {
1615         if(!UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
1616             statusByte = WaitForIdleLong(chan);
1617             KdPrint2((PRINT_PREFIX "IssueIdentify: Checking for ATAPI (2). Status (%#x)\n", statusByte));
1618         }
1619         atapiDev = TRUE;
1620     }
1621 
1622 //    if(deviceExtension->HwFlags & UNIATA_SATA) {
1623     if(use_ahci) {
1624         statusByte = UniataAhciSendPIOCommand(HwDeviceExtension, lChannel, DeviceNumber,
1625             (PSCSI_REQUEST_BLOCK)NULL,
1626             (PUCHAR)(&deviceExtension->FullIdentifyData),
1627             DEV_BSIZE,
1628             Command,
1629             0, 0,
1630             0,
1631             0 /* ahci flags */ ,
1632             ATA_WAIT_INTR,
1633             1000 /* timeout 1 sec */
1634             );
1635         j = 9; // AHCI is rather different, skip loop at all
1636     } else
1637     if(LunExt->DeviceFlags & DFLAGS_MANUAL_CHS) {
1638         j = 9; // don't send IDENTIFY, assume it is not supported
1639         KdPrint2((PRINT_PREFIX "IssueIdentify: Manual CHS\n"));
1640         RtlZeroMemory(&(deviceExtension->FullIdentifyData), sizeof(deviceExtension->FullIdentifyData));
1641         RtlCopyMemory(&(deviceExtension->FullIdentifyData), &(LunExt->IdentifyData), sizeof(LunExt->IdentifyData));
1642     } else
1643     if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
1644         j = 4; // skip old-style checks
1645     } else {
1646         j = 0;
1647     }
1648     for (; j < 4*2; j++) {
1649         // Send IDENTIFY command.
1650 
1651         // Load CylinderHigh and CylinderLow with number bytes to transfer for old devices, use 0 for newer.
1652 
1653         statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, Command, (j < 4) ? DEV_BSIZE : 0 /* cyl */, 0, 0, 0, 0, ATA_WAIT_INTR);
1654         // Clear interrupt
1655 
1656         if (!statusByte) {
1657             KdPrint2((PRINT_PREFIX "IssueIdentify: 0-status, not present\n"));
1658             return FALSE;
1659         } else
1660         if (statusByte & IDE_STATUS_DRQ) {
1661             // Read status to acknowledge any interrupts generated.
1662             KdPrint2((PRINT_PREFIX "IssueIdentify: IDE_STATUS_DRQ (%#x)\n", statusByte));
1663             GetBaseStatus(chan, statusByte);
1664             // One last check for Atapi.
1665             if (Command == IDE_COMMAND_IDENTIFY) {
1666                 signatureLow = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
1667                 signatureHigh = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
1668 
1669                 if (signatureLow == ATAPI_MAGIC_LSB &&
1670                     signatureHigh == ATAPI_MAGIC_MSB) {
1671                     KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (3) (dev %d)\n", DeviceNumber));
1672                     // Device is Atapi.
1673                     return FALSE;
1674                 }
1675             }
1676             break;
1677         } else {
1678             KdPrint2((PRINT_PREFIX "IssueIdentify: !IDE_STATUS_DRQ (%#x)\n", statusByte));
1679             if (Command == IDE_COMMAND_IDENTIFY) {
1680                 // Check the signature. If DRQ didn't come up it's likely Atapi.
1681                 signatureLow = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
1682                 signatureHigh = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
1683 
1684                 if (signatureLow == ATAPI_MAGIC_LSB &&
1685                     signatureHigh == ATAPI_MAGIC_MSB) {
1686                     // Device is Atapi.
1687                     KdPrint2((PRINT_PREFIX "IssueIdentify: this is ATAPI (4) (dev %d)\n", DeviceNumber));
1688                     return FALSE;
1689                 }
1690             } else {
1691                 if(!(statusByte & IDE_STATUS_ERROR) && (statusByte & IDE_STATUS_BUSY)) {
1692                     KdPrint2((PRINT_PREFIX "IssueIdentify: DRQ not asserted immediately, BUSY -> WaitForDrq\n"));
1693                     break;
1694                 }
1695             }
1696             // Device didn't respond correctly. It will be given one more chance.
1697             KdPrint2((PRINT_PREFIX "IssueIdentify: DRQ never asserted (%#x). Error reg (%#x)\n",
1698                         statusByte, AtapiReadPort1(chan, IDX_IO1_i_Error)));
1699             GetBaseStatus(chan, statusByte);
1700             AtapiSoftReset(chan,DeviceNumber);
1701 
1702             AtapiDisableInterrupts(deviceExtension, lChannel);
1703             AtapiEnableInterrupts(deviceExtension, lChannel);
1704 
1705             GetBaseStatus(chan, statusByte);
1706             //GetStatus(chan, statusByte);
1707             KdPrint2((PRINT_PREFIX "IssueIdentify: Status after soft reset (%#x)\n", statusByte));
1708         }
1709     }
1710     // Check for error on really stupid master devices that assert random
1711     // patterns of bits in the status register at the slave address.
1712     if ((Command == IDE_COMMAND_IDENTIFY) && (statusByte & IDE_STATUS_ERROR)) {
1713         KdPrint2((PRINT_PREFIX "IssueIdentify: Exit on error (%#x)\n", statusByte));
1714         return FALSE;
1715     }
1716 
1717     if(use_ahci) {
1718         // everything should already be done by controller
1719     } else
1720     if(LunExt->DeviceFlags & DFLAGS_MANUAL_CHS) {
1721         j = 9; // don't send IDENTIFY, assume it is not supported
1722         KdPrint2((PRINT_PREFIX "IssueIdentify: Manual CHS (2)\n"));
1723         statusByte = WaitForDrq(chan);
1724         statusByte = WaitOnBusyLong(chan);
1725             KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
1726         GetBaseStatus(chan, statusByte);
1727     } else {
1728 
1729         KdPrint2((PRINT_PREFIX "IssueIdentify: Status before read words %#x\n", statusByte));
1730         // Suck out 256 words. After waiting for one model that asserts busy
1731         // after receiving the Packet Identify command.
1732         statusByte = WaitForDrq(chan);
1733         statusByte = WaitOnBusyLong(chan);
1734             KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
1735 
1736         if (!(statusByte & IDE_STATUS_DRQ)) {
1737             KdPrint2((PRINT_PREFIX "IssueIdentify: !IDE_STATUS_DRQ (2) (%#x)\n", statusByte));
1738             GetBaseStatus(chan, statusByte);
1739             return FALSE;
1740         }
1741         GetBaseStatus(chan, statusByte);
1742         KdPrint2((PRINT_PREFIX "IssueIdentify: BASE statusByte %#x\n", statusByte));
1743 
1744 #ifdef _DEBUG
1745         if(atapiDev) {
1746           j = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & ATAPI_IR_Mask);
1747           KdPrint3((PRINT_PREFIX "IssueIdentify: iReason %x\n", j));
1748 
1749           j =
1750               AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow);
1751 
1752           j |=
1753               (USHORT)AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8;
1754           KdPrint3((PRINT_PREFIX "IssueIdentify: wCount %x\n", j));
1755 
1756         }
1757 #endif //_DEBUG
1758 
1759         if (atapiDev || !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/) {
1760 
1761             KdPrint2((PRINT_PREFIX "  use 16bit IO\n"));
1762             // ATI/SII chipsets with memory-mapped IO hangs when
1763             // I call ReadBuffer(), probably due to PCI burst/prefetch enabled
1764             // Unfortunately, I don't know yet how to workaround it except
1765             // spacifying manual delay in the way you see below.
1766             ReadBuffer(chan, (PUSHORT)&deviceExtension->FullIdentifyData, 256, PIO0_TIMING);
1767 
1768             // Work around for some IDE and one model Atapi that will present more than
1769             // 256 bytes for the Identify data.
1770             KdPrint2((PRINT_PREFIX "IssueIdentify: suck data port\n", statusByte));
1771             statusByte = AtapiSuckPort2(chan);
1772         } else {
1773             KdPrint2((PRINT_PREFIX "  use 32bit IO\n"));
1774             ReadBuffer2(chan, (PULONG)&deviceExtension->FullIdentifyData, 256/2, PIO0_TIMING);
1775         }
1776 
1777         KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
1778         statusByte = WaitForDrq(chan);
1779         KdPrint2((PRINT_PREFIX "IssueIdentify: statusByte %#x\n", statusByte));
1780         GetBaseStatus(chan, statusByte);
1781     }
1782     KdPrint2((PRINT_PREFIX "IssueIdentify: Status after read words %#x\n", statusByte));
1783 
1784     if(NoSetup) {
1785         KdPrint2((PRINT_PREFIX "IssueIdentify: no setup, exiting\n"));
1786         return TRUE;
1787     }
1788 
1789     KdPrint2((PRINT_PREFIX "Model: %20.20s\n", deviceExtension->FullIdentifyData.ModelNumber));
1790     KdPrint2((PRINT_PREFIX "FW:    %4.4s\n", deviceExtension->FullIdentifyData.FirmwareRevision));
1791     KdPrint2((PRINT_PREFIX "S/N:   %20.20s\n", deviceExtension->FullIdentifyData.SerialNumber));
1792     if(g_opt_VirtualMachine == VM_AUTO) {
1793         if((deviceExtension->FullIdentifyData.FirmwareRevision[0] == 0 ||
1794            deviceExtension->FullIdentifyData.FirmwareRevision[0] == ' ') &&
1795            (deviceExtension->FullIdentifyData.FirmwareRevision[1] == 0 ||
1796            deviceExtension->FullIdentifyData.FirmwareRevision[1] == ' ')) {
1797             // Check for BOCHS VM signature. If no additional PCI devices (e.g. VGA)
1798             // are declared BOCHS looks like regular PC
1799             if (!atapiDev && !AtapiStringCmp ((PCCHAR)(deviceExtension->FullIdentifyData.SerialNumber), "XBDH00", 6)) {
1800                 KdPrint2((PRINT_PREFIX "IssueIdentify: BOCHS HDD\n"));
1801                 g_opt_VirtualMachine = VM_BOCHS;
1802             } else
1803             if (atapiDev && !AtapiStringCmp ((PCCHAR)(deviceExtension->FullIdentifyData.SerialNumber), "XBDC00", 6)) {
1804                 KdPrint2((PRINT_PREFIX "IssueIdentify: BOCHS CD\n"));
1805                 g_opt_VirtualMachine = VM_BOCHS;
1806             }
1807         }
1808     }
1809 
1810     KdPrint2((PRINT_PREFIX "Pio:   %x\n", deviceExtension->FullIdentifyData.PioCycleTimingMode));
1811     if(deviceExtension->FullIdentifyData.PioTimingsValid) {
1812         KdPrint2((PRINT_PREFIX "APio:  %x\n", deviceExtension->FullIdentifyData.AdvancedPIOModes));
1813     }
1814     KdPrint2((PRINT_PREFIX "SWDMA: %x\n", deviceExtension->FullIdentifyData.SingleWordDMAActive));
1815     KdPrint2((PRINT_PREFIX "MWDMA: %x\n", deviceExtension->FullIdentifyData.MultiWordDMAActive));
1816     if(deviceExtension->FullIdentifyData.UdmaModesValid) {
1817         KdPrint2((PRINT_PREFIX "UDMA:  %x/%x\n", deviceExtension->FullIdentifyData.UltraDMAActive, deviceExtension->FullIdentifyData.UltraDMASupport));
1818     }
1819     KdPrint2((PRINT_PREFIX "SATA:  %x\n", deviceExtension->FullIdentifyData.SataEnable));
1820     KdPrint2((PRINT_PREFIX "SATA support: %x, CAPs %#x\n",
1821         deviceExtension->FullIdentifyData.SataSupport,
1822         deviceExtension->FullIdentifyData.SataCapabilities));
1823 
1824     LunExt->LimitedTransferMode =
1825     LunExt->OrigTransferMode =
1826         (UCHAR)ata_cur_mode_from_ident(&(deviceExtension->FullIdentifyData), IDENT_MODE_MAX);
1827     LunExt->TransferMode =
1828         (UCHAR)ata_cur_mode_from_ident(&(deviceExtension->FullIdentifyData), IDENT_MODE_ACTIVE);
1829 
1830     KdPrint2((PRINT_PREFIX "OrigTransferMode: %x, Active: %x\n", LunExt->OrigTransferMode, LunExt->TransferMode));
1831     KdPrint2((PRINT_PREFIX "Accoustic %d, cur %d\n",
1832         deviceExtension->FullIdentifyData.VendorAcoustic,
1833         deviceExtension->FullIdentifyData.CurrentAcoustic
1834         ));
1835     KdPrint2((PRINT_PREFIX "AdvPowerMode %d\n",
1836         deviceExtension->FullIdentifyData.CfAdvPowerMode
1837         ));
1838 
1839     KdPrint2((PRINT_PREFIX "PowerMngt %d/%d, APM %d/%d\n",
1840         deviceExtension->FullIdentifyData.FeaturesEnabled.PowerMngt,
1841         deviceExtension->FullIdentifyData.FeaturesSupport.PowerMngt,
1842         deviceExtension->FullIdentifyData.FeaturesEnabled.APM,
1843         deviceExtension->FullIdentifyData.FeaturesSupport.APM
1844         ));
1845 
1846     // Check out a few capabilities / limitations of the device.
1847     if (deviceExtension->FullIdentifyData.RemovableStatus & 1) {
1848         // Determine if this drive supports the MSN functions.
1849         KdPrint2((PRINT_PREFIX "IssueIdentify: Marking drive %d as removable. SFE = %d\n",
1850                     DeviceNumber,
1851                     deviceExtension->FullIdentifyData.RemovableStatus));
1852         LunExt->DeviceFlags |= DFLAGS_REMOVABLE_DRIVE;
1853     }
1854     if(use_ahci) {
1855         // AHCI doesn't recommend using PIO and multiblock
1856         LunExt->MaximumBlockXfer = 0;
1857     } else
1858     if (deviceExtension->FullIdentifyData.MaximumBlockTransfer) {
1859         // Determine max. block transfer for this device.
1860         LunExt->MaximumBlockXfer =
1861             (UCHAR)(deviceExtension->FullIdentifyData.MaximumBlockTransfer & 0xFF);
1862     }
1863     LunExt->NumOfSectors = 0;
1864     if (Command == IDE_COMMAND_IDENTIFY) {
1865         ULONGLONG NumOfSectors=0;
1866         ULONGLONG NativeNumOfSectors=0;
1867         ULONGLONG cylinders=0;
1868         ULONGLONG tmp_cylinders=0;
1869 
1870         KdPrint2((PRINT_PREFIX "PhysLogSectorSize %#x, %#x, offset %#x\n",
1871                 deviceExtension->FullIdentifyData.PhysLogSectorSize,
1872                 deviceExtension->FullIdentifyData.LargeSectorSize,
1873                 deviceExtension->FullIdentifyData.LogicalSectorOffset
1874                 ));
1875 
1876         KdPrint2((PRINT_PREFIX "NV PM_Sup %d, PM_En %d, En %d, PM ver %#x ver %#x\n",
1877                 deviceExtension->FullIdentifyData.NVCache_PM_Supported,
1878                 deviceExtension->FullIdentifyData.NVCache_PM_Enabled,
1879                 deviceExtension->FullIdentifyData.NVCache_Enabled,
1880                 deviceExtension->FullIdentifyData.NVCache_PM_Version,
1881                 deviceExtension->FullIdentifyData.NVCache_Version
1882                 ));
1883 
1884         KdPrint2((PRINT_PREFIX "R-rate %d\n",
1885                 deviceExtension->FullIdentifyData.NominalMediaRotationRate
1886                 ));
1887         KdPrint2((PRINT_PREFIX "WC %d/%d, LA %d/%d, WB %d/%d, RB %d/%d, Q %d/%d\n",
1888                 deviceExtension->FullIdentifyData.FeaturesEnabled.WriteCache,
1889                 deviceExtension->FullIdentifyData.FeaturesSupport.WriteCache,
1890                 deviceExtension->FullIdentifyData.FeaturesEnabled.LookAhead,
1891                 deviceExtension->FullIdentifyData.FeaturesSupport.LookAhead,
1892                 deviceExtension->FullIdentifyData.FeaturesEnabled.WriteBuffer,
1893                 deviceExtension->FullIdentifyData.FeaturesSupport.WriteBuffer,
1894                 deviceExtension->FullIdentifyData.FeaturesEnabled.ReadBuffer,
1895                 deviceExtension->FullIdentifyData.FeaturesSupport.ReadBuffer,
1896                 deviceExtension->FullIdentifyData.FeaturesEnabled.Queued,
1897                 deviceExtension->FullIdentifyData.FeaturesSupport.Queued
1898                 ));
1899 
1900         KdPrint2((PRINT_PREFIX "Protected %d/%d status %#x, rev %#x\n",
1901                 deviceExtension->FullIdentifyData.FeaturesEnabled.Protected,
1902                 deviceExtension->FullIdentifyData.FeaturesSupport.Protected,
1903                 deviceExtension->FullIdentifyData.SecurityStatus,
1904                 deviceExtension->FullIdentifyData.MasterPasswdRevision
1905                 ));
1906 
1907         // Read very-old-style drive geometry
1908         KdPrint2((PRINT_PREFIX "CHS %#x:%#x:%#x\n",
1909                 deviceExtension->FullIdentifyData.NumberOfCylinders,
1910                 deviceExtension->FullIdentifyData.NumberOfHeads,
1911                 deviceExtension->FullIdentifyData.SectorsPerTrack
1912                 ));
1913         NumOfSectors = deviceExtension->FullIdentifyData.NumberOfCylinders *
1914                        deviceExtension->FullIdentifyData.NumberOfHeads *
1915                        deviceExtension->FullIdentifyData.SectorsPerTrack;
1916         KdPrint2((PRINT_PREFIX "NumOfSectors %#I64x\n", NumOfSectors));
1917         // Check for HDDs > 8Gb
1918         if ((deviceExtension->FullIdentifyData.NumberOfCylinders == 0x3fff) &&
1919 /*            (deviceExtension->FullIdentifyData.TranslationFieldsValid) &&*/
1920              deviceExtension->FullIdentifyData.NumberOfHeads &&
1921              deviceExtension->FullIdentifyData.SectorsPerTrack &&
1922             (NumOfSectors < deviceExtension->FullIdentifyData.UserAddressableSectors)) {
1923             KdPrint2((PRINT_PREFIX "NumberOfCylinders == 0x3fff\n"));
1924             cylinders =
1925                 (deviceExtension->FullIdentifyData.UserAddressableSectors /
1926                     (deviceExtension->FullIdentifyData.NumberOfHeads *
1927                        deviceExtension->FullIdentifyData.SectorsPerTrack));
1928 
1929             KdPrint2((PRINT_PREFIX "cylinders %#I64x\n", cylinders));
1930 
1931             NumOfSectors = cylinders *
1932                            deviceExtension->FullIdentifyData.NumberOfHeads *
1933                            deviceExtension->FullIdentifyData.SectorsPerTrack;
1934 
1935             KdPrint2((PRINT_PREFIX "NumOfSectors %#I64x\n", NumOfSectors));
1936         } else {
1937 
1938         }
1939         // Check for LBA mode
1940         KdPrint2((PRINT_PREFIX "SupportLba flag %#x\n", deviceExtension->FullIdentifyData.SupportLba));
1941         KdPrint2((PRINT_PREFIX "SupportDMA flag %#x\n", deviceExtension->FullIdentifyData.SupportDma));
1942         KdPrint2((PRINT_PREFIX "SoftReset %#x\n", deviceExtension->FullIdentifyData.SoftReset));
1943         KdPrint2((PRINT_PREFIX "SupportIordy %#x, DisableIordy %#x\n",
1944             deviceExtension->FullIdentifyData.SupportIordy,
1945             deviceExtension->FullIdentifyData.DisableIordy
1946             ));
1947         KdPrint2((PRINT_PREFIX "MajorRevision %#x\n", deviceExtension->FullIdentifyData.MajorRevision));
1948         KdPrint2((PRINT_PREFIX "UserAddressableSectors %#x\n", deviceExtension->FullIdentifyData.UserAddressableSectors));
1949         if ( deviceExtension->FullIdentifyData.SupportLba
1950                             ||
1951             (deviceExtension->FullIdentifyData.MajorRevision &&
1952 /*             deviceExtension->FullIdentifyData.TranslationFieldsValid &&*/
1953              deviceExtension->FullIdentifyData.UserAddressableSectors)) {
1954             KdPrint2((PRINT_PREFIX "LBA mode\n"));
1955             LunExt->DeviceFlags |= DFLAGS_LBA_ENABLED;
1956         } else {
1957             KdPrint2((PRINT_PREFIX "Keep orig geometry\n"));
1958             LunExt->DeviceFlags |= DFLAGS_ORIG_GEOMETRY;
1959             goto skip_lba_staff;
1960         }
1961         // Check for LBA48 support
1962         if(LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) {
1963             if(deviceExtension->FullIdentifyData.FeaturesSupport.Address48 &&
1964                deviceExtension->FullIdentifyData.FeaturesEnabled.Address48 &&
1965                deviceExtension->FullIdentifyData.NumberOfHeads &&
1966                deviceExtension->FullIdentifyData.SectorsPerTrack &&
1967                (deviceExtension->FullIdentifyData.UserAddressableSectors48 > NumOfSectors)
1968                ) {
1969                 KdPrint2((PRINT_PREFIX "LBA48\n"));
1970                 cylinders =
1971                     (deviceExtension->FullIdentifyData.UserAddressableSectors48 /
1972                         (deviceExtension->FullIdentifyData.NumberOfHeads *
1973                            deviceExtension->FullIdentifyData.SectorsPerTrack));
1974 
1975                 KdPrint2((PRINT_PREFIX "cylinders %#I64x\n", cylinders));
1976 
1977                 NativeNumOfSectors = cylinders *
1978                                deviceExtension->FullIdentifyData.NumberOfHeads *
1979                                deviceExtension->FullIdentifyData.SectorsPerTrack;
1980 
1981                 KdPrint2((PRINT_PREFIX "NativeNumOfSectors %#I64x\n", NativeNumOfSectors));
1982 
1983                 if(NativeNumOfSectors > NumOfSectors) {
1984                     KdPrint2((PRINT_PREFIX "Update NumOfSectors to %#I64x\n", NativeNumOfSectors));
1985                     NumOfSectors = NativeNumOfSectors;
1986                 }
1987             }
1988 
1989             // Check drive capacity report for LBA48-capable drives.
1990             if(deviceExtension->FullIdentifyData.FeaturesSupport.Address48) {
1991                 ULONG hNativeNumOfSectors;
1992                 KdPrint2((PRINT_PREFIX "Use IDE_COMMAND_READ_NATIVE_SIZE48\n"));
1993 
1994                 statusByte = AtaCommand48(deviceExtension, DeviceNumber, lChannel,
1995                              IDE_COMMAND_READ_NATIVE_SIZE48, 0, 0, 0, ATA_WAIT_READY);
1996 
1997                 if(!(statusByte & IDE_STATUS_ERROR)) {
1998                     if(use_ahci) {
1999                         NativeNumOfSectors = chan->AhciInternalAtaReq->ahci.in_lba;
2000                     } else {
2001                         NativeNumOfSectors = (ULONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) |
2002                                             ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow)  << 8) |
2003                                             ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 16) ;
2004 
2005                         AtapiWritePort1(chan, IDX_IO2_o_Control,
2006                                                IDE_DC_USE_HOB );
2007 
2008                         KdPrint2((PRINT_PREFIX "Read high order bytes\n"));
2009                         NativeNumOfSectors |=
2010                                             (ULONG)((ULONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber)  << 24 );
2011                         hNativeNumOfSectors=
2012                                              (ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) |
2013                                             ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 8) ;
2014                         ((PULONG)&NativeNumOfSectors)[1] = hNativeNumOfSectors;
2015                     }
2016                     KdPrint2((PRINT_PREFIX "NativeNumOfSectors %#I64x\n", NativeNumOfSectors));
2017 
2018                     // Some drives report LBA48 capability while has capacity below 128Gb
2019                     // Probably they support large block-counters.
2020                     // But the problem is that some of them reports higher part of Max LBA equal to lower part.
2021                     // Here we check this
2022                     if((NativeNumOfSectors & 0xffffff) == ((NativeNumOfSectors >> 24) & 0xffffff)) {
2023                         KdPrint2((PRINT_PREFIX "High-order bytes == Low-order bytes !!!\n"));
2024 
2025                         statusByte = AtaCommand48(deviceExtension, DeviceNumber, lChannel,
2026                                      IDE_COMMAND_READ_NATIVE_SIZE48, 0, 0, 0, ATA_WAIT_READY);
2027 
2028                         if(!(statusByte & IDE_STATUS_ERROR)) {
2029                             if(use_ahci) {
2030                                 NativeNumOfSectors = chan->AhciInternalAtaReq->ahci.in_lba;
2031                             } else {
2032                                 NativeNumOfSectors = (ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) |
2033                                                 ((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber)  << 24) |
2034                                                 ((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow)  << 8 ) |
2035                                                 ((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow)  << 32) |
2036                                                 ((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 16) |
2037                                                 ((ULONGLONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 40)
2038                                                 ;
2039                             }
2040                         }
2041 
2042                         if((NativeNumOfSectors & 0xffffff) == ((NativeNumOfSectors >> 24) & 0xffffff)) {
2043                             KdPrint2((PRINT_PREFIX "High-order bytes == Low-order bytes !!! (2)\n"));
2044                             NativeNumOfSectors = 0;
2045                         }
2046                     }
2047 
2048                     if(NumOfSectors <= ATA_MAX_LBA28 &&
2049                        NativeNumOfSectors > NumOfSectors) {
2050 
2051                         KdPrint2((PRINT_PREFIX "Use IDE_COMMAND_SET_NATIVE_SIZE48\n"));
2052                         KdPrint2((PRINT_PREFIX "Update NumOfSectors to %#I64x\n", NativeNumOfSectors));
2053 
2054                         statusByte = AtaCommand48(deviceExtension, DeviceNumber, lChannel,
2055                                      IDE_COMMAND_SET_NATIVE_SIZE, NativeNumOfSectors, 0, 0, ATA_WAIT_READY);
2056                         if(!(statusByte & IDE_STATUS_ERROR)) {
2057                             NumOfSectors = NativeNumOfSectors;
2058                         }
2059                     }
2060                 } // !error
2061             }
2062 
2063             if(NumOfSectors < 0x2100000 /*&& NumOfSectors > 31*1000*1000*/) {
2064                 // check for native LBA size
2065                 // some drives report ~32Gb in Identify Block
2066                 KdPrint2((PRINT_PREFIX "Use IDE_COMMAND_READ_NATIVE_SIZE\n"));
2067 
2068                 statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_READ_NATIVE_SIZE,
2069                              0, IDE_USE_LBA, 0, 0, 0, ATA_WAIT_READY);
2070 
2071                 if(!(statusByte & IDE_STATUS_ERROR)) {
2072                     if(use_ahci) {
2073                         NativeNumOfSectors = chan->AhciInternalAtaReq->ahci.in_lba;
2074                     } else {
2075                         NativeNumOfSectors = (ULONG)AtapiReadPort1(chan, IDX_IO1_i_BlockNumber) |
2076                                             ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderLow) << 8) |
2077                                             ((ULONG)AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh) << 16) |
2078                                            (((ULONG)AtapiReadPort1(chan, IDX_IO1_i_DriveSelect) & 0xf) << 24);
2079                     }
2080                     KdPrint2((PRINT_PREFIX "NativeNumOfSectors %#I64x\n", NativeNumOfSectors));
2081 
2082                     if(NativeNumOfSectors > NumOfSectors) {
2083 
2084                         KdPrint2((PRINT_PREFIX "Use IDE_COMMAND_SET_NATIVE_SIZE\n"));
2085                         KdPrint2((PRINT_PREFIX "Update NumOfSectors to %#I64x\n", NativeNumOfSectors));
2086 
2087                         statusByte = AtaCommand48(deviceExtension, DeviceNumber, lChannel,
2088                                      IDE_COMMAND_SET_NATIVE_SIZE, NativeNumOfSectors, 0, 0, ATA_WAIT_READY);
2089                         if(!(statusByte & IDE_STATUS_ERROR)) {
2090                             NumOfSectors = NativeNumOfSectors;
2091                         }
2092                     }
2093                 }
2094             }
2095 
2096             if(NumOfSectors > ATA_MAX_IOLBA28) {
2097               KdPrint2((PRINT_PREFIX "2TB threshold, force LBA64 WRITE requirement\n"));
2098               LunExt->DeviceFlags |= DFLAGS_LBA32plus;
2099             }
2100         } // if(LunExt->DeviceFlags & DFLAGS_LBA_ENABLED)
2101 
2102         // fill IdentifyData with bogus geometry
2103         KdPrint2((PRINT_PREFIX "requested LunExt->GeomType=%x\n", LunExt->opt_GeomType));
2104         if(deviceExtension->FullIdentifyData.CurrentSectorsPerTrack &&
2105            deviceExtension->FullIdentifyData.NumberOfCurrentHeads) {
2106           tmp_cylinders = NumOfSectors / (deviceExtension->FullIdentifyData.CurrentSectorsPerTrack *
2107                                           deviceExtension->FullIdentifyData.NumberOfCurrentHeads);
2108         } else
2109         if(deviceExtension->FullIdentifyData.SectorsPerTrack &&
2110            deviceExtension->FullIdentifyData.NumberOfHeads) {
2111             KdPrint2((PRINT_PREFIX "Current C/H = %#I64x/%#I64x\n",
2112                 deviceExtension->FullIdentifyData.CurrentSectorsPerTrack,
2113                 deviceExtension->FullIdentifyData.NumberOfCurrentHeads));
2114             tmp_cylinders = NumOfSectors / (deviceExtension->FullIdentifyData.SectorsPerTrack *
2115                                             deviceExtension->FullIdentifyData.NumberOfHeads);
2116         } else {
2117             tmp_cylinders = 0;
2118         }
2119         KdPrint2((PRINT_PREFIX "tmp_cylinders = %#I64x\n", tmp_cylinders));
2120         if((tmp_cylinders < 0xffff) || (LunExt->opt_GeomType == GEOM_ORIG)) {
2121             // ok, we can keep original values
2122             if(LunExt->opt_GeomType == GEOM_AUTO) {
2123                 LunExt->opt_GeomType = GEOM_ORIG;
2124             }
2125         } else {
2126             tmp_cylinders = NumOfSectors / (255*63);
2127             if(tmp_cylinders < 0xffff) {
2128                 // we can use generic values for H/S for generic geometry approach
2129                 if(LunExt->opt_GeomType == GEOM_AUTO) {
2130                     LunExt->opt_GeomType = GEOM_STD;
2131                 }
2132             } else {
2133                 // we should use UNIATA geometry approach
2134                 if(LunExt->opt_GeomType == GEOM_AUTO) {
2135                     LunExt->opt_GeomType = GEOM_UNIATA;
2136                 }
2137             }
2138         }
2139 
2140         if(!deviceExtension->FullIdentifyData.SectorsPerTrack ||
2141            !deviceExtension->FullIdentifyData.NumberOfHeads) {
2142             KdPrint2((PRINT_PREFIX "Zero S/H -> Force Use GEOM_STD\n"));
2143         }
2144 
2145         if(LunExt->opt_GeomType == GEOM_STD) {
2146             deviceExtension->FullIdentifyData.CurrentSectorsPerTrack =
2147             deviceExtension->FullIdentifyData.SectorsPerTrack = 63;
2148 
2149             deviceExtension->FullIdentifyData.NumberOfCurrentHeads =
2150             deviceExtension->FullIdentifyData.NumberOfHeads   = 255;
2151 
2152             cylinders = NumOfSectors / (255*63);
2153             KdPrint2((PRINT_PREFIX "Use GEOM_STD, CHS=%I64x/%x/%x\n", cylinders, 255, 63));
2154         } else
2155         if(LunExt->opt_GeomType == GEOM_UNIATA) {
2156             while ((cylinders > 0xffff) && (deviceExtension->FullIdentifyData.SectorsPerTrack < 0x80)) {
2157                 cylinders /= 2;
2158                 KdPrint2((PRINT_PREFIX "cylinders /= 2\n"));
2159                 deviceExtension->FullIdentifyData.SectorsPerTrack *= 2;
2160                 deviceExtension->FullIdentifyData.CurrentSectorsPerTrack *= 2;
2161             }
2162             while ((cylinders > 0xffff) && (deviceExtension->FullIdentifyData.NumberOfHeads < 0x80)) {
2163                 cylinders /= 2;
2164                 KdPrint2((PRINT_PREFIX "cylinders /= 2 (2)\n"));
2165                 deviceExtension->FullIdentifyData.NumberOfHeads *= 2;
2166                 deviceExtension->FullIdentifyData.NumberOfCurrentHeads *= 2;
2167             }
2168             while ((cylinders > 0xffff) && (deviceExtension->FullIdentifyData.SectorsPerTrack < 0x8000)) {
2169                 cylinders /= 2;
2170                 KdPrint2((PRINT_PREFIX "cylinders /= 2 (3)\n"));
2171                 deviceExtension->FullIdentifyData.SectorsPerTrack *= 2;
2172                 deviceExtension->FullIdentifyData.CurrentSectorsPerTrack *= 2;
2173             }
2174             while ((cylinders > 0xffff) && (deviceExtension->FullIdentifyData.NumberOfHeads < 0x8000)) {
2175                 cylinders /= 2;
2176                 KdPrint2((PRINT_PREFIX "cylinders /= 2 (4)\n"));
2177                 deviceExtension->FullIdentifyData.NumberOfHeads *= 2;
2178                 deviceExtension->FullIdentifyData.NumberOfCurrentHeads *= 2;
2179             }
2180             KdPrint2((PRINT_PREFIX "Use GEOM_UNIATA, CHS=%I64x/%x/%x\n", cylinders,
2181                 deviceExtension->FullIdentifyData.NumberOfCurrentHeads,
2182                 deviceExtension->FullIdentifyData.CurrentSectorsPerTrack));
2183         }
2184         if(!cylinders) {
2185             KdPrint2((PRINT_PREFIX "cylinders = tmp_cylinders (%x = %x)\n", cylinders, tmp_cylinders));
2186             cylinders = tmp_cylinders;
2187         }
2188         deviceExtension->FullIdentifyData.NumberOfCurrentCylinders =
2189         deviceExtension->FullIdentifyData.NumberOfCylinders = (USHORT)cylinders;
2190 
2191 skip_lba_staff:
2192 
2193         KdPrint2((PRINT_PREFIX "Geometry: C %#x (%#x)\n",
2194                   deviceExtension->FullIdentifyData.NumberOfCylinders,
2195                   deviceExtension->FullIdentifyData.NumberOfCurrentCylinders
2196                   ));
2197         KdPrint2((PRINT_PREFIX "Geometry: H %#x (%#x)\n",
2198                   deviceExtension->FullIdentifyData.NumberOfHeads,
2199                   deviceExtension->FullIdentifyData.NumberOfCurrentHeads
2200                   ));
2201         KdPrint2((PRINT_PREFIX "Geometry: S %#x (%#x)\n",
2202                   deviceExtension->FullIdentifyData.SectorsPerTrack,
2203                   deviceExtension->FullIdentifyData.CurrentSectorsPerTrack
2204                   ));
2205 
2206         if(NumOfSectors) {
2207             LunExt->NumOfSectors = NumOfSectors;
2208         }
2209         if(deviceExtension->FullIdentifyData.MajorRevision &&
2210            deviceExtension->FullIdentifyData.DoubleWordIo) {
2211             LunExt->DeviceFlags |= DFLAGS_DWORDIO_ENABLED;
2212             KdPrint2((PRINT_PREFIX "IssueIdentify: DWORDIO supported\n"));
2213         }
2214     } else {
2215         // ATAPI
2216         if(deviceExtension->FullIdentifyData.MajorRevision &&
2217            deviceExtension->FullIdentifyData.DoubleWordIo) {
2218             LunExt->DeviceFlags |= DFLAGS_DWORDIO_ENABLED;
2219             KdPrint2((PRINT_PREFIX "IssueIdentify: DFLAGS_DWORDIO_ENABLED.\n"));
2220         }
2221         if(deviceExtension->FullIdentifyData.AtapiDMA.DMADirRequired) {
2222             KdPrint2((PRINT_PREFIX "DMADirRequired.\n"));
2223         }
2224         if(deviceExtension->FullIdentifyData.AtapiByteCount0) {
2225             KdPrint2((PRINT_PREFIX "AtapiByteCount0=%x\n", deviceExtension->FullIdentifyData.AtapiByteCount0));
2226         }
2227     }
2228 
2229     ScsiPortMoveMemory(&LunExt->IdentifyData,
2230                        &deviceExtension->FullIdentifyData,sizeof(IDENTIFY_DATA2));
2231 
2232     InitBadBlocks(LunExt);
2233 
2234     if ((LunExt->IdentifyData.DrqType & ATAPI_DRQT_INTR) &&
2235         (Command != IDE_COMMAND_IDENTIFY)) {
2236 
2237         // This device interrupts with the assertion of DRQ after receiving
2238         // Atapi Packet Command
2239         LunExt->DeviceFlags |= DFLAGS_INT_DRQ;
2240         KdPrint2((PRINT_PREFIX "IssueIdentify: Device interrupts on assertion of DRQ.\n"));
2241 
2242     } else {
2243         KdPrint2((PRINT_PREFIX "IssueIdentify: Device does not interrupt on assertion of DRQ.\n"));
2244     }
2245 
2246     if(Command != IDE_COMMAND_IDENTIFY) {
2247         // ATAPI branch
2248         if(LunExt->IdentifyData.DeviceType == ATAPI_TYPE_TAPE) {
2249             // This is a tape.
2250             LunExt->DeviceFlags |= DFLAGS_TAPE_DEVICE;
2251             KdPrint2((PRINT_PREFIX "IssueIdentify: Device is a tape drive.\n"));
2252         } else
2253         if(LunExt->IdentifyData.DeviceType == ATAPI_TYPE_CDROM ||
2254             LunExt->IdentifyData.DeviceType == ATAPI_TYPE_OPTICAL) {
2255             KdPrint2((PRINT_PREFIX "IssueIdentify: Device is CD/Optical drive.\n"));
2256             // set CD default costs
2257             LunExt->RwSwitchCost  = REORDER_COST_SWITCH_RW_CD;
2258             LunExt->RwSwitchMCost = REORDER_MCOST_SWITCH_RW_CD;
2259             LunExt->SeekBackMCost = REORDER_MCOST_SEEK_BACK_CD;
2260             statusByte = WaitForDrq(chan);
2261         } else {
2262             KdPrint2((PRINT_PREFIX "IssueIdentify: ATAPI drive type %#x.\n",
2263                 LunExt->IdentifyData.DeviceType));
2264         }
2265         KdPrint2((PRINT_PREFIX "IssueIdentify: AtapiCmdSize %#x\n", deviceExtension->FullIdentifyData.AtapiCmdSize));
2266     } else {
2267         KdPrint2((PRINT_PREFIX "IssueIdentify: hard drive.\n"));
2268     }
2269 
2270     GetBaseStatus(chan, statusByte);
2271     KdPrint2((PRINT_PREFIX "IssueIdentify: final Status on exit (%#x)\n", statusByte));
2272     return TRUE;
2273 
2274 } // end IssueIdentify()
2275 
2276 
2277 /*++
2278 
2279 Routine Description:
2280     Set drive parameters using the IDENTIFY data.
2281 
2282 Arguments:
2283     HwDeviceExtension - HBA miniport driver's adapter data storage
2284     DeviceNumber - Indicates which device.
2285 
2286 Return Value:
2287     TRUE if all goes well.
2288 
2289 --*/
2290 BOOLEAN
2291 NTAPI
2292 SetDriveParameters(
2293     IN PVOID HwDeviceExtension,
2294     IN ULONG DeviceNumber,
2295     IN ULONG lChannel
2296     )
2297 {
2298     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
2299     PIDENTIFY_DATA2      identifyData;
2300     PHW_LU_EXTENSION     LunExt;
2301 //    ULONG i;
2302     UCHAR statusByte;
2303     UCHAR errorByte;
2304 
2305     LunExt = deviceExtension->chan[lChannel].lun[DeviceNumber];
2306     identifyData = &(LunExt->IdentifyData);
2307 
2308     if(LunExt->DeviceFlags &
2309           (DFLAGS_LBA_ENABLED | DFLAGS_ORIG_GEOMETRY))
2310        return TRUE;
2311 
2312     KdPrint2((PRINT_PREFIX "SetDriveParameters: Number of heads %#x\n", identifyData->NumberOfHeads));
2313     KdPrint2((PRINT_PREFIX "SetDriveParameters: Sectors per track %#x\n", identifyData->SectorsPerTrack));
2314 
2315     // Send SET PARAMETER command.
2316     statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel,
2317                             IDE_COMMAND_SET_DRIVE_PARAMETERS, 0,
2318                             (identifyData->NumberOfHeads - 1), 0,
2319                             (UCHAR)identifyData->SectorsPerTrack, 0, ATA_WAIT_IDLE);
2320 
2321     statusByte = UniataIsIdle(deviceExtension, statusByte);
2322     if(statusByte & IDE_STATUS_ERROR) {
2323         errorByte = AtapiReadPort1(&deviceExtension->chan[lChannel], IDX_IO1_i_Error);
2324         KdPrint2((PRINT_PREFIX "SetDriveParameters: Error bit set. Status %#x, error %#x\n",
2325                     errorByte, statusByte));
2326         return FALSE;
2327     }
2328 
2329     if(statusByte == IDE_STATUS_IDLE) {
2330         return TRUE;
2331     }
2332 
2333     return FALSE;
2334 
2335 } // end SetDriveParameters()
2336 
2337 VOID
2338 NTAPI
2339 UniataForgetDevice(
2340     PHW_LU_EXTENSION   LunExt
2341     )
2342 {
2343     // keep only DFLAGS_HIDDEN flag
2344     LunExt->DeviceFlags &= DFLAGS_HIDDEN;
2345     LunExt->AtapiReadyWaitDelay = 0;
2346 } // end UniataForgetDevice()
2347 
2348 
2349 /*++
2350 
2351 Routine Description:
2352     Reset IDE controller and/or Atapi device.
2353     ->HwResetBus
2354 
2355 Arguments:
2356     HwDeviceExtension - HBA miniport driver's adapter data storage
2357 
2358 Return Value:
2359     Nothing.
2360 
2361 
2362 --*/
2363 BOOLEAN
2364 NTAPI
2365 AtapiResetController(
2366     IN PVOID HwDeviceExtension,
2367     IN ULONG PathId
2368     )
2369 {
2370     KdPrint2((PRINT_PREFIX "AtapiResetController(%x)\n", PathId));
2371     return AtapiResetController__(HwDeviceExtension, PathId, RESET_COMPLETE_ALL);
2372 } // end AtapiResetController()
2373 
2374 BOOLEAN
2375 NTAPI
2376 AtapiResetController__(
2377     IN PVOID HwDeviceExtension,
2378     IN ULONG PathId,
2379     IN BOOLEAN CompleteType
2380     )
2381 {
2382     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
2383     ULONG                numberChannels  = deviceExtension->NumberChannels;
2384     PHW_CHANNEL          chan = NULL;
2385     ULONG i,j;
2386     ULONG MaxLuns;
2387     UCHAR statusByte;
2388     PSCSI_REQUEST_BLOCK CurSrb;
2389     ULONG ChannelCtrlFlags;
2390     UCHAR dma_status = 0;
2391 
2392     ULONG slotNumber = deviceExtension->slotNumber;
2393     ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber;
2394     ULONG VendorID =  deviceExtension->DevID        & 0xffff;
2395 #ifdef _DEBUG
2396     ULONG DeviceID = (deviceExtension->DevID >> 16) & 0xffff;
2397 #endif
2398     //ULONG RevID    =  deviceExtension->RevID;
2399     ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK;
2400     //UCHAR tmp8;
2401     USHORT tmp16;
2402 
2403     KdPrint2((PRINT_PREFIX "AtapiResetController: Reset IDE %#x/%#x @ %#x\n", VendorID, DeviceID, slotNumber));
2404     KdPrint2((PRINT_PREFIX "simplexOnly %d, VM %x\n", deviceExtension->simplexOnly, g_opt_VirtualMachine));
2405 
2406     if(!deviceExtension->simplexOnly && (PathId != CHAN_NOT_SPECIFIED)) {
2407         // we shall reset both channels on SimplexOnly devices,
2408         // It's not worth doing so on normal controllers
2409         j = PathId;
2410         numberChannels = min(j+1, deviceExtension->NumberChannels);
2411     } else {
2412         j=0;
2413         numberChannels = deviceExtension->NumberChannels;
2414     }
2415 
2416     for (; j < numberChannels; j++) {
2417 
2418         KdPrint2((PRINT_PREFIX "AtapiResetController: Reset lchannel %d[%d]\n", j, deviceExtension->Channel));
2419         chan = &(deviceExtension->chan[j]);
2420         MaxLuns = chan->NumberLuns;
2421         // Save control flags
2422         ChannelCtrlFlags = chan->ChannelCtrlFlags;
2423         KdPrint2((PRINT_PREFIX "  CompleteType %#x, Luns %d, chan %#x, sptr %#x, flags %#x\n", CompleteType, MaxLuns, chan, &chan, ChannelCtrlFlags));
2424         //MaxLuns = (chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE) ? 1 : 2;
2425         if(CompleteType != RESET_COMPLETE_NONE) {
2426 #ifndef UNIATA_CORE
2427             while((CurSrb = UniataGetCurRequest(chan))) {
2428 
2429                 PHW_LU_EXTENSION     LunExt;
2430                 PATA_REQ AtaReq = (PATA_REQ)(CurSrb->SrbExtension);
2431 
2432                 i = GET_CDEV(CurSrb);
2433                 KdPrint2((PRINT_PREFIX "  Lun %x\n", i));
2434                 LunExt = chan->lun[i];
2435 
2436                 KdPrint2((PRINT_PREFIX "AtapiResetController: pending SRB %#x, chan %#x\n", CurSrb, chan));
2437                 if(CurSrb->Cdb[0] == SCSIOP_MECHANISM_STATUS) {
2438                     KdPrint2((PRINT_PREFIX "  was MechStatus\n"));
2439 
2440                     if(!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED)) {
2441                         LunExt->DeviceFlags |= DFLAGS_CHANGER_INITED;
2442                         KdPrint2((PRINT_PREFIX "  set DFLAGS_CHANGER_INITED\n"));
2443                     }
2444                 }
2445                 // Check and see if we are processing an internal srb
2446                 if (AtaReq->OriginalSrb) {
2447                     KdPrint2((PRINT_PREFIX "  restore original SRB %#x\n", AtaReq->OriginalSrb));
2448                     AtaReq->Srb = AtaReq->OriginalSrb;
2449                     CurSrb->SrbExtension = NULL;
2450                     AtaReq->OriginalSrb = NULL;
2451                     // NOTE: internal SRB doesn't get to SRB queue !!!
2452                     CurSrb = AtaReq->Srb;
2453                 }
2454 
2455                 // Remove current request from queue
2456                 UniataRemoveRequest(chan, CurSrb);
2457 
2458                 // Check if request is in progress.
2459                 ASSERT(AtaReq->Srb == CurSrb);
2460                 if (CurSrb) {
2461                     // Complete outstanding request with SRB_STATUS_BUS_RESET.
2462                     UCHAR CurPathId = CurSrb->PathId;
2463                     UCHAR TargetId = CurSrb->TargetId;
2464                     UCHAR Lun = CurSrb->Lun;
2465 
2466                     CurSrb->SrbStatus = ((CompleteType == RESET_COMPLETE_ALL) ? SRB_STATUS_BUS_RESET : SRB_STATUS_ABORTED) | SRB_STATUS_AUTOSENSE_VALID;
2467                     CurSrb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
2468 
2469                     if (CurSrb->SenseInfoBuffer) {
2470 
2471                         PSENSE_DATA  senseBuffer = (PSENSE_DATA)CurSrb->SenseInfoBuffer;
2472                         KdPrint2((PRINT_PREFIX "  senseBuffer %#x, chan %#x, ReqFlags %#x\n", senseBuffer, chan, AtaReq->Flags));
2473 
2474                         senseBuffer->ErrorCode = 0x70;
2475                         senseBuffer->Valid     = 1;
2476                         senseBuffer->AdditionalSenseLength = 0xb;
2477                         if(CompleteType == RESET_COMPLETE_ALL) {
2478                             KdPrint2((PRINT_PREFIX "AtapiResetController: report SCSI_SENSE_UNIT_ATTENTION + SCSI_ADSENSE_BUS_RESET\n"));
2479                             senseBuffer->SenseKey = SCSI_SENSE_UNIT_ATTENTION;
2480                             senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_BUS_RESET;
2481                             senseBuffer->AdditionalSenseCodeQualifier = SCSI_SENSEQ_SCSI_BUS;
2482                         } else {
2483                             KdPrint2((PRINT_PREFIX "AtapiResetController: report SCSI_SENSE_ABORTED_COMMAND\n"));
2484                             senseBuffer->SenseKey = SCSI_SENSE_ABORTED_COMMAND;
2485                             senseBuffer->AdditionalSenseCode = 0;
2486                             senseBuffer->AdditionalSenseCodeQualifier = 0;
2487                         }
2488                     }
2489 
2490                     if(!ATAPI_DEVICE(chan, i) && AtaReq->bcount && AtaReq->retry < MAX_RETRIES) {
2491                         KdPrint2((PRINT_PREFIX "Save IDE retry status %d\n", AtaReq->retry));
2492                         LunExt->errLastLba = AtaReq->lba;
2493                         LunExt->errBCount = AtaReq->bcount;
2494                         LunExt->errRetry = AtaReq->retry+1;
2495                         //KdPrint2((PRINT_PREFIX "AtaReq->Flags & REQ_FLAG_RW_MASK = %x (%x)\n", (AtaReq->Flags & REQ_FLAG_RW_MASK), REQ_FLAG_READ));
2496                         //KdPrint2((PRINT_PREFIX "ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION = %x (%x)\n", ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE, CTRFLAGS_DMA_OPERATION));
2497                         //KdPrint2((PRINT_PREFIX "g_opt_VirtualMachine = %x (%x)\n", g_opt_VirtualMachine, VM_BOCHS));
2498                         if(((AtaReq->Flags & REQ_FLAG_RW_MASK) == REQ_FLAG_READ) &&
2499                            (ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) &&
2500                            (g_opt_VirtualMachine == VM_BOCHS)) {
2501                             KdPrint2((PRINT_PREFIX "set CTRFLAGS_DMA_BEFORE_R on BOCHS\n"));
2502                             g_opt_BochsDmaReadWorkaround = TRUE;
2503                             g_opt_AtapiNoDma = TRUE;
2504                         } else {
2505                             KdPrint2((PRINT_PREFIX "do nothing\n"));
2506                         }
2507                     } else
2508                     if(ATAPI_DEVICE(chan, i) && AtaReq->bcount && !AtaReq->retry) {
2509                         KdPrint2((PRINT_PREFIX "Save ATAPI retry status %d\n", AtaReq->retry));
2510                         LunExt->errLastLba = AtaReq->lba;
2511                         LunExt->errBCount = AtaReq->bcount;
2512                         LunExt->errRetry = AtaReq->retry+1;
2513                         if(((AtaReq->Flags & REQ_FLAG_RW_MASK) == REQ_FLAG_READ) &&
2514                            (ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) &&
2515                            (g_opt_VirtualMachine == VM_BOCHS)) {
2516                             KdPrint2((PRINT_PREFIX "set CTRFLAGS_DMA_BEFORE_R on BOCHS ATAPI\n"));
2517                             //g_opt_BochsDmaReadWorkaround = TRUE;
2518                             g_opt_AtapiNoDma = TRUE;
2519                         } else {
2520                             KdPrint2((PRINT_PREFIX "do nothing\n"));
2521                         }
2522                     } else {
2523                         LunExt->errRetry = 0;
2524                     }
2525 
2526                     // Clear request tracking fields.
2527                     AtaReq->WordsLeft = 0;
2528                     AtaReq->DataBuffer = NULL;
2529                     AtaReq->TransferLength = 0;
2530                     KdPrint2((PRINT_PREFIX "chan %#x\n", chan));
2531 
2532                     ScsiPortNotification(RequestComplete,
2533                                          deviceExtension,
2534                                          CurSrb);
2535 
2536                     // Indicate ready for next request.
2537                     ScsiPortNotification(NextLuRequest,
2538                                          deviceExtension,
2539                                          CurPathId,
2540                                          TargetId,
2541                                          Lun);
2542                 }
2543                 if(CompleteType != RESET_COMPLETE_ALL)
2544                     break;
2545             } // end while()
2546 #endif //UNIATA_CORE
2547         } // end if (!CompleteType != RESET_COMPLETE_NONE)
2548 
2549         // Clear expecting interrupt flag.
2550         UniataExpectChannelInterrupt(chan, FALSE);
2551         chan->RDP = FALSE;
2552         chan->ChannelCtrlFlags = ChannelCtrlFlags & CTRFLAGS_PERMANENT;
2553         InterlockedExchange(&(chan->CheckIntr),
2554                                       CHECK_INTR_IDLE);
2555 
2556         for (i = 0; i < MaxLuns; i++) {
2557             chan->lun[i]->PowerState = 0;
2558         }
2559         // Reset controller
2560         if(ChipFlags & UNIATA_AHCI) {
2561             KdPrint2((PRINT_PREFIX "  AHCI path\n"));
2562             if(UniataAhciChanImplemented(deviceExtension, j)) {
2563 #ifdef _DEBUG
2564                 UniataDumpAhciPortRegs(chan);
2565 #endif
2566                 AtapiDisableInterrupts(deviceExtension, j);
2567                 UniataAhciReset(HwDeviceExtension, j);
2568             } else {
2569                 KdPrint2((PRINT_PREFIX "  skip not implemented\n"));
2570                 continue;
2571             }
2572         } else {
2573             KdPrint2((PRINT_PREFIX "  ATA path, chan %#x\n", chan));
2574             KdPrint2((PRINT_PREFIX "  disable intr (0)\n"));
2575             AtapiDisableInterrupts(deviceExtension, j);
2576             KdPrint2((PRINT_PREFIX "  done\n"));
2577             switch(VendorID) {
2578             case ATA_INTEL_ID: {
2579                 ULONG mask;
2580                 ULONG pshift;
2581                 ULONG timeout;
2582                 if(!(ChipFlags & UNIATA_SATA)) {
2583                     goto default_reset;
2584                 }
2585                 if(!UniataIsSATARangeAvailable(deviceExtension, j)) {
2586                     goto default_reset;
2587                 }
2588 
2589 #if 0
2590                 /* ICH6 & ICH7 in compat mode has 4 SATA ports as master/slave on 2 ch's */
2591                 if(ChipFlags & UNIATA_AHCI) {
2592                     mask = 0x0005 << j;
2593                 } else {
2594                     /* ICH5 in compat mode has SATA ports as master/slave on 1 channel */
2595                     GetPciConfig1(0x90, tmp8);
2596                     if(tmp8 & 0x04) {
2597                         mask = 0x0003;
2598                     } else {
2599                         mask = 0x0001 << j;
2600                     }
2601                 }
2602 #else
2603                 mask = 1 << chan->lun[0]->SATA_lun_map;
2604                 if (MaxLuns > 1) {
2605                     mask |= (1 << chan->lun[1]->SATA_lun_map);
2606                 }
2607 #endif
2608                 ChangePciConfig2(0x92, a & ~mask);
2609                 AtapiStallExecution(10);
2610                 ChangePciConfig2(0x92, a | mask);
2611                 timeout = 100;
2612 
2613                 /* Wait up to 1 sec for "connect well". */
2614                 if (ChipFlags & (I6CH | I6CH2)) {
2615                     pshift = 8;
2616                 } else {
2617                     pshift = 4;
2618                 }
2619                 while (timeout--) {
2620                     GetPciConfig2(0x92, tmp16);
2621                     if (((tmp16 >> pshift) & mask) == mask) {
2622                         GetBaseStatus(chan, statusByte);
2623                         if(statusByte != IDE_STATUS_WRONG) {
2624                             break;
2625                         }
2626                     }
2627                     AtapiStallExecution(10000);
2628                 }
2629                 break; }
2630             case ATA_SIS_ID: {
2631                 KdPrint2((PRINT_PREFIX "  SIS\n"));
2632                 if(!(ChipFlags & UNIATA_SATA))
2633                     goto default_reset;
2634                 break; }
2635 #if 0
2636             case ATA_NVIDIA_ID: {
2637                 KdPrint2((PRINT_PREFIX "  nVidia\n"));
2638                 if(!(ChipFlags & UNIATA_SATA))
2639                     goto default_reset;
2640                 break; }
2641 #else
2642             case ATA_NVIDIA_ID: {
2643                 ULONG offs;
2644                 ULONG Channel = deviceExtension->Channel + j;
2645                 KdPrint2((PRINT_PREFIX "  nVidia\n"));
2646                 if(!(ChipFlags & UNIATA_SATA)) {
2647                     goto default_reset;
2648                 }
2649                 offs = (ChipFlags & NV4OFF) ? 0x0440 : 0x0010;
2650 
2651                 KdPrint2((PRINT_PREFIX "  disable Phy intr, offs %#x, c %u\n", offs, Channel));
2652                 /* disable device and PHY state change interrupts */
2653                 if(ChipFlags & NVQ) {
2654                     KdPrint2((PRINT_PREFIX "  NVQ, 32bits reg\n"));
2655                     AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+4,
2656                         AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+4) & ((~(ULONG)0x0000000d) << (!Channel*16)) );
2657                 } else {
2658                     AtapiWritePortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+1,
2659                         AtapiReadPortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+1) & ((~(UCHAR)0x0d) << (!Channel*4)) );
2660                 }
2661                 tmp16 = UniataSataPhyEnable(HwDeviceExtension, j, 0/* dev0*/, UNIATA_SATA_RESET_ENABLE);
2662 
2663                 KdPrint2((PRINT_PREFIX "  enable Phy intr, offs %#x\n", offs));
2664                 /* enable device and PHY state change interrupts */
2665                 if(ChipFlags & NVQ) {
2666                     AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+4,
2667                         AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+4) | (((ULONG)0x0000000d) << (!Channel*16)) );
2668                 } else {
2669                     AtapiWritePortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+1,
2670                         AtapiReadPortEx1(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs+1) | (((UCHAR)0x0d) << (!Channel*4)) );
2671                 }
2672 
2673                 KdPrint2((PRINT_PREFIX "  dev status %#x\n", tmp16));
2674                 if(tmp16 != IDE_STATUS_WRONG) {
2675                     goto default_reset;
2676                 }
2677                 break; }
2678 #endif //0
2679             case ATA_SILICON_IMAGE_ID: {
2680                 ULONG offset;
2681                 ULONG Channel = deviceExtension->Channel + j;
2682                 if(!(ChipFlags & UNIATA_SATA))
2683                     goto default_reset;
2684                 offset = ((Channel & 1) << 7) + ((Channel & 2) << 8);
2685                 /* disable PHY state change interrupt */
2686                 AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x148 + offset, 0);
2687 
2688                 UniataSataClearErr(HwDeviceExtension, j, UNIATA_SATA_IGNORE_CONNECT, 0);
2689 
2690                 /* reset controller part for this channel */
2691                 AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x48,
2692                      AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x48) | (0xc0 >> Channel));
2693                 AtapiStallExecution(1000);
2694                 AtapiWritePortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x48,
2695                      AtapiReadPortEx4(NULL, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), 0x48) & ~(0xc0 >> Channel));
2696 
2697 
2698                 break; }
2699             case ATA_PROMISE_ID: {
2700                 break; }
2701             default:
2702                 if(ChipFlags & UNIATA_SATA) {
2703                     KdPrint2((PRINT_PREFIX "  SATA generic reset\n"));
2704                     UniataSataClearErr(HwDeviceExtension, j, UNIATA_SATA_IGNORE_CONNECT, 0);
2705                 }
2706 default_reset:
2707 /*
2708                 AtapiWritePort1(chan, IDX_IO2_o_Control, IDE_DC_DISABLE_INTERRUPTS |
2709                                                                         IDE_DC_RESET_CONTROLLER );
2710                 chan->last_devsel = -1;
2711                 KdPrint2((PRINT_PREFIX "  wait a little\n"));
2712                 AtapiStallExecution(10000);
2713                 // Disable interrupts
2714                 KdPrint2((PRINT_PREFIX "  disable intr\n"));
2715                 AtapiDisableInterrupts(deviceExtension, j);
2716                 AtapiStallExecution(100);
2717                 KdPrint2((PRINT_PREFIX "  re-enable intr\n"));
2718                 AtapiEnableInterrupts(deviceExtension, j);
2719                 KdPrint2((PRINT_PREFIX "  wait a little (2)\n"));
2720                 AtapiStallExecution(100000);
2721 */
2722                 AtapiHardReset(chan, TRUE, 100000);
2723                 KdPrint2((PRINT_PREFIX "  disable intr\n"));
2724                 AtapiDisableInterrupts(deviceExtension, j);
2725                 AtapiStallExecution(100);
2726                 KdPrint2((PRINT_PREFIX "  re-enable intr\n"));
2727                 AtapiEnableInterrupts(deviceExtension, j);
2728                 KdPrint2((PRINT_PREFIX "  done\n"));
2729 
2730                 break;
2731             } // end switch()
2732 
2733             //if(!(ChipFlags & UNIATA_SATA)) {}
2734             if(!UniataIsSATARangeAvailable(deviceExtension, j)) {
2735                 // Reset DMA engine if active
2736                 KdPrint2((PRINT_PREFIX "  check DMA engine\n"));
2737                 dma_status = GetDmaStatus(chan->DeviceExtension, chan->lChannel);
2738                 KdPrint2((PRINT_PREFIX "  DMA status %#x\n", dma_status));
2739                 if((ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE) ||
2740                    (dma_status & BM_STATUS_INTR)) {
2741                     AtapiDmaDone(HwDeviceExtension, 0, j, NULL);
2742                 }
2743             }
2744         } // ATA vs AHCI
2745 
2746         // all these shall be performed inside AtapiHwInitialize__() ?
2747 #if 1
2748         KdPrint2((PRINT_PREFIX "  process connected devices 0 - %d\n", MaxLuns-1));
2749         // Do special processing for ATAPI and IDE disk devices.
2750         for (i = 0; i < MaxLuns; i++) {
2751 
2752             // Check if device present.
2753             KdPrint2((PRINT_PREFIX "  Chan %#x\n", chan));
2754             KdPrint2((PRINT_PREFIX "  Lun %#x\n", i));
2755             KdPrint2((PRINT_PREFIX "  Lun ptr %#x\n", chan->lun[i]));
2756             if (!(chan->lun[i]->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
2757                 if(ChipFlags & UNIATA_AHCI) {
2758                     // everything is done in UniataAhciReset()
2759                     KdPrint2((PRINT_PREFIX "  device have gone\n"));
2760                     continue;
2761                 }
2762 #ifdef NAVO_TEST
2763                 continue;
2764 #else //NAVO_TEST
2765                 //if(!CheckDevice(HwDeviceExtension, i, j, FALSE))
2766                 if(!UniataAnybodyHome(HwDeviceExtension, j, i)) {
2767                     continue;
2768                 }
2769                 if(!CheckDevice(HwDeviceExtension, j, i, TRUE)) {
2770                     continue;
2771                 }
2772             } else {
2773                 if(ChipFlags & UNIATA_AHCI) {
2774                     // everything is done in UniataAhciReset()
2775                     KdPrint2((PRINT_PREFIX "  found some device\n"));
2776 
2777                     if(!IssueIdentify(HwDeviceExtension,
2778                                   i, j,
2779                              ATAPI_DEVICE(chan, i) ?
2780                                   IDE_COMMAND_ATAPI_IDENTIFY : IDE_COMMAND_IDENTIFY,
2781                                   FALSE)) {
2782                         KdPrint2((PRINT_PREFIX "  identify failed !\n"));
2783                         UniataForgetDevice(chan->lun[i]);
2784                     }
2785                     continue;
2786                 }
2787                 if(!UniataAnybodyHome(HwDeviceExtension, j, i)) {
2788                     KdPrint2((PRINT_PREFIX "  device have gone\n"));
2789                     UniataForgetDevice(chan->lun[i]);
2790                 }
2791 #endif //NAVO_TEST
2792             }
2793 
2794             SelectDrive(chan, i);
2795             AtapiStallExecution(10);
2796             statusByte = WaitOnBusyLong(chan);
2797             statusByte = UniataIsIdle(deviceExtension, statusByte);
2798             if(statusByte == IDE_STATUS_WRONG) {
2799                 KdPrint2((PRINT_PREFIX
2800                            "no drive, status %#x\n",
2801                            statusByte));
2802                 UniataForgetDevice(chan->lun[i]);
2803             } else
2804             // Check for ATAPI disk.
2805             if (ATAPI_DEVICE(chan, i)) {
2806                 // Issue soft reset and issue identify.
2807                 GetStatus(chan, statusByte);
2808                 KdPrint2((PRINT_PREFIX "AtapiResetController: Status before Atapi reset (%#x).\n",
2809                             statusByte));
2810 
2811                 AtapiDisableInterrupts(deviceExtension, j);
2812                 AtapiSoftReset(chan, i);
2813                 AtapiEnableInterrupts(deviceExtension, j);
2814 
2815                 GetStatus(chan, statusByte);
2816 
2817                 if(statusByte != IDE_STATUS_SUCCESS) {
2818                     ULONG k;
2819                     k = UniataAnybodyHome(deviceExtension, j, i);
2820                     if(k == ATA_AT_HOME_HDD) {
2821                         // device reset in progress, perform additional wait
2822                         KdPrint2((PRINT_PREFIX "  long reset, wait up to 4.5 s\n"));
2823                         k = 30 * 1000;
2824                         while ((AtapiReadPort1(chan, IDX_IO1_i_Status) & IDE_STATUS_BUSY) &&
2825                                k--)
2826                         {
2827                             AtapiStallExecution(150);
2828                         }
2829                         KdPrint2((PRINT_PREFIX " exit after %u loops\n", k));
2830                         GetStatus(chan, statusByte);
2831                     }
2832                 }
2833                 if(statusByte == IDE_STATUS_SUCCESS) {
2834 
2835                     IssueIdentify(HwDeviceExtension,
2836                                   i, j,
2837                                   IDE_COMMAND_ATAPI_IDENTIFY, FALSE);
2838                 } else {
2839 
2840                     KdPrint2((PRINT_PREFIX
2841                                "AtapiResetController: Status after soft reset %#x\n",
2842                                statusByte));
2843                 }
2844                 GetBaseStatus(chan, statusByte);
2845 
2846             } else {
2847                 // Issue identify and reinit after channel reset.
2848 
2849                 if (statusByte != IDE_STATUS_IDLE &&
2850                     statusByte != IDE_STATUS_SUCCESS &&
2851                     statusByte != IDE_STATUS_DRDY) {
2852 //                    result2 = FALSE;
2853                     KdPrint2((PRINT_PREFIX "AtapiResetController: IdeHardReset failed\n"));
2854                 } else
2855                 if(!IssueIdentify(HwDeviceExtension,
2856                                   i, j,
2857                                   IDE_COMMAND_IDENTIFY, FALSE)) {
2858 //                    result2 = FALSE;
2859                     KdPrint2((PRINT_PREFIX "AtapiResetController: IDE IssueIdentify failed\n"));
2860                 } else
2861                 // Set disk geometry parameters.
2862                 if (!SetDriveParameters(HwDeviceExtension, i, j)) {
2863                     KdPrint2((PRINT_PREFIX "AtapiResetController: SetDriveParameters failed\n"));
2864                 }
2865                 GetBaseStatus(chan, statusByte);
2866             }
2867             // force DMA mode reinit
2868             KdPrint2((PRINT_PREFIX " set DFLAGS_REINIT_DMA\n"));
2869             chan->lun[i]->DeviceFlags |= DFLAGS_REINIT_DMA;
2870         }
2871 #endif //0
2872 
2873         // Enable interrupts, note, we can have here recursive disable
2874         AtapiStallExecution(10);
2875         KdPrint2((PRINT_PREFIX "AtapiResetController: deviceExtension->chan[%d].DisableIntr %d -> 1\n",
2876             j,
2877             chan->DisableIntr));
2878         AtapiEnableInterrupts(deviceExtension, j);
2879 
2880         // Call the HwInitialize routine to setup multi-block.
2881         AtapiHwInitialize__(deviceExtension, j);
2882     } // for(channel)
2883     ScsiPortNotification(NextRequest, deviceExtension, NULL);
2884 
2885     return TRUE;
2886 
2887 } // end AtapiResetController__()
2888 
2889 
2890 /*++
2891 
2892 Routine Description:
2893     This routine maps ATAPI and IDE errors to specific SRB statuses.
2894 
2895 Arguments:
2896     HwDeviceExtension - HBA miniport driver's adapter data storage
2897     Srb - IO request packet
2898 
2899 Return Value:
2900     SRB status
2901 
2902 --*/
2903 ULONG
2904 NTAPI
2905 MapError(
2906     IN PVOID HwDeviceExtension,
2907     IN PSCSI_REQUEST_BLOCK Srb
2908     )
2909 {
2910     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
2911     ULONG lChannel = GET_CHANNEL(Srb);
2912     PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]);
2913 //    ULONG i;
2914     UCHAR errorByte = 0;
2915     UCHAR srbStatus = SRB_STATUS_SUCCESS;
2916     UCHAR scsiStatus;
2917     ULONG DeviceNumber = GET_CDEV(Srb);
2918     PHW_LU_EXTENSION     LunExt = chan->lun[DeviceNumber];
2919 
2920     // Read the error register.
2921 
2922     if(deviceExtension->HwFlags & UNIATA_AHCI) {
2923         PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension);
2924         if(AtaReq) {
2925             errorByte = AtaReq->ahci.in_error;
2926         } else {
2927         }
2928     } else {
2929         errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
2930     }
2931     KdPrint2((PRINT_PREFIX
2932                "MapError: Error register is %#x\n",
2933                errorByte));
2934 
2935     if (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
2936 
2937         switch (errorByte >> 4) {
2938         case SCSI_SENSE_NO_SENSE:
2939 
2940             KdPrint2((PRINT_PREFIX
2941                        "ATAPI: No sense information\n"));
2942             scsiStatus = SCSISTAT_CHECK_CONDITION;
2943             srbStatus = SRB_STATUS_ERROR;
2944             break;
2945 
2946         case SCSI_SENSE_RECOVERED_ERROR:
2947 
2948             KdPrint2((PRINT_PREFIX
2949                        "ATAPI: Recovered error\n"));
2950             scsiStatus = 0;
2951             srbStatus = SRB_STATUS_SUCCESS;
2952             break;
2953 
2954         case SCSI_SENSE_NOT_READY:
2955 
2956             KdPrint2((PRINT_PREFIX
2957                        "ATAPI: Device not ready\n"));
2958             scsiStatus = SCSISTAT_CHECK_CONDITION;
2959             srbStatus = SRB_STATUS_ERROR;
2960             break;
2961 
2962         case SCSI_SENSE_MEDIUM_ERROR:
2963 
2964             KdPrint2((PRINT_PREFIX
2965                        "ATAPI: Media error\n"));
2966             scsiStatus = SCSISTAT_CHECK_CONDITION;
2967             srbStatus = SRB_STATUS_ERROR;
2968             break;
2969 
2970         case SCSI_SENSE_HARDWARE_ERROR:
2971 
2972             KdPrint2((PRINT_PREFIX
2973                        "ATAPI: Hardware error\n"));
2974             scsiStatus = SCSISTAT_CHECK_CONDITION;
2975             srbStatus = SRB_STATUS_ERROR;
2976             break;
2977 
2978         case SCSI_SENSE_ILLEGAL_REQUEST:
2979 
2980             KdPrint2((PRINT_PREFIX
2981                        "ATAPI: Illegal request\n"));
2982             scsiStatus = SCSISTAT_CHECK_CONDITION;
2983             srbStatus = SRB_STATUS_ERROR;
2984             break;
2985 
2986         case SCSI_SENSE_UNIT_ATTENTION:
2987 
2988             KdPrint2((PRINT_PREFIX
2989                        "ATAPI: Unit attention\n"));
2990             scsiStatus = SCSISTAT_CHECK_CONDITION;
2991             srbStatus = SRB_STATUS_ERROR;
2992             break;
2993 
2994         case SCSI_SENSE_DATA_PROTECT:
2995 
2996             KdPrint2((PRINT_PREFIX
2997                        "ATAPI: Data protect\n"));
2998             scsiStatus = SCSISTAT_CHECK_CONDITION;
2999             srbStatus = SRB_STATUS_ERROR;
3000             break;
3001 
3002         case SCSI_SENSE_BLANK_CHECK:
3003 
3004             KdPrint2((PRINT_PREFIX
3005                        "ATAPI: Blank check\n"));
3006             scsiStatus = SCSISTAT_CHECK_CONDITION;
3007             srbStatus = SRB_STATUS_ERROR;
3008             break;
3009 
3010         case SCSI_SENSE_ABORTED_COMMAND:
3011             KdPrint2((PRINT_PREFIX
3012                         "Atapi: Command Aborted\n"));
3013             scsiStatus = SCSISTAT_CHECK_CONDITION;
3014             srbStatus = SRB_STATUS_ERROR;
3015             break;
3016 
3017         default:
3018 
3019             KdPrint2((PRINT_PREFIX
3020                        "ATAPI: Invalid sense information\n"));
3021             scsiStatus = 0;
3022             srbStatus = SRB_STATUS_ERROR;
3023             break;
3024         }
3025 
3026     } else {
3027 
3028         scsiStatus = 0;
3029 
3030         // Save errorByte,to be used by SCSIOP_REQUEST_SENSE.
3031         chan->ReturningMediaStatus = errorByte;
3032 
3033         if (errorByte & IDE_ERROR_MEDIA_CHANGE_REQ) {
3034             KdPrint2((PRINT_PREFIX
3035                        "IDE: Media change\n"));
3036             scsiStatus = SCSISTAT_CHECK_CONDITION;
3037             srbStatus = SRB_STATUS_ERROR;
3038 
3039             if (Srb->SenseInfoBuffer) {
3040 
3041                 PSENSE_DATA  senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
3042 
3043                 senseBuffer->ErrorCode = 0x70;
3044                 senseBuffer->Valid     = 1;
3045                 senseBuffer->AdditionalSenseLength = 0xb;
3046                 senseBuffer->SenseKey =  SCSI_SENSE_UNIT_ATTENTION;
3047                 senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED;
3048                 senseBuffer->AdditionalSenseCodeQualifier = 0;
3049 
3050                 srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
3051             }
3052 
3053         } else if (errorByte & IDE_ERROR_COMMAND_ABORTED) {
3054             KdPrint2((PRINT_PREFIX
3055                        "IDE: Command abort\n"));
3056             srbStatus = SRB_STATUS_ABORTED;
3057             scsiStatus = SCSISTAT_CHECK_CONDITION;
3058 
3059             if (Srb->SenseInfoBuffer) {
3060 
3061                 PSENSE_DATA  senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
3062 
3063                 senseBuffer->ErrorCode = 0x70;
3064                 senseBuffer->Valid     = 1;
3065                 senseBuffer->AdditionalSenseLength = 0xb;
3066                 senseBuffer->SenseKey =  SCSI_SENSE_ABORTED_COMMAND;
3067                 senseBuffer->AdditionalSenseCode = 0;
3068                 senseBuffer->AdditionalSenseCodeQualifier = 0;
3069 
3070                 srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
3071             }
3072 
3073             LunExt->ErrorCount++;
3074 
3075         } else if (errorByte & IDE_ERROR_END_OF_MEDIA) {
3076 
3077             KdPrint2((PRINT_PREFIX
3078                        "IDE: End of media\n"));
3079             scsiStatus = SCSISTAT_CHECK_CONDITION;
3080             srbStatus = SRB_STATUS_ERROR;
3081 
3082             if (Srb->SenseInfoBuffer) {
3083 
3084                 PSENSE_DATA  senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
3085 
3086                 senseBuffer->ErrorCode = 0x70;
3087                 senseBuffer->Valid     = 1;
3088                 senseBuffer->AdditionalSenseLength = 0xb;
3089                 senseBuffer->SenseKey =  SCSI_SENSE_UNIT_ATTENTION;
3090                 senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIA_STATE;
3091                 senseBuffer->AdditionalSenseCodeQualifier = SCSI_SENSEQ_END_OF_MEDIUM;
3092                 senseBuffer->EndOfMedia = 1;
3093 
3094                 srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
3095             }
3096 
3097             if (!(LunExt->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED)){
3098                 LunExt->ErrorCount++;
3099             }
3100 
3101         } else if (errorByte & IDE_ERROR_ILLEGAL_LENGTH) {
3102 
3103             KdPrint2((PRINT_PREFIX
3104                        "IDE: Illegal length\n"));
3105             srbStatus = SRB_STATUS_INVALID_REQUEST;
3106 
3107             if (Srb->SenseInfoBuffer) {
3108 
3109                 PSENSE_DATA  senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
3110 
3111                 senseBuffer->ErrorCode = 0x70;
3112                 senseBuffer->Valid     = 1;
3113                 senseBuffer->AdditionalSenseLength = 0xb;
3114                 senseBuffer->SenseKey =  SCSI_SENSE_ILLEGAL_REQUEST;
3115                 senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_INVALID_VALUE;
3116                 senseBuffer->AdditionalSenseCodeQualifier = SCSI_SENSEQ_PARAM_INVALID_VALUE;
3117                 senseBuffer->IncorrectLength = 1;
3118 
3119                 srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
3120             }
3121 
3122         } else if (errorByte & IDE_ERROR_BAD_BLOCK) {
3123 
3124             KdPrint2((PRINT_PREFIX
3125                        "IDE: Bad block\n"));
3126             srbStatus = SRB_STATUS_ERROR;
3127             scsiStatus = SCSISTAT_CHECK_CONDITION;
3128             if (Srb->SenseInfoBuffer) {
3129 
3130                 PSENSE_DATA  senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
3131 
3132                 senseBuffer->ErrorCode = 0x70;
3133                 senseBuffer->Valid     = 1;
3134                 senseBuffer->AdditionalSenseLength = 0xb;
3135                 senseBuffer->SenseKey =  SCSI_SENSE_MEDIUM_ERROR;
3136                 senseBuffer->AdditionalSenseCode = 0;
3137                 senseBuffer->AdditionalSenseCodeQualifier = 0;
3138 
3139                 srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
3140             }
3141 
3142         } else if (errorByte & IDE_ERROR_ID_NOT_FOUND) {
3143 
3144             KdPrint2((PRINT_PREFIX
3145                        "IDE: Id not found\n"));
3146             srbStatus = SRB_STATUS_ERROR;
3147             scsiStatus = SCSISTAT_CHECK_CONDITION;
3148 
3149             if (Srb->SenseInfoBuffer) {
3150 
3151                 PSENSE_DATA  senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
3152 
3153                 senseBuffer->ErrorCode = 0x70;
3154                 senseBuffer->Valid     = 1;
3155                 senseBuffer->AdditionalSenseLength = 0xb;
3156                 senseBuffer->SenseKey =  SCSI_SENSE_MEDIUM_ERROR;
3157                 senseBuffer->AdditionalSenseCode = 0;
3158                 senseBuffer->AdditionalSenseCodeQualifier = 0;
3159 
3160                 srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
3161             }
3162 
3163             LunExt->ErrorCount++;
3164 
3165         } else if (errorByte & IDE_ERROR_MEDIA_CHANGE) {
3166 
3167             KdPrint2((PRINT_PREFIX
3168                        "IDE: Media change\n"));
3169             scsiStatus = SCSISTAT_CHECK_CONDITION;
3170             srbStatus = SRB_STATUS_ERROR;
3171 
3172             if (Srb->SenseInfoBuffer) {
3173 
3174                 PSENSE_DATA  senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
3175 
3176                 senseBuffer->ErrorCode = 0x70;
3177                 senseBuffer->Valid     = 1;
3178                 senseBuffer->AdditionalSenseLength = 0xb;
3179                 senseBuffer->SenseKey =  SCSI_SENSE_UNIT_ATTENTION;
3180                 senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED;
3181                 senseBuffer->AdditionalSenseCodeQualifier = 0;
3182 
3183                 srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
3184             }
3185 
3186         } else if (errorByte & IDE_ERROR_DATA_ERROR) {
3187 
3188             KdPrint2((PRINT_PREFIX
3189                    "IDE: Data error\n"));
3190             scsiStatus = SCSISTAT_CHECK_CONDITION;
3191             srbStatus = SRB_STATUS_ERROR;
3192 
3193             if (!(LunExt->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED)){
3194                 LunExt->ErrorCount++;
3195             }
3196 
3197             // Build sense buffer
3198             if (Srb->SenseInfoBuffer) {
3199 
3200                 PSENSE_DATA  senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
3201 
3202                 senseBuffer->ErrorCode = 0x70;
3203                 senseBuffer->Valid     = 1;
3204                 senseBuffer->AdditionalSenseLength = 0xb;
3205                 senseBuffer->SenseKey =  SCSI_SENSE_MEDIUM_ERROR;
3206                 senseBuffer->AdditionalSenseCode = 0;
3207                 senseBuffer->AdditionalSenseCodeQualifier = 0;
3208 
3209                 srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
3210             }
3211         }
3212 
3213         if (LunExt->ErrorCount >= MAX_ERRORS) {
3214 //            deviceExtension->DWordIO = FALSE;
3215 
3216             KdPrint2((PRINT_PREFIX
3217                         "MapError: ErrorCount >= MAX_ERRORS\n"));
3218 
3219             LunExt->DeviceFlags &= ~DFLAGS_DWORDIO_ENABLED;
3220             LunExt->MaximumBlockXfer = 0;
3221             BrutePoint();
3222 
3223             KdPrint2((PRINT_PREFIX
3224                         "MapError: Disabling 32-bit PIO and Multi-sector IOs\n"));
3225 
3226             // Log the error.
3227             KdPrint2((PRINT_PREFIX
3228                         "ScsiPortLogError: devExt %#x, Srb %#x, P:T:D=%d:%d:%d, MsgId %#x (%d)\n",
3229                               HwDeviceExtension,
3230                               Srb,
3231                               Srb->PathId,
3232                               Srb->TargetId,
3233                               Srb->Lun,
3234                               SP_BAD_FW_WARNING,
3235                               4
3236                         ));
3237             ScsiPortLogError( HwDeviceExtension,
3238                               Srb,
3239                               Srb->PathId,
3240                               Srb->TargetId,
3241                               Srb->Lun,
3242                               SP_BAD_FW_WARNING,
3243                               4);
3244 
3245             // Reprogram to not use Multi-sector.
3246             UCHAR statusByte;
3247 
3248             if (LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT &&
3249                  !(LunExt->DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_MANUAL_CHS))) {
3250 
3251                 statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_SET_MULTIPLE, 0, 0, 0, 0, 0, ATA_WAIT_BASE_READY);
3252 
3253                 // Check for errors. Reset the value to 0 (disable MultiBlock) if the
3254                 // command was aborted.
3255                 if (statusByte & IDE_STATUS_ERROR) {
3256 
3257                     // Read the error register.
3258                     errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
3259 
3260                     KdPrint2((PRINT_PREFIX "MapError: Error setting multiple mode. Status %#x, error byte %#x\n",
3261                                 statusByte,
3262                                 errorByte));
3263 
3264                     // Adjust the devExt. value, if necessary.
3265                     LunExt->MaximumBlockXfer = 0;
3266                     BrutePoint();
3267 
3268                 }
3269             }
3270         }
3271     }
3272 
3273     // Set SCSI status to indicate a check condition.
3274     Srb->ScsiStatus = scsiStatus;
3275 
3276     return srbStatus;
3277 
3278 } // end MapError()
3279 
3280 
3281 /*++
3282 
3283 Routine Description:
3284 
3285 Arguments:
3286     HwDeviceExtension - HBA miniport driver's adapter data storage
3287     ->HwInitialize
3288 
3289 Return Value:
3290     TRUE - if initialization successful.
3291     FALSE - if initialization unsuccessful.
3292 
3293 --*/
3294 BOOLEAN
3295 NTAPI
3296 AtapiHwInitialize(
3297     IN PVOID HwDeviceExtension
3298     )
3299 {
3300     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
3301     ULONG                numberChannels  = deviceExtension->NumberChannels;
3302     ULONG c;
3303 
3304     KdPrint2((PRINT_PREFIX "AtapiHwInitialize: (base)\n"));
3305 
3306     if(WinVer_WDM_Model) {
3307         AtapiResetController__(HwDeviceExtension, CHAN_NOT_SPECIFIED, RESET_COMPLETE_ALL);
3308     }
3309     if(deviceExtension->MasterDev) {
3310         KdPrint2((PRINT_PREFIX "  mark chan %d of master controller [%x] as inited\n",
3311             deviceExtension->Channel, deviceExtension->DevIndex));
3312         BMList[deviceExtension->DevIndex].ChanInitOk |= 0x01 << deviceExtension->Channel;
3313     }
3314 
3315     /* do extra chipset specific setups */
3316     AtapiChipInit(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, CHAN_NOT_SPECIFIED);
3317 /*
3318     if(deviceExtension->Isr2DevObj && (deviceExtension->HwFlags & UNIATA_SATA)) {
3319         KdPrint2((PRINT_PREFIX " enable ISR2 to catch unexpected interrupts\n"));
3320         BMList[deviceExtension->DevIndex].Isr2Enable = TRUE;
3321     }
3322 */
3323     for (c = 0; c < numberChannels; c++) {
3324         AtapiHwInitialize__(deviceExtension, c);
3325     }
3326     KdPrint2((PRINT_PREFIX "AtapiHwInitialize: (base) done\n"));
3327     return TRUE;
3328 } // end AtapiHwInitialize()
3329 
3330 VOID
3331 NTAPI
3332 AtapiHwInitialize__(
3333     IN PHW_DEVICE_EXTENSION deviceExtension,
3334     IN ULONG lChannel
3335     )
3336 {
3337     ULONG i;
3338     UCHAR statusByte, errorByte;
3339     PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]);
3340     PHW_LU_EXTENSION     LunExt;
3341 //    ULONG tmp32;
3342     ULONG PreferedMode = 0xffffffff;
3343 
3344     if((deviceExtension->HwFlags & UNIATA_AHCI) &&
3345        !UniataAhciChanImplemented(deviceExtension, lChannel)) {
3346         return;
3347     }
3348 
3349     AtapiChipInit(deviceExtension, DEVNUM_NOT_SPECIFIED, lChannel);
3350     FindDevices(deviceExtension, 0, lChannel);
3351 
3352     for (i = 0; i < chan->NumberLuns; i++) {
3353 
3354         KdPrint3((PRINT_PREFIX "AtapiHwInitialize: lChannel %#x, dev %x\n", lChannel, i));
3355 
3356         LunExt = chan->lun[i];
3357         // skip empty slots
3358         if (!(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
3359             continue;
3360         }
3361 
3362         AtapiDisableInterrupts(deviceExtension, lChannel);
3363         AtapiStallExecution(1);
3364 
3365         if (!(LunExt->DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_MANUAL_CHS))) {
3366 
3367             KdPrint2((PRINT_PREFIX "AtapiHwInitialize: IDE branch\n"));
3368             // Enable media status notification
3369             IdeMediaStatus(TRUE,deviceExtension,lChannel,(UCHAR)i);
3370 
3371             // If supported, setup Multi-block transfers.
3372             statusByte = AtaCommand(deviceExtension, i, lChannel,
3373                                 IDE_COMMAND_SET_MULTIPLE, 0, 0, 0,
3374                                 LunExt->MaximumBlockXfer, 0, ATA_WAIT_BASE_READY);
3375 
3376             // Check for errors. Reset the value to 0 (disable MultiBlock) if the
3377             // command was aborted.
3378             if (statusByte & IDE_STATUS_ERROR) {
3379 
3380                 // Read the error register.
3381                 errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
3382 
3383                 KdPrint2((PRINT_PREFIX "AtapiHwInitialize: Error setting multiple mode. Status %#x, error byte %#x\n",
3384                             statusByte,
3385                             errorByte));
3386 
3387                 statusByte = AtaCommand(deviceExtension, i, lChannel,
3388                                     IDE_COMMAND_SET_MULTIPLE, 0, 0, 0,
3389                                     0, 0, ATA_WAIT_BASE_READY);
3390 
3391                 if (statusByte & IDE_STATUS_ERROR) {
3392                     // Read the error register.
3393                     errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
3394 
3395                     KdPrint2((PRINT_PREFIX "AtapiHwInitialize: Error disabling multiple mode. Status %#x, error byte %#x\n",
3396                                 statusByte,
3397                                 errorByte));
3398                 }
3399                 // Adjust the devExt. value, if necessary.
3400                 LunExt->MaximumBlockXfer = 0;
3401 
3402             } else {
3403                 KdPrint2((PRINT_PREFIX
3404                             "AtapiHwInitialize: Using Multiblock on Device %d. Blocks / int - %d\n",
3405                             i,
3406                             LunExt->MaximumBlockXfer));
3407             }
3408 
3409             if(LunExt->IdentifyData.MajorRevision) {
3410 
3411                 if(LunExt->opt_ReadCacheEnable) {
3412                     KdPrint2((PRINT_PREFIX "  Try Enable Read Cache\n"));
3413                     // If supported, setup read/write cacheing
3414                     statusByte = AtaCommand(deviceExtension, i, lChannel,
3415                                         IDE_COMMAND_SET_FEATURES, 0, 0, 0,
3416                                         0, ATA_C_F_ENAB_RCACHE, ATA_WAIT_BASE_READY);
3417 
3418                     // Check for errors.
3419                     if (statusByte & IDE_STATUS_ERROR) {
3420                         KdPrint2((PRINT_PREFIX
3421                                     "AtapiHwInitialize: Enable read/write cacheing on Device %d failed\n",
3422                                     i));
3423                         LunExt->DeviceFlags &= ~DFLAGS_RCACHE_ENABLED;
3424                     } else {
3425                         LunExt->DeviceFlags |= DFLAGS_RCACHE_ENABLED;
3426                     }
3427                 } else {
3428                     KdPrint2((PRINT_PREFIX "  Disable Read Cache\n"));
3429                     statusByte = AtaCommand(deviceExtension, i, lChannel,
3430                                         IDE_COMMAND_SET_FEATURES, 0, 0, 0,
3431                                         0, ATA_C_F_DIS_RCACHE, ATA_WAIT_BASE_READY);
3432                     LunExt->DeviceFlags &= ~DFLAGS_RCACHE_ENABLED;
3433                 }
3434                 if(LunExt->IdentifyData.FeaturesSupport.WriteCache) {
3435                     if(LunExt->opt_WriteCacheEnable) {
3436                         KdPrint2((PRINT_PREFIX "  Try Enable Write Cache\n"));
3437                         // If supported & allowed, setup write cacheing
3438                         statusByte = AtaCommand(deviceExtension, i, lChannel,
3439                                             IDE_COMMAND_SET_FEATURES, 0, 0, 0,
3440                                             0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_BASE_READY);
3441                         // Check for errors.
3442                         if (statusByte & IDE_STATUS_ERROR) {
3443                             KdPrint2((PRINT_PREFIX
3444                                         "AtapiHwInitialize: Enable write cacheing on Device %d failed\n",
3445                                         i));
3446                             LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
3447                         } else {
3448                             LunExt->DeviceFlags |= DFLAGS_WCACHE_ENABLED;
3449                         }
3450                     } else {
3451                         KdPrint2((PRINT_PREFIX "  Disable Write Cache\n"));
3452                         statusByte = AtaCommand(deviceExtension, i, lChannel,
3453                                             IDE_COMMAND_SET_FEATURES, 0, 0, 0,
3454                                             0, ATA_C_F_DIS_WCACHE, ATA_WAIT_BASE_READY);
3455                         LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
3456                     }
3457                 }
3458 
3459                 if(/*LunExt->IdentifyData.FeaturesSupport.PowerMngt ||*/
3460                    LunExt->IdentifyData.FeaturesSupport.APM) {
3461 
3462                     if(LunExt->opt_AdvPowerMode) {
3463                         KdPrint2((PRINT_PREFIX "  Try Enable Adv. Power Mgmt\n"));
3464                         // setup APM
3465                         statusByte = AtaCommand(deviceExtension, i, lChannel,
3466                                             IDE_COMMAND_SET_FEATURES, 0, 0, 0,
3467                                             LunExt->opt_AdvPowerMode, ATA_C_F_ENAB_APM, ATA_WAIT_BASE_READY);
3468                         // Check for errors.
3469                         if (statusByte & IDE_STATUS_ERROR) {
3470                             KdPrint2((PRINT_PREFIX
3471                                         "AtapiHwInitialize: Enable APM on Device %d failed\n",
3472                                         i));
3473                         }
3474                     } else {
3475                         KdPrint2((PRINT_PREFIX "  Disable Adv. Power Mgmt\n"));
3476                         statusByte = AtaCommand(deviceExtension, i, lChannel,
3477                                             IDE_COMMAND_SET_FEATURES, 0, 0, 0,
3478                                             0, ATA_C_F_DIS_APM, ATA_WAIT_BASE_READY);
3479                     }
3480                 }
3481                 if(LunExt->IdentifyData.FeaturesSupport.AutoAcoustic) {
3482                     if(LunExt->opt_AcousticMode) {
3483                         KdPrint2((PRINT_PREFIX "  Try Enable Acoustic Mgmt\n"));
3484                         // setup acoustic mgmt
3485                         statusByte = AtaCommand(deviceExtension, i, lChannel,
3486                                             IDE_COMMAND_SET_FEATURES, 0, 0, 0,
3487                                             LunExt->opt_AcousticMode, ATA_C_F_ENAB_ACOUSTIC, ATA_WAIT_BASE_READY);
3488                         // Check for errors.
3489                         if (statusByte & IDE_STATUS_ERROR) {
3490                             KdPrint2((PRINT_PREFIX
3491                                         "AtapiHwInitialize: Enable Acoustic Mgmt on Device %d failed\n",
3492                                         i));
3493                         }
3494                     } else {
3495                         KdPrint2((PRINT_PREFIX "  Disable Acoustic Mgmt\n"));
3496                         statusByte = AtaCommand(deviceExtension, i, lChannel,
3497                                             IDE_COMMAND_SET_FEATURES, 0, 0, 0,
3498                                             0, ATA_C_F_DIS_ACOUSTIC, ATA_WAIT_BASE_READY);
3499                     }
3500                 }
3501                 if(LunExt->IdentifyData.FeaturesSupport.Standby) {
3502                     KdPrint2((PRINT_PREFIX "  Try init standby timer: %d\n"));
3503                     // setup standby timer
3504                     statusByte = AtaCommand(deviceExtension, i, lChannel,
3505                                         IDE_COMMAND_IDLE, 0, 0, 0,
3506                                         LunExt->opt_StandbyTimer, 0, ATA_WAIT_BASE_READY);
3507                     // Check for errors.
3508                     if (statusByte & IDE_STATUS_ERROR) {
3509                         KdPrint2((PRINT_PREFIX
3510                                     "AtapiHwInitialize: standby timer on Device %d failed\n",
3511                                     i));
3512                     }
3513                 }
3514             }
3515 
3516         } else if (!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED)){
3517 
3518             ULONG j;
3519             //BOOLEAN isSanyo = FALSE;
3520             CCHAR vendorId[26];
3521 
3522             KdPrint2((PRINT_PREFIX "AtapiHwInitialize: ATAPI/Changer branch\n"));
3523 
3524             // Attempt to identify any special-case devices - psuedo-atapi changers, atapi changers, etc.
3525             for (j = 0; j < 26; j += 2) {
3526 
3527                 // Build a buffer based on the identify data.
3528                 MOV_DW_SWP(vendorId[j], ((PUCHAR)LunExt->IdentifyData.ModelNumber)[j]);
3529             }
3530 
3531             if (!AtapiStringCmp (vendorId, "CD-ROM  CDR", 11)) {
3532 
3533                 // Inquiry string for older model had a '-', newer is '_'
3534                 if (vendorId[12] == 'C') {
3535 
3536                     // Torisan changer. Set the bit. This will be used in several places
3537                     // acting like 1) a multi-lun device and 2) building the 'special' TUR's.
3538                     LunExt->DeviceFlags |= (DFLAGS_CHANGER_INITED | DFLAGS_SANYO_ATAPI_CHANGER);
3539                     LunExt->DiscsPresent = 3;
3540                     //isSanyo = TRUE;
3541                 }
3542             }
3543         }
3544 
3545         PreferedMode = LunExt->opt_MaxTransferMode;
3546         if((PreferedMode == 0xffffffff) || (PreferedMode > chan->MaxTransferMode)) {
3547             KdPrint2((PRINT_PREFIX "MaxTransferMode (overriden): %#x\n", chan->MaxTransferMode));
3548             PreferedMode = chan->MaxTransferMode;
3549         }
3550 
3551         if(LunExt->opt_PreferedTransferMode != 0xffffffff) {
3552             KdPrint2((PRINT_PREFIX "PreferedTransferMode: %#x\n", PreferedMode));
3553             PreferedMode = min(LunExt->opt_PreferedTransferMode, PreferedMode);
3554         }
3555 
3556         KdPrint2((PRINT_PREFIX "  try mode %#x\n", PreferedMode));
3557         LunExt->LimitedTransferMode =
3558         LunExt->TransferMode =
3559             (CHAR)PreferedMode;
3560 
3561         AtapiDmaInit__(deviceExtension, LunExt);
3562 
3563         LunExt->LimitedTransferMode =
3564             LunExt->TransferMode;
3565         KdPrint2((PRINT_PREFIX "Using %#x mode\n", LunExt->TransferMode));
3566 
3567         // We need to get our device ready for action before
3568         // returning from this function
3569 
3570         // According to the atapi spec 2.5 or 2.6, an atapi device
3571         // clears its status BSY bit when it is ready for atapi commands.
3572         // However, some devices (Panasonic SQ-TC500N) are still
3573         // not ready even when the status BSY is clear.  They don't react
3574         // to atapi commands.
3575         //
3576         // Since there is really no other indication that tells us
3577         // the drive is really ready for action.  We are going to check BSY
3578         // is clear and then just wait for an arbitrary amount of time!
3579         //
3580         if (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
3581             ULONG waitCount;
3582 
3583             // have to get out of the loop sometime!
3584             // 10000 * 100us = 1000,000us = 1000ms = 1s
3585             waitCount = 10000;
3586             GetStatus(chan, statusByte);
3587             if(statusByte == IDE_STATUS_WRONG) {
3588                 waitCount = 0;
3589             }
3590             while ((statusByte & IDE_STATUS_BUSY) && waitCount) {
3591 
3592                 KdPrint2((PRINT_PREFIX "Wait for ATAPI (status %x)\n", statusByte));
3593                 // Wait for Busy to drop.
3594                 AtapiStallExecution(100);
3595                 GetStatus(chan, statusByte);
3596                 waitCount--;
3597             }
3598 
3599             // 5000 * 100us = 500,000us = 500ms = 0.5s
3600             if(statusByte != IDE_STATUS_WRONG) {
3601                 waitCount = 5000;
3602                 do {
3603                     AtapiStallExecution(100);
3604                 } while (waitCount--);
3605             }
3606         }
3607         GetBaseStatus(chan, statusByte);
3608         AtapiEnableInterrupts(deviceExtension, lChannel);
3609         AtapiStallExecution(10);
3610     }
3611 
3612     return;
3613 
3614 } // end AtapiHwInitialize__()
3615 
3616 
3617 #ifndef UNIATA_CORE
3618 
3619 VOID
3620 NTAPI
3621 AtapiHwInitializeChanger(
3622     IN PVOID HwDeviceExtension,
3623     IN PSCSI_REQUEST_BLOCK Srb,
3624     IN PMECHANICAL_STATUS_INFORMATION_HEADER MechanismStatus)
3625 {
3626     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
3627     ULONG lChannel = GET_CHANNEL(Srb);
3628     PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]);
3629     ULONG DeviceNumber = GET_CDEV(Srb);
3630     PHW_LU_EXTENSION     LunExt = chan->lun[DeviceNumber];
3631 
3632     if (MechanismStatus) {
3633         LunExt->DiscsPresent = MechanismStatus->NumberAvailableSlots;
3634         if (LunExt->DiscsPresent > 1) {
3635             LunExt->DeviceFlags |= DFLAGS_ATAPI_CHANGER;
3636         }
3637     }
3638     return;
3639 } // end AtapiHwInitializeChanger()
3640 
3641 
3642 /*++
3643 
3644 Routine Description:
3645     This routine will parse the string for a match on the keyword, then
3646     calculate the value for the keyword and return it to the caller.
3647 
3648 Arguments:
3649     String - The ASCII string to parse.
3650     KeyWord - The keyword for the value desired.
3651 
3652 Return Values:
3653     Zero if value not found
3654     Value converted from ASCII to binary.
3655 
3656 --*/
3657 ULONG
3658 NTAPI
3659 AtapiParseArgumentString(
3660     IN PCCH String,
3661     IN PCCH KeyWord
3662     )
3663 {
3664     PCCH cptr;
3665     PCCH kptr;
3666     ULONG value;
3667     ULONG stringLength = 0;
3668     ULONG keyWordLength = 0;
3669     ULONG index;
3670 
3671     if (!String) {
3672         return 0;
3673     }
3674     if (!KeyWord) {
3675         return 0;
3676     }
3677 
3678     // Calculate the string length and lower case all characters.
3679     cptr = String;
3680     while (*cptr++) {
3681         stringLength++;
3682     }
3683 
3684     // Calculate the keyword length.
3685     kptr = KeyWord;
3686     while (*kptr++) {
3687         keyWordLength++;
3688     }
3689 
3690     if (keyWordLength > stringLength) {
3691 
3692         // Can't possibly have a match.
3693         return 0;
3694     }
3695 
3696     // Now setup and start the compare.
3697     cptr = String;
3698 
3699 ContinueSearch:
3700 
3701     // The input string may start with white space.  Skip it.
3702     while (*cptr == ' ' || *cptr == '\t') {
3703         cptr++;
3704     }
3705 
3706     if (*cptr == '\0') {
3707         // end of string.
3708         return 0;
3709     }
3710 
3711     kptr = KeyWord;
3712     while ((*cptr == *kptr) ||
3713            (*cptr >= 'A' && *cptr <= 'Z' && *cptr + ('a' - 'A') == *kptr) ||
3714            (*cptr >= 'a' && *cptr <= 'z' && *cptr - ('a' - 'A') == *kptr)) {
3715         cptr++;
3716         kptr++;
3717 
3718         if (*cptr == '\0') {
3719             // end of string
3720             return 0;
3721         }
3722     }
3723 
3724     if (*kptr == '\0') {
3725 
3726         // May have a match backup and check for blank or equals.
3727         while (*cptr == ' ' || *cptr == '\t') {
3728             cptr++;
3729         }
3730 
3731         // Found a match.  Make sure there is an equals.
3732         if (*cptr != '=') {
3733 
3734             // Not a match so move to the next semicolon.
3735             while (*cptr) {
3736                 if (*cptr++ == ';') {
3737                     goto ContinueSearch;
3738                 }
3739             }
3740             return 0;
3741         }
3742         // Skip the equals sign.
3743         cptr++;
3744 
3745         // Skip white space.
3746         while ((*cptr == ' ') || (*cptr == '\t')) {
3747             cptr++;
3748         }
3749 
3750         if (*cptr == '\0') {
3751             // Early end of string, return not found
3752             return 0;
3753         }
3754 
3755         if (*cptr == ';') {
3756             // This isn't it either.
3757             cptr++;
3758             goto ContinueSearch;
3759         }
3760 
3761         value = 0;
3762         if ((*cptr == '0') && ((*(cptr + 1) == 'x') || (*(cptr + 1) == 'X'))) {
3763             // Value is in Hex.  Skip the "0x"
3764             cptr += 2;
3765             for (index = 0; *(cptr + index); index++) {
3766 
3767                 if (*(cptr + index) == ' ' ||
3768                     *(cptr + index) == '\t' ||
3769                     *(cptr + index) == ';') {
3770                      break;
3771                 }
3772 
3773                 if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) {
3774                     value = (16 * value) + (*(cptr + index) - '0');
3775                 } else {
3776                     if ((*(cptr + index) >= 'a') && (*(cptr + index) <= 'f')) {
3777                         value = (16 * value) + (*(cptr + index) - 'a' + 10);
3778                     } else if ((*(cptr + index) >= 'A') && (*(cptr + index) <= 'F')) {
3779                         value = (16 * value) + (*(cptr + index) - 'A' + 10);
3780                     } else {
3781                         // Syntax error, return not found.
3782                         return 0;
3783                     }
3784                 }
3785             }
3786         } else {
3787 
3788             // Value is in Decimal.
3789             for (index = 0; *(cptr + index); index++) {
3790 
3791                 if (*(cptr + index) == ' ' ||
3792                     *(cptr + index) == '\t' ||
3793                     *(cptr + index) == ';') {
3794                      break;
3795                 }
3796 
3797                 if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) {
3798                     value = (10 * value) + (*(cptr + index) - '0');
3799                 } else {
3800 
3801                     // Syntax error return not found.
3802                     return 0;
3803                 }
3804             }
3805         }
3806 
3807         return value;
3808     } else {
3809 
3810         // Not a match check for ';' to continue search.
3811         while (*cptr) {
3812             if (*cptr++ == ';') {
3813                 goto ContinueSearch;
3814             }
3815         }
3816 
3817         return 0;
3818     }
3819 } // end AtapiParseArgumentString()_
3820 
3821 /*
3822     Timer callback
3823 */
3824 VOID
3825 NTAPI
3826 AtapiCallBack__(
3827     IN PVOID HwDeviceExtension,
3828     IN UCHAR lChannel
3829     )
3830 {
3831 
3832     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
3833     PHW_CHANNEL chan = &(deviceExtension->chan[lChannel]);
3834     ULONG c, _c;
3835 
3836     PSCSI_REQUEST_BLOCK  srb = UniataGetCurRequest(chan);
3837     UCHAR statusByte;
3838 
3839     KdPrint2((PRINT_PREFIX "AtapiCallBack:\n"));
3840     // If the last command was DSC restrictive, see if it's set. If so, the device is
3841     // ready for a new request. Otherwise, reset the timer and come back to here later.
3842 
3843     // If ISR decided to wait for BUSY or DRQ in DPC, we shall also get here.
3844     // In this case chan->ExpectingInterrupt == TRUE, but interrupts are disabled, thus,
3845     // we shall have no problem with interrupt handler.
3846     if (!srb || chan->ExpectingInterrupt) {
3847         KdPrint2((PRINT_PREFIX "AtapiCallBack: Calling ISR directly due to BUSY\n"));
3848         chan->DpcState = DPC_STATE_TIMER;
3849         if(!AtapiInterrupt__(HwDeviceExtension, lChannel)) {
3850             InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE);
3851             KdPrint2((PRINT_PREFIX "AtapiCallBack: What's fucking this ???\n"));
3852         }
3853         goto ReturnCallback;
3854     }
3855 
3856 #ifdef _DEBUG
3857     if (!IS_RDP((srb->Cdb[0]))) {
3858         KdPrint2((PRINT_PREFIX "AtapiCallBack: Invalid CDB marked as RDP - %#x\n", srb->Cdb[0]));
3859     }
3860 #endif
3861     if(!(chan->RDP)) {
3862         goto ReturnEnableIntr;
3863     }
3864     GetStatus(chan, statusByte);
3865     if (statusByte & IDE_STATUS_DSC) {
3866 
3867         UCHAR PathId   = srb->PathId;
3868         UCHAR TargetId = srb->TargetId;
3869         UCHAR Lun      = srb->Lun;
3870 
3871         KdPrint2((PRINT_PREFIX "AtapiCallBack: Found DSC for RDP - %#x\n", srb->Cdb[0]));
3872         AtapiDmaDBSync(chan, srb);
3873         UniataRemoveRequest(chan, srb);
3874         ScsiPortNotification(RequestComplete, deviceExtension, srb);
3875         // Clear current SRB.
3876         if(!deviceExtension->simplexOnly) {
3877             srb = UniataGetCurRequest(chan);
3878         } else {
3879             srb = NULL;
3880         }
3881         chan->RDP = FALSE;
3882 
3883         // Ask for next request.
3884         ScsiPortNotification(NextLuRequest,
3885                              deviceExtension,
3886                              PathId,
3887                              TargetId,
3888                              Lun);
3889         ScsiPortNotification(NextRequest, deviceExtension, NULL);
3890 
3891         if(srb) {
3892             AtapiStartIo__(HwDeviceExtension, srb, FALSE);
3893         }
3894 
3895     } else {
3896         KdPrint2((PRINT_PREFIX "AtapiCallBack: Requesting another timer for Op %#x\n",
3897                     srb->Cdb[0]));
3898 
3899         AtapiQueueTimerDpc(HwDeviceExtension, lChannel,
3900                              AtapiCallBack_X,
3901                              1000);
3902 
3903         goto ReturnCallback;
3904     }
3905 
3906 ReturnEnableIntr:
3907 
3908     if(CrNtInterlockedExchangeAdd(&(chan->DisableIntr), 0)) {
3909         KdPrint2((PRINT_PREFIX "AtapiCallBack: CallDisableInterrupts\n"));
3910         //ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
3911 #ifdef UNIATA_USE_XXableInterrupts
3912         chan->ChannelCtrlFlags |= CTRFLAGS_ENABLE_INTR_REQ;
3913         // must be called on DISPATCH_LEVEL
3914         ScsiPortNotification(CallDisableInterrupts, HwDeviceExtension,
3915                              AtapiEnableInterrupts__);
3916 #else
3917         AtapiEnableInterrupts(HwDeviceExtension, lChannel);
3918         InterlockedExchange(&(chan->CheckIntr),
3919                                       CHECK_INTR_IDLE);
3920         // Will raise IRQL to DIRQL
3921         AtapiQueueTimerDpc(HwDeviceExtension, lChannel,
3922                              AtapiEnableInterrupts__,
3923                              1);
3924         KdPrint2((PRINT_PREFIX "AtapiInterrupt: Timer DPC inited\n"));
3925 #endif // UNIATA_USE_XXableInterrupts
3926     } else {
3927         //ASSERT(!deviceExtension->simplexOnly);
3928     }
3929 
3930 ReturnCallback:
3931 
3932     // Check other channel
3933     // In simplex mode no interrupts must appear on other channels
3934     for(_c=0; _c<deviceExtension->NumberChannels; _c++) {
3935         c = (_c+deviceExtension->FirstChannelToCheck) % deviceExtension->NumberChannels;
3936 
3937         if(c == lChannel) {
3938             continue;
3939         }
3940 
3941         chan = &(deviceExtension->chan[c]);
3942 
3943         if((ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(chan->CheckIntr),
3944                                       CRNT_ILK_TYPE CHECK_INTR_ACTIVE,
3945                                       CRNT_ILK_TYPE CHECK_INTR_DETECTED) == CHECK_INTR_DETECTED)
3946         {
3947             //ASSERT(!deviceExtension->simplexOnly);
3948             chan->DpcState = DPC_STATE_ISR;
3949             if(!AtapiInterrupt__(HwDeviceExtension, (UCHAR)c)) {
3950                 InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE);
3951             }
3952         }
3953     }
3954     KdPrint2((PRINT_PREFIX "AtapiCallBack: return\n"));
3955     return;
3956 
3957 } // end AtapiCallBack__()
3958 
3959 VOID
3960 NTAPI
3961 AtapiCallBack_X(
3962     IN PVOID HwDeviceExtension
3963     )
3964 {
3965     AtapiCallBack__(HwDeviceExtension, (UCHAR)((PHW_DEVICE_EXTENSION)HwDeviceExtension)->ActiveDpcChan);
3966 } // end AtapiCallBack_X()
3967 
3968 #endif //UNIATA_CORE
3969 
3970 /*++
3971 
3972 Routine Description:
3973 
3974     This is the interrupt service routine for ATAPI IDE miniport driver.
3975 
3976 Arguments:
3977 
3978     HwDeviceExtension - HBA miniport driver's adapter data storage
3979 
3980 Return Value:
3981 
3982     TRUE if expecting an interrupt.
3983 
3984 --*/
3985 BOOLEAN
3986 NTAPI
3987 AtapiInterrupt(
3988     IN PVOID HwDeviceExtension
3989     )
3990 {
3991     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
3992     ULONG c, _c;
3993     BOOLEAN status = FALSE;
3994     ULONG c_state;
3995     ULONG i_res = 0;
3996     ULONG pass;
3997     //BOOLEAN checked[AHCI_MAX_PORT];
3998     ULONG hIS;
3999     ULONG checked;
4000 
4001     KdPrint2((PRINT_PREFIX "Intr: DeviceID+VendorID/Rev %#x/%#x (ex %d)\n",
4002         deviceExtension->DevID, deviceExtension->RevID, deviceExtension->ExpectingInterrupt ));
4003 
4004     if(deviceExtension->HwFlags & UNIATA_AHCI) {
4005         // AHCI may generate state change notification, never skip this check
4006         hIS = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_IS);
4007         KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): AHCI: hIS=%x cntrlr %#x chan %#x\n",hIS, deviceExtension->DevIndex, deviceExtension->Channel));
4008         if(!hIS) {
4009             return FALSE;
4010         }
4011         // assume all non-interrupted ports to be already checked
4012         checked = ~hIS;
4013         // assume all not implemented ports to be already checked
4014         checked |= ~deviceExtension->AHCI_PI;
4015     } else {
4016         checked = 0; // assume all ports are not checked
4017     }
4018 
4019     if(!deviceExtension->ExpectingInterrupt) {
4020         // if we do not expect interrupt, exit now,
4021         // but keep in mind that it can be unexpected one
4022         // Note: this is just a hint, not exact counter
4023         KdPrint2((PRINT_PREFIX "unexpected, 1st chance\n"));
4024         //deviceExtension->ExpectingInterrupt++;
4025         //return FALSE;
4026     }
4027     // clear this flag now, it can be set again in sub-calls
4028     deviceExtension->ExpectingInterrupt=0;
4029 
4030 
4031 //    for(_c=0; _c<deviceExtension->NumberChannels; _c++) {
4032 //        checked[_c] = (UCHAR)((hIS >> _c) & 0x01);
4033 //    }
4034 
4035 //    fc =
4036     for(pass=0; pass<2; pass++) {
4037         //KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): pass %d\n", pass));
4038         if(status && pass) {
4039             // we catched some expected interrupts now.
4040             // do not touch unexpected until next ISR call
4041             break;
4042         }
4043         for(_c=0; _c<deviceExtension->NumberChannels; _c++) {
4044 
4045             c = (_c+deviceExtension->FirstChannelToCheck) % deviceExtension->NumberChannels;
4046 
4047             if((checked>>c) & 0x01)
4048                 continue;
4049 
4050             // check non-empty and expecting interrupt channels first
4051             if(!pass && !deviceExtension->chan[c].ExpectingInterrupt)
4052                 continue;
4053 
4054             checked |= (ULONG)1 << c;
4055 
4056             KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): cntrlr %#x chan %#x\n",deviceExtension->DevIndex, c));
4057 
4058             if(CrNtInterlockedExchangeAdd(&(deviceExtension->chan[c].DisableIntr), 0)) {
4059                 // we get here on idle channels or when ISR is posted to DPC
4060                 KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): disabled INTR on ch %d\n", c));
4061                 continue;
4062             }
4063             // lock channel. Wait, while 2nd ISR checks interrupt on this channel
4064             do {
4065                 KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): try lock\n"));
4066                 // c_state = deviceExtension->chan[c].CheckIntr;
4067                 // if (deviceExtension->chan[c].CheckIntr == CHECK_INTR_DETECTED) {
4068                 //     deviceExtension->chan[c].CheckIntr = CHECK_INTR_ACTIVE;
4069                 // }
4070                 c_state =
4071                     (ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(deviceExtension->chan[c].CheckIntr),
4072                                               CRNT_ILK_TYPE CHECK_INTR_ACTIVE,
4073                                               CRNT_ILK_TYPE CHECK_INTR_DETECTED);
4074                 if(c_state == CHECK_INTR_IDLE) {
4075                     // c_state = deviceExtension->chan[c].CheckIntr;
4076                     // if (deviceExtension->chan[c].CheckIntr == CHECK_INTR_IDLE) {
4077                     //     deviceExtension->chan[c].CheckIntr = CHECK_INTR_ACTIVE
4078                     // }
4079                     c_state =
4080                         (ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(deviceExtension->chan[c].CheckIntr),
4081                                                   CRNT_ILK_TYPE CHECK_INTR_ACTIVE,
4082                                                   CRNT_ILK_TYPE CHECK_INTR_IDLE);
4083                 }
4084             } while(c_state == CHECK_INTR_CHECK);
4085             KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): locked\n"));
4086             // check if already serviced
4087             if(c_state == CHECK_INTR_ACTIVE) {
4088                 KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): CHECK_INTR_ACTIVE\n"));
4089                 continue;
4090             }
4091 
4092             if((c_state == CHECK_INTR_DETECTED) ||
4093                (i_res = AtapiCheckInterrupt__(deviceExtension, (UCHAR)c))) {
4094 
4095                 if(i_res == INTERRUPT_REASON_UNEXPECTED) {
4096                     KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): Catch unexpected\n"));
4097                     InterlockedExchange(&(deviceExtension->chan[c].CheckIntr), CHECK_INTR_IDLE);
4098                     //return TRUE;
4099                     status = TRUE;
4100                     continue;
4101                 }
4102                 // disable interrupts on other channel of legacy mode
4103                 // ISA-bridged onboard controller
4104                 if(deviceExtension->simplexOnly /*||
4105                    ((WinVer_Id() > WinVer_NT) && BMList[deviceExtension->DevIndex].MasterDev)*/) {
4106                     AtapiDisableInterrupts(deviceExtension, !c);
4107                 }
4108 
4109                 deviceExtension->chan[c].DpcState = DPC_STATE_ISR;
4110                 if(AtapiInterrupt__(HwDeviceExtension, (UCHAR)c)) {
4111                     deviceExtension->LastInterruptedChannel = (UCHAR)c;
4112                     KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): return status TRUE\n"));
4113                     status = TRUE;
4114                 } else {
4115                     KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): set CHECK_INTR_IDLE\n"));
4116                     InterlockedExchange(&(deviceExtension->chan[c].CheckIntr), CHECK_INTR_IDLE);
4117                 }
4118 
4119                 // re-enable interrupts on other channel
4120                 if(deviceExtension->simplexOnly /*||
4121                    ((WinVer_Id() > WinVer_NT) && BMList[deviceExtension->DevIndex].MasterDev)*/) {
4122                     AtapiEnableInterrupts(deviceExtension, !c);
4123                 }
4124 
4125             } else {
4126                 KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): set CHECK_INTR_IDLE (2)\n"));
4127                 InterlockedExchange(&(deviceExtension->chan[c].CheckIntr), CHECK_INTR_IDLE);
4128             }
4129 
4130         }
4131     }
4132     KdPrint2((PRINT_PREFIX "AtapiInterrupt(base): exit with status %#x\n", status));
4133     if(status) {
4134         deviceExtension->FirstChannelToCheck++;
4135         if(deviceExtension->FirstChannelToCheck >= deviceExtension->NumberChannels)
4136             deviceExtension->FirstChannelToCheck = 0;
4137     }
4138     return status;
4139 } // end AtapiInterrupt()
4140 
4141 //ULONG i2c = 0;
4142 #ifndef UNIATA_CORE
4143 
4144 BOOLEAN
4145 NTAPI
4146 AtapiInterrupt2(
4147     IN PKINTERRUPT Interrupt,
4148     IN PVOID Isr2HwDeviceExtension
4149     )
4150 {
4151     // This ISR is intended to catch interrupts when we are already in other ISR instance
4152     // for the same device. This may happen when we have multiple channels,
4153     // especially on SMP machines
4154 
4155     PISR2_DEVICE_EXTENSION Isr2DeviceExtension = (PISR2_DEVICE_EXTENSION)Isr2HwDeviceExtension;
4156     PHW_DEVICE_EXTENSION deviceExtension = Isr2DeviceExtension->HwDeviceExtension;
4157     ULONG c;
4158     BOOLEAN status = FALSE;
4159     ULONG c_count = 0;
4160     ULONG i_res;
4161     ULONG hIS;
4162     ULONG checked;
4163 
4164     // we should never get here for ISA/MCA
4165     if(!BMList[deviceExtension->DevIndex].Isr2Enable) {
4166         KdPrint2((PRINT_PREFIX "AtapiInterrupt2: NOT ACTIVE cntrlr %#x chan %#x\n",deviceExtension->DevIndex, deviceExtension->Channel));
4167         return FALSE;
4168     }
4169 
4170     if(deviceExtension->HwFlags & UNIATA_AHCI) {
4171         // AHCI may generate state change notification, never skip this check
4172         hIS = UniataAhciReadHostPort4(deviceExtension, IDX_AHCI_IS);
4173         KdPrint2((PRINT_PREFIX "AtapiInterrupt2: AHCI: hIS=%x cntrlr %#x chan %#x\n",hIS, deviceExtension->DevIndex, deviceExtension->Channel));
4174         if(!hIS) {
4175             return FALSE;
4176         }
4177         // assume all non-interrupted ports to be already checked
4178         checked = ~hIS;
4179         // assume all not implemented ports to be already checked
4180         checked |= ~deviceExtension->AHCI_PI;
4181 
4182     } else {
4183         checked = 0; // assume all ports are not checked
4184     }
4185     if(!deviceExtension->ExpectingInterrupt) {
4186         KdPrint2((PRINT_PREFIX "AtapiInterrupt2: !deviceExtension->ExpectingInterrupt\n"));
4187         deviceExtension->ExpectingInterrupt++;
4188         return FALSE;
4189     }
4190     //deviceExtension->ExpectingInterrupt = 0;
4191 
4192     for(c=0; c<deviceExtension->NumberChannels; c++) {
4193         KdPrint2((PRINT_PREFIX "AtapiInterrupt2: cntrlr %#x chan %#x\n",deviceExtension->DevIndex, c));
4194 
4195         if((checked>>c) & 0x01)
4196             continue;
4197 
4198         checked |= (ULONG)1 << c;
4199 
4200         if(CrNtInterlockedExchangeAdd(&(deviceExtension->chan[c].DisableIntr), 0)) {
4201             KdPrint2((PRINT_PREFIX "AtapiInterrupt2: disabled INTR\n"));
4202             continue;
4203         }
4204 
4205         if((ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(deviceExtension->chan[c].CheckIntr),
4206                                       CRNT_ILK_TYPE CHECK_INTR_CHECK,
4207                                       CRNT_ILK_TYPE CHECK_INTR_IDLE) != CHECK_INTR_IDLE)
4208         {
4209             KdPrint2((PRINT_PREFIX "AtapiInterrupt2: !CHECK_INTR_IDLE\n"));
4210             // hunt on unexpected intr (Some devices generate double interrupts,
4211             // some controllers (at least CMD649) interrupt twice with small delay.
4212             // If interrupts are disabled, they queue interrupt and re-issue it later,
4213             // when we do not expect it.
4214             continue;
4215         }
4216 
4217         c_count++;
4218         if((i_res = AtapiCheckInterrupt__(deviceExtension, (UCHAR)c))) {
4219 
4220             KdPrint2((PRINT_PREFIX "AtapiInterrupt2: intr\n"));
4221             if(i_res == INTERRUPT_REASON_UNEXPECTED) {
4222                 KdPrint2((PRINT_PREFIX "AtapiInterrupt2: Catch unexpected\n"));
4223                 InterlockedExchange(&(deviceExtension->chan[c].CheckIntr), CHECK_INTR_IDLE);
4224                 return TRUE;
4225             }
4226 
4227             status = TRUE;
4228             InterlockedExchange(&(deviceExtension->chan[c].CheckIntr), CHECK_INTR_DETECTED);
4229         } else {
4230             InterlockedExchange(&(deviceExtension->chan[c].CheckIntr), CHECK_INTR_IDLE);
4231         }
4232     }
4233     KdPrint2((PRINT_PREFIX "AtapiInterrupt2: status %d, c_count %d\n", status, c_count));
4234     if(status && (c_count != deviceExtension->NumberChannels)) {
4235         // there is an active ISR/DPC for one channel, but
4236         // we have an interrupt from another one
4237         // Lets inform current ISR/DPC about new interrupt
4238         InterlockedExchange(&(deviceExtension->ReCheckIntr), CHECK_INTR_DETECTED);
4239     } else {
4240         status = FALSE;
4241     }
4242     KdPrint2((PRINT_PREFIX "AtapiInterrupt2: return %d\n", status));
4243     return status;
4244 
4245 } // end AtapiInterrupt2()
4246 
4247 RETTYPE_XXableInterrupts
4248 NTAPI
4249 AtapiInterruptDpc(
4250     IN PVOID HwDeviceExtension
4251     )
4252 {
4253     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
4254     ULONG c;
4255 
4256     for(c=0; c<deviceExtension->NumberChannels; c++) {
4257         KdPrint2((PRINT_PREFIX "AtapiInterruptDpc: %#x\n",c));
4258 
4259         if(!(deviceExtension->chan[c].ChannelCtrlFlags & CTRFLAGS_DPC_REQ)) {
4260 
4261             if((ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(deviceExtension->chan[c].CheckIntr),
4262                                           CRNT_ILK_TYPE CHECK_INTR_ACTIVE,
4263                                           CRNT_ILK_TYPE CHECK_INTR_DETECTED) != CHECK_INTR_DETECTED)
4264             {
4265                 continue;
4266             }
4267 
4268         } else {
4269             deviceExtension->chan[c].ChannelCtrlFlags &= ~CTRFLAGS_DPC_REQ;
4270         }
4271 /*
4272         if(OldReqState != REQ_STATE_DPC_INTR_REQ) {
4273             AtapiDisableInterrupts(deviceExtension, lChannel);
4274         }
4275 */
4276         deviceExtension->chan[c].DpcState = DPC_STATE_DPC;
4277         if(!AtapiInterrupt__(HwDeviceExtension, (UCHAR)c)) {
4278             InterlockedExchange(&(deviceExtension->chan[c].CheckIntr), CHECK_INTR_IDLE);
4279         }
4280     }
4281     return RETVAL_XXableInterrupts;
4282 } // end AtapiInterruptDpc()
4283 
4284 
4285 RETTYPE_XXableInterrupts
4286 NTAPI
4287 AtapiEnableInterrupts__(
4288     IN PVOID HwDeviceExtension
4289     )
4290 {
4291     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
4292     KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts__():\n"));
4293     ULONG c;
4294     PHW_CHANNEL chan = NULL;
4295 
4296     for(c=0; c<deviceExtension->NumberChannels; c++) {
4297         KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts__(2): %#x\n",c));
4298         chan = &(deviceExtension->chan[c]);
4299 
4300         if(chan->ChannelCtrlFlags & CTRFLAGS_ENABLE_INTR_REQ) {
4301             // enable intrs on requested channel
4302             chan->ChannelCtrlFlags &= ~CTRFLAGS_ENABLE_INTR_REQ;
4303             AtapiEnableInterrupts(HwDeviceExtension, c);
4304             InterlockedExchange(&(chan->CheckIntr),
4305                                           CHECK_INTR_IDLE);
4306 
4307             // check if current or other channel(s) interrupted
4308             //AtapiInterrupt(HwDeviceExtension);
4309 
4310             if(deviceExtension->simplexOnly) {
4311                 break;
4312             }
4313         } else {
4314             // check if other channel(s) interrupted
4315             // must do nothing in simplex mode
4316             if((ULONG)CrNtInterlockedCompareExchange(CRNT_ILK_PTYPE &(chan->CheckIntr),
4317                                           CRNT_ILK_TYPE CHECK_INTR_ACTIVE,
4318                                           CRNT_ILK_TYPE CHECK_INTR_DETECTED) != CHECK_INTR_DETECTED) {
4319                 continue;
4320             }
4321             //ASSERT(!deviceExtension->simplexOnly);
4322             chan->DpcState = DPC_STATE_ISR;
4323             if(!AtapiInterrupt__(HwDeviceExtension, (UCHAR)c)) {
4324                 InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE);
4325             }
4326         }
4327     }
4328     // In simplex mode next command must be sent to device here
4329     if(deviceExtension->simplexOnly && chan) {
4330         PSCSI_REQUEST_BLOCK srb;
4331         chan = UniataGetNextChannel(chan);
4332         if(chan) {
4333             srb = UniataGetCurRequest(chan);
4334         } else {
4335             srb = NULL;
4336         }
4337         if(srb) {
4338             AtapiStartIo__(HwDeviceExtension, srb, FALSE);
4339         }
4340     }
4341 
4342     return RETVAL_XXableInterrupts;
4343 
4344 } // end AtapiEnableInterrupts__()
4345 
4346 #endif //UNIATA_CORE
4347 
4348 
4349 VOID
4350 NTAPI
4351 AtapiEnableInterrupts(
4352     IN PVOID HwDeviceExtension,
4353     IN ULONG c
4354     )
4355 {
4356     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
4357     PHW_CHANNEL chan;
4358     //UCHAR statusByte;
4359 
4360     if(c >= deviceExtension->NumberChannels) {
4361         KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts_%d: WRONG CHANNEL\n",c));
4362         return;
4363     }
4364     if((deviceExtension->HwFlags & UNIATA_AHCI) &&
4365        !UniataAhciChanImplemented(deviceExtension, c)) {
4366         KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts_%d: not imp. CHANNEL\n",c));
4367         return;
4368     }
4369 
4370     chan = &(deviceExtension->chan[c]);
4371     KdPrint2((PRINT_PREFIX "AtapiEnableInterrupts_%d: %d\n",c, chan->DisableIntr));
4372     if(!InterlockedDecrement(&chan->DisableIntr)) {
4373         if(deviceExtension->HwFlags & UNIATA_AHCI) {
4374             UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE,
4375                 (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF |
4376                  ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_INF | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF |
4377                  ((/*ch->pm_level == */0) ? ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC : 0) |
4378                  ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC | /* DEBUG */
4379                  ATA_AHCI_P_IX_DI |
4380                  ATA_AHCI_P_IX_DP | ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB |
4381                  ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR)
4382                 );
4383         } else {
4384             //SelectDrive(chan, 0);
4385             //GetBaseStatus(chan, statusByte);
4386             AtapiWritePort1(chan, IDX_IO2_o_Control,
4387                                    0 | IDE_DC_A_4BIT );
4388             //if(chan->NumberLuns) {
4389             //    SelectDrive(chan, 1);
4390             //    GetBaseStatus(chan, statusByte);
4391             //    AtapiWritePort1(chan, IDX_IO2_o_Control,
4392             //                           IDE_DC_A_4BIT );
4393             //    SelectDrive(chan, chan->cur_cdev);
4394             //}
4395         }
4396         chan->ChannelCtrlFlags &= ~CTRFLAGS_INTR_DISABLED;
4397     } else {
4398         if(deviceExtension->HwFlags & UNIATA_AHCI) {
4399             // keep interrupts disabled
4400             UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, 0);
4401         } else {
4402             AtapiWritePort1(chan, IDX_IO2_o_Control,
4403                                IDE_DC_DISABLE_INTERRUPTS /*| IDE_DC_A_4BIT*/ );
4404         }
4405     }
4406     return;
4407 } // end AtapiEnableInterrupts()
4408 
4409 VOID
4410 NTAPI
4411 AtapiDisableInterrupts(
4412     IN PVOID HwDeviceExtension,
4413     IN ULONG c
4414     )
4415 {
4416     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
4417     PHW_CHANNEL chan;
4418     if(c >= deviceExtension->NumberChannels) {
4419         KdPrint2((PRINT_PREFIX "AtapiDisableInterrupts_%d: WRONG CHANNEL\n",c));
4420         return;
4421     }
4422     chan = &(deviceExtension->chan[c]);
4423     KdPrint2((PRINT_PREFIX "AtapiDisableInterrupts_%d: %d\n",c, chan->DisableIntr));
4424     // mark channel as busy
4425     if(InterlockedIncrement(&chan->DisableIntr)) {
4426         if(deviceExtension->HwFlags & UNIATA_AHCI) {
4427             UniataAhciWriteChannelPort4(chan, IDX_AHCI_P_IE, 0);
4428         } else {
4429             //SelectDrive(chan, 0);
4430             AtapiWritePort1(chan, IDX_IO2_o_Control,
4431                                    IDE_DC_DISABLE_INTERRUPTS /*| IDE_DC_A_4BIT*/ );
4432             //if(chan->NumberLuns) {
4433             //    SelectDrive(chan, 1);
4434             //    AtapiWritePort1(chan, IDX_IO2_o_Control,
4435             //                           IDE_DC_DISABLE_INTERRUPTS /*| IDE_DC_A_4BIT*/ );
4436             //    SelectDrive(chan, chan->cur_cdev);
4437             //}
4438         }
4439         chan->ChannelCtrlFlags |= CTRFLAGS_INTR_DISABLED;
4440     }
4441 
4442     return;
4443 } // end AtapiDisableInterrupts()
4444 
4445 VOID
4446 UniataExpectChannelInterrupt(
4447     IN struct _HW_CHANNEL* chan,
4448     IN BOOLEAN Expecting
4449     )
4450 {
4451     chan->ExpectingInterrupt = Expecting;
4452     if(Expecting) {
4453         chan->DeviceExtension->ExpectingInterrupt++;
4454     } else
4455     if(chan->DeviceExtension->ExpectingInterrupt) {
4456         chan->DeviceExtension->ExpectingInterrupt--;
4457     }
4458     return;
4459 } // end UniataExpectChannelInterrupt()
4460 
4461 /*
4462     Check hardware for interrupt state
4463  */
4464 BOOLEAN
4465 NTAPI
4466 AtapiCheckInterrupt__(
4467     IN PVOID HwDeviceExtension,
4468     IN UCHAR c // logical channel
4469     )
4470 {
4471     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
4472     PHW_CHANNEL chan = &(deviceExtension->chan[c]);
4473     PHW_LU_EXTENSION LunExt;
4474 
4475     ULONG VendorID  = deviceExtension->DevID & 0xffff;
4476     ULONG ChipType  = deviceExtension->HwFlags & CHIPTYPE_MASK;
4477 
4478     ULONG status;
4479     ULONG pr_status = 0;
4480     UCHAR dma_status = 0;
4481     UCHAR reg8 = 0;
4482     ULONG reg32 = 0;
4483     UCHAR statusByte = 0;
4484     ULONG slotNumber = deviceExtension->slotNumber;
4485     ULONG SystemIoBusNumber = deviceExtension->SystemIoBusNumber;
4486     ULONG ChipFlags = deviceExtension->HwFlags & CHIPFLAG_MASK;
4487     UCHAR Channel;
4488     UCHAR lChannel;
4489     BOOLEAN DmaTransfer = FALSE;
4490     BOOLEAN OurInterrupt = FALSE;
4491     BOOLEAN StatusValid = FALSE;
4492 //    ULONG k;
4493     UCHAR interruptReason;
4494     BOOLEAN EarlyIntr = FALSE;
4495     BOOLEAN SingleBlockIntr = FALSE;
4496 
4497     KdPrint2((PRINT_PREFIX "AtapiCheckInterrupt__:\n"));
4498 
4499     lChannel = c;
4500     Channel = (UCHAR)(deviceExtension->Channel + lChannel);
4501     LunExt = chan->lun[chan->cur_cdev];
4502 
4503     //KdPrint2((PRINT_PREFIX "AtapiCheckInterrupt__ chan %#x:\n", chan));
4504     //KdPrint2((PRINT_PREFIX "AtapiCheckInterrupt__ (%d/%d):\n", Channel, chan->cur_cdev));
4505 
4506     if((ChipFlags & UNIATA_AHCI) &&
4507         UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
4508 
4509         if(!UniataAhciChanImplemented(deviceExtension, lChannel)) {
4510             return OurInterrupt;
4511         }
4512 
4513         OurInterrupt = UniataAhciStatus(HwDeviceExtension, lChannel, DEVNUM_NOT_SPECIFIED);
4514         if((OurInterrupt == INTERRUPT_REASON_UNEXPECTED) &&
4515            (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE)) {
4516             UniataAhciWaitCommandReady(chan, 2 /* ms */ );
4517             statusByte = (UCHAR)UniataAhciWaitReady(chan, 0 /* immediate */);
4518             if(!(statusByte & (IDE_STATUS_BUSY)) ) {
4519                 KdPrint2((PRINT_PREFIX "ATAPI special case READY\n"));
4520                 //deviceExtension->ExpectingInterrupt++; // will be updated in ISR on ReturnEnableInterrupts
4521                 OurInterrupt = INTERRUPT_REASON_OUR;
4522             } else
4523             if((statusByte & (IDE_STATUS_BUSY | IDE_STATUS_DRDY)) == (IDE_STATUS_BUSY | IDE_STATUS_DRDY) ) {
4524                 KdPrint2((PRINT_PREFIX "ATAPI special case pre ERR-READY\n"));
4525                 OurInterrupt = INTERRUPT_REASON_OUR;
4526             } else
4527             if(statusByte & IDE_STATUS_ERROR) {
4528                 KdPrint2((PRINT_PREFIX "ATAPI special case ERR-READY\n"));
4529                 OurInterrupt = INTERRUPT_REASON_OUR;
4530             } else {
4531                 KdPrint2((PRINT_PREFIX "ATAPI special case ? %x\n", statusByte));
4532                 OurInterrupt = INTERRUPT_REASON_OUR;
4533             }
4534         }
4535         return OurInterrupt;
4536     }
4537 
4538     if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE) {
4539         DmaTransfer = TRUE;
4540         KdPrint2((PRINT_PREFIX "  cntrlr %#x:%#x, lch %#x DmaTransfer = TRUE\n", deviceExtension->DevIndex,
4541             deviceExtension->Channel + c, c));
4542     } else {
4543         KdPrint2((PRINT_PREFIX "  cntrlr %#x:%#x, lch %#x DmaTransfer = FALSE\n", deviceExtension->DevIndex,
4544             deviceExtension->Channel + c, c));
4545         dma_status = GetDmaStatus(deviceExtension, lChannel);
4546         KdPrint2((PRINT_PREFIX "  DMA status %#x\n", dma_status));
4547     }
4548 
4549     // do controller-specific interrupt servicing staff
4550     if(deviceExtension->UnknownDev) {
4551         KdPrint2((PRINT_PREFIX "  UnknownDev\n"));
4552         goto check_unknown;
4553     }
4554 
4555     // Attention !
4556     // We can catch (BM_STATUS_ACTIVE + BM_STATUS_INTR) when operation is actually completed
4557     // Such behavior was observed with Intel ICH-xxx chips
4558     // This condition shall also be treated as 'our interrupt' because of BM_STATUS_INTR flag
4559 
4560     switch(VendorID) {
4561 
4562     case ATA_PROMISE_ID: {
4563         switch(ChipType) {
4564         case PROLD:
4565         case PRNEW:
4566             status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x1c);
4567             if (!DmaTransfer)
4568                 break;
4569             if (!(status &
4570                   ((Channel) ? 0x00004000 : 0x00000400))) {
4571                 KdPrint2((PRINT_PREFIX "  Promise old/new unexpected\n"));
4572                 return INTERRUPT_REASON_IGNORE;
4573             }
4574             break;
4575         case PRTX:
4576             AtapiWritePort1(chan, IDX_BM_DeviceSpecific0, 0x0b);
4577             status = AtapiReadPort1(chan, IDX_BM_DeviceSpecific1);
4578             if (!DmaTransfer)
4579                 break;
4580             if(!(status & 0x20)) {
4581                 KdPrint2((PRINT_PREFIX "  Promise tx unexpected\n"));
4582                 return INTERRUPT_REASON_IGNORE;
4583             }
4584             break;
4585         case PRMIO: {
4586             ULONG stat_reg = (ChipFlags & PRG2) ? 0x60 : 0x6c;
4587             status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x40);
4588             AtapiWritePortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),0x40, status);
4589 
4590             if(status & (1 << (Channel+1))) {
4591                 // our
4592             } else {
4593                 KdPrint2((PRINT_PREFIX "  Promise mio unexpected\n"));
4594                 return INTERRUPT_REASON_IGNORE;
4595             }
4596 
4597             if(!(ChipFlags & UNIATA_SATA))
4598                 break;
4599 
4600             pr_status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),stat_reg);
4601             AtapiWritePortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressBM_0),stat_reg, (pr_status & (0x11 << Channel)));
4602             if(pr_status & (0x11 << Channel)) {
4603                 // TODO: reset channel
4604                 KdPrint2((PRINT_PREFIX "  Promise mio unexpected + reset req\n"));
4605                 UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH, 0);
4606             }
4607             if(!(status & (0x01 << Channel))) {
4608                 // Connect event
4609                 KdPrint2((PRINT_PREFIX "  Promise mio unexpected attach\n"));
4610                 UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH, 0);
4611             }
4612             if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT, 0)) {
4613                 OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
4614             } else {
4615                 return INTERRUPT_REASON_IGNORE;
4616             }
4617 
4618             AtapiWritePort4(chan, IDX_BM_DeviceSpecific0, 0x00000001);
4619             break; }
4620         }
4621         break; }
4622     case ATA_NVIDIA_ID: {
4623         if(!(ChipFlags & UNIATA_SATA) || (ChipFlags & NVGEN))
4624             break;
4625 
4626         KdPrint2((PRINT_PREFIX "NVIDIA\n"));
4627 
4628         ULONG offs = (ChipFlags & NV4OFF) ? 0x0440 : 0x0010;
4629         ULONG shift = Channel * ((ChipFlags & NVQ) ? 4 : 16);
4630 
4631         /* get and clear interrupt status */
4632         if(ChipFlags & NVQ) {
4633             pr_status = AtapiReadPortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs);
4634             AtapiWritePortEx4(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs, (0x0fUL << shift) | 0x00f000f0);
4635         } else {
4636             pr_status = AtapiReadPortEx1(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs);
4637             AtapiWritePortEx1(chan, (ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0),offs, (0x0f << shift));
4638         }
4639         KdPrint2((PRINT_PREFIX "  pr_status %x, shift %x\n", pr_status, shift));
4640 
4641         /* check for and handle connect events */
4642         if(((pr_status & (0x0cUL << shift)) == (0x04UL << shift)) ) {
4643             UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_ATTACH, 0);
4644         }
4645         /* check for and handle disconnect events */
4646         if((pr_status & (0x08UL << shift)) &&
4647             !((pr_status & (0x04UL << shift) &&
4648             UniataSataReadPort4(chan, IDX_SATA_SStatus, 0))) ) {
4649             UniataSataEvent(deviceExtension, lChannel, UNIATA_SATA_EVENT_DETACH, 0);
4650         }
4651         /* do we have any device action ? */
4652         if(!(pr_status & (0x01UL << shift))) {
4653             KdPrint2((PRINT_PREFIX "  nVidia unexpected\n"));
4654             if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT, 0)) {
4655                 OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
4656             } else {
4657                 return INTERRUPT_REASON_IGNORE;
4658             }
4659         }
4660 
4661         break; }
4662     case ATA_ATI_ID:
4663         KdPrint2((PRINT_PREFIX "ATI\n"));
4664         if(ChipType == SIIMIO) {
4665             // fall to SiI
4666         } else {
4667             break;
4668         }
4669     case ATA_SILICON_IMAGE_ID:
4670 
4671         if(ChipType == SIIMIO) {
4672 
4673             reg32 = AtapiReadPort4(chan, IDX_BM_DeviceSpecific0);
4674             KdPrint2((PRINT_PREFIX "  Sii DS0 %x\n", reg32));
4675             if(reg32 == 0xffffffff) {
4676                 KdPrint2((PRINT_PREFIX "  Sii mio unexpected\n"));
4677                 return INTERRUPT_REASON_IGNORE;
4678             }
4679             if(!(reg32 & (BM_DS0_SII_DMA_SATA_IRQ | BM_DS0_SII_DMA_COMPLETE | BM_DS0_SII_IRQ | BM_DS0_SII_DMA_ENABLE | BM_DS0_SII_DMA_ERROR))) {
4680                 KdPrint2((PRINT_PREFIX "  Sii mio unexpected (2)\n"));
4681                 return INTERRUPT_REASON_IGNORE;
4682             }
4683 
4684             if(ChipFlags & UNIATA_SATA) {
4685                 if(reg32 & (BM_DS0_SII_DMA_SATA_IRQ | BM_DS0_SII_IRQ)) {
4686 
4687                     /* SIEN doesn't mask SATA IRQs on some 3112s.  Those
4688                     * controllers continue to assert IRQ as long as
4689                     * SError bits are pending.  Clear SError immediately.
4690                     */
4691                     if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT, 0)) {
4692                         OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
4693                     }
4694                 }
4695             }
4696 
4697             if (!DmaTransfer)
4698                 break;
4699             if (!((dma_status = GetDmaStatus(deviceExtension, lChannel)) & BM_STATUS_INTR)) {
4700                 KdPrint2((PRINT_PREFIX "  Sii mio unexpected (3)\n"));
4701                 return OurInterrupt;
4702             }
4703             AtapiWritePort1(chan, IDX_BM_Status, dma_status & ~BM_STATUS_ERR);
4704             goto skip_dma_stat_check;
4705 
4706         } else {
4707             if(!(deviceExtension->HwFlags & SIIINTR))
4708                 break;
4709             GetPciConfig1(0x71, reg8);
4710             KdPrint2((PRINT_PREFIX "  0x71 = %#x\n", reg8));
4711             if (!(reg8 &
4712                   (Channel ? 0x08 : 0x04))) {
4713                 return INTERRUPT_REASON_IGNORE;
4714             }
4715             if (!DmaTransfer) {
4716                 KdPrint2((PRINT_PREFIX "  cmd our\n"));
4717                 OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
4718             }
4719             SetPciConfig1(0x71, (Channel ? 0x08 : 0x04));
4720         }
4721         break;
4722 
4723     case ATA_ACARD_ID:
4724         if (!DmaTransfer)
4725             break;
4726         //dma_status = GetDmaStatus(deviceExtension, lChannel);
4727         if (!((dma_status = GetDmaStatus(deviceExtension, lChannel)) & BM_STATUS_INTR)) {
4728             KdPrint2((PRINT_PREFIX "  Acard unexpected\n"));
4729             return INTERRUPT_REASON_IGNORE;
4730         }
4731         AtapiWritePort1(chan, IDX_BM_Status, dma_status | BM_STATUS_INTR);
4732         AtapiStallExecution(1);
4733         AtapiWritePort1(chan, IDX_BM_Command,
4734             AtapiReadPort1(chan, IDX_BM_Command) & ~BM_COMMAND_START_STOP);
4735         goto skip_dma_stat_check;
4736     case ATA_INTEL_ID:
4737         if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
4738             if(ChipFlags & UNIATA_AHCI) {
4739                 // Do nothing here
4740             } else
4741             if(ChipFlags & UNIATA_SATA) {
4742                 if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT, 0)) {
4743                     OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
4744                 }
4745                 if(!(chan->ChannelCtrlFlags & CTRFLAGS_NO_SLAVE)) {
4746                     if(UniataSataClearErr(chan->DeviceExtension, chan->lChannel, UNIATA_SATA_IGNORE_CONNECT, 1)) {
4747                         OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
4748                     }
4749                 }
4750             }
4751         }
4752         break;
4753     default:
4754         if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
4755             if(ChipFlags & UNIATA_AHCI) {
4756                 // Do nothing here
4757             } else
4758             if(ChipFlags & UNIATA_SATA) {
4759                 if(UniataSataClearErr(HwDeviceExtension, c, UNIATA_SATA_DO_CONNECT, 0)) {
4760                     OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
4761                 }
4762             }
4763         }
4764     }
4765 check_unknown:
4766     KdPrint2((PRINT_PREFIX "  perform generic check\n"));
4767     if (DmaTransfer) {
4768         if (!((dma_status = GetDmaStatus(deviceExtension, lChannel)) & BM_STATUS_INTR)) {
4769             KdPrint2((PRINT_PREFIX "  DmaTransfer + !BM_STATUS_INTR (%x)\n", dma_status));
4770             if(dma_status & BM_STATUS_ERR) {
4771                 KdPrint2((PRINT_PREFIX "  DmaTransfer + BM_STATUS_ERR -> our\n"));
4772                 OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
4773             } else {
4774                 KdPrint2((PRINT_PREFIX "  getting status...\n"));
4775                 GetStatus(chan, statusByte);
4776                 StatusValid = 1;
4777                 KdPrint2((PRINT_PREFIX "  status %#x\n", statusByte));
4778                 if(statusByte & IDE_STATUS_ERROR) {
4779                     KdPrint2((PRINT_PREFIX "  IDE_STATUS_ERROR -> our\n", statusByte));
4780                     OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
4781                 } else
4782                 if ((statusByte & IDE_STATUS_DSC) &&
4783                     (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) &&
4784                     (dma_status == BM_STATUS_ACTIVE)) {
4785                     KdPrint2((PRINT_PREFIX "  special case DMA + ATAPI + IDE_STATUS_DSC -> our\n", statusByte));
4786                     // some devices interrupts on each block transfer even in DMA mode
4787                     if(LunExt->TransferMode >= ATA_SDMA && LunExt->TransferMode <= ATA_WDMA2) {
4788                         KdPrint2((PRINT_PREFIX "  wait for completion\n"));
4789                         ///* clear interrupt and get status */
4790                         //GetBaseStatus(chan, statusByte);
4791                         //return INTERRUPT_REASON_IGNORE;
4792                         SingleBlockIntr = TRUE;
4793                     }
4794                 } else {
4795                     return INTERRUPT_REASON_IGNORE;
4796                 }
4797             }
4798         }
4799     } else {
4800         if(dma_status & BM_STATUS_INTR) {
4801             // bullshit, we have DMA interrupt, but had never initiate DMA operation
4802             KdPrint2((PRINT_PREFIX "  clear unexpected DMA intr\n"));
4803             AtapiDmaDone(deviceExtension, DEVNUM_NOT_SPECIFIED ,lChannel, NULL);
4804             // catch it !
4805             OurInterrupt = INTERRUPT_REASON_UNEXPECTED;
4806         }
4807     }
4808 skip_dma_stat_check:
4809     if(!(ChipFlags & UNIATA_SATA) && chan->ExpectingInterrupt) {
4810         AtapiStallExecution(1);
4811     }
4812 
4813     /* if drive is busy it didn't interrupt */
4814     /* the exception is DCS + BSY state of ATAPI devices */
4815     if(!StatusValid) {
4816         KdPrint2((PRINT_PREFIX "  getting status...\n"));
4817         GetStatus(chan, statusByte);
4818     }
4819     if(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
4820         KdPrint3((PRINT_PREFIX "  ATAPI status %#x\n", statusByte));
4821     } else {
4822         KdPrint2((PRINT_PREFIX "  IDE status %#x\n", statusByte));
4823     }
4824     if (statusByte == IDE_STATUS_WRONG) {
4825         // interrupt from empty controller ?
4826     } else
4827     if (statusByte & IDE_STATUS_BUSY) {
4828         if(!chan->ExpectingInterrupt) {
4829             KdPrint3((PRINT_PREFIX "  unexpected intr + BUSY\n"));
4830             return OurInterrupt;
4831         }
4832 
4833         if(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
4834             KdPrint2((PRINT_PREFIX "  ATAPI additional check\n"));
4835         } else {
4836             KdPrint2((PRINT_PREFIX "  expecting intr + BUSY (3), non ATAPI\n"));
4837             return INTERRUPT_REASON_IGNORE;
4838         }
4839         if((statusByte & ~(IDE_STATUS_DRQ | IDE_STATUS_INDEX)) !=
4840            (IDE_STATUS_BUSY | IDE_STATUS_DRDY | IDE_STATUS_DSC)) {
4841             KdPrint3((PRINT_PREFIX "  unexpected status, seems it is not our\n"));
4842             return INTERRUPT_REASON_IGNORE;
4843         }
4844         if(!(LunExt->DeviceFlags & DFLAGS_INT_DRQ) && (statusByte & IDE_STATUS_DRQ)) {
4845             KdPrint3((PRINT_PREFIX "  unexpected DRQ, seems it is not our\n"));
4846             return INTERRUPT_REASON_IGNORE;
4847         }
4848 
4849         EarlyIntr = TRUE;
4850 
4851         if(dma_status & BM_STATUS_INTR) {
4852             KdPrint3((PRINT_PREFIX "  our interrupt with BSY set, try wait in ISR or post to DPC\n"));
4853             /* clear interrupt and get status */
4854             GetBaseStatus(chan, statusByte);
4855             if(!(dma_status & BM_STATUS_ACTIVE)) {
4856                 AtapiDmaDone(deviceExtension, DEVNUM_NOT_SPECIFIED ,lChannel, NULL);
4857             }
4858             KdPrint3((PRINT_PREFIX "  base status %#x (+BM_STATUS_INTR)\n", statusByte));
4859             return INTERRUPT_REASON_OUR;
4860         }
4861 
4862         if(g_WaitBusyInISR) {
4863             GetStatus(chan, statusByte);
4864             KdPrint2((PRINT_PREFIX "  status re-check %#x\n", statusByte));
4865             reg8 = AtapiReadPort1(chan, IDX_IO1_i_Error);
4866             KdPrint2((PRINT_PREFIX "  Error reg (%#x)\n", reg8));
4867             if (!(statusByte & IDE_STATUS_BUSY)) {
4868                 KdPrint2((PRINT_PREFIX "  expecting intr + cleared BUSY\n"));
4869             }
4870             if (statusByte & IDE_STATUS_BUSY) {
4871                 KdPrint2((PRINT_PREFIX "  still BUSY, seems it is not our\n"));
4872                 return INTERRUPT_REASON_IGNORE;
4873             }
4874         }
4875 
4876     }
4877 
4878     /* clear interrupt and get status */
4879     GetBaseStatus(chan, statusByte);
4880     KdPrint2((PRINT_PREFIX "  base status %#x\n", statusByte));
4881     if (statusByte == IDE_STATUS_WRONG) {
4882         // interrupt from empty controller ?
4883     } else
4884     if(!(statusByte & (IDE_STATUS_DRQ | IDE_STATUS_DRDY))) {
4885         KdPrint2((PRINT_PREFIX "  no DRQ/DRDY set\n"));
4886         return OurInterrupt;
4887     }
4888 
4889 #ifndef UNIATA_PIO_ONLY
4890     if(DmaTransfer) {
4891         if(!SingleBlockIntr && (!EarlyIntr || g_WaitBusyInISR)) {
4892             dma_status = AtapiDmaDone(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, lChannel, NULL/*srb*/);
4893         } else {
4894             PSCSI_REQUEST_BLOCK srb = UniataGetCurRequest(chan);
4895             PATA_REQ AtaReq = srb ? (PATA_REQ)(srb->SrbExtension) : NULL;
4896 
4897             //ASSERT(AtaReq);
4898 
4899             if(SingleBlockIntr) {
4900                 KdPrint2((PRINT_PREFIX "  set REQ_STATE_ATAPI_EXPECTING_DATA_INTR2.\n"));
4901             } else {
4902                 KdPrint2((PRINT_PREFIX "  set REQ_STATE_EARLY_INTR.\n"));
4903             }
4904             if(AtaReq) {
4905                 AtaReq->ReqState = SingleBlockIntr ? REQ_STATE_ATAPI_EXPECTING_DATA_INTR2 : REQ_STATE_EARLY_INTR;
4906             }
4907         }
4908     }
4909 #endif //
4910 
4911     if (!(chan->ExpectingInterrupt)) {
4912 
4913         KdPrint2((PRINT_PREFIX "  Unexpected interrupt.\n"));
4914 
4915         if(LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) {
4916             KdPrint2((PRINT_PREFIX "  ATAPI additional check\n"));
4917         } else {
4918             KdPrint2((PRINT_PREFIX "  OurInterrupt = %d\n", OurInterrupt));
4919             return OurInterrupt;
4920         }
4921         interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & ATAPI_IR_Mask);
4922         KdPrint3((PRINT_PREFIX "AtapiCheckInterrupt__: ATAPI int reason %x\n", interruptReason));
4923         return OurInterrupt;
4924     }
4925     //ASSERT(!chan->queue_depth || chan->cur_req);
4926 
4927     KdPrint2((PRINT_PREFIX "AtapiCheckInterrupt__: exit with TRUE\n"));
4928     return INTERRUPT_REASON_OUR;
4929 
4930 } // end AtapiCheckInterrupt__()
4931 
4932 
4933 BOOLEAN
4934 NTAPI
4935 AtapiInterrupt__(
4936     IN PVOID HwDeviceExtension,
4937     IN UCHAR c
4938     )
4939 {
4940     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
4941     PHW_CHANNEL chan = &(deviceExtension->chan[c]);
4942     // Get current Srb
4943     PSCSI_REQUEST_BLOCK srb = UniataGetCurRequest(chan);
4944     PATA_REQ AtaReq = srb ? (PATA_REQ)(srb->SrbExtension) : NULL;
4945 
4946     ULONG wordCount = 0, wordsThisInterrupt = DEV_BSIZE/2;
4947     ULONG status = SRB_STATUS_SUCCESS;
4948     UCHAR dma_status = 0;
4949     ULONG i;
4950     ULONG k;
4951     UCHAR statusByte = 0,interruptReason;
4952 
4953     BOOLEAN atapiDev = FALSE;
4954 
4955 #ifdef _DEBUG
4956     UCHAR Channel;
4957 #endif //_DEBUG
4958     UCHAR lChannel;
4959     UCHAR DeviceNumber;
4960     BOOLEAN DmaTransfer = FALSE;
4961     UCHAR error = 0;
4962     ULONG TimerValue = 1000;
4963     ULONG TotalTimerValue = 0;
4964 #ifdef UNIATA_USE_XXableInterrupts
4965     BOOLEAN InDpc = (KeGetCurrentIrql() == DISPATCH_LEVEL);
4966 #else
4967     BOOLEAN InDpc = (chan->DpcState != DPC_STATE_ISR);
4968 #endif // UNIATA_USE_XXableInterrupts
4969     BOOLEAN UseDpc = deviceExtension->UseDpc;
4970 //    BOOLEAN RestoreUseDpc = FALSE;
4971     BOOLEAN DataOverrun = FALSE;
4972     BOOLEAN NoStartIo = TRUE;
4973     BOOLEAN NoRetry = FALSE;
4974 
4975     KdPrint2((PRINT_PREFIX "AtapiInterrupt:\n"));
4976     if(InDpc) {
4977         KdPrint2((PRINT_PREFIX "  InDpc = TRUE\n"));
4978         //ASSERT((chan->ChannelCtrlFlags & CTRFLAGS_INTR_DISABLED));
4979     }
4980 
4981     UCHAR PathId;
4982     UCHAR TargetId;
4983     UCHAR Lun;
4984     UCHAR OldReqState = REQ_STATE_NONE;
4985     //ULONG ldev;
4986     PHW_LU_EXTENSION LunExt;
4987 
4988     lChannel = c;
4989 
4990 #ifdef _DEBUG
4991     Channel = (UCHAR)(deviceExtension->Channel + lChannel);
4992 
4993     KdPrint2((PRINT_PREFIX "  cntrlr %#x:%d, irql %#x, c %d\n", deviceExtension->DevIndex, Channel, KeGetCurrentIrql(), c));
4994 #endif //_DEBUG
4995 
4996     if((chan->ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE) ||
4997        (AtaReq && (AtaReq->Flags & REQ_FLAG_DMA_OPERATION)) ||
4998        (deviceExtension->HwFlags & UNIATA_AHCI)) {
4999         DmaTransfer = TRUE;
5000         KdPrint2((PRINT_PREFIX "  DmaTransfer = TRUE\n"));
5001     }
5002 
5003     if (srb) {
5004         PathId   = srb->PathId;
5005         TargetId = srb->TargetId;
5006         Lun      = srb->Lun;
5007     } else {
5008         PathId = (UCHAR)c;
5009         TargetId =
5010         Lun      = 0;
5011         goto enqueue_next_req;
5012     }
5013 
5014     //ldev = GET_LDEV2(PathId, TargetId, Lun);
5015     DeviceNumber = (UCHAR)(TargetId);
5016     LunExt = chan->lun[DeviceNumber];
5017     atapiDev = (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) ? TRUE : FALSE;
5018     KdPrint2((PRINT_PREFIX "  dev_type %s\n", atapiDev ? "ATAPI" : "IDE"));
5019 
5020     // check if we are in ISR DPC
5021     if(InDpc) {
5022         KdPrint2((PRINT_PREFIX "  InDpc -> CTRFLAGS_INTR_DISABLED\n"));
5023         goto ServiceInterrupt;
5024     }
5025 
5026     if (DmaTransfer) {
5027         dma_status = GetDmaStatus(deviceExtension, lChannel);
5028     }
5029 
5030     if (!(chan->ExpectingInterrupt)) {
5031 
5032         KdPrint2((PRINT_PREFIX "  Unexpected interrupt for this channel.\n"));
5033         return FALSE;
5034     }
5035 
5036     // change request state
5037     if(AtaReq) {
5038         OldReqState = AtaReq->ReqState;
5039         AtaReq->ReqState = REQ_STATE_PROCESSING_INTR;
5040         KdPrint2((PRINT_PREFIX "  OldReqState = %x\n", OldReqState));
5041     }
5042 
5043     // We don't want using DPC for fast operations, like
5044     // DMA completion, sending CDB, short ATAPI transfers, etc.
5045     // !!!! BUT !!!!
5046     // We MUST use DPC, because of interprocessor synchronization
5047     // on multiprocessor platforms
5048 
5049     if(DmaTransfer)
5050         goto ServiceInterrupt;
5051 
5052     switch(OldReqState) {
5053     case REQ_STATE_ATAPI_EXPECTING_CMD_INTR:
5054         KdPrint3((PRINT_PREFIX "  EXPECTING_CMD_INTR\n"));
5055     case REQ_STATE_ATAPI_EXPECTING_DATA_INTR:
5056     case REQ_STATE_ATAPI_EXPECTING_DATA_INTR2:
5057     case REQ_STATE_DPC_WAIT_BUSY0:
5058     case REQ_STATE_DPC_WAIT_BUSY1:
5059         KdPrint2((PRINT_PREFIX "  continue service interrupt\n"));
5060         goto ServiceInterrupt;
5061     case REQ_STATE_ATAPI_DO_NOTHING_INTR:
5062         KdPrint2((PRINT_PREFIX "  do nothing on interrupt\n"));
5063         return TRUE;
5064     }
5065 
5066     if((!DmaTransfer && !atapiDev) || deviceExtension->DriverMustPoll) {
5067         KdPrint2((PRINT_PREFIX "  service PIO HDD\n"));
5068         UseDpc = FALSE;
5069     }
5070 
5071 #ifndef UNIATA_CORE
5072 
5073     if(!UseDpc)
5074         goto ServiceInterrupt;
5075 
5076 #ifdef UNIATA_USE_XXableInterrupts
5077     if(InDpc) {
5078         KdPrint2((PRINT_PREFIX "  Unexpected InDpc\n"));
5079         ASSERT(FALSE);
5080         // shall never get here
5081         TimerValue = 1;
5082         goto CallTimerDpc;
5083     }
5084 
5085     KdPrint2((PRINT_PREFIX "  this is direct DPC call on DRQL\n"));
5086     if(AtaReq) {
5087         AtaReq->ReqState = REQ_STATE_DPC_INTR_REQ;
5088         KdPrint2((PRINT_PREFIX "  ReqState -> REQ_STATE_DPC_INTR_REQ\n"));
5089     } else {
5090         KdPrint2((PRINT_PREFIX "  DPC without AtaReq!!!\n"));
5091     }
5092 #else
5093     KdPrint2((PRINT_PREFIX "call service interrupt\n"));
5094     goto ServiceInterrupt;
5095 #endif // UNIATA_USE_XXableInterrupts
5096 
5097 PostToDpc:
5098 
5099     // Attention !!!
5100     // AtapiInterruptDpc() is called on DISPATCH_LEVEL
5101     // We always get here when are called from timer callback, which is invoked on DRQL.
5102     // It is intended to lower IRQL and let other interrupts to be serviced while we are waiting for BUSY release
5103 
5104     KdPrint2((PRINT_PREFIX "AtapiInterrupt: start DPC init...\n"));
5105     // disable interrupts for this channel,
5106     // but avoid recursion and double-disable
5107     if(OldReqState != REQ_STATE_DPC_WAIT_BUSY1) {
5108         UniataExpectChannelInterrupt(chan, FALSE);
5109         AtapiDisableInterrupts(deviceExtension, lChannel);
5110     }
5111     // go to ISR DPC
5112     chan->ChannelCtrlFlags |= CTRFLAGS_DPC_REQ;
5113 
5114 #ifdef UNIATA_USE_XXableInterrupts
5115     // Will lower IRQL to DISPATCH_LEVEL
5116     ScsiPortNotification(CallEnableInterrupts, HwDeviceExtension,
5117                          /*c ?*/ AtapiInterruptDpc/*_1 : AtapiInterruptDpc_0*/);
5118     KdPrint2((PRINT_PREFIX "AtapiInterrupt: DPC inited\n"));
5119 #else
5120     // Will raise IRQL to DIRQL
5121     AtapiQueueTimerDpc(HwDeviceExtension, c,
5122                          AtapiInterruptDpc,
5123                          TimerValue);
5124     KdPrint2((PRINT_PREFIX "AtapiInterrupt: Timer DPC inited\n"));
5125 #endif // UNIATA_USE_XXableInterrupts
5126     return TRUE;
5127 
5128 #ifndef UNIATA_CORE
5129 CallTimerDpc:
5130     AtaReq->ReqState = REQ_STATE_PROCESSING_INTR;
5131 CallTimerDpc2:
5132     if(!InDpc && OldReqState != REQ_STATE_DPC_WAIT_BUSY1) {
5133         // we must block interrupts from this channel
5134         // If device generate new interrupt before we get to DPC,
5135         // ISR will assume, that it is NOT our interrupt
5136         AtapiDisableInterrupts(deviceExtension, lChannel);
5137         // We should not clean ExpectingInterrupt flag on channel, since it is used in DPC
5138     }
5139     // Will raise IRQL to DIRQL
5140     AtapiQueueTimerDpc(HwDeviceExtension, c,
5141                          AtapiCallBack_X,
5142                          TimerValue);
5143     return TRUE;
5144 #endif //UNIATA_CORE
5145 
5146 ServiceInterrupt:
5147 
5148     if(AtaReq && InDpc) {
5149         switch(AtaReq->ReqState) {
5150         case REQ_STATE_DPC_WAIT_DRQ0:
5151             goto PIO_wait_DRQ0;
5152         case REQ_STATE_DPC_WAIT_BUSY:
5153             goto PIO_wait_busy;
5154         case REQ_STATE_DPC_WAIT_DRQ:
5155             goto PIO_wait_DRQ;
5156         case REQ_STATE_DPC_WAIT_DRQ_ERR:
5157             goto continue_err;
5158         case REQ_STATE_DPC_WAIT_BUSY0:
5159         case REQ_STATE_DPC_WAIT_BUSY1:
5160             // continue normal execution
5161             break;
5162         }
5163     }
5164 #else
5165 ServiceInterrupt:
5166 #endif //UNIATA_CORE
5167 /*
5168     // make additional delay for old devices (if we are not in DPC)
5169     if((!LunExt->IdentifyData.MajorRevision || (deviceExtension->lun[DeviceNumber].TransferMode < ATA_PIO4))
5170              &&
5171        !InDpc &&
5172        !atapiDev &&
5173        !(deviceExtension->HwFlags & UNIATA_SATA)
5174        ) {
5175         KdPrint2((PRINT_PREFIX "  additional delay 10us for old devices\n"));
5176         AtapiStallExecution(10);
5177     }
5178 */
5179 
5180     /* clear interrupt and get status */
5181     if(deviceExtension->HwFlags & UNIATA_AHCI) {
5182         UniataAhciEndTransaction(HwDeviceExtension, lChannel, DeviceNumber, srb);
5183         statusByte = (UCHAR)(AtaReq->ahci.in_status & IDE_STATUS_MASK);
5184 
5185         if(chan->AhciLastIS & ~(ATA_AHCI_P_IX_DHR | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_SDB)) {
5186             KdPrint3((PRINT_PREFIX "Err intr (%#x), SE (%#x)\n",
5187                 chan->AhciLastIS & ~(ATA_AHCI_P_IX_DHR | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_SDB),
5188                 chan->AhciLastSError));
5189             if(chan->AhciLastIS & ~ATA_AHCI_P_IX_OF) {
5190 
5191                 if((chan->AhciLastIS == ATA_AHCI_P_IX_INF) &&
5192                    !(statusByte & IDE_STATUS_ERROR) &&
5193                    !chan->AhciLastSError &&
5194                    srb && (srb->SrbFlags & SRB_FLAGS_DATA_IN)
5195                    ) {
5196                   KdPrint3((PRINT_PREFIX "ATA_AHCI_P_IX_INF on READ, assume underflow\n"));
5197                   // continue processing in regular way
5198                 } else {
5199 
5200                   //KdPrint3((PRINT_PREFIX "Err mask (%#x)\n", chan->AhciLastIS & ~ATA_AHCI_P_IX_OF));
5201                   // We have some other error except Overflow
5202                   // Just signal ERROR, operation will be aborted in ERROR branch.
5203                   statusByte |= IDE_STATUS_ERROR;
5204                   AtaReq->ahci.in_serror = chan->AhciLastSError;
5205                   if(chan->AhciLastSError & (ATA_SE_HANDSHAKE_ERR | ATA_SE_LINKSEQ_ERR | ATA_SE_TRANSPORT_ERR | ATA_SE_UNKNOWN_FIS)) {
5206                       KdPrint2((PRINT_PREFIX "Unrecoverable\n"));
5207                       NoRetry = TRUE;
5208                   }
5209                 }
5210             } else {
5211                 // We have only Overflow. Abort operation and continue
5212 #ifdef _DEBUG
5213                 UniataDumpAhciPortRegs(chan);
5214 #endif
5215                 if(!UniataAhciAbortOperation(chan)) {
5216                     KdPrint2((PRINT_PREFIX "need UniataAhciReset\n"));
5217                 }
5218 #ifdef _DEBUG
5219                 UniataDumpAhciPortRegs(chan);
5220 #endif
5221                 UniataAhciWaitCommandReady(chan, 10);
5222             }
5223         }
5224 
5225     } else {
5226         GetBaseStatus(chan, statusByte);
5227     }
5228     if(atapiDev) {
5229         KdPrint3((PRINT_PREFIX "AtapiInterrupt: ATAPI Entered with status (%#x)\n", statusByte));
5230     } else {
5231         KdPrint2((PRINT_PREFIX "AtapiInterrupt: Entered with status (%#x)\n", statusByte));
5232     }
5233 
5234     if(!UseDpc) {
5235         KdPrint2((PRINT_PREFIX "  operate like in DPC\n"));
5236         InDpc = TRUE;
5237     }
5238 
5239     if (!atapiDev) {
5240         // IDE
5241         if(deviceExtension->HwFlags & UNIATA_AHCI) {
5242             KdPrint3((PRINT_PREFIX "  AHCI branch (IDE)\n"));
5243         } else
5244         if (statusByte & IDE_STATUS_BUSY) {
5245             if (deviceExtension->DriverMustPoll) {
5246                 // Crashdump is polling and we got caught with busy asserted.
5247                 // Just go away, and we will be polled again shortly.
5248                 KdPrint2((PRINT_PREFIX "  Hit BUSY while polling during crashdump.\n"));
5249                 goto ReturnEnableIntr;
5250             }
5251 try_dpc_wait:
5252             // Ensure BUSY is non-asserted.
5253             // make a very small idle before falling to DPC
5254             k = (InDpc && UseDpc) ? 1000 : 2;
5255 
5256             for (i = 0; i < k; i++) {
5257 
5258                 GetBaseStatus(chan, statusByte);
5259                 if (!(statusByte & IDE_STATUS_BUSY)) {
5260                     break;
5261                 }
5262                 AtapiStallExecution(10);
5263             }
5264 
5265             if (!InDpc && UseDpc && i == 2) {
5266 
5267                 KdPrint2((PRINT_PREFIX "  BUSY on entry. Status %#x, Base IO %#x\n", statusByte));
5268 
5269                 TimerValue = 50;
5270                 AtaReq->ReqState = REQ_STATE_DPC_WAIT_BUSY0;
5271 
5272 #ifndef UNIATA_CORE
5273                 goto PostToDpc;
5274 #else //UNIATA_CORE
5275                 AtapiStallExecution(TimerValue);
5276                 goto ServiceInterrupt;
5277 #endif //UNIATA_CORE
5278             } else
5279             if (InDpc && i == k) {
5280                 // reset the controller.
5281                 KdPrint2((PRINT_PREFIX
5282                             "  Resetting due to BUSY on entry - %#x.\n",
5283                             statusByte));
5284                 goto IntrPrepareResetController;
5285             }
5286         }
5287     } else {
5288         // ATAPI
5289         if(!LunExt->IdentifyData.MajorRevision &&
5290             InDpc &&
5291             /*!atapiDev &&*/
5292             !(deviceExtension->HwFlags & UNIATA_SATA)
5293             ) {
5294             //KdPrint2((PRINT_PREFIX "  additional delay 10us for old devices (2)\n"));
5295             //AtapiStallExecution(10);
5296         }
5297         if(deviceExtension->HwFlags & UNIATA_AHCI) {
5298             KdPrint3((PRINT_PREFIX "  AHCI branch (ATAPI)\n"));
5299         } else {
5300             interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & ATAPI_IR_Mask);
5301             KdPrint3((PRINT_PREFIX "AtapiInterrupt: iReason %x\n", interruptReason));
5302         }
5303 
5304         if (statusByte & IDE_STATUS_BUSY) {
5305         //if(chan->ChannelCtrlFlags & CTRFLAGS_DSC_BSY) {}
5306 /*
5307 #ifndef UNIATA_CORE
5308             // This is just workaround
5309             // We should DISABLE interrupts before entering WAIT state
5310             UniataExpectChannelInterrupt(chan, TRUE);
5311 #endif //UNIATA_CORE
5312 */
5313             KdPrint3((PRINT_PREFIX "  BUSY on ATAPI device, waiting %d us\n", LunExt->AtapiReadyWaitDelay));
5314 #ifndef UNIATA_CORE
5315             if(LunExt->AtapiReadyWaitDelay && (LunExt->AtapiReadyWaitDelay > g_opt_MaxIsrWait) && !InDpc && UseDpc) {
5316                 TimerValue = LunExt->AtapiReadyWaitDelay;
5317                 KdPrint2((PRINT_PREFIX "  too long wait: ISR -> DPC (0)\n"));
5318                 AtaReq->ReqState = REQ_STATE_DPC_WAIT_BUSY0;
5319                 goto CallTimerDpc2;
5320             }
5321 #endif //UNIATA_CORE
5322             TimerValue = 10;
5323             for(k=20; k; k--) {
5324                 GetBaseStatus(chan, statusByte);
5325                 KdPrint3((PRINT_PREFIX "  status re-check %#x\n", statusByte));
5326                 KdPrint3((PRINT_PREFIX "  Error reg (%#x)\n",
5327                             AtapiReadPort1(chan, IDX_ATAPI_IO1_i_Error)));
5328                 if (!(statusByte & IDE_STATUS_BUSY)) {
5329                     KdPrint2((PRINT_PREFIX "  expecting intr + cleared BUSY\n"));
5330                     break;
5331                 }
5332                 TotalTimerValue += TimerValue;
5333                 if(k <= 1) {
5334                     KdPrint3((PRINT_PREFIX "  too long wait -> DPC\n"));
5335                     if(!InDpc) {
5336                         KdPrint2((PRINT_PREFIX "  too long wait: ISR -> DPC\n"));
5337                         TimerValue = 100;
5338                         AtaReq->ReqState = REQ_STATE_DPC_WAIT_BUSY0;
5339                     } else {
5340                         KdPrint2((PRINT_PREFIX "  too long wait: DPC -> DPC\n"));
5341                         TimerValue = 1000;
5342                         AtaReq->ReqState = REQ_STATE_DPC_WAIT_BUSY1;
5343                     }
5344 #ifndef UNIATA_CORE
5345                     if(UseDpc) {
5346                         if(!LunExt->AtapiReadyWaitDelay) {
5347                             LunExt->AtapiReadyWaitDelay = TotalTimerValue*2/3;
5348                         }
5349                         goto CallTimerDpc2;
5350                     }
5351 #endif //UNIATA_CORE
5352                 }
5353 
5354                 AtapiStallExecution(TimerValue);
5355                 TimerValue += 10;
5356             }
5357             if(!LunExt->AtapiReadyWaitDelay) {
5358                 LunExt->AtapiReadyWaitDelay = TotalTimerValue*2/3;
5359                 KdPrint2((PRINT_PREFIX "  store AtapiReadyWaitDelay: %d\n", LunExt->AtapiReadyWaitDelay));
5360             }
5361             if (statusByte & IDE_STATUS_BUSY) {
5362                 KdPrint3((PRINT_PREFIX "  expecting intr + BUSY (2), try DPC wait\n"));
5363                 goto try_dpc_wait;
5364             }
5365         }
5366     }
5367 
5368     if(AtaReq && DmaTransfer && !(deviceExtension->HwFlags & UNIATA_AHCI)) {
5369         switch(OldReqState) {
5370         case REQ_STATE_EARLY_INTR:
5371         case REQ_STATE_DPC_WAIT_BUSY0:
5372 
5373             if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_ACTIVE) {
5374                 KdPrint2((PRINT_PREFIX "AtapiInterrupt: DMA still active\n"));
5375                 dma_status = AtapiDmaDone(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, lChannel, NULL/*srb*/);
5376             }
5377             break;
5378         }
5379     }
5380 
5381 //retry_check:
5382     // Check for error conditions.
5383     if ((statusByte & IDE_STATUS_ERROR) ||
5384         (dma_status & BM_STATUS_ERR)) {
5385 
5386         if(deviceExtension->HwFlags & UNIATA_AHCI) {
5387             error = AtaReq->ahci.in_error;
5388             // wait ready
5389 #ifdef _DEBUG
5390             UniataDumpAhciPortRegs(chan);
5391 #endif
5392             if(!UniataAhciAbortOperation(chan)) {
5393                 KdPrint2((PRINT_PREFIX "need UniataAhciReset\n"));
5394             }
5395             // clear interrupts again
5396             UniataAhciWaitCommandReady(chan, 10);
5397 #ifdef _DEBUG
5398             UniataDumpAhciPortRegs(chan);
5399 #endif
5400             UniataAhciStatus(HwDeviceExtension, lChannel, DEVNUM_NOT_SPECIFIED);
5401             if(NoRetry) {
5402                 AtaReq->retry += MAX_RETRIES;
5403                 if(!error && (statusByte & IDE_STATUS_ERROR)) {
5404                     KdPrint2((PRINT_PREFIX "AtapiInterrupt: force error status\n"));
5405                     error |= IDE_STATUS_ERROR;
5406                 }
5407             }
5408 #ifdef _DEBUG
5409             UniataDumpAhciPortRegs(chan);
5410 #endif
5411         } else {
5412             error = AtapiReadPort1(chan, IDX_IO1_i_Error);
5413         }
5414         KdPrint2((PRINT_PREFIX "AtapiInterrupt: Error %#x\n", error));
5415 /*
5416         if(error & IDE_STATUS_CORRECTED_ERROR) {
5417             KdPrint2((PRINT_PREFIX "AtapiInterrupt: (corrected)\n"));
5418             statusByte &= ~IDE_STATUS_ERROR;
5419             goto retry_check;
5420         }
5421 */
5422         if(AtaReq) {
5423             KdPrint2((PRINT_PREFIX "  Bad Lba %#I64x\n", AtaReq->lba));
5424         } else {
5425             KdPrint2((PRINT_PREFIX "  Bad Lba unknown\n"));
5426         }
5427 
5428         if(deviceExtension->HwFlags & UNIATA_AHCI) {
5429             KdPrint2((PRINT_PREFIX "  no wait ready after error\n"));
5430         } else
5431         if(!atapiDev) {
5432             KdPrint2((PRINT_PREFIX "  wait 100 ready after IDE error\n"));
5433             AtapiStallExecution(100);
5434         } else {
5435             KdPrint2((PRINT_PREFIX "  wait 10 ready after ATAPI error\n"));
5436             AtapiStallExecution(10);
5437         }
5438 continue_err:
5439 
5440         KdPrint3((PRINT_PREFIX "  Intr on DRQ %x\n",
5441             LunExt->DeviceFlags & DFLAGS_INT_DRQ));
5442 
5443         for (k = atapiDev ? 0 : 200; k; k--) {
5444             GetBaseStatus(chan, statusByte);
5445             if (!(statusByte & IDE_STATUS_DRQ)) {
5446                 AtapiStallExecution(50);
5447             } else {
5448                 break;
5449             }
5450         }
5451 
5452         if (!atapiDev) {
5453             /* if this is a UDMA CRC error, reinject request */
5454 
5455             AtaReq->retry++;
5456             if(AtaReq->retry < MAX_RETRIES) {
5457 #ifdef IO_STATISTICS
5458                 chan->lun[DeviceNumber]->ModeErrorCount[AtaReq->retry]++;
5459 #endif //IO_STATISTICS
5460                 if(DmaTransfer /*&&
5461                    (error & IDE_ERROR_ICRC)*/) {
5462                     KdPrint2((PRINT_PREFIX "Errors in DMA mode\n"));
5463                     if(AtaReq->retry < MAX_RETRIES) {
5464 //fallback_pio:
5465                         if(!(deviceExtension->HwFlags & UNIATA_AHCI)) {
5466                             //AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
5467                             // Downrate will happen in AtapiDmaReinit(), try UDMA-2 for HDD only
5468                             AtaReq->Flags |= REQ_FLAG_FORCE_DOWNRATE;
5469                         }
5470                         AtaReq->ReqState = REQ_STATE_QUEUED;
5471                         goto reenqueue_req;
5472                     }
5473                 } else {
5474                     if(!(AtaReq->Flags & REQ_FLAG_FORCE_DOWNRATE)) {
5475                         AtaReq->retry++;
5476                     }
5477                     KdPrint2((PRINT_PREFIX "Errors in PIO mode\n"));
5478                 }
5479             }
5480         } else {
5481             interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & ATAPI_IR_Mask);
5482             KdPrint3((PRINT_PREFIX "AtapiInterrupt: ATAPI Error, int reason %x\n", interruptReason));
5483 
5484             if(UniataIsSATARangeAvailable(deviceExtension, lChannel)) {
5485                 if(deviceExtension->HwFlags & UNIATA_AHCI) {
5486                     // Do nothing here
5487                 } else
5488                 if(deviceExtension->HwFlags & UNIATA_SATA) {
5489                     UniataSataClearErr(HwDeviceExtension, lChannel, UNIATA_SATA_IGNORE_CONNECT, 0);
5490                 }
5491             }
5492 
5493             if(DmaTransfer && (chan->lun[DeviceNumber]->TransferMode > ATA_UDMA2) &&
5494                ((error >> 4) == SCSI_SENSE_HARDWARE_ERROR)) {
5495                 if(AtaReq->retry < MAX_RETRIES) {
5496 //fallback_pio:
5497                     // Downrate will happen in AtapiDmaReinit(), use PIO immediately for ATAPI
5498                     AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
5499                     AtaReq->Flags |= REQ_FLAG_FORCE_DOWNRATE;
5500 //                        LunExt->DeviceFlags |= DFLAGS_FORCE_DOWNRATE;
5501                     AtaReq->ReqState = REQ_STATE_QUEUED;
5502                     goto reenqueue_req;
5503                 }
5504             } else {
5505                 if(!(AtaReq->Flags & REQ_FLAG_FORCE_DOWNRATE)) {
5506                     AtaReq->retry++;
5507                 }
5508                 KdPrint3((PRINT_PREFIX "Errors in PIO mode\n"));
5509             }
5510         }
5511 
5512         KdPrint3((PRINT_PREFIX "AtapiInterrupt: Error\n"));
5513         if (srb->Cdb[0] != SCSIOP_REQUEST_SENSE) {
5514             // Fail this request.
5515             status = SRB_STATUS_ERROR;
5516             goto CompleteRequest;
5517         } else {
5518             KdPrint2((PRINT_PREFIX "  continue with SCSIOP_REQUEST_SENSE\n"));
5519         }
5520     } else
5521     if(AtaReq->Flags & REQ_FLAG_FORCE_DOWNRATE_LBA48) {
5522         KdPrint2((PRINT_PREFIX "DMA doesn't work right with LBA48\n"));
5523         deviceExtension->HbaCtrlFlags |= HBAFLAGS_DMA_DISABLED_LBA48;
5524     } else
5525     if(AtaReq->Flags & REQ_FLAG_FORCE_DOWNRATE) {
5526 #ifdef IO_STATISTICS
5527         KdPrint2((PRINT_PREFIX "Some higher mode doesn't work right :((\n"));
5528         KdPrint2((PRINT_PREFIX "Recovery stats[%d]: %d vs %d\n",
5529               AtaReq->retry,
5530               LunExt->RecoverCount[AtaReq->retry],
5531               LunExt->BlockIoCount
5532               ));
5533         LunExt->RecoverCount[AtaReq->retry]++;
5534         if(LunExt->RecoverCount[AtaReq->retry] >= LunExt->BlockIoCount/3 ||
5535            (deviceExtension->HwFlags & UNIATA_NO80CHK)
5536            ) {
5537 #else
5538         if(deviceExtension->HwFlags & UNIATA_NO80CHK) {
5539 #endif //IO_STATISTICS
5540             KdPrint2((PRINT_PREFIX "Limit transfer rate to %x\n", LunExt->TransferMode));
5541             LunExt->LimitedTransferMode =
5542                 LunExt->TransferMode;
5543         }
5544     }
5545 #ifdef IO_STATISTICS
5546     if(AtaReq->bcount) {
5547         // we need stats for Read/Write operations
5548         LunExt->BlockIoCount++;
5549     }
5550     LunExt->IoCount++;
5551 #endif //IO_STATISTICS
5552 
5553 continue_PIO:
5554 
5555     // check reason for this interrupt.
5556     if (atapiDev) {
5557 
5558         KdPrint2((PRINT_PREFIX "AtapiInterrupt: ATAPI branch\n"));
5559         // ATAPI branch
5560 
5561         interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & ATAPI_IR_Mask);
5562         KdPrint3((PRINT_PREFIX "AtapiInterrupt: iReason %x\n", interruptReason));
5563         if(DmaTransfer) {
5564             wordsThisInterrupt = DEV_BSIZE/2*512;
5565         } else {
5566             wordsThisInterrupt = DEV_BSIZE/2;
5567         }
5568 
5569     } else {
5570 
5571         // ATA branch
5572 
5573         if(DmaTransfer) {
5574             // simulate DRQ for DMA transfers
5575             statusByte |= IDE_STATUS_DRQ;
5576         }
5577         if (statusByte & IDE_STATUS_DRQ) {
5578 
5579             if(DmaTransfer) {
5580                 wordsThisInterrupt = DEV_BSIZE/2*512;
5581             } else
5582             if (LunExt->MaximumBlockXfer) {
5583                 wordsThisInterrupt = DEV_BSIZE/2 * LunExt->MaximumBlockXfer;
5584             }
5585 
5586             if (srb->SrbFlags & SRB_FLAGS_DATA_IN) {
5587 
5588                 interruptReason = ATAPI_IR_IO_toHost;
5589 
5590             } else if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
5591                 interruptReason = ATAPI_IR_IO_toDev;
5592 
5593             } else {
5594                 status = SRB_STATUS_ERROR;
5595                 goto CompleteRequest;
5596             }
5597 
5598         } else if (statusByte & IDE_STATUS_BUSY) {
5599 
5600             //AtapiEnableInterrupts(deviceExtension, lChannel);
5601             KdPrint2((PRINT_PREFIX "AtapiInterrupt: return FALSE on ATA IDE_STATUS_BUSY\n"));
5602             return FALSE;
5603 
5604         } else {
5605 
5606             KdPrint2((PRINT_PREFIX "AtapiInterrupt: !DRQ, !BUSY, WordsLeft %#x\n", AtaReq->WordsLeft));
5607             if (AtaReq->WordsLeft) {
5608 
5609                 // Funky behaviour seen with PCI IDE (not all, just one).
5610 PIO_wait_DRQ0:
5611                 // The ISR hits with DRQ low, but comes up later.
5612                 for (k = 0; k < 5000; k++) {
5613                     GetBaseStatus(chan, statusByte);
5614                     if (statusByte & IDE_STATUS_DRQ) {
5615                         break;
5616                     }
5617                     if(!InDpc) {
5618                         // goto DPC
5619                         AtaReq->ReqState = REQ_STATE_DPC_WAIT_DRQ0;
5620                         TimerValue = 100;
5621                         KdPrint2((PRINT_PREFIX "AtapiInterrupt: go to DPC (drq0)\n"));
5622 #ifndef UNIATA_CORE
5623                         goto PostToDpc;
5624 #else //UNIATA_CORE
5625                         AtapiStallExecution(TimerValue);
5626                         goto ServiceInterrupt;
5627 #endif //UNIATA_CORE
5628                     }
5629                     AtapiStallExecution(100);
5630                 }
5631                 if (k == 5000) {
5632                     // reset the controller.
5633                     KdPrint2((PRINT_PREFIX "AtapiInterrupt: Resetting due to DRQ not up. Status %#x\n",
5634                                 statusByte));
5635 IntrPrepareResetController:
5636                     AtapiResetController__(HwDeviceExtension, lChannel, RESET_COMPLETE_CURRENT);
5637                     goto ReturnEnableIntr;
5638 
5639                 } else {
5640                     interruptReason = (srb->SrbFlags & SRB_FLAGS_DATA_IN) ? ATAPI_IR_IO_toHost : ATAPI_IR_IO_toDev;
5641                 }
5642 
5643             } else {
5644                 // Command complete - verify, write, or the SMART enable/disable.
5645                 // Also get_media_status
5646                 interruptReason = ATAPI_IR_IO_toHost | ATAPI_IR_COD_Cmd;
5647             }
5648         }
5649     }
5650 
5651     KdPrint2((PRINT_PREFIX "AtapiInterrupt: i-reason=%d, status=%#x\n", interruptReason, statusByte));
5652     if(deviceExtension->HwFlags & UNIATA_AHCI) {
5653         KdPrint2((PRINT_PREFIX "  AHCI path, WordsTransfered %x, WordsLeft %x\n", AtaReq->WordsTransfered, AtaReq->WordsLeft));
5654 /*        if(chan->AhciLastIS & ATA_AHCI_P_IX_OF) {
5655             //status = SRB_STATUS_DATA_OVERRUN;
5656             DataOverrun = TRUE;
5657         } else {
5658             status = SRB_STATUS_SUCCESS;
5659         }*/
5660         if(AtaReq->WordsTransfered >= AtaReq->WordsLeft) {
5661             AtaReq->WordsLeft = 0;
5662         } else {
5663             AtaReq->WordsLeft -= AtaReq->WordsTransfered;
5664         }
5665         //if(AtaReq->WordsLeft && (status == SRB_STATUS_SUCCESS)) {
5666         //    status = SRB_STATUS_DATA_OVERRUN;
5667         //}
5668         status = SRB_STATUS_SUCCESS;
5669         chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
5670         goto CompleteRequest;
5671     } else
5672     if ((interruptReason == ATAPI_IR_COD_Cmd) && (statusByte & IDE_STATUS_DRQ)) {
5673         if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) {
5674             AtapiDmaDBPreSync(HwDeviceExtension, chan, srb);
5675         }
5676         // Write the packet.
5677         KdPrint3((PRINT_PREFIX "AtapiInterrupt: Writing Atapi packet.\n"));
5678         // Send CDB to device.
5679         WriteBuffer(chan, (PUSHORT)srb->Cdb,
5680                           LunExt->IdentifyData.AtapiCmdSize ? 8 : 6,
5681                           /*0*/ PIO0_TIMING);
5682         AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
5683 
5684         if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) {
5685             KdPrint2((PRINT_PREFIX "AtapiInterrupt: AtapiDmaStart().\n"));
5686             AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, srb);
5687         }
5688 
5689         goto ReturnEnableIntr;
5690 
5691     } else if ((interruptReason == ATAPI_IR_IO_toDev) && (statusByte & IDE_STATUS_DRQ)) {
5692 
5693         // Write the data.
5694         if (atapiDev) {
5695 
5696             // Pick up bytes to transfer and convert to words.
5697             wordCount =
5698                 AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow);
5699 
5700             wordCount |=
5701                 (USHORT)AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8;
5702 
5703             // Covert bytes to words.
5704             wordCount >>= 1;
5705             KdPrint2((PRINT_PREFIX "AtapiInterrupt: get W wordCount %#x\n", wordCount));
5706 
5707             if (wordCount != AtaReq->WordsLeft) {
5708                 KdPrint2((PRINT_PREFIX
5709                            "AtapiInterrupt: %d words requested; %d words xferred\n",
5710                            AtaReq->WordsLeft,
5711                            wordCount));
5712             }
5713 
5714             // Verify this makes sense.
5715             if (wordCount > AtaReq->WordsLeft) {
5716                 wordCount = AtaReq->WordsLeft;
5717                 KdPrint2((PRINT_PREFIX
5718                            "AtapiInterrupt: Write underrun\n"));
5719                 DataOverrun = TRUE;
5720             }
5721 
5722         } else {
5723 
5724             // IDE path. Check if words left is at least DEV_BSIZE/2 = 256.
5725             if (AtaReq->WordsLeft < wordsThisInterrupt) {
5726                // Transfer only words requested.
5727                wordCount = AtaReq->WordsLeft;
5728             } else {
5729                // Transfer next block.
5730                wordCount = wordsThisInterrupt;
5731             }
5732         }
5733 
5734         if (DmaTransfer &&
5735             (chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION)) {
5736             //ASSERT(AtaReq->WordsLeft == wordCount);
5737             if(AtaReq->ReqState == REQ_STATE_ATAPI_EXPECTING_DATA_INTR2) {
5738                 KdPrint2((PRINT_PREFIX
5739                           "IdeIntr: DMA tmp INTR %#x vs %#x\n", AtaReq->WordsLeft, wordCount));
5740                 if(AtaReq->WordsLeft > wordCount) {
5741                     AtaReq->WordsLeft -= wordCount;
5742                     AtaReq->WordsTransfered += wordCount;
5743                     AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
5744                     goto ReturnEnableIntr;
5745                 }
5746                 dma_status = AtapiDmaDone(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, lChannel, NULL/*srb*/);
5747             }
5748             AtaReq->WordsTransfered = AtaReq->WordsLeft;
5749             AtaReq->WordsLeft = 0;
5750             status = SRB_STATUS_SUCCESS;
5751             chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
5752             goto CompleteRequest;
5753         }
5754 
5755         // Ensure that this is a write command.
5756         if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
5757 
5758            KdPrint2((PRINT_PREFIX
5759                       "AtapiInterrupt: Write interrupt\n"));
5760 
5761            statusByte = WaitOnBusy(chan);
5762 
5763             if (/*atapiDev || */ !(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) /*!deviceExtension->DWordIO*/
5764                 || (wordCount & 1)) {
5765 
5766                WriteBuffer(chan,
5767                            AtaReq->DataBuffer,
5768                            wordCount,
5769                            UniataGetPioTiming(LunExt));
5770            } else {
5771 
5772                WriteBuffer2(chan,
5773                            (PULONG)(AtaReq->DataBuffer),
5774                            wordCount / 2,
5775                            UniataGetPioTiming(LunExt));
5776            }
5777         } else {
5778 
5779             KdPrint3((PRINT_PREFIX
5780                         "AtapiInterrupt: Int reason %#x, but srb is for a read %#x.\n",
5781                         interruptReason,
5782                         srb));
5783 
5784             // Fail this request.
5785             status = SRB_STATUS_ERROR;
5786             if(!wordCount && atapiDev && (srb->Cdb[0] != SCSIOP_REQUEST_SENSE)) {
5787                 // some devices feel bad after incorrect commands and may need reset
5788                 KdPrint2((PRINT_PREFIX
5789                           "AtapiInterrupt: Try ATAPI reset\n"));
5790 
5791                 AtapiDisableInterrupts(deviceExtension, lChannel);
5792                 AtapiSoftReset(chan, DeviceNumber);
5793                 AtapiEnableInterrupts(deviceExtension, lChannel);
5794                 status = SRB_STATUS_BUS_RESET;
5795                 AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
5796 
5797 //                goto IntrPrepareResetController;
5798             }
5799             goto CompleteRequest;
5800         }
5801         // Advance data buffer pointer and bytes left.
5802         AtaReq->DataBuffer += wordCount;
5803         AtaReq->WordsLeft -= wordCount;
5804         AtaReq->WordsTransfered += wordCount;
5805 
5806         if (atapiDev) {
5807             AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
5808         }
5809 
5810         goto ReturnEnableIntr;
5811 
5812     } else if (interruptReason == ATAPI_IR_IO_toHost && (statusByte & IDE_STATUS_DRQ)) {
5813 
5814 continue_read_drq:
5815 
5816         if (atapiDev) {
5817 
5818             // Pick up bytes to transfer and convert to words.
5819             wordCount =
5820                 (ULONG)AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountLow) |
5821                 ((ULONG)AtapiReadPort1(chan, IDX_ATAPI_IO1_i_ByteCountHigh) << 8);
5822 
5823             // Convert bytes to words.
5824             KdPrint2((PRINT_PREFIX "AtapiInterrupt: get R byteCount %#x\n", wordCount));
5825             wordCount >>= 1;
5826             /*
5827                 When ATAPI 64k PIO read is requested we may have 0xfffe byte
5828                 count reported for 0x10000 bytes in single interrupt.
5829                 It is not allowed to read entire 64k block with DwordIo intead of
5830                 wait for last word.
5831             */
5832             if (wordCount != AtaReq->WordsLeft) {
5833                 KdPrint2((PRINT_PREFIX
5834                            "AtapiInterrupt: %d words requested; %d words xferred\n",
5835                            AtaReq->WordsLeft,
5836                            wordCount));
5837             }
5838 
5839             // Verify this makes sense.
5840             if (wordCount > AtaReq->WordsLeft) {
5841                 wordCount = AtaReq->WordsLeft;
5842                 DataOverrun = TRUE;
5843             }
5844 
5845         } else {
5846 
5847             // Check if words left is at least 256.
5848             if (AtaReq->WordsLeft < wordsThisInterrupt) {
5849                // Transfer only words requested.
5850                wordCount = AtaReq->WordsLeft;
5851             } else {
5852                // Transfer next block.
5853                wordCount = wordsThisInterrupt;
5854             }
5855         }
5856 
5857         if(DmaTransfer &&
5858            (chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION)) {
5859             if(AtaReq->ReqState == REQ_STATE_ATAPI_EXPECTING_DATA_INTR2) {
5860                 KdPrint2((PRINT_PREFIX
5861                           "IdeIntr: DMA tmp INTR %#x vs %#x\n", AtaReq->WordsLeft, wordCount));
5862                 if(AtaReq->WordsLeft > wordCount) {
5863                     AtaReq->WordsLeft -= wordCount;
5864                     AtaReq->WordsTransfered += wordCount;
5865                     AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
5866                     goto ReturnEnableIntr;
5867                 }
5868                 dma_status = AtapiDmaDone(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, lChannel, NULL/*srb*/);
5869             }
5870             //ASSERT(AtaReq->WordsLeft == wordCount);
5871             AtaReq->WordsTransfered = AtaReq->WordsLeft;
5872             AtaReq->WordsLeft = 0;
5873             status = SRB_STATUS_SUCCESS;
5874             chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
5875             goto CompleteRequest;
5876         }
5877         // Ensure that this is a read command.
5878         if (srb->SrbFlags & SRB_FLAGS_DATA_IN) {
5879 
5880 /*           KdPrint2((
5881                       "AtapiInterrupt: Read interrupt\n"));*/
5882 
5883             statusByte = WaitOnBusy(chan);
5884 
5885             if(wordCount&1 && atapiDev && (g_opt_VirtualMachine == VM_BOCHS)) {
5886                 KdPrint2((PRINT_PREFIX
5887                           "IdeIntr: unaligned ATAPI %#x Words\n", wordCount));
5888             } else
5889             if(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) {
5890                 KdPrint2((PRINT_PREFIX
5891                           "IdeIntr: pre-Read %#x Dwords\n", wordCount/2));
5892 
5893                 ReadBuffer2(chan,
5894                            (PULONG)(AtaReq->DataBuffer),
5895                            wordCount / 2,
5896                            UniataGetPioTiming(LunExt));
5897                 // Advance data buffer pointer and bytes left.
5898                 AtaReq->DataBuffer += wordCount & ~1;
5899                 AtaReq->WordsLeft -= wordCount & ~1;
5900                 AtaReq->WordsTransfered += wordCount & ~1;
5901                 wordCount &= 1;
5902             }
5903             if (wordCount) {
5904                 KdPrint2((PRINT_PREFIX
5905                            "IdeIntr: Read %#x words\n", wordCount));
5906 
5907                 ReadBuffer(chan,
5908                           AtaReq->DataBuffer,
5909                           wordCount,
5910                           UniataGetPioTiming(LunExt));
5911             }
5912 
5913             KdPrint2(("IdeIntr: PIO Read AtaReq->DataBuffer %#x, srb->DataBuffer %#x\n", AtaReq->DataBuffer, (srb ? srb->DataBuffer : (void*)-1) ));
5914             //KdDump(AtaReq->DataBuffer, wordCount*2);
5915             if(srb && atapiDev && srb->Cdb[0] == SCSIOP_REQUEST_SENSE) {
5916                 KdDump(AtaReq->DataBuffer, wordCount*2);
5917             }
5918 
5919             GetBaseStatus(chan, statusByte);
5920             KdPrint2((PRINT_PREFIX "  status re-check %#x\n", statusByte));
5921 
5922             if(DataOverrun) {
5923                 KdPrint2((PRINT_PREFIX "  DataOverrun\n"));
5924                 AtapiSuckPort2(chan);
5925                 GetBaseStatus(chan, statusByte);
5926             }
5927 
5928             if(statusByte & IDE_STATUS_BUSY) {
5929                 for (i = 0; i < 2; i++) {
5930                     AtapiStallExecution(10);
5931                     GetBaseStatus(chan, statusByte);
5932                     if (!(statusByte & IDE_STATUS_BUSY)) {
5933                         break;
5934                     }
5935                 }
5936             }
5937 
5938         } else {
5939 
5940             KdPrint3((PRINT_PREFIX
5941                         "AtapiInterrupt: Int reason %#x, but srb is for a read %#x.\n",
5942                         interruptReason,
5943                         srb));
5944 
5945             // Fail this request.
5946             status = SRB_STATUS_ERROR;
5947             goto CompleteRequest;
5948         }
5949 //continue_atapi_pio_read:
5950         // Advance data buffer pointer and bytes left.
5951         AtaReq->DataBuffer += wordCount;
5952         AtaReq->WordsLeft -= wordCount;
5953         AtaReq->WordsTransfered += wordCount;
5954 
5955         // Check for read command complete.
5956         if (AtaReq->WordsLeft == 0) {
5957 
5958             KdPrint2((PRINT_PREFIX "AtapiInterrupt: all transferred, AtaReq->WordsLeft == 0\n"));
5959             if (atapiDev) {
5960 
5961                 if(LunExt->IdentifyData.DeviceType == ATAPI_TYPE_CDROM) {
5962 
5963                     // Work around to make many atapi devices return correct sector size
5964                     // of 2048. Also certain devices will have sector count == 0x00, check
5965                     // for that also.
5966                     if (srb->Cdb[0] == SCSIOP_READ_CAPACITY) {
5967 
5968                         AtaReq->DataBuffer -= AtaReq->WordsTransfered;
5969                         if (AtaReq->DataBuffer[0] == 0x00) {
5970                             *((ULONG *) &(AtaReq->DataBuffer[0])) = 0xFFFFFF7F;
5971                         }
5972 
5973                         *((ULONG *) &(AtaReq->DataBuffer[2])) = 0x00080000;
5974                         AtaReq->DataBuffer += AtaReq->WordsTransfered;
5975                     }
5976 #ifndef UNIATA_INIT_CHANGERS
5977                     else
5978                     if (srb->Cdb[0] == SCSIOP_MECHANISM_STATUS) {
5979 
5980                         KdPrint3((PRINT_PREFIX "AtapiInterrupt: SCSIOP_MECHANISM_STATUS status %#x\n", status));
5981                         // Bingo!!
5982                         AtapiHwInitializeChanger (HwDeviceExtension,
5983                                                   srb,
5984                                                   (PMECHANICAL_STATUS_INFORMATION_HEADER) srb->DataBuffer);
5985                         LunExt->DeviceFlags |= DFLAGS_CHANGER_INITED;
5986                         KdPrint2((PRINT_PREFIX "  set DFLAGS_CHANGER_INITED\n"));
5987                     }
5988 #endif // UNIATA_INIT_CHANGERS
5989                 }
5990                 GetStatus(chan, statusByte);
5991                 if(!(statusByte & IDE_STATUS_BUSY)) {
5992                     // Assume command is completed if BUSY is cleared
5993                     // and all data read
5994                     // Optionally, we may receive COMPLETE interrupt later and
5995                     // treat it as unexpected
5996                     KdPrint2((PRINT_PREFIX "AtapiInterrupt: early complete ? status %x\n", statusByte));
5997 
5998                     status = SRB_STATUS_SUCCESS;
5999                     goto CompleteRequest;
6000                 }
6001 
6002             } else {
6003 
6004             /*
6005                 // Completion for IDE drives.
6006                 if (AtaReq->WordsLeft) {
6007                     status = SRB_STATUS_DATA_OVERRUN;
6008                 } else {
6009                     status = SRB_STATUS_SUCCESS;
6010                 }
6011 
6012                 goto CompleteRequest;
6013             */
6014                 status = SRB_STATUS_SUCCESS;
6015                 goto CompleteRequest;
6016 
6017             }
6018         } else {
6019             if (atapiDev) {
6020                 AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
6021                 GetStatus(chan, statusByte);
6022                 if(!(statusByte & IDE_STATUS_BUSY)) {
6023                     // Assume command is completed if BUSY is cleared
6024                     // even if NOT all data read
6025                     // Optionally, we may receive COMPLETE interrupt later and
6026                     // treat it as unexpected
6027                     KdPrint2((PRINT_PREFIX "AtapiInterrupt: early complete + underrun ? status %x\n", statusByte));
6028 
6029                     status = SRB_STATUS_SUCCESS;
6030                     goto CompleteRequest;
6031                 }
6032             } else {
6033                 if(!atapiDev && !DataOverrun && (srb->SrbFlags & SRB_FLAGS_DATA_IN) &&
6034                     ((statusByte & ~IDE_STATUS_INDEX) == (IDE_STATUS_IDLE | IDE_STATUS_DRQ))) {
6035                     KdPrint2((PRINT_PREFIX "  HDD read data ready \n"));
6036                     goto continue_read_drq;
6037                 }
6038             }
6039         }
6040 
6041         goto ReturnEnableIntr;
6042 
6043     } else if (interruptReason == (ATAPI_IR_IO_toHost | ATAPI_IR_COD_Cmd) && !(statusByte & IDE_STATUS_DRQ)) {
6044 
6045         KdPrint2((PRINT_PREFIX "AtapiInterrupt: interruptReason = CompleteRequest\n"));
6046         // Command complete. We exactly know this because of IReason.
6047 
6048         if(DmaTransfer) {
6049             KdPrint2((PRINT_PREFIX "AtapiInterrupt: CompleteRequest, was DmaTransfer\n"));
6050             AtaReq->WordsTransfered += AtaReq->WordsLeft;
6051             AtaReq->WordsLeft = 0;
6052         } else {
6053             KdPrint2((PRINT_PREFIX "AtapiInterrupt: CompleteRequest, was PIO\n"));
6054 
6055             wordCount = AtaReq->WordsLeft;
6056             // Advance data buffer pointer and bytes left.
6057             AtaReq->DataBuffer += wordCount;
6058             AtaReq->WordsLeft -= wordCount;
6059             AtaReq->WordsTransfered += wordCount;
6060 
6061             KdPrint2((PRINT_PREFIX "AtapiInterrupt: wordCount %#x, WordsTransfered %#x\n", wordCount, AtaReq->WordsTransfered));
6062 
6063         }
6064         //if (AtaReq->WordsLeft) {
6065         //    status = SRB_STATUS_DATA_OVERRUN;
6066         //} else {
6067             status = SRB_STATUS_SUCCESS;
6068         //}
6069 
6070 #ifdef UNIATA_DUMP_ATAPI
6071         if(srb &&
6072            srb->SrbFlags & SRB_FLAGS_DATA_IN) {
6073             UCHAR                   ScsiCommand;
6074             PCDB                    Cdb;
6075             PCHAR                   CdbData;
6076             PCHAR                   ModeSelectData;
6077             ULONG                   CdbDataLen;
6078             PSCSI_REQUEST_BLOCK     Srb = srb;
6079 
6080             Cdb = (PCDB)(Srb->Cdb);
6081             ScsiCommand = Cdb->CDB6.OperationCode;
6082             CdbData = (PCHAR)(Srb->DataBuffer);
6083             CdbDataLen = Srb->DataTransferLength;
6084 
6085             if(CdbDataLen > 0x1000) {
6086                 CdbDataLen = 0x1000;
6087             }
6088 
6089             KdPrint(("--\n"));
6090             KdPrint2(("DeviceID+VendorID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID));
6091             KdPrint2(("P:T:D=%d:%d:%d\n",
6092                                       Srb->PathId,
6093                                       Srb->TargetId,
6094                                       Srb->Lun));
6095             KdPrint(("Complete SCSI Command %2.2x\n", ScsiCommand));
6096             KdDump(Cdb, 16);
6097 
6098             if(ScsiCommand == SCSIOP_MODE_SENSE) {
6099                 KdPrint(("ModeSense 6\n"));
6100                 PMODE_PARAMETER_HEADER ParamHdr = (PMODE_PARAMETER_HEADER)CdbData;
6101                 ModeSelectData = CdbData+4;
6102                 KdDump(CdbData, CdbDataLen);
6103             } else
6104             if(ScsiCommand == SCSIOP_MODE_SENSE10) {
6105                 KdPrint(("ModeSense 10\n"));
6106                 PMODE_PARAMETER_HEADER ParamHdr = (PMODE_PARAMETER_HEADER)CdbData;
6107                 ModeSelectData = CdbData+8;
6108                 KdDump(CdbData, CdbDataLen);
6109             } else {
6110                 if(srb->SrbFlags & SRB_FLAGS_DATA_IN) {
6111                     KdPrint(("Read buffer from device:\n"));
6112                     KdDump(CdbData, CdbDataLen);
6113                 }
6114             }
6115             KdPrint(("--\n"));
6116         }
6117 #endif //UNIATA_DUMP_ATAPI
6118 
6119 CompleteRequest:
6120 
6121         KdPrint2((PRINT_PREFIX "AtapiInterrupt: CompleteRequest, srbstatus %x\n", status));
6122         // Check and see if we are processing our secret (mechanism status/request sense) srb
6123 
6124         if(AtaReq->WordsLeft && (status == SRB_STATUS_SUCCESS)) {
6125             KdPrint2((PRINT_PREFIX "WordsLeft %#x -> SRB_STATUS_DATA_OVERRUN\n", AtaReq->WordsLeft));
6126             status = SRB_STATUS_DATA_OVERRUN;
6127         }
6128 
6129         if (AtaReq->OriginalSrb) {
6130 
6131             ULONG srbStatus;
6132 
6133             KdPrint2((PRINT_PREFIX "AtapiInterrupt: OriginalSrb != NULL\n"));
6134             if (srb->Cdb[0] == SCSIOP_MECHANISM_STATUS) {
6135 #ifdef UNIATA_INIT_CHANGERS
6136                 // We can get here only when UNIATA_INIT_CHANGERS is defined
6137                 KdPrint3((PRINT_PREFIX "AtapiInterrupt: SCSIOP_MECHANISM_STATUS status %#x\n", status));
6138                 if (status == SRB_STATUS_SUCCESS) {
6139                     // Bingo!!
6140                     AtapiHwInitializeChanger (HwDeviceExtension,
6141                                               srb,
6142                                               (PMECHANICAL_STATUS_INFORMATION_HEADER) srb->DataBuffer);
6143 
6144                     // Get ready to issue the original srb
6145                     srb = AtaReq->Srb = AtaReq->OriginalSrb;
6146                     AtaReq->OriginalSrb = NULL;
6147 
6148                 } else {
6149                     // failed!  Get the sense key and maybe try again
6150                     srb = AtaReq->Srb = BuildRequestSenseSrb (
6151                                                           HwDeviceExtension,
6152                                                           AtaReq->OriginalSrb);
6153                 }
6154 /*
6155                 // do not enable interrupts in DPC, do not waste time, do it now!
6156                 if(UseDpc && chan->DisableIntr) {
6157                     AtapiEnableInterrupts(HwDeviceExtension, c);
6158                     UseDpc = FALSE;
6159                     RestoreUseDpc = TRUE;
6160                 }
6161 */
6162                 srbStatus = AtapiSendCommand(HwDeviceExtension, srb, CMD_ACTION_ALL);
6163 
6164                 KdPrint3((PRINT_PREFIX "AtapiInterrupt: chan->ExpectingInterrupt %d (1)\n", chan->ExpectingInterrupt));
6165 
6166                 if (srbStatus == SRB_STATUS_PENDING) {
6167                     KdPrint2((PRINT_PREFIX "AtapiInterrupt: send orig SRB_STATUS_PENDING (1)\n"));
6168                     goto ReturnEnableIntr;
6169                 }
6170 /*
6171                 if(RestoreUseDpc) {
6172                     // restore state on error
6173                     UseDpc = TRUE;
6174                     AtapiDisableInterrupts(HwDeviceExtension, c);
6175                 }
6176 */
6177 #else
6178                 KdPrint((PRINT_PREFIX "AtapiInterrupt: ERROR: internal SCSIOP_MECHANISM_STATUS !!!!\n"));
6179                 ASSERT(FALSE);
6180 #endif // UNIATA_INIT_CHANGERS
6181             } else { // srb->Cdb[0] == SCSIOP_REQUEST_SENSE)
6182 
6183                 PSENSE_DATA senseData = (PSENSE_DATA) srb->DataBuffer;
6184 #ifdef __REACTOS__
6185                 (void)senseData;
6186 #endif
6187 
6188                 KdPrint3((PRINT_PREFIX "AtapiInterrupt: ATAPI command status %#x\n", status));
6189                 if (status == SRB_STATUS_DATA_OVERRUN) {
6190                     // Check to see if we at least get mininum number of bytes
6191                     if ((srb->DataTransferLength - AtaReq->WordsLeft) >
6192                         (FIELD_OFFSET (SENSE_DATA, AdditionalSenseLength) + sizeof(senseData->AdditionalSenseLength))) {
6193                         status = SRB_STATUS_SUCCESS;
6194                     }
6195                 }
6196 
6197                 if (status == SRB_STATUS_SUCCESS) {
6198 #ifndef UNIATA_CORE
6199 #ifdef UNIATA_INIT_CHANGERS
6200                     if ((senseData->SenseKey != SCSI_SENSE_ILLEGAL_REQUEST) &&
6201                         FALSE &&
6202                         chan->MechStatusRetryCount) {
6203 
6204                         KdPrint3((PRINT_PREFIX "AtapiInterrupt: MechStatusRetryCount %#x\n", chan->MechStatusRetryCount));
6205                         // The sense key doesn't say the last request is illegal, so try again
6206                         chan->MechStatusRetryCount--;
6207                         srb = AtaReq->Srb = BuildMechanismStatusSrb (
6208                                                               HwDeviceExtension,
6209                                                               AtaReq->OriginalSrb);
6210                     } else
6211 #endif // UNIATA_INIT_CHANGERS
6212                     {
6213                         // Get ready to issue the original srb
6214                         srb = AtaReq->Srb = AtaReq->OriginalSrb;
6215                         AtaReq->OriginalSrb = NULL;
6216                     }
6217 #endif //UNIATA_CORE
6218 /*
6219                     // do not enable interrupts in DPC, do not waste time, do it now!
6220                     if(UseDpc && chan->DisableIntr) {
6221                         AtapiEnableInterrupts(HwDeviceExtension, c);
6222                         UseDpc = FALSE;
6223                         RestoreUseDpc = TRUE;
6224                     }
6225 */
6226                     srbStatus = AtapiSendCommand(HwDeviceExtension, srb, CMD_ACTION_ALL);
6227 
6228                     KdPrint3((PRINT_PREFIX "AtapiInterrupt: chan->ExpectingInterrupt %d (2)\n", chan->ExpectingInterrupt));
6229 
6230                     if (srbStatus == SRB_STATUS_PENDING) {
6231                         KdPrint2((PRINT_PREFIX "AtapiInterrupt: send orig SRB_STATUS_PENDING (2)\n"));
6232                         goto ReturnEnableIntr;
6233                     }
6234 /*
6235                     if(RestoreUseDpc) {
6236                         // restore state on error
6237                         UseDpc = TRUE;
6238                         AtapiDisableInterrupts(HwDeviceExtension, c);
6239                     }
6240 */
6241                 }
6242             }
6243 
6244             // If we get here, it means AtapiSendCommand() has failed
6245             // Can't recover.  Pretend the original srb has failed and complete it.
6246 
6247             KdPrint3((PRINT_PREFIX "AtapiInterrupt: Error. complete OriginalSrb\n"));
6248 
6249             if (AtaReq->OriginalSrb) {
6250                 srb = AtaReq->Srb = AtaReq->OriginalSrb;
6251                 AtaReq->OriginalSrb = NULL;
6252             }
6253 
6254             KdPrint2((PRINT_PREFIX "AtapiInterrupt: chan->ExpectingInterrupt %d (3)\n", chan->ExpectingInterrupt));
6255 
6256             // fake an error and read no data
6257             status = SRB_STATUS_ERROR;
6258             srb->ScsiStatus = 0;
6259             AtaReq->DataBuffer = (PUSHORT)(srb->DataBuffer);
6260             AtaReq->WordsLeft = srb->DataTransferLength;
6261             chan->RDP = FALSE;
6262 
6263         } else if (status == SRB_STATUS_ERROR) {
6264 
6265             // Map error to specific SRB status and handle request sense.
6266             KdPrint3((PRINT_PREFIX "AtapiInterrupt: Error. Begin mapping...\n"));
6267             status = MapError(deviceExtension,
6268                               srb);
6269 
6270             chan->RDP = FALSE;
6271 
6272         } else if(!DmaTransfer) {
6273 
6274             KdPrint2((PRINT_PREFIX "AtapiInterrupt: PIO completion\n"));
6275             // Command complete.
6276 PIO_wait_busy:
6277             KdPrint2((PRINT_PREFIX "AtapiInterrupt: PIO completion, wait BUSY\n"));
6278             // Wait for busy to drop.
6279             for (i = 0; i < 5*30; i++) {
6280                 GetBaseStatus(chan, statusByte);
6281                 if (!(statusByte & IDE_STATUS_BUSY)) {
6282                     break;
6283                 }
6284                 if(!InDpc) {
6285                     // goto DPC
6286                     AtaReq->ReqState = REQ_STATE_DPC_WAIT_BUSY;
6287                     TimerValue = 200;
6288                     KdPrint2((PRINT_PREFIX "AtapiInterrupt: go to DPC (busy)\n"));
6289 #ifndef UNIATA_CORE
6290                     goto PostToDpc;
6291 #else //UNIATA_CORE
6292                     AtapiStallExecution(TimerValue);
6293                     goto ServiceInterrupt;
6294 #endif //UNIATA_CORE
6295                 }
6296                 AtapiStallExecution(100);
6297             }
6298 
6299             if (i == 5*30) {
6300 
6301                 // reset the controller.
6302                 KdPrint2((PRINT_PREFIX
6303                             "AtapiInterrupt: Resetting due to BSY still up - %#x.\n",
6304                             statusByte));
6305                 goto IntrPrepareResetController;
6306             }
6307             // Check to see if DRQ is still up.
6308             if(statusByte & IDE_STATUS_DRQ) {
6309                 KdPrint2((PRINT_PREFIX "AtapiInterrupt: DRQ...\n"));
6310                 if(srb) {
6311                     if(srb->SrbFlags & SRB_FLAGS_DATA_IN) {
6312                         KdPrint2((PRINT_PREFIX "srb %x data in\n", srb));
6313                     } else {
6314                         KdPrint2((PRINT_PREFIX "srb %x data out\n", srb));
6315                     }
6316                 } else {
6317                     KdPrint2((PRINT_PREFIX "srb NULL\n"));
6318                 }
6319                 if(AtaReq) {
6320                     KdPrint2((PRINT_PREFIX "AtaReq %x AtaReq->WordsLeft=%x\n", AtaReq, AtaReq->WordsLeft));
6321                 } else {
6322                     KdPrint2((PRINT_PREFIX "AtaReq NULL\n"));
6323                 }
6324                 if(AtaReq && AtaReq->WordsLeft /*&&
6325                    !(LunExt->DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_TAPE_DEVICE | DFLAGS_LBA_ENABLED))*/) {
6326                     KdPrint2((PRINT_PREFIX "DRQ+AtaReq->WordsLeft -> next portion\n"));
6327                     goto continue_PIO;
6328                 }
6329             }
6330             //if (atapiDev && (statusByte & IDE_STATUS_DRQ)) {}
6331             //if ((statusByte & IDE_STATUS_DRQ)) {}
6332             if((statusByte & IDE_STATUS_DRQ) &&
6333                (LunExt->DeviceFlags & (DFLAGS_ATAPI_DEVICE | DFLAGS_TAPE_DEVICE | DFLAGS_LBA_ENABLED)) ) {
6334 
6335 PIO_wait_DRQ:
6336                 KdPrint2((PRINT_PREFIX "AtapiInterrupt: PIO_wait_DRQ\n"));
6337                 for (i = 0; i < 200; i++) {
6338                     GetBaseStatus(chan, statusByte);
6339                     if (!(statusByte & IDE_STATUS_DRQ)) {
6340                         break;
6341                     }
6342                     if(!InDpc) {
6343                         // goto DPC
6344                         KdPrint2((PRINT_PREFIX "AtapiInterrupt: go to DPC (drq)\n"));
6345                         AtaReq->ReqState = REQ_STATE_DPC_WAIT_DRQ;
6346                         TimerValue = 100;
6347 #ifndef UNIATA_CORE
6348                         goto PostToDpc;
6349 #else //UNIATA_CORE
6350                         AtapiStallExecution(TimerValue);
6351                         goto ServiceInterrupt;
6352 #endif //UNIATA_CORE
6353                     }
6354                     AtapiStallExecution(100);
6355                 }
6356 
6357                 if (i == 200) {
6358                     // reset the controller.
6359                     KdPrint2((PRINT_PREFIX   "AtapiInterrupt: Resetting due to DRQ still up - %#x\n",
6360                                 statusByte));
6361                     goto IntrPrepareResetController;
6362                 }
6363             }
6364             if(atapiDev) {
6365                 KdPrint2(("IdeIntr: ATAPI Read AtaReq->DataBuffer %#x, srb->DataBuffer %#x, len %#x\n",
6366                      AtaReq->DataBuffer, (srb ? srb->DataBuffer : (void*)(-1)), srb->DataTransferLength ));
6367                 //KdDump(srb->DataBuffer, srb->DataTransferLength);
6368             }
6369             if(!AtapiDmaPioSync(HwDeviceExtension, srb, (PUCHAR)(srb->DataBuffer), srb->DataTransferLength)) {
6370                 KdPrint2(("IdeIntr: Can't sync DMA and PIO buffers\n"));
6371             }
6372         }
6373 
6374         // Clear interrupt expecting flag.
6375         UniataExpectChannelInterrupt(chan, FALSE);
6376         // clear this flag now, it can be set again in sub-calls
6377         InterlockedExchange(&(chan->CheckIntr),
6378                                       CHECK_INTR_IDLE);
6379 
6380         // Sanity check that there is a current request.
6381         if(srb != NULL) {
6382             // Set status in SRB.
6383             srb->SrbStatus = (UCHAR)status;
6384 
6385             // Check for underflow.
6386             if(AtaReq->WordsLeft) {
6387 
6388                 KdPrint2((PRINT_PREFIX "AtapiInterrupt: Check for underflow, AtaReq->WordsLeft %x\n", AtaReq->WordsLeft));
6389                 // Subtract out residual words and update if filemark hit,
6390                 // setmark hit , end of data, end of media...
6391                 if (!(LunExt->DeviceFlags & DFLAGS_TAPE_DEVICE)) {
6392                     if (status == SRB_STATUS_DATA_OVERRUN) {
6393                         srb->DataTransferLength -= AtaReq->WordsLeft*2;
6394                     } else {
6395                         srb->DataTransferLength = 0;
6396                     }
6397                 } else {
6398                     srb->DataTransferLength -= AtaReq->WordsLeft*2;
6399                 }
6400             }
6401             if(status == SRB_STATUS_SUCCESS) {
6402                 //if(!(deviceExtension->HwFlags & UNIATA_AHCI) && !atapiDev) {
6403                 //    // This should be set in UniataAhciEndTransaction() for AHCI
6404                 //    AtaReq->WordsTransfered += AtaReq->bcount * DEV_BSIZE/2;
6405                 //}
6406                 if(!atapiDev &&
6407                    AtaReq->WordsTransfered*2 < AtaReq->TransferLength) {
6408                     KdPrint2((PRINT_PREFIX "AtapiInterrupt: more I/O required (%x of %x bytes) -> reenqueue\n",
6409                          AtaReq->WordsTransfered*2, AtaReq->TransferLength));
6410                     AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
6411                     AtaReq->ReqState = REQ_STATE_PREPARE_TO_NEXT;
6412                     goto reenqueue_req;
6413                 } else {
6414                     KdPrint2((PRINT_PREFIX "   Transfered %x, full size %x\n",
6415                         AtaReq->WordsTransfered*2, AtaReq->TransferLength));
6416                 }
6417             }
6418 
6419             if (srb->Function != SRB_FUNCTION_IO_CONTROL) {
6420 
6421 CompleteRDP:
6422                 // Indicate command complete.
6423                 if (!(chan->RDP)) {
6424                     KdPrint2((PRINT_PREFIX "AtapiInterrupt: RequestComplete\n"));
6425 IntrCompleteReq:
6426 
6427                     if (status == SRB_STATUS_SUCCESS &&
6428                         srb->SenseInfoBuffer &&
6429                         srb->SenseInfoBufferLength >= sizeof(SENSE_DATA)) {
6430 
6431                         PSENSE_DATA  senseBuffer = (PSENSE_DATA)srb->SenseInfoBuffer;
6432 
6433                         KdPrint2((PRINT_PREFIX "AtapiInterrupt: set AutoSense\n"));
6434                         senseBuffer->ErrorCode = 0;
6435                         senseBuffer->Valid     = 1;
6436                         senseBuffer->AdditionalSenseLength = 0xb;
6437                         senseBuffer->SenseKey =  0;
6438                         senseBuffer->AdditionalSenseCode = 0;
6439                         senseBuffer->AdditionalSenseCodeQualifier = 0;
6440 
6441                         srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
6442                     }
6443                     AtapiDmaDBSync(chan, srb);
6444                     KdPrint2((PRINT_PREFIX "AtapiInterrupt: remove srb %#x, status %x\n", srb, status));
6445                     UniataRemoveRequest(chan, srb);
6446                     KdPrint2((PRINT_PREFIX "AtapiInterrupt: RequestComplete, srb %#x\n", srb));
6447                     ScsiPortNotification(RequestComplete,
6448                                          deviceExtension,
6449                                          srb);
6450                 }
6451             } else {
6452 
6453                 KdPrint2((PRINT_PREFIX "AtapiInterrupt: IOCTL completion\n"));
6454 
6455                 if (status != SRB_STATUS_SUCCESS) {
6456                     error = AtapiReadPort1(chan, IDX_IO1_i_Error);
6457                     KdPrint2((PRINT_PREFIX "AtapiInterrupt: error %#x\n", error));
6458                 }
6459 
6460                 if(!AtapiStringCmp( (PCHAR)(((PSRB_IO_CONTROL)(srb->DataBuffer))->Signature),"SCSIDISK",sizeof("SCSIDISK")-1)) {
6461 
6462                     PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
6463                     // Build the SMART status block depending upon the completion status.
6464                     cmdOutParameters->cBufferSize = wordCount;
6465                     cmdOutParameters->DriverStatus.bDriverError = (error) ? SMART_IDE_ERROR : 0;
6466                     cmdOutParameters->DriverStatus.bIDEError = error;
6467 
6468                     // If the sub-command is return smart status, jam the value from cylinder low and high, into the
6469                     // data buffer.
6470                     if (chan->SmartCommand == RETURN_SMART_STATUS) {
6471                         PIDEREGS_EX regs = (PIDEREGS_EX)&(cmdOutParameters->bBuffer);
6472 
6473                         regs->bOpFlags = 0;
6474                         UniataSnapAtaRegs(chan, 0, regs);
6475 
6476                         regs->bCommandReg = SMART_CMD;
6477                         regs->bFeaturesReg = RETURN_SMART_STATUS;
6478 
6479                         cmdOutParameters->cBufferSize = 8;
6480                     }
6481                     chan->SmartCommand = 0; // cleanup after execution
6482                 }
6483                 // Indicate command complete.
6484                 goto IntrCompleteReq;
6485             }
6486 
6487         } else {
6488 
6489             KdPrint2((PRINT_PREFIX "AtapiInterrupt: No SRB!\n"));
6490         }
6491 
6492         if (chan->RDP) {
6493             // Check DSC
6494             for (i = 0; i < 5; i++) {
6495                 GetBaseStatus(chan, statusByte);
6496                 if(!(statusByte & IDE_STATUS_BUSY)) {
6497                     KdPrint2((PRINT_PREFIX "AtapiInterrupt: RDP + cleared BUSY\n"));
6498                     chan->RDP = FALSE;
6499                     goto CompleteRDP;
6500                 } else
6501                 if (statusByte & IDE_STATUS_DSC) {
6502                     KdPrint2((PRINT_PREFIX "AtapiInterrupt: Clear RDP\n"));
6503                     chan->RDP = FALSE;
6504                     goto CompleteRDP;
6505                 }
6506                 AtapiStallExecution(50);
6507             }
6508         }
6509         // RDP can be cleared since previous check
6510         if (chan->RDP) {
6511             KdPrint2((PRINT_PREFIX "AtapiInterrupt: RequestTimerCall 2000\n"));
6512 
6513             TimerValue = 2000;
6514 #ifndef UNIATA_CORE
6515             goto CallTimerDpc;
6516 #else //UNIATA_CORE
6517             AtapiStallExecution(TimerValue);
6518             goto ServiceInterrupt;
6519 #endif //UNIATA_CORE
6520         }
6521 
6522 //            ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
6523 enqueue_next_req:
6524         // Get next request
6525         srb = UniataGetCurRequest(chan);
6526 
6527 reenqueue_req:
6528 
6529 #ifndef UNIATA_CORE
6530         KdPrint2((PRINT_PREFIX "AtapiInterrupt: NextRequest, srb=%#x\n",srb));
6531         if(!srb) {
6532             ScsiPortNotification(NextRequest,
6533                                  deviceExtension,
6534                                  NULL);
6535         } else {
6536             ScsiPortNotification(NextLuRequest,
6537                                  deviceExtension,
6538                                  PathId,
6539                                  TargetId,
6540                                  Lun);
6541             // in simplex mode next command must NOT be sent here
6542             if(!deviceExtension->simplexOnly) {
6543                 AtapiStartIo__(HwDeviceExtension, srb, FALSE);
6544             }
6545         }
6546         // Try to get SRB fron any non-empty queue (later)
6547         if(deviceExtension->simplexOnly) {
6548             NoStartIo = FALSE;
6549         }
6550 #endif //UNIATA_CORE
6551 
6552         goto ReturnEnableIntr;
6553 
6554     } else {
6555 
6556         // Unexpected int. Catch it
6557         KdPrint2((PRINT_PREFIX "AtapiInterrupt: Unexpected ATAPI interrupt. InterruptReason %#x. Status %#x.\n",
6558                     interruptReason,
6559                     statusByte));
6560 
6561         if(g_opt_VirtualMachine == VM_QEMU) {
6562             if(interruptReason == ATAPI_IR_IO_toDev && !(statusByte & IDE_STATUS_DRQ) && !DmaTransfer) {
6563                 statusByte = WaitForDrq(chan);
6564                 if(statusByte & IDE_STATUS_DRQ) {
6565                     goto continue_PIO;
6566                 }
6567             }
6568         }
6569 
6570         if(OldReqState == REQ_STATE_DPC_WAIT_BUSY0 &&
6571            AtaReq->WordsLeft == 0) {
6572             KdPrint2((PRINT_PREFIX "AtapiInterrupt: pending WAIT_BUSY0. Complete.\n"));
6573             status = SRB_STATUS_SUCCESS;
6574             chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
6575             goto CompleteRequest;
6576         }
6577     }
6578 
6579 ReturnEnableIntr:
6580 
6581     KdPrint2((PRINT_PREFIX "AtapiInterrupt: ReturnEnableIntr\n",srb));
6582     //UniataExpectChannelInterrupt(chan, TRUE); // device may interrupt
6583     deviceExtension->ExpectingInterrupt = TRUE;
6584     if(UseDpc) {
6585         if(CrNtInterlockedExchangeAdd(&(chan->DisableIntr), 0)) {
6586             KdPrint2((PRINT_PREFIX "AtapiInterrupt: call AtapiEnableInterrupts__()\n"));
6587 #ifdef UNIATA_USE_XXableInterrupts
6588             //ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
6589             chan->ChannelCtrlFlags |= CTRFLAGS_ENABLE_INTR_REQ;
6590             // must be called on DISPATCH_LEVEL
6591             ScsiPortNotification(CallDisableInterrupts, HwDeviceExtension,
6592                                  AtapiEnableInterrupts__);
6593 #else
6594             AtapiEnableInterrupts(HwDeviceExtension, c);
6595             InterlockedExchange(&(chan->CheckIntr),
6596                                           CHECK_INTR_IDLE);
6597             // Will raise IRQL to DIRQL
6598 #ifndef UNIATA_CORE
6599             AtapiQueueTimerDpc(HwDeviceExtension, lChannel,
6600                                  AtapiEnableInterrupts__,
6601                                  1);
6602 #endif // UNIATA_CORE
6603             KdPrint2((PRINT_PREFIX "AtapiInterrupt: Timer DPC inited\n"));
6604 #endif // UNIATA_USE_XXableInterrupts
6605         }
6606     }
6607 
6608     InterlockedExchange(&(chan->CheckIntr), CHECK_INTR_IDLE);
6609     // in simplex mode next command must be sent here if
6610     // DPC is not used
6611     KdPrint2((PRINT_PREFIX "AtapiInterrupt: exiting, UseDpc=%d, NoStartIo=%d\n", UseDpc, NoStartIo));
6612 
6613 #ifndef UNIATA_CORE
6614     if(!UseDpc && /*deviceExtension->simplexOnly &&*/ !NoStartIo) {
6615         chan = UniataGetNextChannel(chan);
6616         if(chan) {
6617             srb = UniataGetCurRequest(chan);
6618         } else {
6619             srb = NULL;
6620         }
6621         KdPrint2((PRINT_PREFIX "AtapiInterrupt: run srb %x\n", srb));
6622         if(srb) {
6623             AtapiStartIo__(HwDeviceExtension, srb, FALSE);
6624         }
6625     }
6626 #endif //UNIATA_CORE
6627     return TRUE;
6628 
6629 } // end AtapiInterrupt__()
6630 
6631 #ifndef UNIATA_CORE
6632 
6633 /*++
6634 
6635 Routine Description:
6636 
6637     This routine handles SMART enable, disable, read attributes and threshold commands.
6638 
6639 Arguments:
6640 
6641     HwDeviceExtension - HBA miniport driver's adapter data storage
6642     Srb - IO request packet
6643 
6644 Return Value:
6645 
6646     SRB status
6647 
6648 --*/
6649 ULONG
6650 NTAPI
6651 IdeSendSmartCommand(
6652     IN PVOID HwDeviceExtension,
6653     IN PSCSI_REQUEST_BLOCK Srb,
6654     IN ULONG targetId // assume it is always valid
6655     )
6656 {
6657     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
6658     ULONG                c               ; // = GET_CHANNEL(Srb); may be invalid
6659     PHW_CHANNEL          chan            ; // = &(deviceExtension->chan[c]);
6660     PATA_REQ             AtaReq          = (PATA_REQ)(Srb->SrbExtension);
6661     PSENDCMDOUTPARAMS    cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
6662     SENDCMDINPARAMS      cmdInParameters = *(PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
6663     PIDEREGS             regs            = &cmdInParameters.irDriveRegs;
6664 //    ULONG                i;
6665     UCHAR                statusByte;
6666     ULONG DeviceNumber;
6667 
6668     if (regs->bCommandReg != SMART_CMD) {
6669         KdPrint2((PRINT_PREFIX
6670                     "IdeSendSmartCommand: bCommandReg != SMART_CMD\n"));
6671         return SRB_STATUS_INVALID_REQUEST;
6672     }
6673 
6674     c = targetId / deviceExtension->NumberLuns;
6675     DeviceNumber = targetId % deviceExtension->NumberLuns;
6676     KdPrint2((PRINT_PREFIX "  c %d, dev %d\n", c, DeviceNumber));
6677 
6678     chan = &(deviceExtension->chan[c]);
6679 
6680     chan->SmartCommand = regs->bFeaturesReg;
6681 
6682     // Determine which of the commands to carry out.
6683     switch(regs->bFeaturesReg) {
6684     case READ_ATTRIBUTES:
6685     case READ_THRESHOLDS:
6686     case READ_LOG_SECTOR:
6687     case WRITE_LOG_SECTOR:
6688 
6689         if(Srb->DataTransferLength < sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDOUTPARAMS) + READ_ATTRIBUTE_BUFFER_SIZE - 1) {
6690             KdPrint2((PRINT_PREFIX
6691                         "IdeSendSmartCommand: wrong buffer size\n"));
6692             return SRB_STATUS_DATA_OVERRUN;
6693         }
6694 
6695         statusByte = WaitOnBusy(chan);
6696 
6697         if (statusByte & IDE_STATUS_BUSY) {
6698             KdPrint2((PRINT_PREFIX
6699                         "IdeSendSmartCommand: Returning BUSY status\n"));
6700             return SRB_STATUS_BUSY;
6701         }
6702 
6703         // Zero the ouput buffer as the input buffer info. has been saved off locally (the buffers are the same).
6704         RtlZeroMemory(cmdOutParameters, sizeof(SENDCMDOUTPARAMS) + READ_ATTRIBUTE_BUFFER_SIZE - 1);
6705 
6706         // Set data buffer pointer and words left.
6707         AtaReq->DataBuffer = (PUSHORT)cmdOutParameters->bBuffer;
6708         AtaReq->WordsLeft = READ_ATTRIBUTE_BUFFER_SIZE / 2;
6709 
6710         statusByte = AtaCommand(deviceExtension, DeviceNumber, c,
6711                    regs->bCommandReg,
6712                    (USHORT)(regs->bCylLowReg) | (((USHORT)(regs->bCylHighReg)) << 8),
6713                    0,
6714                    regs->bSectorNumberReg,
6715                    regs->bSectorCountReg,
6716                    regs->bFeaturesReg,
6717                    ATA_IMMEDIATE);
6718 
6719         if(!(statusByte & IDE_STATUS_ERROR)) {
6720             // Wait for interrupt.
6721             return SRB_STATUS_PENDING;
6722         }
6723         return SRB_STATUS_ERROR;
6724 
6725     case ENABLE_SMART:
6726     case DISABLE_SMART:
6727     case RETURN_SMART_STATUS:
6728     case ENABLE_DISABLE_AUTOSAVE:
6729     case EXECUTE_OFFLINE_DIAGS:
6730     case SAVE_ATTRIBUTE_VALUES:
6731     case AUTO_OFFLINE:
6732 
6733         statusByte = WaitOnBusy(chan);
6734 
6735         if (statusByte & IDE_STATUS_BUSY) {
6736             KdPrint2((PRINT_PREFIX
6737                         "IdeSendSmartCommand: Returning BUSY status\n"));
6738             return SRB_STATUS_BUSY;
6739         }
6740 
6741         // Zero the ouput buffer as the input buffer info. has been saved off locally (the buffers are the same).
6742         RtlZeroMemory(cmdOutParameters, sizeof(SENDCMDOUTPARAMS) - 1);
6743 
6744         // Set data buffer pointer and indicate no data transfer.
6745         AtaReq->DataBuffer = (PUSHORT)cmdOutParameters->bBuffer;
6746         AtaReq->WordsLeft = 0;
6747 
6748         statusByte = AtaCommand(deviceExtension, DeviceNumber, c,
6749                    regs->bCommandReg,
6750                    (USHORT)(regs->bCylLowReg) | (((USHORT)(regs->bCylHighReg)) << 8),
6751                    0,
6752                    regs->bSectorNumberReg,
6753                    regs->bSectorCountReg,
6754                    regs->bFeaturesReg,
6755                    ATA_IMMEDIATE);
6756 
6757         if(!(statusByte & IDE_STATUS_ERROR)) {
6758             // Wait for interrupt.
6759             UniataExpectChannelInterrupt(chan, TRUE); // device may interrupt
6760             return SRB_STATUS_PENDING;
6761         }
6762         return SRB_STATUS_ERROR;
6763     } // end switch(regs->bFeaturesReg)
6764 
6765     return SRB_STATUS_INVALID_REQUEST;
6766 
6767 } // end IdeSendSmartCommand()
6768 
6769 #endif //UNIATA_CORE
6770 
6771 ULONGLONG
6772 NTAPI
6773 UniAtaCalculateLBARegs(
6774     PHW_LU_EXTENSION     LunExt,
6775     ULONGLONG            startingSector,
6776     PULONG               max_bcount
6777     )
6778 {
6779     UCHAR                drvSelect,sectorNumber;
6780     USHORT               cylinder;
6781     ULONG                tmp;
6782 
6783     if(LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) {
6784         (*max_bcount) = 0;
6785         if(LunExt->LimitedTransferMode >= ATA_DMA) {
6786             if(LunExt->DeviceExtension) {
6787                 (*max_bcount) = LunExt->DeviceExtension->MaximumDmaTransferLength / DEV_BSIZE;
6788             }
6789         }
6790         return startingSector;
6791     }
6792     tmp = LunExt->IdentifyData.SectorsPerTrack *
6793                        LunExt->IdentifyData.NumberOfHeads;
6794     if(!tmp) {
6795         KdPrint2((PRINT_PREFIX "UniAtaCalculateLBARegs: 0-sized\n"));
6796         cylinder     = 0;
6797         drvSelect    = 0;
6798         sectorNumber = 1;
6799         (*max_bcount) = LunExt->IdentifyData.SectorsPerTrack;
6800     } else {
6801         cylinder =    (USHORT)(startingSector / tmp);
6802         drvSelect =   (UCHAR)((startingSector % tmp) / LunExt->IdentifyData.SectorsPerTrack);
6803         sectorNumber = (UCHAR)(startingSector % LunExt->IdentifyData.SectorsPerTrack) + 1;
6804         (*max_bcount) = LunExt->IdentifyData.SectorsPerTrack - sectorNumber + 1;
6805         KdPrint2((PRINT_PREFIX "UniAtaCalculateLBARegs: C:H:S=%#x:%#x:%#x, max_bc %#x\n",
6806             cylinder, drvSelect, sectorNumber, (*max_bcount)));
6807     }
6808 
6809     return (ULONG)(sectorNumber&0xff) | (((ULONG)cylinder&0xffff)<<8) | (((ULONG)drvSelect&0xf)<<24);
6810 } // end UniAtaCalculateLBARegs()
6811 
6812 ULONGLONG
6813 NTAPI
6814 UniAtaCalculateLBARegsBack(
6815     PHW_LU_EXTENSION     LunExt,
6816     ULONGLONG            lba
6817     )
6818 {
6819     ULONG                drvSelect,sectorNumber;
6820     ULONG                cylinder;
6821     ULONG                tmp;
6822 
6823     if(LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) {
6824         return lba;
6825     }
6826     tmp = LunExt->IdentifyData.SectorsPerTrack *
6827                        LunExt->IdentifyData.NumberOfHeads;
6828 
6829     cylinder     = (USHORT)((lba >> 8) & 0xffff);
6830     drvSelect    = (UCHAR)((lba >> 24) & 0xf);
6831     sectorNumber = (UCHAR)(lba & 0xff);
6832 
6833     lba = sectorNumber-1 +
6834           (drvSelect*LunExt->IdentifyData.SectorsPerTrack) +
6835           (cylinder*tmp);
6836 
6837     return lba;
6838 } // end UniAtaCalculateLBARegsBack()
6839 
6840 
6841 /*++
6842 
6843 Routine Description:
6844 
6845     This routine handles IDE read and writes.
6846 
6847 Arguments:
6848 
6849     HwDeviceExtension - HBA miniport driver's adapter data storage
6850     Srb - IO request packet
6851 
6852 Return Value:
6853 
6854     SRB status
6855 
6856 --*/
6857 ULONG
6858 NTAPI
6859 IdeReadWrite(
6860     IN PVOID HwDeviceExtension,
6861     IN PSCSI_REQUEST_BLOCK Srb,
6862     IN ULONG CmdAction
6863     )
6864 {
6865     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
6866     UCHAR                lChannel = GET_CHANNEL(Srb);
6867     PHW_CHANNEL          chan = &(deviceExtension->chan[lChannel]);
6868     PHW_LU_EXTENSION     LunExt;
6869     PATA_REQ             AtaReq = (PATA_REQ)(Srb->SrbExtension);
6870     //ULONG                ldev = GET_LDEV(Srb);
6871     UCHAR                DeviceNumber = GET_CDEV(Srb);;
6872     ULONGLONG            startingSector=0;
6873     ULONG                max_bcount = 0;
6874     ULONG                wordCount = 0;
6875     UCHAR                statusByte,statusByte2;
6876     UCHAR                cmd;
6877     ULONGLONG            lba;
6878     BOOLEAN              use_dma = FALSE;
6879     ULONG                fis_size;
6880 
6881     AtaReq->Flags |= REQ_FLAG_REORDERABLE_CMD;
6882     LunExt = chan->lun[DeviceNumber];
6883 
6884     if((CmdAction & CMD_ACTION_PREPARE) &&
6885        (AtaReq->ReqState != REQ_STATE_READY_TO_TRANSFER)) {
6886 
6887         if(LunExt->opt_ReadOnly &&
6888            (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)) {
6889             if(LunExt->opt_ReadOnly == 1) {
6890                 KdPrint2((PRINT_PREFIX "Abort WRITE (Soft R/O)\n"));
6891                 return SRB_STATUS_ERROR;
6892             } else {
6893                 KdPrint2((PRINT_PREFIX "Ignore WRITE (Soft R/O)\n"));
6894                 return SRB_STATUS_SUCCESS;
6895             }
6896         }
6897 
6898         // Set data buffer pointer and words left.
6899         AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
6900 
6901         if(AtaReq->WordsTransfered) {
6902             AtaReq->DataBuffer = ((PUSHORT)(Srb->DataBuffer)) + AtaReq->WordsTransfered;
6903             startingSector = (UniAtaCalculateLBARegsBack(LunExt, AtaReq->lba)) /* latest lba */ + AtaReq->bcount /* previous bcount */;
6904             AtaReq->bcount = (AtaReq->TransferLength - AtaReq->WordsTransfered*2 + DEV_BSIZE-1) / DEV_BSIZE;
6905             KdPrint2((PRINT_PREFIX "IdeReadWrite (Chained REQ): Starting sector %I64x, OrigWordsRequested %#x, WordsTransfered %#x, DevSize %#x\n",
6906                        startingSector,
6907                        AtaReq->TransferLength/2,
6908                        AtaReq->WordsTransfered,
6909                        AtaReq->bcount));
6910         } else {
6911             AtaReq->DataBuffer = (PUSHORT)(Srb->DataBuffer);
6912             AtaReq->TransferLength = Srb->DataTransferLength;
6913             // Set up 1st block.
6914             switch(Srb->Cdb[0]) {
6915             case SCSIOP_WRITE:
6916                 if(LunExt->DeviceFlags & DFLAGS_LBA32plus) {
6917                   KdPrint2((PRINT_PREFIX "Attention: SCSIOP_WRITE on 2TB\n"));
6918                   //return SRB_STATUS_ERROR;
6919                 }
6920                 // FALLTHROUGH
6921             case SCSIOP_READ:
6922                 MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB10.LBA);
6923                 MOV_SWP_DW2DD(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB10.TransferBlocks);
6924                 break;
6925             case SCSIOP_WRITE12:
6926                 if(LunExt->DeviceFlags & DFLAGS_LBA32plus) {
6927                   KdPrint2((PRINT_PREFIX "Attention: SCSIOP_WRITE12 on 2TB\n"));
6928                   //return SRB_STATUS_ERROR;
6929                 }
6930                 // FALLTHROUGH
6931             case SCSIOP_READ12:
6932                 MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB12READWRITE.LBA);
6933                 MOV_DD_SWP(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB12READWRITE.NumOfBlocks);
6934                 break;
6935             case SCSIOP_READ16:
6936             case SCSIOP_WRITE16:
6937                 MOV_QD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB16READWRITE.LBA);
6938                 MOV_DD_SWP(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB16READWRITE.NumOfBlocks);
6939                 break;
6940             }
6941             KdPrint2((PRINT_PREFIX "IdeReadWrite (Orig REQ): Starting sector %I64x, OrigWordsRequested %#x, DevSize %#x\n",
6942                        startingSector,
6943                        AtaReq->TransferLength/2,
6944                        AtaReq->bcount));
6945         }
6946         lba = UniAtaCalculateLBARegs(LunExt, startingSector, &max_bcount);
6947 
6948         if(max_bcount) {
6949             AtaReq->bcount = min(AtaReq->bcount, max_bcount);
6950         }
6951         AtaReq->WordsLeft = min(AtaReq->TransferLength - AtaReq->WordsTransfered*2,
6952                                 AtaReq->bcount * DEV_BSIZE) / 2;
6953 
6954         KdPrint2((PRINT_PREFIX "IdeReadWrite (REQ): Starting sector is %I64x, Number of WORDS %#x, DevSize %#x\n",
6955                    startingSector,
6956                    AtaReq->WordsLeft,
6957                    AtaReq->bcount));
6958 
6959         AtaReq->lba = lba;
6960         if(LunExt->errRetry &&
6961            lba == LunExt->errLastLba &&
6962            /* AtaReq->bcount && */ // errRetry can be set only for non-zero bcount
6963            AtaReq->bcount == LunExt->errBCount) {
6964             KdPrint3((PRINT_PREFIX "IdeReadWrite: Retry after BUS_RESET %d @%#I64x (%#x)\n",
6965                 LunExt->errRetry, LunExt->errLastLba, LunExt->errBCount));
6966             if(AtaReq->retry < MAX_RETRIES) {
6967                 AtaReq->retry = LunExt->errRetry;
6968                 AtaReq->Flags |= REQ_FLAG_FORCE_DOWNRATE;
6969             }
6970             LunExt->errRetry = 0;
6971         }
6972 
6973         // assume best case here
6974         // we cannot reinit Dma until previous request is completed
6975         if(deviceExtension->HwFlags & UNIATA_AHCI) {
6976             UniataAhciSetupCmdPtr(AtaReq);
6977             if(!AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb,
6978                           (PUCHAR)(AtaReq->DataBuffer),
6979                           AtaReq->bcount * DEV_BSIZE)) {
6980                 KdPrint3((PRINT_PREFIX "IdeReadWrite: AHCI !DMA\n"));
6981                 return SRB_STATUS_ERROR;
6982             }
6983         } else
6984         if ((LunExt->LimitedTransferMode >= ATA_DMA)) {
6985             use_dma = TRUE;
6986             // this will set REQ_FLAG_DMA_OPERATION in AtaReq->Flags on success
6987             if(!AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb,
6988                           (PUCHAR)(AtaReq->DataBuffer),
6989                           AtaReq->bcount * DEV_BSIZE)) {
6990                 use_dma = FALSE;
6991             }
6992         }
6993 
6994         if(deviceExtension->HwFlags & UNIATA_AHCI) {
6995             KdPrint2((PRINT_PREFIX "IdeReadWrite: setup AHCI FIS\n"));
6996             RtlZeroMemory(&(AtaReq->ahci.ahci_cmd_ptr->cfis), sizeof(AtaReq->ahci_cmd0.cfis));
6997 
6998             fis_size = UniataAhciSetupFIS_H2D(deviceExtension, DeviceNumber, lChannel,
6999                    &(AtaReq->ahci.ahci_cmd_ptr->cfis[0]),
7000                     (AtaReq->Flags & REQ_FLAG_READ) ? IDE_COMMAND_READ_DMA : IDE_COMMAND_WRITE_DMA,
7001                     lba,
7002                      (USHORT)(AtaReq->bcount),
7003                     0
7004                     /*,(AtaReq->Flags & REQ_FLAG_READ) ? 0 : ATA_AHCI_CMD_WRITE*/
7005                     );
7006 
7007             if(!fis_size) {
7008                 KdPrint3((PRINT_PREFIX "IdeReadWrite: AHCI !FIS\n"));
7009                 return SRB_STATUS_ERROR;
7010             }
7011 
7012             AtaReq->ahci.io_cmd_flags = UniAtaAhciAdjustIoFlags(0, (AtaReq->Flags & REQ_FLAG_READ) ? 0 : ATA_AHCI_CMD_WRITE, fis_size, DeviceNumber);
7013             KdPrint2((PRINT_PREFIX "IdeReadWrite ahci io flags %x: \n", AtaReq->ahci.io_cmd_flags));
7014         }
7015 
7016         AtaReq->ReqState = REQ_STATE_READY_TO_TRANSFER;
7017 
7018     } else { // exec_only
7019         KdPrint2((PRINT_PREFIX "IdeReadWrite (ExecOnly): \n"));
7020         lba = AtaReq->lba;
7021 
7022         if(AtaReq->Flags & REQ_FLAG_DMA_OPERATION) {
7023             use_dma = TRUE;
7024         }
7025     }
7026     if(!(CmdAction & CMD_ACTION_EXEC)) {
7027 
7028         return SRB_STATUS_PENDING;
7029     }
7030 
7031     // if this is queued request, reinit DMA and check
7032     // if DMA mode is still available
7033     AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
7034     if (/*EnableDma &&*/
7035         (LunExt->TransferMode >= ATA_DMA)) {
7036         use_dma = TRUE;
7037     } else {
7038         AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
7039         use_dma = FALSE;
7040     }
7041 
7042     // Check if write request.
7043     if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
7044 
7045         // Prepare read command.
7046         if(use_dma) {
7047             cmd = IDE_COMMAND_READ_DMA;
7048         } else
7049         if(LunExt->MaximumBlockXfer) {
7050             cmd = IDE_COMMAND_READ_MULTIPLE;
7051         } else {
7052             cmd = IDE_COMMAND_READ;
7053         }
7054     } else {
7055 
7056         // Prepare write command.
7057         if (use_dma) {
7058             wordCount = AtaReq->bcount*DEV_BSIZE/2;
7059             cmd = IDE_COMMAND_WRITE_DMA;
7060         } else
7061         if (LunExt->MaximumBlockXfer) {
7062             wordCount = DEV_BSIZE/2 * LunExt->MaximumBlockXfer;
7063 
7064             if (AtaReq->WordsLeft < wordCount) {
7065                // Transfer only words requested.
7066                wordCount = AtaReq->WordsLeft;
7067             }
7068             cmd = IDE_COMMAND_WRITE_MULTIPLE;
7069 
7070         } else {
7071             wordCount = DEV_BSIZE/2;
7072             cmd = IDE_COMMAND_WRITE;
7073         }
7074     }
7075 
7076     // Send IO command.
7077     KdPrint2((PRINT_PREFIX "IdeReadWrite: Lba %#I64x, Count %#x(%#x)\n", lba, ((Srb->DataTransferLength + 0x1FF) / 0x200),
7078                                                            ((wordCount*2 + DEV_BSIZE-1) / DEV_BSIZE)));
7079     if(use_dma) {
7080         chan->ChannelCtrlFlags |= CTRFLAGS_DMA_OPERATION;
7081     } else {
7082         chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
7083     }
7084 
7085     if(deviceExtension->HwFlags & UNIATA_AHCI) {
7086         // AHCI doesn't distinguish DMA and PIO
7087         //AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
7088         UniataAhciBeginTransaction(HwDeviceExtension, lChannel, DeviceNumber, Srb);
7089         UniataExpectChannelInterrupt(chan, TRUE); // device may interrupt
7090         InterlockedExchange(&(chan->CheckIntr),
7091                                       CHECK_INTR_IDLE);
7092         return SRB_STATUS_PENDING;
7093     }
7094 
7095     if ((Srb->SrbFlags & SRB_FLAGS_DATA_IN) ||
7096         use_dma) {
7097         if(use_dma) {
7098             AtapiDmaDBPreSync(HwDeviceExtension, chan, Srb);
7099             if(g_opt_BochsDmaReadWorkaround &&
7100                (Srb->SrbFlags & SRB_FLAGS_DATA_IN)) {
7101                 KdPrint2((PRINT_PREFIX "CTRFLAGS_DMA_BEFORE_R on BOCHS\n"));
7102                 AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
7103             }
7104         }
7105         statusByte2 = AtaCommand48(deviceExtension, DeviceNumber, lChannel,
7106                      cmd, lba,
7107                      (USHORT)(AtaReq->bcount),
7108 //                     (UCHAR)((wordCount*2 + DEV_BSIZE-1) / DEV_BSIZE),
7109                      0, ATA_IMMEDIATE);
7110 /*        if(statusByte2 != IDE_STATUS_WRONG) {
7111             GetStatus(chan, statusByte2);
7112         }*/
7113         if(statusByte2 & IDE_STATUS_ERROR) {
7114             // Unfortunately, we cannot handle errors in such a way in real life (except known bad blocks).
7115             // Because some devices doesn't reset ERR from previous command immediately after getting new one.
7116             // On the other hand we cannot wait here because of possible timeout condition
7117             statusByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
7118             KdPrint2((PRINT_PREFIX "IdeReadWrite: status %#x, error %#x\n", statusByte2, statusByte));
7119             return SRB_STATUS_ERROR;
7120         }
7121         if(use_dma) {
7122            if(!g_opt_BochsDmaReadWorkaround ||
7123               !(Srb->SrbFlags & SRB_FLAGS_DATA_IN)) {
7124                 //GetStatus(chan, statusByte2);
7125                 AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
7126             }
7127         }
7128         return SRB_STATUS_PENDING;
7129     }
7130 
7131     statusByte = AtaCommand48(deviceExtension, DeviceNumber, lChannel,
7132                  cmd, lba,
7133                  (USHORT)(AtaReq->bcount),
7134 //                 (UCHAR)((wordCount*2 + DEV_BSIZE-1) / DEV_BSIZE),
7135                  0, ATA_WAIT_INTR);
7136 
7137     if (!(statusByte & IDE_STATUS_DRQ) ||
7138         statusByte == IDE_STATUS_WRONG) {
7139 
7140         if(statusByte == IDE_STATUS_WRONG) {
7141             KdPrint2((PRINT_PREFIX
7142                        "IdeReadWrite: error sending command (%#x)\n",
7143                        statusByte));
7144         } else {
7145             KdPrint2((PRINT_PREFIX
7146                        "IdeReadWrite: DRQ never asserted (%#x)\n",
7147                        statusByte));
7148         }
7149 
7150         AtaReq->WordsLeft = 0;
7151 
7152         // Clear interrupt expecting flag.
7153         UniataExpectChannelInterrupt(chan, FALSE);
7154         InterlockedExchange(&(chan->CheckIntr),
7155                                       CHECK_INTR_IDLE);
7156 
7157         // Clear current SRB.
7158         UniataRemoveRequest(chan, Srb);
7159 
7160         return (statusByte == IDE_STATUS_WRONG) ? SRB_STATUS_ERROR : SRB_STATUS_TIMEOUT;
7161     }
7162 
7163     UniataExpectChannelInterrupt(chan, TRUE);
7164     InterlockedExchange(&(chan->CheckIntr),
7165                                   CHECK_INTR_IDLE);
7166 
7167     // Write next DEV_BSIZE/2*N words.
7168     if (!(LunExt->DeviceFlags & DFLAGS_DWORDIO_ENABLED) || (wordCount & 1)) {
7169         KdPrint2((PRINT_PREFIX
7170                    "IdeReadWrite: Write %#x words\n", wordCount));
7171 
7172         WriteBuffer(chan,
7173                   AtaReq->DataBuffer,
7174                   wordCount,
7175                   UniataGetPioTiming(LunExt));
7176 
7177     } else {
7178 
7179         KdPrint2((PRINT_PREFIX
7180                    "IdeReadWrite: Write %#x Dwords\n", wordCount/2));
7181 
7182         WriteBuffer2(chan,
7183                    (PULONG)(AtaReq->DataBuffer),
7184                    wordCount / 2,
7185                    UniataGetPioTiming(LunExt));
7186     }
7187 
7188     // Adjust buffer address and words left count.
7189     AtaReq->WordsLeft -= wordCount;
7190     AtaReq->DataBuffer += wordCount;
7191     AtaReq->WordsTransfered += wordCount;
7192 
7193     // Wait for interrupt.
7194     return SRB_STATUS_PENDING;
7195 
7196 } // end IdeReadWrite()
7197 
7198 #ifndef UNIATA_CORE
7199 
7200 /*++
7201 
7202 Routine Description:
7203     This routine handles IDE Verify.
7204 
7205 Arguments:
7206     HwDeviceExtension - HBA miniport driver's adapter data storage
7207     Srb - IO request packet
7208     `
7209 Return Value:
7210     SRB status
7211 
7212 --*/
7213 ULONG
7214 NTAPI
7215 IdeVerify(
7216     IN PVOID HwDeviceExtension,
7217     IN PSCSI_REQUEST_BLOCK Srb
7218     )
7219 {
7220     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
7221     UCHAR                lChannel = GET_CHANNEL(Srb);
7222     PHW_CHANNEL          chan = &(deviceExtension->chan[lChannel]);
7223     PATA_REQ             AtaReq = (PATA_REQ)(Srb->SrbExtension);
7224     PHW_LU_EXTENSION     LunExt;
7225     //ULONG                ldev = GET_LDEV(Srb);
7226     ULONG                DeviceNumber = GET_CDEV(Srb);
7227     UCHAR                statusByte;
7228     ULONGLONG            startingSector=0;
7229     ULONG                max_bcount;
7230     ULONGLONG            sectors;
7231     ULONGLONG            endSector;
7232     ULONG                sectorCount=0;
7233     ULONGLONG            lba;
7234 
7235     LunExt = chan->lun[DeviceNumber];
7236     // Drive has these number sectors.
7237     if(!(sectors = (ULONG)(LunExt->NumOfSectors))) {
7238         sectors = LunExt->IdentifyData.SectorsPerTrack *
7239                   LunExt->IdentifyData.NumberOfHeads *
7240                   LunExt->IdentifyData.NumberOfCylinders;
7241     }
7242 
7243     KdPrint2((PRINT_PREFIX
7244                 "IdeVerify: Total sectors %#I64x\n",
7245                 sectors));
7246 
7247     // Get starting sector number from CDB.
7248     switch(Srb->Cdb[0]) {
7249     case SCSIOP_VERIFY:
7250         MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB10.LBA);
7251         MOV_SWP_DW2DD(sectorCount, ((PCDB)Srb->Cdb)->CDB10.TransferBlocks);
7252         break;
7253     case SCSIOP_VERIFY12:
7254         MOV_DD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB12READWRITE.LBA);
7255         MOV_DD_SWP(sectorCount, ((PCDB)Srb->Cdb)->CDB12READWRITE.NumOfBlocks);
7256         break;
7257     case SCSIOP_VERIFY16:
7258         MOV_QD_SWP(startingSector, ((PCDB)Srb->Cdb)->CDB16READWRITE.LBA);
7259         MOV_DD_SWP(sectorCount, ((PCDB)Srb->Cdb)->CDB16READWRITE.NumOfBlocks);
7260         break;
7261     }
7262 
7263     KdPrint2((PRINT_PREFIX
7264                 "IdeVerify: Starting sector %#I64x. Number of blocks %#x\n",
7265                 startingSector,
7266                 sectorCount));
7267 
7268     endSector = startingSector + sectorCount;
7269 
7270     KdPrint2((PRINT_PREFIX
7271                 "IdeVerify: Ending sector %#I64x\n",
7272                 endSector));
7273 
7274     if (endSector > sectors) {
7275 
7276         // Too big, round down.
7277         KdPrint2((PRINT_PREFIX
7278                     "IdeVerify: Truncating request to %#x blocks\n",
7279                     sectors - startingSector - 1));
7280 
7281         sectorCount = (ULONG)(sectors - startingSector - 1);
7282 
7283     } else {
7284 
7285         // Set up sector count register. Round up to next block.
7286         if (sectorCount > 0xFF) {
7287             sectorCount = (USHORT)0xFF;
7288         }
7289     }
7290 
7291     // Set data buffer pointer and words left.
7292     AtaReq->DataBuffer = (PUSHORT)Srb->DataBuffer;
7293     AtaReq->WordsLeft = Srb->DataTransferLength / 2;
7294 
7295     // Indicate expecting an interrupt.
7296     InterlockedExchange(&(chan->CheckIntr),
7297                                   CHECK_INTR_IDLE);
7298 
7299     lba = UniAtaCalculateLBARegs(LunExt, startingSector, &max_bcount);
7300 
7301     statusByte = AtaCommand48(deviceExtension, LunExt->Lun, GET_CHANNEL(Srb),
7302                  IDE_COMMAND_VERIFY, lba,
7303                  (USHORT)sectorCount,
7304                  0, ATA_IMMEDIATE);
7305 
7306     if(!(statusByte & IDE_STATUS_ERROR)) {
7307         // Wait for interrupt.
7308         UniataExpectChannelInterrupt(chan, TRUE);
7309         return SRB_STATUS_PENDING;
7310     }
7311     return SRB_STATUS_ERROR;
7312 
7313 } // end IdeVerify()
7314 
7315 #endif //UNIATA_CORE
7316 
7317 /*++
7318 
7319 Routine Description:
7320     Send ATAPI packet command to device.
7321 
7322 Arguments:
7323     HwDeviceExtension - HBA miniport driver's adapter data storage
7324     Srb - IO request packet
7325 
7326 Return Value:
7327 
7328 --*/
7329 ULONG
7330 NTAPI
7331 AtapiSendCommand(
7332     IN PVOID HwDeviceExtension,
7333     IN PSCSI_REQUEST_BLOCK Srb,
7334     IN ULONG CmdAction
7335     )
7336 {
7337     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
7338     UCHAR                lChannel = GET_CHANNEL(Srb);
7339     PHW_CHANNEL          chan = &(deviceExtension->chan[lChannel]);
7340     PATA_REQ             AtaReq = (PATA_REQ)(Srb->SrbExtension);
7341     PHW_LU_EXTENSION     LunExt;
7342     //ULONG                ldev = GET_LDEV(Srb);
7343     ULONG                DeviceNumber = GET_CDEV(Srb);
7344     ULONG flags;
7345     UCHAR statusByte,statusByte0,byteCountLow,byteCountHigh;
7346     UCHAR interruptReason;
7347     BOOLEAN use_dma = FALSE;
7348     BOOLEAN dma_reinited = FALSE;
7349     BOOLEAN retried = FALSE;
7350     ULONG                fis_size, i;
7351     UCHAR FeatureReg=0;
7352 
7353     LunExt = chan->lun[DeviceNumber];
7354 
7355     KdPrint3((PRINT_PREFIX "AtapiSendCommand: req state %#x, Action %x\n", AtaReq->ReqState, CmdAction));
7356     if(AtaReq->ReqState < REQ_STATE_PREPARE_TO_TRANSFER)
7357         AtaReq->ReqState = REQ_STATE_PREPARE_TO_TRANSFER;
7358 
7359 
7360 #ifdef UNIATA_DUMP_ATAPI
7361     if(CmdAction & CMD_ACTION_PREPARE) {
7362         UCHAR                   ScsiCommand;
7363         PCDB                    Cdb;
7364         PCHAR                   CdbData;
7365         PCHAR                   ModeSelectData;
7366         ULONG                   CdbDataLen;
7367 
7368         Cdb = (PCDB)(Srb->Cdb);
7369         ScsiCommand = Cdb->CDB6.OperationCode;
7370         CdbData = (PCHAR)(Srb->DataBuffer);
7371         CdbDataLen = Srb->DataTransferLength;
7372 
7373         if(CdbDataLen > 0x1000) {
7374             CdbDataLen = 0x1000;
7375         }
7376 
7377         KdPrint(("--\n"));
7378         KdPrint2(("DeviceID+VendorID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID));
7379         KdPrint2(("P:T:D=%d:%d:%d\n",
7380                                   Srb->PathId,
7381                                   Srb->TargetId,
7382                                   Srb->Lun));
7383         KdPrint(("SCSI Command %2.2x\n", ScsiCommand));
7384         KdDump(Cdb, 16);
7385 
7386         if(ScsiCommand == SCSIOP_WRITE_CD) {
7387             KdPrint(("Write10, LBA %2.2x%2.2x%2.2x%2.2x\n",
7388                      Cdb->WRITE_CD.LBA[0],
7389                      Cdb->WRITE_CD.LBA[1],
7390                      Cdb->WRITE_CD.LBA[2],
7391                      Cdb->WRITE_CD.LBA[3]
7392                      ));
7393         } else
7394         if(ScsiCommand == SCSIOP_WRITE12) {
7395             KdPrint(("Write12, LBA %2.2x%2.2x%2.2x%2.2x\n",
7396                      Cdb->CDB12READWRITE.LBA[0],
7397                      Cdb->CDB12READWRITE.LBA[1],
7398                      Cdb->CDB12READWRITE.LBA[2],
7399                      Cdb->CDB12READWRITE.LBA[3]
7400                      ));
7401         } else
7402         if(ScsiCommand == SCSIOP_WRITE16) {
7403             KdPrint(("Write16, LBA %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
7404                      Cdb->CDB16READWRITE.LBA[0],
7405                      Cdb->CDB16READWRITE.LBA[1],
7406                      Cdb->CDB16READWRITE.LBA[2],
7407                      Cdb->CDB16READWRITE.LBA[3],
7408                      Cdb->CDB16READWRITE.LBA[4],
7409                      Cdb->CDB16READWRITE.LBA[5],
7410                      Cdb->CDB16READWRITE.LBA[6],
7411                      Cdb->CDB16READWRITE.LBA[7]
7412                      ));
7413         } else
7414         if(ScsiCommand == SCSIOP_MODE_SELECT) {
7415             KdPrint(("ModeSelect 6\n"));
7416             PMODE_PARAMETER_HEADER ParamHdr = (PMODE_PARAMETER_HEADER)CdbData;
7417             ModeSelectData = CdbData+4;
7418             KdDump(CdbData, CdbDataLen);
7419         } else
7420         if(ScsiCommand == SCSIOP_MODE_SELECT10) {
7421             KdPrint(("ModeSelect 10\n"));
7422             PMODE_PARAMETER_HEADER ParamHdr = (PMODE_PARAMETER_HEADER)CdbData;
7423             ModeSelectData = CdbData+8;
7424             KdDump(CdbData, CdbDataLen);
7425         } else {
7426             if(Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
7427                 KdPrint(("Send buffer to device:\n"));
7428                 KdDump(CdbData, CdbDataLen);
7429             }
7430         }
7431         KdPrint(("--\n"));
7432     }
7433 #endif //UNIATA_DUMP_ATAPI
7434 
7435 
7436     if(CmdAction == CMD_ACTION_PREPARE) {
7437         KdPrint2((PRINT_PREFIX "AtapiSendCommand: CMD_ACTION_PREPARE, Cdb %x\n", &(Srb->Cdb)));
7438 
7439         switch (Srb->Cdb[0]) {
7440         case SCSIOP_RECEIVE:
7441         case SCSIOP_SEND:
7442         case SCSIOP_READ:
7443         case SCSIOP_WRITE:
7444         case SCSIOP_READ12:
7445         case SCSIOP_WRITE12:
7446         case SCSIOP_READ16:
7447         case SCSIOP_WRITE16:
7448             // all right
7449             break;
7450         case SCSIOP_READ_CD:
7451         case SCSIOP_READ_CD_MSF:
7452             if(deviceExtension->opt_AtapiDmaRawRead) {
7453                 // all right
7454                 break;
7455             }
7456             /* FALL THROUGH */
7457         default:
7458             KdPrint2((PRINT_PREFIX "AtapiSendCommand: SRB_STATUS_BUSY\n"));
7459             return SRB_STATUS_BUSY;
7460         }
7461         //
7462 #ifdef UNIATA_INIT_CHANGERS
7463         if (!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED) &&
7464             !AtaReq->OriginalSrb) {
7465             KdPrint2((PRINT_PREFIX "AtapiSendCommand: SRB_STATUS_BUSY (2)\n"));
7466             return SRB_STATUS_BUSY;
7467         }
7468 #endif // UNIATA_INIT_CHANGERS
7469     }
7470 
7471 #ifndef UNIATA_CORE
7472     // standard atapi.sys claims:
7473 
7474     // We need to know how many platters our atapi cd-rom device might have.
7475     // Before anyone tries to send a srb to our target for the first time,
7476     // we must "secretly" send down a separate mechanism status srb in order to
7477     // initialize our device extension changer data.  That's how we know how
7478     // many platters our target has.
7479 
7480     // BUT!
7481     // some devices freeze (sometimes) forever on this command
7482     // Let CD-ROM driver send this command itself, if it find it necessary
7483     // We shall just parse output (if any)
7484 
7485 #ifdef UNIATA_INIT_CHANGERS
7486     if (!(LunExt->DeviceFlags & DFLAGS_CHANGER_INITED) &&
7487         !AtaReq->OriginalSrb) {
7488 
7489         ULONG srbStatus;
7490 
7491         KdPrint3((PRINT_PREFIX "AtapiSendCommand: BuildMechanismStatusSrb()\n"));
7492         // Set this flag now. If the device hangs on the mech. status
7493         // command, we will not have the chance to set it.
7494         LunExt->DeviceFlags |= DFLAGS_CHANGER_INITED;
7495 
7496         chan->MechStatusRetryCount = 3;
7497         AtaReq->OriginalSrb = Srb;
7498         AtaReq->Srb = BuildMechanismStatusSrb (
7499                                         HwDeviceExtension,
7500                                         Srb);
7501 
7502         KdPrint3((PRINT_PREFIX "AtapiSendCommand: AtapiSendCommand recursive\n"));
7503         srbStatus = AtapiSendCommand(HwDeviceExtension, AtaReq->Srb, CMD_ACTION_ALL);
7504         if (srbStatus == SRB_STATUS_PENDING) {
7505             KdPrint2((PRINT_PREFIX "AtapiSendCommand: SRB_STATUS_PENDING (2)\n"));
7506             return srbStatus;
7507         } else {
7508 
7509             // failed!  Get the sense key and maybe try again
7510             AtaReq->Srb = BuildRequestSenseSrb (  HwDeviceExtension,
7511                                                   AtaReq->OriginalSrb);
7512 
7513             srbStatus = AtapiSendCommand(HwDeviceExtension, AtaReq->Srb, CMD_ACTION_ALL);
7514 
7515             KdPrint3((PRINT_PREFIX "AtapiSendCommand: chan->ExpectingInterrupt %d (1)\n", chan->ExpectingInterrupt));
7516 
7517             if (srbStatus == SRB_STATUS_PENDING) {
7518                 KdPrint2((PRINT_PREFIX "AtapiSendCommand: send orig SRB_STATUS_PENDING (2.1)\n"));
7519                 return srbStatus;
7520             }
7521 
7522             // failed again ? should not get here
7523             AtaReq->Srb = AtaReq->OriginalSrb;
7524             AtaReq->OriginalSrb = NULL;
7525             // fall out
7526         }
7527     }
7528 #endif // UNIATA_INIT_CHANGERS
7529 #endif //UNIATA_CORE
7530 
7531     if((CmdAction & CMD_ACTION_PREPARE) &&
7532        (AtaReq->ReqState != REQ_STATE_READY_TO_TRANSFER)) {
7533 
7534         KdPrint2((PRINT_PREFIX "AtapiSendCommand: prepare..., ATAPI CMD %x (Cdb %x)\n", Srb->Cdb[0], &(Srb->Cdb)));
7535 
7536         if(!LunExt->IdentifyData.AtapiCmdSize &&
7537             (Srb->CdbLength > 12)) {
7538             KdPrint2((PRINT_PREFIX "Cdb16 not supported\n"));
7539             return SRB_STATUS_INVALID_REQUEST;
7540         }
7541 
7542         // Set data buffer pointer and words left.
7543         AtaReq->DataBuffer = (PUSHORT)Srb->DataBuffer;
7544         AtaReq->WordsLeft = Srb->DataTransferLength / 2;
7545         AtaReq->TransferLength = Srb->DataTransferLength;
7546         AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
7547         // reset this to force PRD init. May be already setup by recursive SRB
7548         AtaReq->dma_entries = 0;
7549 
7550         // check if reorderable
7551         switch(Srb->Cdb[0]) {
7552         case SCSIOP_READ16:
7553         case SCSIOP_WRITE16:
7554 
7555             MOV_DD_SWP(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB16READWRITE.NumOfBlocks);
7556             MOV_QD_SWP(AtaReq->lba, ((PCDB)Srb->Cdb)->CDB16READWRITE.LBA);
7557             goto GetLba2;
7558 
7559         case SCSIOP_READ12:
7560         case SCSIOP_WRITE12:
7561 
7562             MOV_DD_SWP(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB12READWRITE.NumOfBlocks);
7563             goto GetLba;
7564 
7565         case SCSIOP_READ:
7566         case SCSIOP_WRITE:
7567 
7568             MOV_SWP_DW2DD(AtaReq->bcount, ((PCDB)Srb->Cdb)->CDB10.TransferBlocks);
7569 GetLba:
7570             MOV_DD_SWP(AtaReq->lba, ((PCDB)Srb->Cdb)->CDB10.LBA);
7571 GetLba2:
7572             AtaReq->Flags |= REQ_FLAG_REORDERABLE_CMD;
7573             AtaReq->Flags &= ~REQ_FLAG_RW_MASK;
7574             AtaReq->Flags |= (Srb->Cdb[0] == SCSIOP_WRITE ||
7575                               Srb->Cdb[0] == SCSIOP_WRITE12 ||
7576                               Srb->Cdb[0] == SCSIOP_WRITE16) ?
7577                               REQ_FLAG_WRITE : REQ_FLAG_READ;
7578             break;
7579         default:
7580             AtaReq->Flags &= ~REQ_FLAG_RW_MASK;
7581             if(!AtaReq->TransferLength) {
7582                 KdPrint(("  assume 0-transfer\n"));
7583             } else
7584             if(Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
7585                 KdPrint(("  assume OUT\n"));
7586                 AtaReq->Flags |= REQ_FLAG_WRITE;
7587             } else
7588             if(Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
7589                 KdPrint(("  assume IN\n"));
7590                 AtaReq->Flags |= REQ_FLAG_READ;
7591             }
7592             break;
7593         }
7594 
7595         // check if DMA read/write
7596         if(g_opt_AtapiNoDma) {
7597             KdPrint2((PRINT_PREFIX "AtapiSendCommand: CTRFLAGS_DMA_BEFORE_R => no dma\n"));
7598             use_dma = FALSE;
7599         } else
7600         if(deviceExtension->HwFlags & UNIATA_AHCI) {
7601             KdPrint2((PRINT_PREFIX "AtapiSendCommand: force use dma (ahci)\n"));
7602             use_dma = TRUE;
7603             goto setup_dma;
7604         } else
7605 /*        if((deviceExtension->HwFlags & UNIATA_SATA) && (LunExt->OrigTransferMode >= ATA_DMA)) {
7606             KdPrint2((PRINT_PREFIX "AtapiSendCommand: force use dma (sata)\n"));
7607             use_dma = TRUE;
7608             goto setup_dma;
7609         } else*/
7610         if(Srb->Cdb[0] == SCSIOP_REQUEST_SENSE) {
7611             KdPrint2((PRINT_PREFIX "AtapiSendCommand: SCSIOP_REQUEST_SENSE, no DMA setup\n"));
7612         } else
7613         if(AtaReq->TransferLength && !(AtaReq->TransferLength & 0x0f)) {
7614             KdPrint2((PRINT_PREFIX "AtapiSendCommand: try DMA setup\n"));
7615             // try use DMA if TransferLength is 16-byte aligned
7616             switch(Srb->Cdb[0]) {
7617             case SCSIOP_WRITE:
7618             case SCSIOP_WRITE12:
7619             case SCSIOP_WRITE16:
7620             case SCSIOP_SEND:
7621                 if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_RO)
7622                     break;
7623                 /* FALLTHROUGH */
7624             case SCSIOP_RECEIVE:
7625             case SCSIOP_READ:
7626             case SCSIOP_READ12:
7627             case SCSIOP_READ16:
7628 
7629                 if(deviceExtension->opt_AtapiDmaReadWrite) {
7630 call_dma_setup:
7631                     if(deviceExtension->HwFlags & UNIATA_AHCI) {
7632                         KdPrint2((PRINT_PREFIX "AtapiSendCommand: use dma (ahci)\n"));
7633                         use_dma = TRUE;
7634                     } else
7635                     if(AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb,
7636                                   (PUCHAR)(AtaReq->DataBuffer),
7637                                   Srb->DataTransferLength
7638                                   /*((Srb->DataTransferLength + DEV_BSIZE-1) & ~(DEV_BSIZE-1))*/
7639                                   )) {
7640                         KdPrint2((PRINT_PREFIX "AtapiSendCommand: use dma\n"));
7641                         use_dma = TRUE;
7642                     }
7643                 }
7644                 break;
7645             case SCSIOP_READ_CD:
7646             case SCSIOP_READ_CD_MSF:
7647                 if(deviceExtension->opt_AtapiDmaRawRead)
7648                     goto call_dma_setup;
7649                 break;
7650             default:
7651 
7652                 if(deviceExtension->opt_AtapiDmaControlCmd) {
7653                     if(Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
7654                         // read operation
7655                         use_dma = TRUE;
7656                     } else {
7657                         // write operation
7658                         if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_RO) {
7659                             KdPrint2((PRINT_PREFIX "dma RO\n"));
7660                             use_dma = FALSE;
7661                         } else {
7662                             use_dma = TRUE;
7663                         }
7664                     }
7665                 }
7666                 break;
7667             }
7668             // try setup DMA
7669 setup_dma:
7670             if(use_dma) {
7671                 if(deviceExtension->HwFlags & UNIATA_AHCI) {
7672                     KdPrint2((PRINT_PREFIX "AtapiSendCommand: use dma (ahci)\n"));
7673                     //use_dma = TRUE;
7674                 } else
7675                 if(!AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb,
7676                               (PUCHAR)(AtaReq->DataBuffer),
7677                               Srb->DataTransferLength)) {
7678                     KdPrint2((PRINT_PREFIX "AtapiSendCommand: no dma\n"));
7679                     use_dma = FALSE;
7680                 } else {
7681                     KdPrint2((PRINT_PREFIX "AtapiSendCommand: use dma\n"));
7682                 }
7683             }
7684         } else {
7685             KdPrint2((PRINT_PREFIX "AtapiSendCommand: zero/unaligned transfer %x, no DMA setup\n", AtaReq->TransferLength));
7686         }
7687 
7688 
7689         if(deviceExtension->HwFlags & UNIATA_AHCI) {
7690 
7691             UniataAhciSetupCmdPtr(AtaReq);
7692 
7693             if(!Srb->DataTransferLength) {
7694                 KdPrint2((PRINT_PREFIX "zero-transfer\n"));
7695                 use_dma = FALSE;
7696             } else
7697             if(!AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb,
7698                           (PUCHAR)(AtaReq->DataBuffer),
7699                           Srb->DataTransferLength)) {
7700                 KdPrint2((PRINT_PREFIX "AtapiSendCommand: no AHCI dma!\n"));
7701                 return SRB_STATUS_ERROR;
7702             }
7703             if(!use_dma) {
7704                 AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
7705             } else {
7706                 FeatureReg |= ATA_F_DMA;
7707                 if(LunExt->IdentifyData.AtapiDMA.DMADirRequired) {
7708                     if(Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
7709                         KdPrint2((PRINT_PREFIX "Set DMADir.\n"));
7710                         FeatureReg |= ATA_F_DMAREAD;
7711                     }
7712                 }
7713             }
7714 
7715             KdPrint2((PRINT_PREFIX "AtapiSendCommand: setup AHCI FIS\n"));
7716             // this is done in UniataAhciSetupFIS_H2D()
7717             //RtlZeroMemory(&(AtaReq->ahci.ahci_cmd_ptr->cfis), sizeof(AtaReq->ahci_cmd0.cfis));
7718             RtlCopyMemory(&(AtaReq->ahci.ahci_cmd_ptr->acmd), Srb->Cdb, Srb->CdbLength);
7719 
7720             fis_size = UniataAhciSetupFIS_H2D(deviceExtension, DeviceNumber, lChannel,
7721                    &(AtaReq->ahci.ahci_cmd_ptr->cfis[0]),
7722                     IDE_COMMAND_ATAPI_PACKET /* command */,
7723                     0 /* lba */,
7724                     (Srb->DataTransferLength >= 0x10000) ? (USHORT)(0xffff) : (USHORT)(Srb->DataTransferLength),
7725                     FeatureReg/* feature */
7726                     );
7727 
7728             if(!fis_size) {
7729                 KdPrint3((PRINT_PREFIX "AtapiSendCommand: AHCI !FIS\n"));
7730                 return SRB_STATUS_ERROR;
7731             }
7732 
7733             AtaReq->ahci.io_cmd_flags = UniAtaAhciAdjustIoFlags(0,
7734                 ((Srb->DataTransferLength && (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)) ? ATA_AHCI_CMD_WRITE : 0) |
7735                 (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH),
7736                 fis_size, DeviceNumber);
7737 
7738             KdPrint2((PRINT_PREFIX "AtapiSendCommand ahci io flags %x: \n", AtaReq->ahci.io_cmd_flags));
7739         }
7740 
7741     } else {
7742         if(AtaReq->Flags & REQ_FLAG_DMA_OPERATION) {
7743             // if this is queued request, reinit DMA and check
7744             // if DMA mode is still available
7745             KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiDmaReinit()  (1)\n"));
7746             AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
7747             if (/*EnableDma &&*/
7748                 (LunExt->TransferMode >= ATA_DMA)) {
7749                 KdPrint2((PRINT_PREFIX "AtapiSendCommand: use dma (2)\n"));
7750                 use_dma = TRUE;
7751             } else {
7752                 AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
7753                 KdPrint2((PRINT_PREFIX "AtapiSendCommand: no dma (2)\n"));
7754                 use_dma = FALSE;
7755             }
7756             dma_reinited = TRUE;
7757         }
7758     }
7759 
7760     if(!(CmdAction & CMD_ACTION_EXEC)) {
7761         KdPrint2((PRINT_PREFIX "AtapiSendCommand: !CMD_ACTION_EXEC => SRB_STATUS_PENDING\n"));
7762         return SRB_STATUS_PENDING;
7763     }
7764     KdPrint3((PRINT_PREFIX "AtapiSendCommand: use_dma=%d, Cmd %x\n", use_dma, Srb->Cdb[0]));
7765     if(AtaReq->Flags & REQ_FLAG_DMA_OPERATION) {
7766         KdPrint2((PRINT_PREFIX "  REQ_FLAG_DMA_OPERATION\n"));
7767     }
7768 
7769     if((Srb->Cdb[0] == SCSIOP_REQUEST_SENSE) && !(deviceExtension->HwFlags & UNIATA_SATA)) {
7770         KdPrint2((PRINT_PREFIX "AtapiSendCommand: SCSIOP_REQUEST_SENSE -> no dma setup (2)\n"));
7771         use_dma = FALSE;
7772         AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
7773         AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
7774     } if(AtaReq->TransferLength) {
7775         if(!dma_reinited) {
7776             KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiDmaReinit()\n"));
7777             AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
7778             if (/*EnableDma &&*/
7779                 (LunExt->TransferMode >= ATA_DMA)) {
7780                 use_dma = TRUE;
7781             } else {
7782                 AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
7783                 use_dma = FALSE;
7784             }
7785         }
7786     } else {
7787         KdPrint2((PRINT_PREFIX "AtapiSendCommand: zero transfer\n"));
7788         use_dma = FALSE;
7789         AtaReq->Flags &= ~REQ_FLAG_DMA_OPERATION;
7790         if(!deviceExtension->opt_AtapiDmaZeroTransfer && !(deviceExtension->HwFlags & UNIATA_SATA)) {
7791             KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiDmaReinit() to PIO\n"));
7792             AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
7793         }
7794     }
7795     KdPrint2((PRINT_PREFIX "AtapiSendCommand: use_dma=%d\n", use_dma));
7796     if(AtaReq->Flags & REQ_FLAG_DMA_OPERATION) {
7797         KdPrint2((PRINT_PREFIX "  REQ_FLAG_DMA_OPERATION\n"));
7798     }
7799 
7800     KdPrint2((PRINT_PREFIX "AtapiSendCommand: CMD_ACTION_EXEC\n"));
7801 
7802     KdPrint3((PRINT_PREFIX "AtapiSendCommand: Cdb %x Command %#x to TargetId %d lun %d\n",
7803                &(Srb->Cdb), Srb->Cdb[0], Srb->TargetId, Srb->Lun));
7804 
7805     // Make sure command is to ATAPI device.
7806     flags = LunExt->DeviceFlags;
7807     if(flags & (DFLAGS_SANYO_ATAPI_CHANGER | DFLAGS_ATAPI_CHANGER)) {
7808         if((Srb->Lun) > (LunExt->DiscsPresent - 1)) {
7809 
7810             // Indicate no device found at this address.
7811             AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
7812             return SRB_STATUS_SELECTION_TIMEOUT;
7813         }
7814     } else if(Srb->Lun > 0) {
7815         AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
7816         return SRB_STATUS_SELECTION_TIMEOUT;
7817     }
7818 
7819     if(!(flags & DFLAGS_ATAPI_DEVICE)) {
7820         AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
7821         return SRB_STATUS_SELECTION_TIMEOUT;
7822     }
7823 retry:
7824     // Select device 0 or 1. Or more for PM
7825     SelectDrive(chan, DeviceNumber);
7826 
7827     // Verify that controller is ready for next command.
7828     GetStatus(chan, statusByte);
7829     KdPrint3((PRINT_PREFIX "AtapiSendCommand: Entered with status %#x\n", statusByte));
7830 
7831     if(statusByte == IDE_STATUS_WRONG) {
7832         KdPrint2((PRINT_PREFIX "AtapiSendCommand: bad status 0xff on entry\n"));
7833         goto make_reset;
7834     }
7835     if(statusByte & IDE_STATUS_BUSY) {
7836         if(statusByte & IDE_STATUS_DSC) {
7837             KdPrint2((PRINT_PREFIX "AtapiSendCommand: DSC on entry (%#x), try exec\n", statusByte));
7838         } else {
7839             KdPrint2((PRINT_PREFIX "AtapiSendCommand: Device busy (%#x) -> reset\n", statusByte));
7840             // We have to make reset here, since we are expecting device to be available
7841             //return SRB_STATUS_BUSY; // this cause queue freeze
7842             goto make_reset;
7843         }
7844     }
7845     if(deviceExtension->HwFlags & UNIATA_AHCI) {
7846         ULONG CI;
7847         // Check if command list is free
7848         CI = UniataAhciReadChannelPort4(chan, IDX_AHCI_P_CI);
7849         if(CI) {
7850             // controller is busy, however we expect it to be free
7851             KdPrint2((PRINT_PREFIX "AtapiSendCommand: Controller busy (CI=%#x) -> reset\n", CI));
7852             goto make_reset;
7853         }
7854     }
7855     if(statusByte & IDE_STATUS_ERROR) {
7856         if (Srb->Cdb[0] != SCSIOP_REQUEST_SENSE) {
7857 
7858             KdPrint3((PRINT_PREFIX "AtapiSendCommand: Error on entry: (%#x)\n", statusByte));
7859             // Read the error reg. to clear it and fail this request.
7860             AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
7861             return MapError(deviceExtension, Srb);
7862         } else {
7863             KdPrint2((PRINT_PREFIX "  continue with SCSIOP_REQUEST_SENSE\n", statusByte));
7864         }
7865     }
7866     // If a tape drive doesn't have DSC set and the last command is restrictive, don't send
7867     // the next command. See discussion of Restrictive Delayed Process commands in QIC-157.
7868     if((!(statusByte & IDE_STATUS_DSC)) &&
7869           (flags & (DFLAGS_TAPE_DEVICE | DFLAGS_ATAPI_DEVICE)) && chan->RDP) {
7870 
7871         AtapiStallExecution(200);
7872         KdPrint2((PRINT_PREFIX "AtapiSendCommand: DSC not set. %#x => SRB_STATUS_PENDING\n",statusByte));
7873         AtaReq->ReqState = REQ_STATE_QUEUED;
7874         return SRB_STATUS_PENDING;
7875     }
7876 
7877     if(IS_RDP(Srb->Cdb[0])) {
7878         chan->RDP = TRUE;
7879         KdPrint2((PRINT_PREFIX "AtapiSendCommand: %#x mapped as DSC restrictive\n", Srb->Cdb[0]));
7880     } else {
7881         chan->RDP = FALSE;
7882     }
7883     if(statusByte & IDE_STATUS_DRQ) {
7884 
7885         KdPrint3((PRINT_PREFIX "AtapiSendCommand: Entered with status (%#x). Attempting to recover.\n",
7886                     statusByte));
7887         // Try to drain the data that one preliminary device thinks that it has
7888         // to transfer. Hopefully this random assertion of DRQ will not be present
7889         // in production devices.
7890         statusByte = AtapiSuckPort2(chan);
7891 /*
7892         for (i = 0; i < 0x10000; i++) {
7893             GetStatus(chan, statusByte);
7894             if(statusByte & IDE_STATUS_DRQ) {
7895                 AtapiReadPort2(chan, IDX_IO1_i_Data);
7896             } else {
7897                 break;
7898             }
7899         }
7900 */
7901         if (statusByte & IDE_STATUS_DRQ) {
7902             KdPrint3((PRINT_PREFIX "AtapiSendCommand: DRQ still asserted. Status (%#x)\n", statusByte));
7903 make_reset:
7904             AtapiDisableInterrupts(deviceExtension, lChannel);
7905 
7906             AtapiSoftReset(chan, DeviceNumber);
7907 
7908             KdPrint2((PRINT_PREFIX "AtapiSendCommand: Issued soft reset to Atapi device. \n"));
7909             // Re-initialize Atapi device.
7910             CheckDevice(HwDeviceExtension, GET_CHANNEL(Srb), DeviceNumber, TRUE);
7911 /*
7912             IssueIdentify(HwDeviceExtension, DeviceNumber, GET_CHANNEL(Srb),
7913                           IDE_COMMAND_ATAPI_IDENTIFY, FALSE);
7914 */
7915             // Inform the port driver that the bus has been reset.
7916             ScsiPortNotification(ResetDetected, HwDeviceExtension, 0);
7917             // Clean up device extension fields that AtapiStartIo won't.
7918             UniataExpectChannelInterrupt(chan, FALSE);
7919             chan->RDP = FALSE;
7920             InterlockedExchange(&(deviceExtension->chan[GET_CHANNEL(Srb)].CheckIntr),
7921                                           CHECK_INTR_IDLE);
7922 
7923             AtapiEnableInterrupts(deviceExtension, lChannel);
7924 /*
7925             AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
7926             return SRB_STATUS_BUS_RESET;
7927 */
7928             if(!retried) {
7929                 KdPrint3((PRINT_PREFIX "AtapiSendCommand: retry after reset.\n"));
7930                 retried = TRUE;
7931                 goto retry;
7932             }
7933             KdPrint3((PRINT_PREFIX "AtapiSendCommand: selection timeout.\n"));
7934             AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
7935             return SRB_STATUS_SELECTION_TIMEOUT;
7936         }
7937     }
7938 
7939     if(flags & (DFLAGS_SANYO_ATAPI_CHANGER | DFLAGS_ATAPI_CHANGER)) {
7940         // As the cdrom driver sets the LUN field in the cdb, it must be removed.
7941         Srb->Cdb[1] &= ~0xE0;
7942         if((Srb->Cdb[0] == SCSIOP_TEST_UNIT_READY) && (flags & DFLAGS_SANYO_ATAPI_CHANGER)) {
7943             // Torisan changer. TUR's are overloaded to be platter switches.
7944             Srb->Cdb[7] = Srb->Lun;
7945         }
7946     }
7947 
7948     // SETUP DMA !!!!!
7949 
7950     if(use_dma) {
7951         chan->ChannelCtrlFlags |= CTRFLAGS_DMA_OPERATION;
7952     } else {
7953         chan->ChannelCtrlFlags &= ~CTRFLAGS_DMA_OPERATION;
7954     }
7955 
7956     if(deviceExtension->HwFlags & UNIATA_AHCI) {
7957         KdPrint2((PRINT_PREFIX "AtapiSendCommand: AHCI, begin transaction\n"));
7958         //AtaReq->Flags = ~REQ_FLAG_DMA_OPERATION; // keep proped DMA flag for proper RETRY handling
7959         UniataExpectChannelInterrupt(chan, TRUE);
7960         UniataAhciBeginTransaction(HwDeviceExtension, lChannel, DeviceNumber, Srb);
7961         return SRB_STATUS_PENDING;
7962     }
7963 
7964     statusByte = WaitOnBusy(chan);
7965     KdPrint3((PRINT_PREFIX "AtapiSendCommand: Entry Status (%#x)\n",
7966                statusByte));
7967 
7968     if(use_dma) {
7969         FeatureReg |= ATA_F_DMA;
7970         if(LunExt->IdentifyData.AtapiDMA.DMADirRequired) {
7971             if(Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
7972                 FeatureReg |= ATA_F_DMAREAD;
7973             }
7974         }
7975     }
7976 
7977     // Write transfer byte count to registers.
7978     if (Srb->DataTransferLength >= 0x10000) {
7979         byteCountLow = byteCountHigh = 0xFF;
7980     } else {
7981         byteCountLow = (UCHAR)(Srb->DataTransferLength & 0xFF);
7982         byteCountHigh = (UCHAR)(Srb->DataTransferLength >> 8);
7983     }
7984 
7985     KdPrint3((PRINT_PREFIX "AtapiSendCommand: F:%#x, CntHL:%#x:%#x.\n", FeatureReg, byteCountHigh, byteCountLow));
7986 
7987     if (flags & DFLAGS_INT_DRQ) {
7988         // This device interrupts when ready to receive the packet.
7989         KdPrint3((PRINT_PREFIX "AtapiSendCommand: Wait for int. to send packet. Status (%#x)\n",
7990                    statusByte));
7991 
7992         UniataExpectChannelInterrupt(chan, TRUE);
7993         AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_CMD_INTR;
7994         InterlockedExchange(&(chan->CheckIntr),
7995                                       CHECK_INTR_IDLE);
7996         // inform driver that packet command must be sent in ISR
7997         flags |= DFLAGS_INT_DRQ;
7998     } else {
7999         // This device quickly sets DRQ when ready to receive the packet.
8000         KdPrint2((PRINT_PREFIX "AtapiSendCommand: Poll for int. to send packet. Status (%#x)\n",
8001                    statusByte));
8002 
8003         UniataExpectChannelInterrupt(chan, TRUE);
8004         AtaReq->ReqState = REQ_STATE_ATAPI_DO_NOTHING_INTR;
8005         InterlockedExchange(&(chan->CheckIntr),
8006                                       CHECK_INTR_IDLE);
8007 
8008         if(g_opt_AtapiSendDisableIntr) {
8009             AtapiDisableInterrupts(deviceExtension, lChannel);
8010         }
8011         // remember status. Later we may check if error appeared after cmd packet
8012         statusByte0 = statusByte;
8013     }
8014 
8015     // must be already selected, experimental for ROS BUG-9119
8016     //AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, IDE_USE_LBA | (DeviceNumber ? IDE_DRIVE_2 : IDE_DRIVE_1) );
8017     AtapiWritePort1(chan, IDX_IO2_o_Control , 0);
8018     AtapiWritePort1(chan, IDX_ATAPI_IO1_o_Feature /*IDX_IO1_o_Feature*/, FeatureReg);
8019     //AtapiWritePort1(chan, IDX_ATAPI_IO1_o_Unused0, 0);  // experimental for ROS BUG-9119
8020     //AtapiWritePort1(chan, IDX_ATAPI_IO1_o_Unused1, 0);  // experimental for ROS BUG-9119
8021     AtapiWritePort1(chan, IDX_ATAPI_IO1_o_ByteCountLow, byteCountLow);
8022     AtapiWritePort1(chan, IDX_ATAPI_IO1_o_ByteCountHigh, byteCountHigh);
8023     // Write ATAPI packet command.
8024     AtapiWritePort1(chan, IDX_ATAPI_IO1_o_Command /*IDX_IO1_o_Command*/, IDE_COMMAND_ATAPI_PACKET);
8025 
8026     if (flags & DFLAGS_INT_DRQ) {
8027         // Wait for interrupt and send PACKET there
8028         KdPrint3((PRINT_PREFIX "AtapiSendCommand: return SRB_STATUS_PENDING (DRQ)\n"));
8029         return SRB_STATUS_PENDING;
8030     }
8031 
8032     WaitOnBusy(chan);
8033 /*
8034     // Wait for DRQ.
8035     statusByte = WaitForDrq(chan);
8036 
8037     // Need to read status register and clear interrupt (if any)
8038     GetBaseStatus(chan, statusByte);
8039 
8040     if (!(statusByte & IDE_STATUS_DRQ)) {
8041         if(g_opt_AtapiSendDisableIntr) {
8042             AtapiEnableInterrupts(deviceExtension, lChannel);
8043         }
8044         KdPrint3((PRINT_PREFIX "AtapiSendCommand: DRQ never asserted (%#x)\n", statusByte));
8045         AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
8046         return SRB_STATUS_ERROR;
8047     }
8048 */
8049     GetStatus(chan, statusByte);
8050     KdPrint3((PRINT_PREFIX "AtapiSendCommand: status (%#x)\n", statusByte));
8051 
8052     //statusByte = WaitOnBaseBusy(chan);
8053 
8054     // Indicate expecting an interrupt and wait for it.
8055     UniataExpectChannelInterrupt(chan, TRUE);
8056 
8057     for(i=0; i<5000; i++) {
8058         if(g_opt_AtapiSendDisableIntr) {
8059             GetStatus(chan, statusByte);
8060         } else {
8061             GetBaseStatus(chan, statusByte);
8062         }
8063         interruptReason = AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason);
8064         //KdPrint3((PRINT_PREFIX "AtapiSendCommand: iReason %x (%d)\n", interruptReason, i));
8065         if(((interruptReason & ATAPI_IR_COD) == ATAPI_IR_COD_Cmd) &&
8066            (((statusByte & (IDE_STATUS_BUSY | IDE_STATUS_DRQ)) == IDE_STATUS_DRQ))) {
8067             break;
8068         }
8069         AtapiStallExecution(g_opt_WaitDrqDelay*2);
8070 #ifdef _DEBUG
8071 //        KdPrint3((PRINT_PREFIX "AtapiSendCommand: wait CoD, status (%#x)\n", interruptReason));
8072 #endif // _DEBUG
8073     }
8074     if(((interruptReason & ATAPI_IR_COD) != ATAPI_IR_COD_Cmd) ||
8075        (((statusByte & (IDE_STATUS_BUSY | IDE_STATUS_DRQ)) != IDE_STATUS_DRQ)) ) {
8076         KdPrint3((PRINT_PREFIX "AtapiSendCommand: no CoD raised, abort cmd\n"));
8077         KdPrint3((PRINT_PREFIX "AtapiSendCommand: iReason %x (%d)\n", interruptReason, i));
8078         KdPrint3((PRINT_PREFIX "AtapiSendCommand: status (%#x)\n", statusByte));
8079         if(g_opt_AtapiSendDisableIntr) {
8080             AtapiEnableInterrupts(deviceExtension, lChannel);
8081         }
8082         KdPrint3((PRINT_PREFIX "AtapiSendCommand: DRQ+CoD never asserted\n"));
8083         statusByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
8084         KdPrint3((PRINT_PREFIX "AtapiSendCommand: Err on cmd: (%#x)\n", statusByte));
8085         if(statusByte >> 4) {
8086             GetBaseStatus(chan, statusByte);
8087             AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
8088             return MapError(deviceExtension, Srb);
8089         }
8090         goto make_reset;
8091 //        AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
8092 //        return SRB_STATUS_ERROR;
8093     } else {
8094         KdPrint3((PRINT_PREFIX "AtapiSendCommand: ready for packet, status %#x, i=%d\n", interruptReason, i));
8095     }
8096     // clear interrupt
8097     GetBaseStatus(chan, statusByte);
8098 
8099     if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) {
8100         AtapiDmaDBPreSync(HwDeviceExtension, chan, Srb);
8101     }
8102     if(g_opt_AtapiSendDisableIntr) {
8103         AtapiEnableInterrupts(deviceExtension, lChannel);
8104     }
8105 
8106     // Send CDB to device.
8107     WriteBuffer(chan,
8108                 (PUSHORT)Srb->Cdb,
8109                 LunExt->IdentifyData.AtapiCmdSize ? 8 : 6,
8110                 /*0*/ PIO0_TIMING);
8111 
8112     GetStatus(chan, statusByte);
8113     KdPrint3((PRINT_PREFIX "AtapiSendCommand: cmd status (%#x)\n", statusByte));
8114 
8115     // When we operate in DMA mode, we should not start transfer when there is an error on entry
8116     // Interrupt may never come in such case.
8117     if(statusByte & IDE_STATUS_ERROR) {
8118 
8119         GetBaseStatus(chan, statusByte);
8120         KdPrint3((PRINT_PREFIX "AtapiSendCommand: Error on cmd: (%#x)\n", statusByte));
8121 
8122         interruptReason = (AtapiReadPort1(chan, IDX_ATAPI_IO1_i_InterruptReason) & ATAPI_IR_Mask);
8123         KdPrint3((PRINT_PREFIX "AtapiSendCommand: iReason %x\n", interruptReason));
8124 
8125         // TODO:  we should check interruptReason and decide what to do now
8126 
8127         // Read the error reg. to clear it and fail this request.
8128         AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
8129         return MapError(deviceExtension, Srb);
8130     }
8131     if(statusByte & IDE_STATUS_DRQ) {
8132         // Some devices require this. If error condition is not checked in such a way,
8133         // device may not operate correctly and would be treated as failed
8134         // (and finally invisible for OS)
8135         KdPrint3((PRINT_PREFIX "AtapiSendCommand: DRQ on cmd: (%#x)\n", statusByte));
8136         // Read the error reg. to clear it and fail this request.
8137         statusByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
8138         KdPrint3((PRINT_PREFIX "AtapiSendCommand: Err on cmd: (%#x)\n", statusByte));
8139         if(statusByte >> 4) {
8140             GetBaseStatus(chan, statusByte);
8141             AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
8142             return MapError(deviceExtension, Srb);
8143         }
8144     }
8145 
8146     if(chan->ChannelCtrlFlags & CTRFLAGS_DMA_OPERATION) {
8147         AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
8148     }
8149 
8150     InterlockedExchange(&(chan->CheckIntr),
8151                                   CHECK_INTR_IDLE);
8152     AtaReq->ReqState = REQ_STATE_ATAPI_EXPECTING_DATA_INTR;
8153 
8154     KdPrint3((PRINT_PREFIX "AtapiSendCommand: ExpectingInterrupt (%#x)\n", chan->ExpectingInterrupt));
8155 
8156     KdPrint2((PRINT_PREFIX "AtapiSendCommand: return SRB_STATUS_PENDING (3)\n"));
8157     return SRB_STATUS_PENDING;
8158 
8159 } // end AtapiSendCommand()
8160 
8161 
8162 #ifndef UNIATA_CORE
8163 
8164 /*++
8165 
8166 Routine Description:
8167     Program ATA registers for IDE disk transfer.
8168 
8169 Arguments:
8170     HwDeviceExtension - ATAPI driver storage.
8171     Srb - System request block.
8172 
8173 Return Value:
8174     SRB status (pending if all goes well).
8175 
8176 --*/
8177 
8178 #ifdef _DEBUG
8179 ULONG check_point = 0;
8180 #define SetCheckPoint(cp)  { check_point = (cp) ; }
8181 #else
8182 #define SetCheckPoint(cp)
8183 #endif
8184 
8185 ULONG
8186 NTAPI
8187 IdeSendCommand(
8188     IN PVOID HwDeviceExtension,
8189     IN PSCSI_REQUEST_BLOCK Srb,
8190     IN ULONG CmdAction
8191     )
8192 {
8193     SetCheckPoint(1);
8194     KdPrint2((PRINT_PREFIX "** Ide: Command: entryway\n"));
8195     SetCheckPoint(2);
8196 
8197     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
8198     SetCheckPoint(3);
8199     UCHAR                lChannel;
8200     PHW_CHANNEL          chan;
8201     PCDB cdb;
8202     PHW_LU_EXTENSION     LunExt;
8203 
8204     SetCheckPoint(4);
8205 
8206     UCHAR statusByte,errorByte;
8207     ULONG status = SRB_STATUS_INVALID_REQUEST;
8208     ULONG i;
8209     ULONGLONG lba;
8210     PMODE_PARAMETER_HEADER   modeData;
8211     //ULONG ldev;
8212     ULONG DeviceNumber;
8213     PATA_REQ AtaReq;
8214     UCHAR command;
8215 
8216     SetCheckPoint(5);
8217     //ULONG __ebp__ = 0;
8218 
8219     SetCheckPoint(0x20);
8220     KdPrint2((PRINT_PREFIX "** Ide: Command:\n\n"));
8221 /*    __asm {
8222         mov eax,ebp
8223         mov __ebp__, eax
8224     }*/
8225     /*KdPrint2((PRINT_PREFIX "** Ide: Command EBP %#x, pCdb %#x, cmd %#x\n",
8226         __ebp__, &(Srb->Cdb[0]), Srb->Cdb[0]));
8227     KdPrint2((PRINT_PREFIX "** Ide: Command %s\n",
8228         (CmdAction == CMD_ACTION_PREPARE) ? "Prep " : ""));
8229     KdPrint2((PRINT_PREFIX "** Ide: Command Srb %#x\n",
8230         Srb));
8231     KdPrint2((PRINT_PREFIX "** Ide: Command SrbExt %#x\n",
8232         Srb->SrbExtension));
8233     KdPrint2((PRINT_PREFIX "** Ide: Command to device %d\n",
8234         Srb->TargetId));*/
8235 
8236     SetCheckPoint(0x30);
8237     AtaReq = (PATA_REQ)(Srb->SrbExtension);
8238 
8239     KdPrint2((PRINT_PREFIX "** Ide: Command &AtaReq %#x\n",
8240         &AtaReq));
8241     KdPrint2((PRINT_PREFIX "** Ide: Command AtaReq %#x\n",
8242         AtaReq));
8243     KdPrint2((PRINT_PREFIX "** --- **\n"));
8244 
8245     lChannel = GET_CHANNEL(Srb);
8246     chan = &(deviceExtension->chan[lChannel]);
8247     //ldev = GET_LDEV(Srb);
8248     DeviceNumber = GET_CDEV(Srb);
8249     LunExt = chan->lun[DeviceNumber];
8250 
8251     SetCheckPoint(0x40);
8252     if(AtaReq->ReqState < REQ_STATE_PREPARE_TO_TRANSFER)
8253         AtaReq->ReqState = REQ_STATE_PREPARE_TO_TRANSFER;
8254 
8255     cdb = (PCDB)(Srb->Cdb);
8256 
8257     if(CmdAction == CMD_ACTION_PREPARE) {
8258         switch (Srb->Cdb[0]) {
8259         case SCSIOP_SERVICE_ACTION16:
8260             if( cdb->SERVICE_ACTION16.ServiceAction==SCSIOP_SA_READ_CAPACITY16 ) {
8261                 // ok
8262             } else {
8263                 goto default_no_prep;
8264             }
8265 #ifdef NAVO_TEST
8266         case SCSIOP_INQUIRY: // now it requires device access
8267 #endif //NAVO_TEST
8268         case SCSIOP_READ_CAPACITY:
8269         case SCSIOP_READ:
8270         case SCSIOP_WRITE:
8271         case SCSIOP_READ12:
8272         case SCSIOP_WRITE12:
8273         case SCSIOP_READ16:
8274         case SCSIOP_WRITE16:
8275         case SCSIOP_REQUEST_SENSE:
8276             // all right
8277             KdPrint2((PRINT_PREFIX "** Ide: Command continue prep\n"));
8278             SetCheckPoint(50);
8279             break;
8280         default:
8281 default_no_prep:
8282             SetCheckPoint(0);
8283             KdPrint2((PRINT_PREFIX "** Ide: Command break prep\n"));
8284             return SRB_STATUS_BUSY;
8285         }
8286     }
8287 
8288     SetCheckPoint(0x100 | Srb->Cdb[0]);
8289     switch (Srb->Cdb[0]) {
8290     case SCSIOP_INQUIRY:
8291 
8292         KdPrint2((PRINT_PREFIX
8293                    "IdeSendCommand: SCSIOP_INQUIRY PATH:LUN:TID = %#x:%#x:%#x\n",
8294                    Srb->PathId, Srb->Lun, Srb->TargetId));
8295         // Filter out wrong TIDs.
8296         if ((Srb->Lun != 0) ||
8297             (Srb->PathId >= deviceExtension->NumberChannels) ||
8298             (Srb->TargetId >= deviceExtension->NumberLuns)) {
8299 
8300             KdPrint2((PRINT_PREFIX
8301                        "IdeSendCommand: SCSIOP_INQUIRY rejected\n"));
8302             // Indicate no device found at this address.
8303             status = SRB_STATUS_SELECTION_TIMEOUT;
8304             break;
8305 
8306         } else {
8307 
8308             KdPrint2((PRINT_PREFIX
8309                        "IdeSendCommand: SCSIOP_INQUIRY ok\n"));
8310             PINQUIRYDATA    inquiryData  = (PINQUIRYDATA)(Srb->DataBuffer);
8311             PIDENTIFY_DATA2 identifyData = &(LunExt->IdentifyData);
8312 
8313             if (!(chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
8314 
8315                 if(!CheckDevice(HwDeviceExtension, lChannel, DeviceNumber, FALSE)) {
8316                     KdPrint2((PRINT_PREFIX
8317                                "IdeSendCommand: SCSIOP_INQUIRY rejected (2)\n"));
8318                     // Indicate no device found at this address.
8319 #ifndef NAVO_TEST
8320                     status = SRB_STATUS_SELECTION_TIMEOUT;
8321                     break;
8322                 }
8323             } else {
8324                 if(!UniataAnybodyHome(HwDeviceExtension, lChannel, DeviceNumber)) {
8325                     KdPrint2((PRINT_PREFIX
8326                                "IdeSendCommand: SCSIOP_INQUIRY device have gone\n"));
8327                     // Indicate no device found at this address.
8328                     UniataForgetDevice(chan->lun[DeviceNumber]);
8329 #endif //NAVO_TEST
8330                     status = SRB_STATUS_SELECTION_TIMEOUT;
8331                     break;
8332                 }
8333             }
8334 
8335             // Zero INQUIRY data structure.
8336             RtlZeroMemory((PCHAR)(Srb->DataBuffer), Srb->DataTransferLength);
8337 
8338             // Standard IDE interface only supports disks.
8339             inquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
8340 
8341             // Set the removable bit, if applicable.
8342             if (LunExt->DeviceFlags & DFLAGS_REMOVABLE_DRIVE) {
8343                 KdPrint2((PRINT_PREFIX
8344                            "RemovableMedia\n"));
8345                 inquiryData->RemovableMedia = 1;
8346             }
8347             // Set the Relative Addressing (LBA) bit, if applicable.
8348             if (LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) {
8349                 inquiryData->RelativeAddressing = 1;
8350                 KdPrint2((PRINT_PREFIX
8351                            "RelativeAddressing\n"));
8352             }
8353             // Set the CommandQueue bit
8354             inquiryData->CommandQueue = 1;
8355 
8356             // Fill in vendor identification fields.
8357             for (i = 0; i < 24; i += 2) {
8358                 MOV_DW_SWP(inquiryData->DeviceIdentificationString[i], ((PUCHAR)identifyData->ModelNumber)[i]);
8359             }
8360 /*
8361             // Initialize unused portion of product id.
8362             for (i = 0; i < 4; i++) {
8363                 inquiryData->ProductId[12+i] = ' ';
8364             }
8365 */
8366             // Move firmware revision from IDENTIFY data to
8367             // product revision in INQUIRY data.
8368             for (i = 0; i < 4; i += 2) {
8369                 MOV_DW_SWP(inquiryData->ProductRevisionLevel[i], ((PUCHAR)identifyData->FirmwareRevision)[i]);
8370             }
8371 
8372             status = SRB_STATUS_SUCCESS;
8373         }
8374 
8375         break;
8376 
8377     case SCSIOP_REPORT_LUNS: {
8378 
8379         ULONG alen;
8380         PREPORT_LUNS_INFO_HDR LunInfo;
8381 
8382         KdPrint2((PRINT_PREFIX
8383                    "IdeSendCommand: SCSIOP_REPORT_LUNS PATH:LUN:TID = %#x:%#x:%#x\n",
8384                    Srb->PathId, Srb->Lun, Srb->TargetId));
8385 
8386         MOV_DD_SWP(alen, cdb->REPORT_LUNS.AllocationLength);
8387 
8388         if(alen < 16) {
8389             goto invalid_cdb;
8390         }
8391         alen = 8;
8392 
8393         LunInfo = (PREPORT_LUNS_INFO_HDR)(Srb->DataBuffer);
8394         RtlZeroMemory(LunInfo, 16);
8395 
8396         MOV_DD_SWP( LunInfo->ListLength, alen );
8397         Srb->DataTransferLength = 16;
8398         status = SRB_STATUS_SUCCESS;
8399 
8400         break; }
8401 
8402     case SCSIOP_MODE_SENSE:
8403 
8404         KdPrint2((PRINT_PREFIX
8405                    "IdeSendCommand: SCSIOP_MODE_SENSE PATH:LUN:TID = %#x:%#x:%#x\n",
8406                    Srb->PathId, Srb->Lun, Srb->TargetId));
8407 
8408         if(cdb->MODE_SENSE.PageCode == MODE_PAGE_POWER_CONDITION) {
8409             PMODE_POWER_CONDITION_PAGE modeData;
8410 
8411             KdPrint2((PRINT_PREFIX "MODE_PAGE_POWER_CONDITION\n"));
8412             modeData = (PMODE_POWER_CONDITION_PAGE)(Srb->DataBuffer);
8413             if(cdb->MODE_SENSE.AllocationLength < sizeof(MODE_POWER_CONDITION_PAGE)) {
8414                 status = SRB_STATUS_DATA_OVERRUN;
8415             } else {
8416                 RtlZeroMemory(modeData, sizeof(MODE_POWER_CONDITION_PAGE));
8417                 modeData->PageCode = MODE_PAGE_POWER_CONDITION;
8418 #ifdef __REACTOS__
8419                 modeData->PageLength = sizeof(MODE_POWER_CONDITION_PAGE)-sizeof(MODE_PARAMETER_HEADER);
8420 #else
8421                 modeData->PageLength = sizeof(MODE_PAGE_POWER_CONDITION)-sizeof(MODE_PARAMETER_HEADER);
8422 #endif
8423                 modeData->Byte3.Fields.Idle = LunExt->PowerState <= StartStop_Power_Idle;
8424                 modeData->Byte3.Fields.Standby = LunExt->PowerState == StartStop_Power_Standby;
8425                 Srb->DataTransferLength = sizeof(MODE_POWER_CONDITION_PAGE);
8426                 status = SRB_STATUS_SUCCESS;
8427             }
8428         } else
8429         if(cdb->MODE_SENSE.PageCode == MODE_PAGE_CACHING) {
8430             PMODE_CACHING_PAGE modeData;
8431 
8432             KdPrint2((PRINT_PREFIX "MODE_PAGE_CACHING\n"));
8433             modeData = (PMODE_CACHING_PAGE)(Srb->DataBuffer);
8434             if(cdb->MODE_SENSE.AllocationLength < sizeof(MODE_CACHING_PAGE)) {
8435                 status = SRB_STATUS_DATA_OVERRUN;
8436             } else {
8437                 RtlZeroMemory(modeData, sizeof(MODE_CACHING_PAGE));
8438                 modeData->PageCode = MODE_PAGE_CACHING;
8439                 modeData->PageLength = sizeof(MODE_CACHING_PAGE)-sizeof(MODE_PARAMETER_HEADER);
8440                 modeData->ReadDisableCache = (LunExt->DeviceFlags & DFLAGS_RCACHE_ENABLED) ? 0 : 1;
8441                 modeData->WriteCacheEnable = (LunExt->DeviceFlags & DFLAGS_WCACHE_ENABLED) ? 1 : 0;
8442                 Srb->DataTransferLength = sizeof(MODE_CACHING_PAGE);
8443                 status = SRB_STATUS_SUCCESS;
8444             }
8445         } else
8446         if (LunExt->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
8447 
8448             // This is used to determine if the media is write-protected.
8449             // Since IDE does not support mode sense then we will modify just the portion we need
8450             // so the higher level driver can determine if media is protected.
8451 
8452             //SelectDrive(chan, DeviceNumber);
8453             //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_GET_MEDIA_STATUS);
8454             //statusByte = WaitOnBusy(chan);
8455             statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_GET_MEDIA_STATUS, 0, 0, 0, 0, 0, ATA_WAIT_READY);
8456 
8457             if (!(statusByte & IDE_STATUS_ERROR)) {
8458 
8459                 // no error occured return success, media is not protected
8460                 UniataExpectChannelInterrupt(chan, FALSE);
8461                 InterlockedExchange(&(chan->CheckIntr),
8462                                               CHECK_INTR_IDLE);
8463                 status = SRB_STATUS_SUCCESS;
8464 
8465             } else {
8466 
8467                 // error occured, handle it locally, clear interrupt
8468                 errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
8469 
8470                 GetBaseStatus(chan, statusByte);
8471                 UniataExpectChannelInterrupt(chan, FALSE);
8472                 InterlockedExchange(&(chan->CheckIntr),
8473                                               CHECK_INTR_IDLE);
8474                 status = SRB_STATUS_SUCCESS;
8475 
8476                 if (errorByte & IDE_ERROR_DATA_ERROR) {
8477 
8478                     //media is write-protected, set bit in mode sense buffer
8479                     modeData = (PMODE_PARAMETER_HEADER)Srb->DataBuffer;
8480 
8481                     Srb->DataTransferLength = sizeof(MODE_PARAMETER_HEADER);
8482                     modeData->DeviceSpecificParameter |= MODE_DSP_WRITE_PROTECT;
8483                 }
8484             }
8485             status = SRB_STATUS_SUCCESS;
8486         } else {
8487             status = SRB_STATUS_INVALID_REQUEST;
8488         }
8489         break;
8490 
8491     case SCSIOP_TEST_UNIT_READY:
8492 
8493         KdPrint2((PRINT_PREFIX
8494                    "IdeSendCommand: SCSIOP_TEST_UNIT_READY PATH:LUN:TID = %#x:%#x:%#x\n",
8495                    Srb->PathId, Srb->Lun, Srb->TargetId));
8496         if (chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
8497 
8498             // Select device 0 or 1.
8499             //SelectDrive(chan, DeviceNumber);
8500             //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_GET_MEDIA_STATUS);
8501             // Wait for busy. If media has not changed, return success
8502             //statusByte = WaitOnBusy(chan);
8503             statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_GET_MEDIA_STATUS, 0, 0, 0, 0, 0, ATA_WAIT_READY);
8504 
8505             if (!(statusByte & IDE_STATUS_ERROR)){
8506                 UniataExpectChannelInterrupt(chan, FALSE);
8507                 InterlockedExchange(&(chan->CheckIntr),
8508                                               CHECK_INTR_IDLE);
8509                 status = SRB_STATUS_SUCCESS;
8510             } else {
8511                 errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
8512                 if (errorByte == IDE_ERROR_DATA_ERROR){
8513 
8514                     // Special case: If current media is write-protected,
8515                     // the 0xDA command will always fail since the write-protect bit
8516                     // is sticky,so we can ignore this error
8517                     GetBaseStatus(chan, statusByte);
8518                     UniataExpectChannelInterrupt(chan, FALSE);
8519                     InterlockedExchange(&(chan->CheckIntr),
8520                                                   CHECK_INTR_IDLE);
8521                     status = SRB_STATUS_SUCCESS;
8522 
8523                 } else {
8524 
8525                     // Request sense buffer to be build
8526                     UniataExpectChannelInterrupt(chan, TRUE);
8527                     InterlockedExchange(&(chan->CheckIntr),
8528                                                   CHECK_INTR_IDLE);
8529                     status = SRB_STATUS_PENDING;
8530                }
8531             }
8532         } else {
8533             status = SRB_STATUS_SUCCESS;
8534         }
8535 
8536         break;
8537 
8538     case SCSIOP_READ_CAPACITY:
8539 
8540         KdPrint2((PRINT_PREFIX
8541                    "** IdeSendCommand: SCSIOP_READ_CAPACITY PATH:LUN:TID = %#x:%#x:%#x\n",
8542                    Srb->PathId, Srb->Lun, Srb->TargetId));
8543         // Claim 512 byte blocks (big-endian).
8544         //((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock = 0x20000;
8545         i = DEV_BSIZE;
8546         RtlZeroMemory(Srb->DataBuffer, sizeof(READ_CAPACITY_DATA));
8547         MOV_DD_SWP( ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock, i );
8548 
8549         // Calculate last sector.
8550         if(!(i = (ULONG)LunExt->NumOfSectors)) {
8551             i = LunExt->IdentifyData.SectorsPerTrack *
8552                 LunExt->IdentifyData.NumberOfHeads *
8553                 LunExt->IdentifyData.NumberOfCylinders;
8554         }
8555         i--;
8556 
8557         //((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress =
8558         //    (((PUCHAR)&i)[0] << 24) |  (((PUCHAR)&i)[1] << 16) |
8559         //    (((PUCHAR)&i)[2] << 8) | ((PUCHAR)&i)[3];
8560 
8561         MOV_DD_SWP( ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress, i );
8562 
8563         KdPrint2((PRINT_PREFIX
8564                    "** IDE disk %#x - #sectors %#x, #heads %#x, #cylinders %#x\n",
8565                    Srb->TargetId,
8566                    LunExt->IdentifyData.SectorsPerTrack,
8567                    LunExt->IdentifyData.NumberOfHeads,
8568                    LunExt->IdentifyData.NumberOfCylinders));
8569 
8570 
8571         status = SRB_STATUS_SUCCESS;
8572         break;
8573 
8574     case SCSIOP_SERVICE_ACTION16:
8575 
8576         if( cdb->SERVICE_ACTION16.ServiceAction==SCSIOP_SA_READ_CAPACITY16 ) {
8577             KdPrint2((PRINT_PREFIX
8578                        "** IdeSendCommand: SCSIOP_READ_CAPACITY PATH:LUN:TID = %#x:%#x:%#x\n",
8579                        Srb->PathId, Srb->Lun, Srb->TargetId));
8580             // Claim 512 byte blocks (big-endian).
8581             //((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock = 0x20000;
8582             i = DEV_BSIZE;
8583             RtlZeroMemory(Srb->DataBuffer, sizeof(READ_CAPACITY16_DATA));
8584             MOV_DD_SWP( ((PREAD_CAPACITY16_DATA)Srb->DataBuffer)->BytesPerBlock, i );
8585 
8586             // Calculate last sector.
8587             if(!(lba = LunExt->NumOfSectors)) {
8588                 lba = LunExt->IdentifyData.SectorsPerTrack *
8589                     LunExt->IdentifyData.NumberOfHeads *
8590                     LunExt->IdentifyData.NumberOfCylinders;
8591             }
8592             lba--;
8593             MOV_QD_SWP( ((PREAD_CAPACITY16_DATA)Srb->DataBuffer)->LogicalBlockAddress, lba );
8594 
8595             KdPrint2((PRINT_PREFIX
8596                        "** IDE disk %#x - #sectors %#x, #heads %#x, #cylinders %#x (16)\n",
8597                        Srb->TargetId,
8598                        LunExt->IdentifyData.SectorsPerTrack,
8599                        LunExt->IdentifyData.NumberOfHeads,
8600                        LunExt->IdentifyData.NumberOfCylinders));
8601 
8602             status = SRB_STATUS_SUCCESS;
8603         } else {
8604             goto default_abort;
8605         }
8606         break;
8607 
8608     case SCSIOP_VERIFY:
8609     case SCSIOP_VERIFY12:
8610     case SCSIOP_VERIFY16:
8611 
8612         KdPrint2((PRINT_PREFIX
8613                    "IdeSendCommand: SCSIOP_VERIFY PATH:LUN:TID = %#x:%#x:%#x\n",
8614                    Srb->PathId, Srb->Lun, Srb->TargetId));
8615         status = IdeVerify(HwDeviceExtension,Srb);
8616 
8617         break;
8618 
8619     case SCSIOP_READ:
8620     case SCSIOP_WRITE:
8621     case SCSIOP_READ12:
8622     case SCSIOP_WRITE12:
8623     case SCSIOP_READ16:
8624     case SCSIOP_WRITE16:
8625 
8626         KdPrint2((PRINT_PREFIX
8627                    "IdeSendCommand: SCSIOP_%s PATH:LUN:TID = %#x:%#x:%#x\n",
8628                    (Srb->Cdb[0] == SCSIOP_WRITE) ? "WRITE" : "READ",
8629                    Srb->PathId, Srb->Lun, Srb->TargetId));
8630         AtaReq->Flags &= ~REQ_FLAG_RW_MASK;
8631         AtaReq->Flags |= (Srb->Cdb[0] == SCSIOP_WRITE ||
8632                           Srb->Cdb[0] == SCSIOP_WRITE12 ||
8633                           Srb->Cdb[0] == SCSIOP_WRITE16) ? REQ_FLAG_WRITE : REQ_FLAG_READ;
8634         status = IdeReadWrite(HwDeviceExtension,
8635                               Srb, CmdAction);
8636         break;
8637 
8638     case SCSIOP_START_STOP_UNIT:
8639 
8640         KdPrint2((PRINT_PREFIX
8641                    "IdeSendCommand: SCSIOP_START_STOP_UNIT immed %d PATH:LUN:TID = %#x:%#x:%#x\n",
8642                    cdb->START_STOP.Immediate, Srb->PathId, Srb->Lun, Srb->TargetId));
8643         //Determine what type of operation we should perform
8644 
8645         command = 0;
8646 
8647         if(cdb->START_STOP.FL ||
8648            cdb->START_STOP.FormatLayerNumber ||
8649            cdb->START_STOP.Reserved2 ||
8650            cdb->START_STOP.Reserved2_2 ||
8651            cdb->START_STOP.Reserved3 ||
8652            FALSE) {
8653             goto invalid_cdb;
8654         }
8655 
8656         if (cdb->START_STOP.PowerConditions) {
8657             KdPrint2((PRINT_PREFIX "START_STOP Power %d\n", cdb->START_STOP.PowerConditions));
8658             switch(cdb->START_STOP.PowerConditions) {
8659             case StartStop_Power_Idle:
8660                 command = IDE_COMMAND_IDLE_IMMED;
8661                 break;
8662             case StartStop_Power_Standby:
8663                 command = IDE_COMMAND_STANDBY_IMMED;
8664                 break;
8665             case StartStop_Power_Sleep:
8666                 // TODO: we should save power state in order to know
8667                 // that RESET sould be issued to revert device into
8668                 // operable state
8669 
8670                 command = IDE_COMMAND_SLEEP;
8671                 break;
8672             default:
8673                 goto invalid_cdb;
8674             }
8675             LunExt->PowerState = cdb->START_STOP.PowerConditions;
8676         } else
8677         if (cdb->START_STOP.LoadEject == 1) {
8678             KdPrint2((PRINT_PREFIX "START_STOP eject\n"));
8679             // Eject media,
8680             // first select device 0 or 1.
8681             //SelectDrive(chan, DeviceNumber);
8682             //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_MEDIA_EJECT);
8683             command = IDE_COMMAND_MEDIA_EJECT;
8684         } else
8685         if (cdb->START_STOP.Start == 0) {
8686             KdPrint2((PRINT_PREFIX "START_STOP standby\n"));
8687             command = IDE_COMMAND_STANDBY_IMMED;
8688         } else {
8689             // TODO: we may need to perform hard reset (after sleep) or
8690             // issue IDE_COMMAND_IDLE_IMMED in order to activate device
8691             KdPrint2((PRINT_PREFIX "START_STOP activate\n"));
8692 
8693             if(LunExt->PowerState == StartStop_Power_Sleep) {
8694                 UniataUserDeviceReset(deviceExtension, LunExt, lChannel);
8695                 status = SRB_STATUS_SUCCESS;
8696                 break;
8697             } else
8698             if(LunExt->PowerState > StartStop_Power_Idle) {
8699                 KdPrint2((PRINT_PREFIX "  issue IDLE\n"));
8700                 command = IDE_COMMAND_IDLE_IMMED;
8701             } else {
8702                 KdPrint2((PRINT_PREFIX "  do nothing\n"));
8703                 status = SRB_STATUS_SUCCESS;
8704                 break;
8705             }
8706         }
8707         if(command) {
8708             statusByte = WaitOnBaseBusy(chan);
8709             statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, command, 0, 0, 0, 0, 0,
8710                 cdb->START_STOP.Immediate ? ATA_IMMEDIATE : ATA_WAIT_READY);
8711             status = (statusByte & IDE_STATUS_ERROR) ? SRB_STATUS_ERROR : SRB_STATUS_SUCCESS;
8712             //UniataExpectChannelInterrupt(chan, TRUE); // device may interrupt
8713 
8714         } else {
8715 invalid_cdb:
8716             KdPrint2((PRINT_PREFIX "START_STOP invalid\n"));
8717             if (Srb->SenseInfoBuffer) {
8718 
8719                 PSENSE_DATA  senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
8720 
8721                 senseBuffer->ErrorCode = 0x70;
8722                 senseBuffer->Valid     = 1;
8723                 senseBuffer->AdditionalSenseLength = 0xb;
8724                 senseBuffer->SenseKey = SCSI_SENSE_ILLEGAL_REQUEST;
8725                 senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_INVALID_CDB;
8726                 senseBuffer->AdditionalSenseCodeQualifier = 0;
8727 
8728                 Srb->SrbStatus = SRB_STATUS_AUTOSENSE_VALID;
8729                 Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
8730             }
8731             status = SRB_STATUS_ERROR;
8732         }
8733         break;
8734 
8735     case SCSIOP_MEDIUM_REMOVAL:
8736 
8737         cdb = (PCDB)Srb->Cdb;
8738 
8739         if(LunExt->IdentifyData.Removable) {
8740             statusByte = WaitOnBaseBusy(chan);
8741 
8742             //SelectDrive(chan, DeviceNumber);
8743             if (cdb->MEDIA_REMOVAL.Prevent == TRUE) {
8744                 //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_DOOR_LOCK);
8745                 statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_DOOR_LOCK, 0, 0, 0, 0, 0, ATA_IMMEDIATE);
8746             } else {
8747                 //AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_DOOR_UNLOCK);
8748                 statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel, IDE_COMMAND_DOOR_UNLOCK, 0, 0, 0, 0, 0, ATA_IMMEDIATE);
8749             }
8750             status = SRB_STATUS_SUCCESS;
8751         } else {
8752             status = SRB_STATUS_INVALID_REQUEST;
8753         }
8754         break;
8755 
8756 #if 0
8757     // Note: I don't implement this, because NTFS driver too often issues this command
8758     // It causes awful performance degrade. However, if somebody wants, I will implement
8759     // SCSIOP_FLUSH_BUFFER/SCSIOP_SYNCHRONIZE_CACHE optionally.
8760     case SCSIOP_FLUSH_BUFFER:
8761     case SCSIOP_SYNCHRONIZE_CACHE:
8762 
8763         SelectDrive(chan, DeviceNumber);
8764         AtapiWritePort1(chan, IDX_IO1_o_Command,IDE_COMMAND_FLUSH_CACHE);
8765         status = SRB_STATUS_SUCCESS;
8766 //        status = SRB_STATUS_PENDING;
8767         statusByte = WaitOnBusy(chan);
8768         break;
8769 #endif
8770 
8771     case SCSIOP_REQUEST_SENSE:
8772         // this function makes sense buffers to report the results
8773         // of the original GET_MEDIA_STATUS command
8774 
8775         KdPrint2((PRINT_PREFIX
8776                    "IdeSendCommand: SCSIOP_REQUEST_SENSE PATH:LUN:TID = %#x:%#x:%#x\n",
8777                    Srb->PathId, Srb->Lun, Srb->TargetId));
8778         if (LunExt->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED) {
8779             status = IdeBuildSenseBuffer(HwDeviceExtension,Srb);
8780             break;
8781         }
8782         status = SRB_STATUS_INVALID_REQUEST;
8783         break;
8784 
8785     // ATA_PASSTHORUGH
8786     case SCSIOP_ATA_PASSTHROUGH:
8787     {
8788         PIDEREGS_EX regs;
8789         BOOLEAN use_dma = FALSE;
8790         ULONG to_lim;
8791 
8792         regs = (PIDEREGS_EX) &(Srb->Cdb[2]);
8793 
8794         if(chan->DeviceExtension->HwFlags & UNIATA_SATA) {
8795             //lChannel = Srb->TargetId >> 1;
8796         } else {
8797             DeviceNumber = max(DeviceNumber, 1);
8798             regs->bDriveHeadReg &= 0x0f;
8799             regs->bDriveHeadReg |= (UCHAR) (((DeviceNumber & 0x1) << 4) | 0xA0);
8800         }
8801 
8802         if((regs->bOpFlags & 1) == 0) {      // execute ATA command
8803 
8804             KdPrint2((PRINT_PREFIX
8805                        "IdeSendCommand: SCSIOP_ATA_PASSTHROUGH (exec) PATH:LUN:TID = %#x:%#x:%#x\n",
8806                        Srb->PathId, Srb->Lun, Srb->TargetId));
8807 
8808             if((regs->bOpFlags & UNIATA_SPTI_EX_SPEC_TO) == UNIATA_SPTI_EX_SPEC_TO) {
8809                 to_lim = Srb->TimeOutValue;
8810             } else {
8811                 if(Srb->TimeOutValue <= 2) {
8812                     to_lim = Srb->TimeOutValue*900;
8813                 } else {
8814                     to_lim = (Srb->TimeOutValue*999) - 500;
8815                 }
8816             }
8817 
8818             AtapiDisableInterrupts(deviceExtension, lChannel);
8819 
8820             if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
8821                 // AHCI
8822                 statusByte = UniataAhciSendPIOCommandDirect(
8823                         deviceExtension,
8824                         lChannel,
8825                         DeviceNumber,
8826                         Srb,
8827                         regs,
8828                         ATA_WAIT_INTR,
8829                         to_lim
8830                         );
8831                 if(statusByte == IDE_STATUS_WRONG) {
8832                     goto passthrough_err;
8833                 }
8834                 if(statusByte & (IDE_STATUS_BUSY | IDE_STATUS_ERROR)) {
8835                     UniataAhciAbortOperation(chan);
8836                     goto passthrough_err;
8837                 }
8838                 goto passthrough_done;
8839             }
8840 
8841             // SATA/PATA
8842             if((AtaCommandFlags[regs->bCommandReg] & ATA_CMD_FLAG_DMA) || (regs->bOpFlags & UNIATA_SPTI_EX_USE_DMA)) {
8843                 if((chan->lun[DeviceNumber]->LimitedTransferMode >= ATA_DMA)) {
8844                     use_dma = TRUE;
8845                     // this will set REQ_FLAG_DMA_OPERATION in AtaReq->Flags on success
8846                     if(!AtapiDmaSetup(HwDeviceExtension, DeviceNumber, lChannel, Srb,
8847                                   (PUCHAR)(Srb->DataBuffer),
8848                                   ((Srb->DataTransferLength + DEV_BSIZE-1) & ~(DEV_BSIZE-1)))) {
8849                         use_dma = FALSE;
8850                     }
8851                 }
8852             }
8853 
8854             AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, regs->bDriveHeadReg);
8855             AtapiStallExecution(10);
8856             if(use_dma) {
8857                 AtapiDmaDBPreSync(HwDeviceExtension, chan, Srb);
8858             }
8859 
8860             if((regs->bOpFlags & ATA_FLAGS_48BIT_COMMAND) == 0) {      // execute ATA command
8861                 AtapiWritePort1(chan, IDX_IO1_o_Feature,      regs->bFeaturesReg);
8862                 AtapiWritePort1(chan, IDX_IO1_o_BlockCount,   regs->bSectorCountReg);
8863                 AtapiWritePort1(chan, IDX_IO1_o_BlockNumber,  regs->bSectorNumberReg);
8864                 AtapiWritePort1(chan, IDX_IO1_o_CylinderLow,  regs->bCylLowReg);
8865                 AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, regs->bCylHighReg);
8866             } else {
8867                 AtapiWritePort1(chan, IDX_IO1_o_Feature,      regs->bFeaturesRegH);
8868                 AtapiWritePort1(chan, IDX_IO1_o_Feature,      regs->bFeaturesReg);
8869                 AtapiWritePort1(chan, IDX_IO1_o_BlockCount,   regs->bSectorCountRegH);
8870                 AtapiWritePort1(chan, IDX_IO1_o_BlockCount,   regs->bSectorCountReg);
8871                 AtapiWritePort1(chan, IDX_IO1_o_BlockNumber,  regs->bSectorNumberRegH);
8872                 AtapiWritePort1(chan, IDX_IO1_o_BlockNumber,  regs->bSectorNumberReg);
8873                 AtapiWritePort1(chan, IDX_IO1_o_CylinderLow,  regs->bCylLowRegH);
8874                 AtapiWritePort1(chan, IDX_IO1_o_CylinderLow,  regs->bCylLowReg);
8875                 AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, regs->bCylHighRegH);
8876                 AtapiWritePort1(chan, IDX_IO1_o_CylinderHigh, regs->bCylHighReg);
8877             }
8878             AtapiWritePort1(chan, IDX_IO1_o_Command,      regs->bCommandReg);
8879 
8880             if(use_dma) {
8881                 GetBaseStatus(chan, statusByte);
8882                 if(statusByte & IDE_STATUS_ERROR) {
8883                     goto passthrough_err;
8884                 }
8885                 AtapiDmaStart(HwDeviceExtension, DeviceNumber, lChannel, Srb);
8886             }
8887 
8888             ScsiPortStallExecution(1);                  // wait for busy to be set
8889 
8890             for(i=0; i<to_lim;i+=2) {      // 2 msec from WaitOnBaseBusy()
8891                 statusByte = WaitOnBaseBusy(chan);      // wait for busy to be clear, up to 2 msec
8892                 GetBaseStatus(chan, statusByte);
8893                 if(statusByte & IDE_STATUS_ERROR) {
8894                     break;
8895                 }
8896                 if(!(statusByte & IDE_STATUS_BUSY)) {
8897                     break;
8898                 }
8899             }
8900             if(i >= to_lim) {
8901                 //if(regs->bOpFlags & UNIATA_SPTI_EX_FREEZE_TO) {
8902                 //}
8903                 AtapiResetController__(HwDeviceExtension, lChannel, RESET_COMPLETE_NONE);
8904                 goto passthrough_err;
8905             }
8906 
8907             if(use_dma) {
8908                 AtapiCheckInterrupt__(deviceExtension, (UCHAR)lChannel);
8909             }
8910             AtapiDmaDone(deviceExtension, DeviceNumber, lChannel, NULL);
8911             GetBaseStatus(chan, statusByte);
8912 
8913             if(statusByte & (IDE_STATUS_BUSY | IDE_STATUS_ERROR)) {
8914                 AtapiSuckPort2(chan);
8915 passthrough_err:
8916                 if (Srb->SenseInfoBuffer) {
8917 
8918                     PSENSE_DATA  senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
8919 
8920                     senseBuffer->ErrorCode = 0x70;
8921                     senseBuffer->Valid     = 1;
8922                     senseBuffer->AdditionalSenseLength = 0xb;
8923                     senseBuffer->SenseKey =  SCSI_SENSE_ABORTED_COMMAND;
8924                     senseBuffer->AdditionalSenseCode = 0;
8925                     senseBuffer->AdditionalSenseCodeQualifier = 0;
8926 
8927                     Srb->SrbStatus = SRB_STATUS_AUTOSENSE_VALID;
8928                     Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
8929                 }
8930                 status = SRB_STATUS_ERROR;
8931             } else {
8932 
8933                 if(!use_dma) {
8934                     if (statusByte & IDE_STATUS_DRQ) {
8935                         if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
8936                             ReadBuffer(chan,
8937                                        (PUSHORT) Srb->DataBuffer,
8938                                        Srb->DataTransferLength / 2,
8939                                        0);
8940                         } else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
8941                             WriteBuffer(chan,
8942                                         (PUSHORT) Srb->DataBuffer,
8943                                         Srb->DataTransferLength / 2,
8944                                         0);
8945                         }
8946                     }
8947                 }
8948                 status = SRB_STATUS_SUCCESS;
8949             }
8950 passthrough_done:;
8951             AtapiEnableInterrupts(deviceExtension, lChannel);
8952 
8953         } else { // read task register
8954 
8955             BOOLEAN use48;
8956             regs = (PIDEREGS_EX) Srb->DataBuffer;
8957 
8958             KdPrint2((PRINT_PREFIX
8959                        "IdeSendCommand: SCSIOP_ATA_PASSTHROUGH (snap) PATH:LUN:TID = %#x:%#x:%#x\n",
8960                        Srb->PathId, Srb->Lun, Srb->TargetId));
8961 
8962             if((Srb->DataTransferLength >= sizeof(IDEREGS_EX)) &&
8963                (regs->bOpFlags & ATA_FLAGS_48BIT_COMMAND)) {
8964                 use48 = TRUE;
8965             } else
8966             if(Srb->DataTransferLength >= sizeof(IDEREGS)) {
8967                 use48 = FALSE;
8968             } else {
8969                 KdPrint2((PRINT_PREFIX " buffer too small \n"));
8970                 status = SRB_STATUS_DATA_OVERRUN;
8971                 break;
8972             }
8973             RtlZeroMemory(regs, use48 ? sizeof(IDEREGS_EX) : sizeof(IDEREGS));
8974             regs->bOpFlags = use48 ? ATA_FLAGS_48BIT_COMMAND : 0;
8975             UniataSnapAtaRegs(chan, 0, regs);
8976 
8977             status = SRB_STATUS_SUCCESS;
8978         }
8979         break;
8980     }
8981 
8982     default:
8983 default_abort:
8984         KdPrint2((PRINT_PREFIX
8985                    "IdeSendCommand: Unsupported command %#x\n",
8986                    Srb->Cdb[0]));
8987 
8988         status = SRB_STATUS_INVALID_REQUEST;
8989 
8990     } // end switch
8991 
8992     if(status == SRB_STATUS_PENDING) {
8993         KdPrint2((PRINT_PREFIX "IdeSendCommand: SRB_STATUS_PENDING\n"));
8994         if(CmdAction & CMD_ACTION_EXEC) {
8995             KdPrint2((PRINT_PREFIX "IdeSendCommand: REQ_STATE_EXPECTING_INTR\n"));
8996             AtaReq->ReqState = REQ_STATE_EXPECTING_INTR;
8997         }
8998     } else {
8999         KdPrint2((PRINT_PREFIX "IdeSendCommand: REQ_STATE_TRANSFER_COMPLETE\n"));
9000         AtaReq->ReqState = REQ_STATE_TRANSFER_COMPLETE;
9001     }
9002 
9003     return status;
9004 
9005 } // end IdeSendCommand()
9006 
9007 
9008 /*++
9009 
9010 Routine Description:
9011     Enables disables media status notification
9012 
9013 Arguments:
9014     HwDeviceExtension - ATAPI driver storage.
9015 
9016 --*/
9017 VOID
9018 NTAPI
9019 IdeMediaStatus(
9020     BOOLEAN EnableMSN,
9021     IN PVOID HwDeviceExtension,
9022     IN ULONG lChannel,
9023     IN ULONG DeviceNumber
9024     )
9025 {
9026     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
9027     PHW_CHANNEL          chan;
9028     UCHAR statusByte,errorByte;
9029 
9030     chan = &(deviceExtension->chan[lChannel]);
9031     SelectDrive(chan, DeviceNumber);
9032 
9033     if (EnableMSN == TRUE){
9034 
9035         // If supported enable Media Status Notification support
9036         if ((chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_REMOVABLE_DRIVE)) {
9037 
9038             // enable
9039             statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel,
9040                                 IDE_COMMAND_SET_FEATURES, 0, 0, 0,
9041                                 0, ATA_C_F_ENAB_MEDIASTAT, ATA_WAIT_BASE_READY);
9042 
9043             if (statusByte & IDE_STATUS_ERROR) {
9044                 // Read the error register.
9045                 errorByte = AtapiReadPort1(chan, IDX_IO1_i_Error);
9046 
9047                 KdPrint2((PRINT_PREFIX
9048                             "IdeMediaStatus: Error enabling media status. Status %#x, error byte %#x\n",
9049                              statusByte,
9050                              errorByte));
9051             } else {
9052                 chan->lun[DeviceNumber]->DeviceFlags |= DFLAGS_MEDIA_STATUS_ENABLED;
9053                 KdPrint2((PRINT_PREFIX "IdeMediaStatus: Media Status Notification Supported\n"));
9054                 chan->ReturningMediaStatus = 0;
9055 
9056             }
9057 
9058         }
9059     } else { // end if EnableMSN == TRUE
9060 
9061         // disable if previously enabled
9062         if ((chan->lun[DeviceNumber]->DeviceFlags & DFLAGS_MEDIA_STATUS_ENABLED)) {
9063 
9064             statusByte = AtaCommand(deviceExtension, DeviceNumber, lChannel,
9065                                 IDE_COMMAND_SET_FEATURES, 0, 0, 0,
9066                                 0, ATA_C_F_DIS_MEDIASTAT, ATA_WAIT_BASE_READY);
9067             chan->lun[DeviceNumber]->DeviceFlags &= ~DFLAGS_MEDIA_STATUS_ENABLED;
9068         }
9069 
9070 
9071     }
9072 
9073 
9074 } // end IdeMediaStatus()
9075 
9076 
9077 /*++
9078 
9079 Routine Description:
9080 
9081     Builts an artificial sense buffer to report the results of a GET_MEDIA_STATUS
9082     command. This function is invoked to satisfy the SCSIOP_REQUEST_SENSE.
9083 Arguments:
9084 
9085     HwDeviceExtension - ATAPI driver storage.
9086     Srb - System request block.
9087 
9088 Return Value:
9089 
9090     SRB status (ALWAYS SUCCESS).
9091 
9092 --*/
9093 ULONG
9094 NTAPI
9095 IdeBuildSenseBuffer(
9096     IN PVOID HwDeviceExtension,
9097     IN PSCSI_REQUEST_BLOCK Srb
9098     )
9099 {
9100     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
9101 //    ULONG status;
9102     PSENSE_DATA  senseBuffer = (PSENSE_DATA)Srb->DataBuffer;
9103     UCHAR ReturningMediaStatus = deviceExtension->chan[GET_CHANNEL(Srb)].ReturningMediaStatus;
9104 
9105     if (senseBuffer){
9106 
9107         if(ReturningMediaStatus & IDE_ERROR_MEDIA_CHANGE) {
9108 
9109             senseBuffer->ErrorCode = 0x70;
9110             senseBuffer->Valid     = 1;
9111             senseBuffer->AdditionalSenseLength = 0xb;
9112             senseBuffer->SenseKey =  SCSI_SENSE_UNIT_ATTENTION;
9113             senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED;
9114             senseBuffer->AdditionalSenseCodeQualifier = 0;
9115         } else if(ReturningMediaStatus & IDE_ERROR_MEDIA_CHANGE_REQ) {
9116 
9117             senseBuffer->ErrorCode = 0x70;
9118             senseBuffer->Valid     = 1;
9119             senseBuffer->AdditionalSenseLength = 0xb;
9120             senseBuffer->SenseKey =  SCSI_SENSE_UNIT_ATTENTION;
9121             senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED;
9122             senseBuffer->AdditionalSenseCodeQualifier = 0;
9123         } else if(ReturningMediaStatus & IDE_ERROR_END_OF_MEDIA) {
9124 
9125             senseBuffer->ErrorCode = 0x70;
9126             senseBuffer->Valid     = 1;
9127             senseBuffer->AdditionalSenseLength = 0xb;
9128             senseBuffer->SenseKey =  SCSI_SENSE_NOT_READY;
9129             senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_NO_MEDIA_IN_DEVICE;
9130             senseBuffer->AdditionalSenseCodeQualifier = 0;
9131         } else if(ReturningMediaStatus & IDE_ERROR_DATA_ERROR) {
9132 
9133             senseBuffer->ErrorCode = 0x70;
9134             senseBuffer->Valid     = 1;
9135             senseBuffer->AdditionalSenseLength = 0xb;
9136             senseBuffer->SenseKey =  SCSI_SENSE_DATA_PROTECT;
9137             senseBuffer->AdditionalSenseCode = 0;
9138             senseBuffer->AdditionalSenseCodeQualifier = 0;
9139         }
9140         return SRB_STATUS_SUCCESS;
9141     }
9142     return SRB_STATUS_ERROR;
9143 
9144 }// End of IdeBuildSenseBuffer
9145 
9146 VOID
9147 NTAPI
9148 UniataUserDeviceReset(
9149     PHW_DEVICE_EXTENSION deviceExtension,
9150     PHW_LU_EXTENSION LunExt,
9151     ULONG lChannel
9152     )
9153 {
9154     ULONG i;
9155     AtapiDisableInterrupts(deviceExtension, lChannel);
9156     if ((LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) &&
9157         (LunExt->PowerState != StartStop_Power_Sleep)) {
9158         KdPrint2((PRINT_PREFIX "UniataUserDeviceReset: Reset ATAPI\n"));
9159         AtapiSoftReset(&(deviceExtension->chan[lChannel]), LunExt->Lun);
9160     } else {
9161         KdPrint2((PRINT_PREFIX "UniataUserDeviceReset: Reset IDE -> reset entire channel\n"));
9162         AtapiResetController__(deviceExtension, lChannel, RESET_COMPLETE_NONE);
9163         for(i=0; i<deviceExtension->NumberLuns; i++) {
9164             deviceExtension->chan[lChannel].lun[i]->DeviceFlags |= DFLAGS_REINIT_DMA;
9165         }
9166     }
9167     LunExt->DeviceFlags |= DFLAGS_REINIT_DMA;  // force PIO/DMA reinit
9168     AtapiEnableInterrupts(deviceExtension, lChannel);
9169     return;
9170 } // end UniataUserDeviceReset()
9171 
9172 BOOLEAN
9173 NTAPI
9174 UniataNeedQueueing(
9175     PHW_DEVICE_EXTENSION deviceExtension,
9176     PHW_CHANNEL          chan,
9177     BOOLEAN              TopLevel
9178     )
9179 {
9180     BOOLEAN PostReq = FALSE;
9181     if(TopLevel) {
9182         KdPrint3((PRINT_PREFIX "UniataNeedQueueing: TopLevel, qd=%x\n", chan->queue_depth));
9183         if(chan->queue_depth > 0) {
9184 #if 0
9185             if(atapiDev &&
9186                ((Srb->Cdb[0] == SCSIOP_TEST_UNIT_READY)/* ||
9187                 (Srb->Cdb[0] == SCSIOP_REQUEST_SENSE)*/) ) {
9188                 KdPrint2((PRINT_PREFIX "spec: SCSIOP_TEST_UNIT_READY\n"));
9189                 //PostReq = FALSE;
9190                 status = SRB_STATUS_BUSY;
9191                 goto skip_exec;
9192             } else {
9193                 PostReq = TRUE;
9194             }
9195 #else
9196             PostReq = TRUE;
9197 #endif
9198         } else
9199         if(deviceExtension->simplexOnly && deviceExtension->queue_depth > 0) {
9200             PostReq = TRUE;
9201         }
9202     } else {
9203         KdPrint3((PRINT_PREFIX "UniataNeedQueueing: qd=%x\n", chan->queue_depth));
9204     }
9205     return PostReq;
9206 } // end UniataNeedQueueing()
9207 
9208 /*++
9209 
9210 Routine Description:
9211 
9212     This routine is called from the SCSI port driver synchronized
9213     with the kernel to start an IO request.
9214     ->HwStartIo
9215 
9216 Arguments:
9217 
9218     HwDeviceExtension - HBA miniport driver's adapter data storage
9219     Srb - IO request packet
9220 
9221 Return Value:
9222 
9223     TRUE
9224 
9225 --*/
9226 BOOLEAN
9227 NTAPI
9228 AtapiStartIo(
9229     IN PVOID HwDeviceExtension,
9230     IN PSCSI_REQUEST_BLOCK Srb
9231     )
9232 {
9233     return AtapiStartIo__(HwDeviceExtension, Srb, TRUE);
9234 } // end AtapiStartIo()
9235 
9236 BOOLEAN
9237 NTAPI
9238 AtapiStartIo__(
9239     IN PVOID HwDeviceExtension,
9240     IN PSCSI_REQUEST_BLOCK Srb,
9241     IN BOOLEAN TopLevel
9242     )
9243 {
9244     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
9245     UCHAR                lChannel;
9246     PHW_CHANNEL          chan;
9247     PHW_LU_EXTENSION     LunExt;
9248     ULONG status;
9249     //ULONG ldev;
9250     ULONG DeviceNumber;
9251     UCHAR PathId;
9252     UCHAR TargetId;
9253     UCHAR Lun;
9254     PATA_REQ AtaReq;
9255     PSCSI_REQUEST_BLOCK tmpSrb;
9256     BOOLEAN PostReq = FALSE;
9257     BOOLEAN atapiDev;
9258     BOOLEAN commPort = FALSE;
9259 
9260     // deviceExtension->Isr2DevObj must always be NULL for non-PCI
9261     if(deviceExtension->Isr2DevObj && !BMList[deviceExtension->DevIndex].Isr2Enable) {
9262         KdPrint2((PRINT_PREFIX "Isr2Enable -> 1\n"));
9263         BMList[deviceExtension->DevIndex].Isr2Enable = TRUE;
9264     }
9265 //    deviceExtension->QueueNewIrql = max(deviceExtension->QueueNewIrql, KeGetCurrentIrql());
9266 
9267 /*                KeBugCheckEx(0xc000000e,
9268                              (Srb->PathId<<16) | (Srb->TargetId<<8) | (Srb->Lun),
9269                              Srb->Function,
9270                              TopLevel, 0x80000001);
9271 */
9272     if(TopLevel && Srb && Srb->SrbExtension) {
9273         KdPrint2((PRINT_PREFIX "TopLevel\n"));
9274         //RtlZeroMemory(Srb->SrbExtension, sizeof(ATA_REQ));
9275         UniAtaClearAtaReq(Srb->SrbExtension);
9276     }
9277 
9278     do { // fetch all queued commands for the channel (if valid)
9279 
9280         lChannel = GET_CHANNEL(Srb);
9281         //ldev = GET_LDEV(Srb);
9282         chan = NULL;
9283         LunExt = NULL;
9284         DeviceNumber = GET_CDEV(Srb);
9285         commPort = FALSE;
9286 
9287         //ASSERT(deviceExtension);
9288         //ASSERT(chan);
9289 
9290         KdPrint2((PRINT_PREFIX
9291                    "** AtapiStartIo: Function %#x, PATH:LUN:TID = %#x:%#x:%#x\n",
9292                    Srb->Function, Srb->PathId, Srb->Lun, Srb->TargetId));
9293         KdPrint2((PRINT_PREFIX "   DeviceID+VendorID/Rev %#x/%#x\n", deviceExtension->DevID, deviceExtension->RevID));
9294 
9295         if(lChannel == deviceExtension->NumberChannels &&
9296            !Srb->Lun && !Srb->TargetId &&
9297            ((Srb->Function == SRB_FUNCTION_IO_CONTROL) ||
9298             (Srb->Function == SRB_FUNCTION_EXECUTE_SCSI && Srb->Cdb[0] == SCSIOP_INQUIRY))
9299            ) {
9300             // This is our virtual device
9301             KdPrint2((PRINT_PREFIX
9302                        "AtapiStartIo: Communication port\n"));
9303             if(Srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
9304 
9305                 if(Srb->DataTransferLength < sizeof(PINQUIRYDATA)) {
9306                     KdPrint2((PRINT_PREFIX "AtapiStartIo: Buffer too small: %#x < %#x\n", Srb->DataTransferLength,
9307                         sizeof(PINQUIRYDATA) ));
9308 wrong_buffer_size:
9309                     status = SRB_STATUS_DATA_OVERRUN;
9310                     goto complete_req;
9311                 }
9312 
9313                 PINQUIRYDATA    inquiryData  = (PINQUIRYDATA)(Srb->DataBuffer);
9314 
9315                 KdPrint2((PRINT_PREFIX
9316                            "  INQUIRY\n"));
9317                 // Zero INQUIRY data structure.
9318                 RtlZeroMemory((PCHAR)(Srb->DataBuffer), Srb->DataTransferLength);
9319 
9320                 inquiryData->DeviceType = COMMUNICATION_DEVICE;
9321 
9322                 // Fill in vendor identification fields.
9323                 RtlCopyMemory(&inquiryData->VendorId, &uniata_comm_name, 28);
9324 
9325                 status = SRB_STATUS_SUCCESS;
9326                 goto complete_req;
9327             }
9328             commPort = TRUE;
9329             /* Pass IOCTL request down */
9330         } else
9331         if(lChannel >= deviceExtension->NumberChannels ||
9332             Srb->TargetId /*DeviceNumber*/ >= deviceExtension->NumberLuns ||
9333             Srb->Lun) {
9334 
9335             if(lChannel >= deviceExtension->NumberChannels) {
9336                 chan = NULL;
9337             }
9338 
9339 reject_srb:
9340             //if(!CheckDevice(HwDeviceExtension, lChannel, DeviceNumber, FALSE)) {
9341             KdPrint3((PRINT_PREFIX
9342                            "AtapiStartIo: SRB rejected\n"));
9343             // Indicate no device found at this address.
9344             KdPrint2((PRINT_PREFIX "SRB_STATUS_SELECTION_TIMEOUT\n"));
9345             status = SRB_STATUS_SELECTION_TIMEOUT;
9346             goto complete_req;
9347             //}
9348         } else
9349         if((deviceExtension->HwFlags & UNIATA_AHCI) &&
9350            !UniataAhciChanImplemented(deviceExtension, lChannel)) {
9351             chan = NULL;
9352         }
9353 
9354         if(!commPort) {
9355             chan = &(deviceExtension->chan[lChannel]);
9356             LunExt = chan->lun[DeviceNumber];
9357             if(!LunExt) {
9358                 goto reject_srb;
9359             }
9360             atapiDev = (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) ? TRUE : FALSE;
9361         } else {
9362             atapiDev = FALSE;
9363         }
9364 
9365 #ifdef _DEBUG
9366         if(!commPort && !LunExt) {
9367 #if 0
9368             PrintNtConsole("de = %#x, chan = %#x , dev %#x, nchan %#x\n",
9369                 deviceExtension,
9370                 chan, DeviceNumber,
9371                 deviceExtension->NumberChannels);
9372             PrintNtConsole("lchan = %#x, cdev %#x, lun0 %#x\n",
9373                 lChannel, GET_CDEV(Srb), deviceExtension->chan[0].lun[0]);
9374             PrintNtConsole("Function %#x, PATH:LUN:TID = %#x:%#x:%#x\n",
9375                        Srb->Function, Srb->PathId, Srb->Lun, Srb->TargetId);
9376 #endif //0
9377 /*
9378             int i;
9379             for(i=0; i<1000; i++) {
9380                 AtapiStallExecution(3*1000);
9381             }
9382 */
9383             goto reject_srb;
9384         }
9385 #endif //_DEBUG
9386 
9387         // Determine which function.
9388         switch (Srb->Function) {
9389 
9390         case SRB_FUNCTION_EXECUTE_SCSI:
9391 
9392             if(!LunExt || !(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
9393                 if(Srb->Cdb[0] == SCSIOP_ATA_PASSTHROUGH) {
9394                     // let passthrough go
9395                 } else
9396                 if(Srb->Cdb[0] == SCSIOP_INQUIRY) {
9397                     // let INQUIRY go
9398                 } else {
9399 
9400                 //if(!CheckDevice(HwDeviceExtension, lChannel, DeviceNumber, FALSE)) {
9401                     KdPrint2((PRINT_PREFIX
9402                                "AtapiStartIo: EXECUTE_SCSI rejected (2)\n"));
9403                     // Indicate no device found at this address.
9404                     KdPrint2((PRINT_PREFIX "SRB_STATUS_SELECTION_TIMEOUT\n"));
9405                     status = SRB_STATUS_SELECTION_TIMEOUT;
9406                     break;
9407                 //}
9408                 }
9409             } else {
9410                 KdPrint2((PRINT_PREFIX
9411                            "  SRB %#x, CDB %#x, AtaReq %#x, SCmd %#x\n", Srb, &(Srb->Cdb), Srb->SrbExtension, Srb->Cdb[0]));
9412             }
9413 /*
9414             __try {
9415                 if(Srb->DataTransferLength) {
9416                     UCHAR a;
9417                     a = ((PUCHAR)(Srb->DataBuffer))[0];
9418                     g_foo += a;
9419                 }
9420             } __except(EXCEPTION_EXECUTE_HANDLER) {
9421                 KdPrint3((PRINT_PREFIX
9422                            "AtapiStartIo: Bad data buffer -> EXECUTE_SCSI rejected\n"));
9423                 // Indicate no device found at this address.
9424                 KdPrint3((PRINT_PREFIX "SRB_STATUS_ERROR\n"));
9425                 status = SRB_STATUS_ERROR;
9426                 KdPrint2((PRINT_PREFIX "  *** Exception...\n"));
9427                 ASSERT(FALSE);
9428                 break;
9429             }
9430 */
9431             PostReq = UniataNeedQueueing(deviceExtension, chan, TopLevel);
9432 
9433             if(PostReq) {
9434 
9435                 KdPrint3((PRINT_PREFIX "Non-empty queue\n"));
9436                 if (atapiDev &&
9437                     (Srb->Cdb[0] != SCSIOP_ATA_PASSTHROUGH)) {
9438                     KdPrint3((PRINT_PREFIX "Try ATAPI prepare\n"));
9439 
9440                     status = AtapiSendCommand(HwDeviceExtension, Srb, CMD_ACTION_PREPARE);
9441                 } else {
9442                     KdPrint2((PRINT_PREFIX "Try IDE prepare\n"));
9443                     status = IdeSendCommand(HwDeviceExtension, Srb, CMD_ACTION_PREPARE);
9444                 }
9445                 /*KeBugCheckEx(0xc000000e,
9446                              (Srb->PathId<<16) | (Srb->TargetId<<8) | (Srb->Lun),
9447                              Srb->Function,
9448                              status, 0x80000001);*/
9449                 if(status == SRB_STATUS_BUSY)
9450                     status = SRB_STATUS_PENDING;
9451                 // Insert requests AFTER they have been initialized on
9452                 // CMD_ACTION_PREPARE stage
9453                 // we should not check TopLevel here (it is always TRUE)
9454                 //ASSERT(chan->lun[GET_CDEV(Srb)]);
9455                 UniataQueueRequest(chan, Srb);
9456 
9457                 KdPrint2((PRINT_PREFIX "AtapiStartIo: Already have %d request(s)!\n", chan->queue_depth));
9458 
9459             } else {
9460 
9461                 // Send command to device.
9462                 KdPrint2((PRINT_PREFIX "Send to device %x\n", Srb->Cdb[0]));
9463                 if(TopLevel) {
9464                     KdPrint2((PRINT_PREFIX "TopLevel (2), srb %#x\n", Srb));
9465                     AtaReq = (PATA_REQ)(Srb->SrbExtension);
9466                     KdPrint2((PRINT_PREFIX "TopLevel (3), AtaReq %#x\n", AtaReq));
9467                     //ASSERT(!AtaReq->Flags);
9468                     //ASSERT(chan->lun[GET_CDEV(Srb)]);
9469                     UniataQueueRequest(chan, Srb);
9470 //                    AtaReq = (PATA_REQ)(Srb->SrbExtension);
9471                     //ASSERT(!AtaReq->Flags);
9472                     AtaReq->ReqState = REQ_STATE_QUEUED;
9473                     //ASSERT(!AtaReq->Flags);
9474                 }
9475 
9476 #ifndef NAVO_TEST
9477                 if(!LunExt || !(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
9478                     if(!LunExt) {
9479                         goto reject_srb;
9480                     }
9481                     if(Srb->Cdb[0] == SCSIOP_INQUIRY) {
9482                         if(UniataAnybodyHome(deviceExtension, chan->lChannel, DeviceNumber)) {
9483                             if(!CheckDevice(HwDeviceExtension, chan->lChannel, DeviceNumber, TRUE)) {
9484                                 goto reject_srb;
9485                             }
9486                         }
9487                         if(!(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
9488                             goto reject_srb;
9489                         }
9490                     } else
9491                     if(Srb->Cdb[0] == SCSIOP_ATA_PASSTHROUGH) {
9492                         // allow
9493                     } else {
9494                         goto reject_srb;
9495                     }
9496                 }
9497 #endif //NAVO_TEST
9498 
9499                 if(atapiDev &&
9500                    (Srb->Cdb[0] != SCSIOP_ATA_PASSTHROUGH)/* &&
9501                    (Srb->Cdb[0] != SCSIOP_REPORT_LUNS)*/) {
9502                     KdPrint3((PRINT_PREFIX "Try ATAPI send %x\n", Srb->Cdb[0]));
9503 #ifdef __REACTOS__
9504                     status = SRB_STATUS_BUSY;
9505 
9506                     if (Srb->Cdb[0] == SCSIOP_INQUIRY &&
9507                         (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) &&
9508                         (LunExt->IdentifyData.DeviceType == ATAPI_TYPE_CDROM ||
9509                         LunExt->IdentifyData.DeviceType == ATAPI_TYPE_OPTICAL) &&
9510                         LunExt->IdentifyData.ModelNumber[0])
9511                     {
9512                         ULONG j;
9513                         CCHAR vendorId[26];
9514 
9515                         // Attempt to identify known broken CD/DVD drives
9516                         for (j = 0; j < sizeof(vendorId); j += 2)
9517                         {
9518                             // Build a buffer based on the identify data.
9519                             MOV_DW_SWP(vendorId[j], ((PUCHAR)LunExt->IdentifyData.ModelNumber)[j]);
9520                         }
9521 
9522                         // Emulate INQUIRY support for broken CD/DVD drives (e.g. Microsoft Xbox).
9523                         // Currently we implement it by explicitly checking the drive name from ATA IDENTIFY PACKET.
9524                         if (!AtapiStringCmp(vendorId, "THOMSON-DVD", 11) ||
9525                             !AtapiStringCmp(vendorId, "PHILIPS XBOX DVD DRIVE", 22) ||
9526                             !AtapiStringCmp(vendorId, "PHILIPS J5 3235C", 16) ||
9527                             !AtapiStringCmp(vendorId, "SAMSUNG DVD-ROM SDG-605B", 24))
9528                         {
9529                             // TODO:
9530                             // Better send INQUIRY and then check for chan->ReturningMediaStatus >> 4 == SCSI_SENSE_ILLEGAL_REQUEST
9531                             // in AtapiInterrupt__() and emulate the response only in this case.
9532 
9533                             // If this hack stays for long enough, consider adding Xbox 360 drive names to the condition,
9534                             // as they are affected by the same problem.
9535 
9536                             // See https://jira.reactos.org/browse/CORE-16692
9537                             ULONG i;
9538                             PINQUIRYDATA inquiryData = (PINQUIRYDATA)(Srb->DataBuffer);
9539                             PIDENTIFY_DATA2 identifyData = &(LunExt->IdentifyData);
9540 
9541                             // Zero INQUIRY data structure.
9542                             RtlZeroMemory((PCHAR)(Srb->DataBuffer), Srb->DataTransferLength);
9543 
9544                             // This is ATAPI CD- or DVD-ROM.
9545                             inquiryData->DeviceType = READ_ONLY_DIRECT_ACCESS_DEVICE;
9546 
9547                             // Set the removable bit, if applicable.
9548                             if (LunExt->DeviceFlags & DFLAGS_REMOVABLE_DRIVE) {
9549                                 KdPrint2((PRINT_PREFIX
9550                                           "RemovableMedia\n"));
9551                                 inquiryData->RemovableMedia = 1;
9552                             }
9553                             // Set the Relative Addressing (LBA) bit, if applicable.
9554                             if (LunExt->DeviceFlags & DFLAGS_LBA_ENABLED) {
9555                                 inquiryData->RelativeAddressing = 1;
9556                                 KdPrint2((PRINT_PREFIX
9557                                           "RelativeAddressing\n"));
9558                             }
9559                             // Set the CommandQueue bit
9560                             inquiryData->CommandQueue = 1;
9561 
9562                             // Fill in vendor identification fields.
9563                             for (i = 0; i < 24; i += 2) {
9564                                 MOV_DW_SWP(inquiryData->DeviceIdentificationString[i], ((PUCHAR)identifyData->ModelNumber)[i]);
9565                             }
9566 
9567                             // Move firmware revision from IDENTIFY data to
9568                             // product revision in INQUIRY data.
9569                             for (i = 0; i < 4; i += 2) {
9570                                 MOV_DW_SWP(inquiryData->ProductRevisionLevel[i], ((PUCHAR)identifyData->FirmwareRevision)[i]);
9571                             }
9572 
9573                             status = SRB_STATUS_SUCCESS;
9574                         }
9575                     }
9576 
9577                     if (status != SRB_STATUS_SUCCESS)
9578 #endif
9579                     status = AtapiSendCommand(HwDeviceExtension, Srb, CMD_ACTION_ALL);
9580                 } else {
9581                     KdPrint2((PRINT_PREFIX "Try IDE send\n"));
9582 /*                    {
9583                         ULONG __ebp__ = 0;
9584                         ULONG __esp__ = 0;
9585 
9586                         KdPrint2((PRINT_PREFIX "** before IdeSendCommand:\n"));
9587                         __asm {
9588                             mov eax,ebp
9589                             mov __ebp__, eax
9590                             mov eax,esp
9591                             mov __esp__, eax
9592                         }
9593                         KdPrint2((PRINT_PREFIX "** before Ide: EBP:%#x ESP:%#x\n", __ebp__, __esp__));
9594                     }*/
9595                     status = IdeSendCommand(HwDeviceExtension, Srb, CMD_ACTION_ALL);
9596                 }
9597 /*                KeBugCheckEx(0xc000000e,
9598                              (Srb->PathId<<16) | (Srb->TargetId<<8) | (Srb->Lun),
9599                              Srb->Function,
9600                              status, 0x80000002);*/
9601 
9602             }
9603 //skip_exec:
9604             TopLevel = FALSE;
9605 
9606             break;
9607 
9608         case SRB_FUNCTION_ABORT_COMMAND:
9609 
9610             tmpSrb = ScsiPortGetSrb(HwDeviceExtension, Srb->PathId, Srb->TargetId, Srb->Lun,
9611                                Srb->QueueTag);
9612             // Verify that SRB to abort is still outstanding.
9613             if((tmpSrb != Srb->NextSrb) ||
9614                !chan->queue_depth) {
9615 
9616                 KdPrint2((PRINT_PREFIX "AtapiStartIo: SRB to abort already completed\n"));
9617 
9618                 // Complete abort SRB.
9619                 status = SRB_STATUS_ABORT_FAILED;
9620                 break;
9621             }
9622 
9623             AtaReq = (PATA_REQ)(tmpSrb->SrbExtension);
9624             if(AtaReq->ReqState > REQ_STATE_READY_TO_TRANSFER) {
9625                 if (!AtapiResetController__(deviceExtension, lChannel, RESET_COMPLETE_CURRENT)) {
9626                       KdPrint2((PRINT_PREFIX "AtapiStartIo: Abort command failed\n"));
9627                     // Log reset failure.
9628                     KdPrint3((PRINT_PREFIX
9629                                 "ScsiPortLogError: devExt %#x, Srb %#x, P:T:D=%d:%d:%d, MsgId %#x (%d)\n",
9630                                       HwDeviceExtension, NULL, 0, 0, 0, SP_INTERNAL_ADAPTER_ERROR, 5 << 8
9631                                 ));
9632                     ScsiPortLogError(HwDeviceExtension, NULL, 0, 0, 0, SP_INTERNAL_ADAPTER_ERROR, 5 << 8);
9633                     status = SRB_STATUS_ERROR;
9634 
9635                 } else {
9636                     status = SRB_STATUS_SUCCESS;
9637                 }
9638             } else {
9639                 KdPrint2((PRINT_PREFIX "AtapiInterrupt: remove aborted srb %#x\n", tmpSrb));
9640                 if (tmpSrb->SenseInfoBuffer &&
9641                     tmpSrb->SenseInfoBufferLength >= sizeof(SENSE_DATA)) {
9642 
9643                     PSENSE_DATA  senseBuffer = (PSENSE_DATA)tmpSrb->SenseInfoBuffer;
9644 
9645                     senseBuffer->ErrorCode = 0;
9646                     senseBuffer->Valid     = 1;
9647                     senseBuffer->AdditionalSenseLength = 0xb;
9648                     senseBuffer->SenseKey =  SCSI_SENSE_ABORTED_COMMAND;
9649                     senseBuffer->AdditionalSenseCode = 0;
9650                     senseBuffer->AdditionalSenseCodeQualifier = 0;
9651 
9652                     tmpSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
9653                 }
9654                 AtapiDmaDBSync(chan, tmpSrb);
9655                 UniataRemoveRequest(chan, tmpSrb);
9656                 // Indicate command complete.
9657                 ScsiPortNotification(RequestComplete,
9658                                      deviceExtension,
9659                                      tmpSrb);
9660                 status = SRB_STATUS_SUCCESS;
9661             }
9662             break;
9663 
9664             // Abort function indicates that a request timed out.
9665             // Call reset routine. Card will only be reset if
9666             // status indicates something is wrong.
9667             // Fall through to reset code.
9668 
9669         case SRB_FUNCTION_RESET_DEVICE:
9670         case SRB_FUNCTION_RESET_LOGICAL_UNIT:
9671 
9672             // Reset single device.
9673             // For now we support only Lun=0
9674 
9675             // Note: reset is immediate command, it cannot be queued since it is usually used to
9676             // revert not-responding device to operational state
9677             KdPrint2((PRINT_PREFIX "AtapiStartIo: Reset device request received\n"));
9678             UniataUserDeviceReset(deviceExtension, LunExt, lChannel);
9679             status = SRB_STATUS_SUCCESS;
9680             break;
9681 
9682         case SRB_FUNCTION_RESET_BUS:
9683 do_bus_reset:
9684             // Reset Atapi and SCSI bus.
9685 
9686             // Note: reset is immediate command, it cannot be queued since it is usually used to
9687             // revert not- responding device to operational state
9688             KdPrint2((PRINT_PREFIX "AtapiStartIo: Reset bus request received\n"));
9689             if (!AtapiResetController__(deviceExtension, lChannel, RESET_COMPLETE_ALL)) {
9690                   KdPrint2((PRINT_PREFIX "AtapiStartIo: Reset bus failed\n"));
9691                 // Log reset failure.
9692                 KdPrint3((PRINT_PREFIX
9693                             "ScsiPortLogError: devExt %#x, Srb %#x, P:T:D=%d:%d:%d, MsgId %#x (%d) - (2)\n",
9694                                   HwDeviceExtension, NULL, 0, 0, 0, SP_INTERNAL_ADAPTER_ERROR, 5 << 8
9695                             ));
9696                 ScsiPortLogError(HwDeviceExtension, NULL, 0, 0, 0, SP_INTERNAL_ADAPTER_ERROR, 5 << 8);
9697                 status = SRB_STATUS_ERROR;
9698 
9699             } else {
9700                 status = SRB_STATUS_SUCCESS;
9701             }
9702 
9703             break;
9704 
9705         case SRB_FUNCTION_SHUTDOWN:
9706 
9707             KdPrint2((PRINT_PREFIX "AtapiStartIo: Shutdown\n"));
9708             if(!LunExt || !(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
9709                 KdPrint2((PRINT_PREFIX "AtapiStartIo: Shutdown - no such device\n"));
9710             } else
9711             if(atapiDev) {
9712                 // FLUSH ATAPI device - do nothing
9713                 KdPrint2((PRINT_PREFIX "AtapiStartIo: Shutdown - ATAPI device\n"));
9714             } else {
9715                 // FLUSH IDE/ATA device
9716                 KdPrint2((PRINT_PREFIX "AtapiStartIo: Shutdown - IDE device\n"));
9717                 AtapiDisableInterrupts(deviceExtension, lChannel);
9718                 status = AtaCommand(deviceExtension, DeviceNumber, GET_CHANNEL(Srb),
9719                            IDE_COMMAND_FLUSH_CACHE, 0, 0, 0, 0, 0, ATA_WAIT_IDLE);
9720                 // If supported & allowed, reset write cacheing
9721                 if(LunExt->DeviceFlags & DFLAGS_WCACHE_ENABLED) {
9722 
9723                     // Disable write cache
9724                     status = AtaCommand(deviceExtension, DeviceNumber, lChannel,
9725                                         IDE_COMMAND_SET_FEATURES, 0, 0, 0,
9726                                         0, ATA_C_F_DIS_WCACHE, ATA_WAIT_BASE_READY);
9727                     // Check for errors.
9728                     if (status & IDE_STATUS_ERROR) {
9729                         KdPrint2((PRINT_PREFIX
9730                                     "AtapiHwInitialize: Disable write cacheing on Device %d failed\n",
9731                                     DeviceNumber));
9732                     }
9733                     LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
9734 
9735                     // Re-enable write cache
9736                     status = AtaCommand(deviceExtension, DeviceNumber, lChannel,
9737                                         IDE_COMMAND_SET_FEATURES, 0, 0, 0,
9738                                         0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_BASE_READY);
9739                     // Check for errors.
9740                     if (status & IDE_STATUS_ERROR) {
9741                         KdPrint2((PRINT_PREFIX
9742                                     "AtapiHwInitialize: Enable write cacheing on Device %d failed\n",
9743                                     DeviceNumber));
9744                         LunExt->DeviceFlags &= ~DFLAGS_WCACHE_ENABLED;
9745                     } else {
9746                         LunExt->DeviceFlags |= DFLAGS_WCACHE_ENABLED;
9747                     }
9748                 }
9749 
9750                 AtapiEnableInterrupts(deviceExtension, lChannel);
9751             }
9752             status = SRB_STATUS_SUCCESS;
9753 
9754             break;
9755 
9756         case SRB_FUNCTION_FLUSH:
9757 
9758             KdPrint2((PRINT_PREFIX "AtapiStartIo: Flush (do nothing)\n"));
9759             status = SRB_STATUS_SUCCESS;
9760             break;
9761 
9762         case SRB_FUNCTION_IO_CONTROL: {
9763 
9764             ULONG len;
9765 
9766             KdPrint2((PRINT_PREFIX "AtapiStartIo: SRB_FUNCTION_IO_CONTROL\n"));
9767 
9768             len = Srb->DataTransferLength;
9769 
9770             if(!AtapiStringCmp( (PCHAR)(((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature),"SCSIDISK",sizeof("SCSIDISK")-1)) {
9771 
9772                 ULONG targetId = (ULONG)(-1);
9773 
9774                 if(len < sizeof(SRB_IO_CONTROL)) {
9775                     goto wrong_buffer_size;
9776                 }
9777 
9778                 // extract bogus bus address
9779                 switch (((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode) {
9780                 case IOCTL_SCSI_MINIPORT_SMART_VERSION: {
9781                     PGETVERSIONINPARAMS versionParameters = (PGETVERSIONINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
9782 
9783                     if(len < sizeof(SRB_IO_CONTROL)+sizeof(GETVERSIONINPARAMS)) {
9784                         goto wrong_buffer_size;
9785                     }
9786 
9787                     targetId = versionParameters->bIDEDeviceMap;
9788                     KdPrint2((PRINT_PREFIX "targetId (smart ver) %d\n", targetId));
9789                     break; }
9790                 case IOCTL_SCSI_MINIPORT_IDENTIFY:
9791                 case IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS:
9792                 case IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS:
9793                 case IOCTL_SCSI_MINIPORT_ENABLE_SMART:
9794                 case IOCTL_SCSI_MINIPORT_DISABLE_SMART:
9795                 case IOCTL_SCSI_MINIPORT_RETURN_STATUS:
9796                 case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE:
9797                 case IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES:
9798                 case IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS:
9799                 case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE:
9800                 case IOCTL_SCSI_MINIPORT_READ_SMART_LOG:
9801                 case IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG:
9802                     {
9803                     PSENDCMDINPARAMS   cmdInParameters = (PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
9804 
9805                     if(len < sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDINPARAMS) - 1) {
9806                         goto wrong_buffer_size;
9807                     }
9808 
9809                     targetId = cmdInParameters->bDriveNumber;
9810                     KdPrint2((PRINT_PREFIX "targetId (smart/ident) %d\n", targetId));
9811                     break; }
9812                 default:
9813 invalid_request:
9814                     KdPrint2((PRINT_PREFIX "AtapiStartIo: invalid IoControl %#x for SCSIDISK signature\n",
9815                                 ((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode ));
9816                     status = SRB_STATUS_INVALID_REQUEST;
9817                     goto complete_req;
9818                 } // end switch()
9819 
9820                 // adjust (if necessary) bus address
9821                 if(targetId != (ULONG)(-1)) {
9822 
9823                     // This is done because of how the IOCTL_SCSI_MINIPORT
9824                     // determines 'targetid's'. Disk.sys places the real target id value
9825                     // in the DeviceMap field. Once we do some parameter checking, the value passed
9826                     // back to the application will be determined.
9827 
9828                     if (deviceExtension->NumberChannels == 1) {
9829                         // do this for legacy controllers and legacy callers
9830                         KdPrint2((PRINT_PREFIX "AtapiStartIo: legacy call\n"));
9831                         DeviceNumber = (targetId & 0x01);
9832                         lChannel = 0;
9833                     } else
9834                     if(commPort) {
9835                         // do this for smartmontools, sending IOCTLs to PhysicalDrive%d
9836                         // due to DISK.SYS design bug, we have invalid SCSI address in SRB
9837                         KdPrint2((PRINT_PREFIX "AtapiStartIo: legacy call (2)\n"));
9838                         if(deviceExtension->HwFlags & UNIATA_AHCI) {
9839                             lChannel = (UCHAR)targetId / 2;
9840                             DeviceNumber = 0;
9841                         } else {
9842                             lChannel = (UCHAR)(targetId / 2);
9843                             DeviceNumber = targetId & 0x01;
9844                         }
9845                     } else {
9846                         // otherwise assume lChannel and DeviceNumber from Srb are ok
9847                     }
9848                     if(lChannel >= deviceExtension->NumberChannels ||
9849                         DeviceNumber >= deviceExtension->NumberLuns) {
9850                         KdPrint2((PRINT_PREFIX
9851                                    "AtapiStartIo: SCSIDISK IOCTL for non-exestent drive %d -> EXECUTE_SCSI rejected (2)\n",
9852                                        targetId));
9853                         // Indicate no device found at this address.
9854                         goto reject_srb;
9855                     }
9856                     targetId = lChannel*deviceExtension->NumberLuns+DeviceNumber;
9857                     chan = &(deviceExtension->chan[lChannel]);
9858                     LunExt = chan->lun[DeviceNumber];
9859                     if(!LunExt) {
9860                         goto reject_srb;
9861                     }
9862                     atapiDev = (LunExt->DeviceFlags & DFLAGS_ATAPI_DEVICE) ? TRUE : FALSE;
9863 
9864                     if (!(LunExt->DeviceFlags & DFLAGS_DEVICE_PRESENT)) {
9865                         goto reject_srb;
9866                     }
9867                 }
9868 
9869                 switch (((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode) {
9870                 case IOCTL_SCSI_MINIPORT_SMART_VERSION: {
9871 
9872                     PGETVERSIONINPARAMS versionParameters = (PGETVERSIONINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
9873                     UCHAR deviceNumberMap;
9874 
9875                     KdPrint2((PRINT_PREFIX "AtapiStartIo: IOCTL_SCSI_MINIPORT_SMART_VERSION\n"));
9876 
9877                     // Version and revision per SMART 1.03
9878 
9879                     versionParameters->bVersion = 1;
9880                     versionParameters->bRevision = 1;
9881                     versionParameters->bReserved = 0;
9882 
9883                     // Indicate that support for IDE IDENTIFY, ATAPI IDENTIFY and SMART commands.
9884                     versionParameters->fCapabilities = (CAP_ATA_ID_CMD | CAP_ATAPI_ID_CMD | CAP_SMART_CMD);
9885 
9886                     if (atapiDev) {
9887                         goto invalid_request;
9888                     }
9889 
9890                     // NOTE: This will only set the bit
9891                     // corresponding to this drive's target id.
9892                     // The bit mask is as follows:
9893                     //
9894                     //     -Sec Pri
9895                     //     S M S M
9896                     //     3 2 1 0
9897 
9898                     if(chan->DeviceExtension->HwFlags & UNIATA_AHCI) {
9899                         deviceNumberMap = 1 << lChannel;
9900                         DeviceNumber = 0;
9901                     } else
9902                     if (deviceExtension->NumberChannels == 1) {
9903                         if (chan->PrimaryAddress) {
9904                             deviceNumberMap = 1 << DeviceNumber;
9905                         } else {
9906                             deviceNumberMap = 4 << DeviceNumber;
9907                         }
9908                     } else {
9909                         deviceNumberMap = 1 << (DeviceNumber+lChannel*2);
9910                     }
9911 
9912                     versionParameters->bIDEDeviceMap = deviceNumberMap;
9913 
9914                     status = SRB_STATUS_SUCCESS;
9915                     break;
9916                 }
9917 
9918                 case IOCTL_SCSI_MINIPORT_IDENTIFY: {
9919 
9920                     PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
9921                     SENDCMDINPARAMS   cmdInParameters = *(PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
9922 
9923                     KdPrint2((PRINT_PREFIX "AtapiStartIo: IOCTL_SCSI_MINIPORT_IDENTIFY\n"));
9924                     // Extract the target.
9925                     KdPrint2((PRINT_PREFIX "targetId %d\n", targetId));
9926 
9927                     switch(cmdInParameters.irDriveRegs.bCommandReg) {
9928                     case ID_CMD:
9929                         if(atapiDev) {
9930                             KdPrint2((PRINT_PREFIX "Error: ID_CMD for ATAPI\n"));
9931                             goto invalid_request;
9932                         }
9933                         /* FALL THROUGH */
9934                     case ATAPI_ID_CMD:
9935 
9936                         if(!atapiDev &&
9937                            (cmdInParameters.irDriveRegs.bCommandReg == ATAPI_ID_CMD)) {
9938                             KdPrint2((PRINT_PREFIX "Error: ATAPI_ID_CMD for non-ATAPI\n"));
9939                             goto invalid_request;
9940                         }
9941 
9942                         len = min(len, sizeof(SENDCMDOUTPARAMS) - 1 + IDENTIFY_BUFFER_SIZE);
9943                         // Zero the output buffer
9944                         RtlZeroMemory(cmdOutParameters, len);
9945 /*                        for (i = 0; i < (sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1); i++) {
9946                             ((PUCHAR)cmdOutParameters)[i] = 0;
9947                         }*/
9948 
9949                         // Build status block.
9950                         cmdOutParameters->cBufferSize = min(IDENTIFY_BUFFER_SIZE, len - sizeof(SENDCMDOUTPARAMS) + 1);
9951                         cmdOutParameters->DriverStatus.bDriverError = 0;
9952                         cmdOutParameters->DriverStatus.bIDEError = 0;
9953 
9954                         // Extract the identify data from the device extension.
9955                         ScsiPortMoveMemory (cmdOutParameters->bBuffer, &(LunExt->IdentifyData),
9956                             cmdOutParameters->cBufferSize);
9957 
9958                         if((cmdOutParameters->cBufferSize == IDENTIFY_BUFFER_SIZE) &&
9959                            (LunExt->IdentifyData.ChecksumValid == ATA_ChecksumValid)) {
9960                             // adjust checksum if it is possible
9961                             CHAR csum = 0;
9962                             ULONG i;
9963 
9964                             for(i=0; i < IDENTIFY_BUFFER_SIZE-1; i++) {
9965                                 csum += (CHAR)(cmdOutParameters->bBuffer[i]);
9966                             }
9967                             cmdOutParameters->bBuffer[i] = -csum;
9968                             KdPrint2((PRINT_PREFIX "AtapiStartIo: adjust checksum %d\n"));
9969                         }
9970                         KdPrint2((PRINT_PREFIX "AtapiStartIo: IOCTL_SCSI_MINIPORT_IDENTIFY Ok\n"));
9971 
9972                         status = SRB_STATUS_SUCCESS;
9973 
9974                         break;
9975                     default:
9976                         KdPrint2((PRINT_PREFIX "AtapiStartIo: not supported ID code %x\n",
9977                             cmdInParameters.irDriveRegs.bCommandReg));
9978                         status = SRB_STATUS_INVALID_REQUEST;
9979                         break;
9980                     }
9981                     break;
9982                 }
9983 /*
9984                 case  IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS:
9985                 case  IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS:
9986                 case  IOCTL_SCSI_MINIPORT_ENABLE_SMART:
9987                 case  IOCTL_SCSI_MINIPORT_DISABLE_SMART:
9988                 case  IOCTL_SCSI_MINIPORT_RETURN_STATUS:
9989                 case  IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE:
9990                 case  IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES:
9991                 case  IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS:
9992 */
9993                 default:
9994                     // *all* IOCTLs here are SMART
9995                     if(commPort) {
9996                         KdPrint2((PRINT_PREFIX
9997                                    "AtapiStartIo: SCSIDISK Smart IOCTL for commPort -> EXECUTE_SCSI rejected (3)\n"));
9998                     }
9999                     if (atapiDev) {
10000                         goto invalid_request;
10001                     }
10002 
10003                     PostReq = UniataNeedQueueing(deviceExtension, chan, TopLevel);
10004 
10005                     if(PostReq || TopLevel) {
10006                         UniataQueueRequest(chan, Srb);
10007                         AtaReq = (PATA_REQ)(Srb->SrbExtension);
10008                         AtaReq->ReqState = REQ_STATE_QUEUED;
10009                     }
10010 
10011                     if(PostReq) {
10012 
10013                         KdPrint2((PRINT_PREFIX "Non-empty queue (SMART)\n"));
10014                         status = SRB_STATUS_PENDING;
10015 
10016                         KdPrint2((PRINT_PREFIX "AtapiStartIo: Already have %d request(s)!\n", chan->queue_depth));
10017                     } else {
10018 
10019                         status = IdeSendSmartCommand(HwDeviceExtension, Srb, targetId);
10020                     }
10021                     break;
10022 
10023                 // we should not get here, checked above
10024 /*                default :
10025                     KdPrint2((PRINT_PREFIX "AtapiStartIo: invalid IoControl %#x for SCSIDISK signature\n",
10026                                 ((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode ));
10027                     status = SRB_STATUS_INVALID_REQUEST;
10028                     break;
10029 */
10030                 }
10031             } else
10032             if(!AtapiStringCmp( (PCHAR)(((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature),"-UNIATA-", sizeof("-UNIATA-")-1)) {
10033 
10034                 PUNIATA_CTL AtaCtl = (PUNIATA_CTL)(Srb->DataBuffer);
10035                 //ULONG ldev = GET_LDEV2(AtaCtl->addr.PathId, AtaCtl->addr.TargetId, 0);
10036                 ULONG DeviceNumber = AtaCtl->addr.TargetId;
10037                 BOOLEAN bad_ldev;
10038                 ULONG i, pos;
10039 
10040                 pos = FIELD_OFFSET(UNIATA_CTL, RawData);
10041                 //chan = &(deviceExtension->chan[lChannel]);
10042                 if(len < pos) {
10043                     KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
10044                         FIELD_OFFSET(UNIATA_CTL, RawData) ));
10045                     goto wrong_buffer_size;
10046                 }
10047 
10048                 if(AtaCtl->addr.Lun ||
10049                    AtaCtl->addr.TargetId >= deviceExtension->NumberLuns ||
10050                    AtaCtl->addr.PathId >= deviceExtension->NumberChannels) {
10051 
10052                     chan = NULL;
10053                     bad_ldev = TRUE;
10054                     LunExt = NULL;
10055 
10056                 } else {
10057                     bad_ldev = FALSE;
10058                     lChannel = AtaCtl->addr.PathId;
10059                     chan = &(deviceExtension->chan[lChannel]);
10060                     LunExt = chan->lun[DeviceNumber];
10061                 }
10062 
10063                 KdPrint2((PRINT_PREFIX "AtapiStartIo: -UNIATA- %#x, dev %#x\n", AtaCtl->hdr.ControlCode, DeviceNumber));
10064 
10065                 /* check for valid LUN */
10066                 switch (AtaCtl->hdr.ControlCode) {
10067                 case  IOCTL_SCSI_MINIPORT_UNIATA_FIND_DEVICES:
10068                 case  IOCTL_SCSI_MINIPORT_UNIATA_RESET_DEVICE:
10069                     // this would be BUS reset
10070                     if(bad_ldev &&
10071                        (AtaCtl->addr.PathId >= deviceExtension->NumberChannels ||
10072                         AtaCtl->addr.TargetId != 0xff ||
10073                         AtaCtl->addr.Lun != 0
10074                         )) {
10075                         if(AtaCtl->hdr.ControlCode == IOCTL_SCSI_MINIPORT_UNIATA_FIND_DEVICES &&
10076                            DeviceNumber < deviceExtension->NumberLuns) { // AtaCtl->addr.TargetId != 0xff
10077                             lChannel = AtaCtl->addr.PathId;
10078                             chan = &(deviceExtension->chan[lChannel]);
10079                             LunExt = chan->lun[DeviceNumber];
10080                             // OK
10081                         } else {
10082                             goto handle_bad_ldev;
10083                         }
10084                     } else {
10085                         lChannel = AtaCtl->addr.PathId;
10086                         chan = &(deviceExtension->chan[lChannel]);
10087                     }
10088                     break;
10089                 case  IOCTL_SCSI_MINIPORT_UNIATA_DELETE_DEVICE:
10090                 case  IOCTL_SCSI_MINIPORT_UNIATA_SET_MAX_MODE:
10091                 case  IOCTL_SCSI_MINIPORT_UNIATA_GET_MODE:
10092                 case  IOCTL_SCSI_MINIPORT_UNIATA_RESETBB:
10093 //                case  IOCTL_SCSI_MINIPORT_UNIATA_REG_IO:
10094                     if(bad_ldev) {
10095 handle_bad_ldev:
10096                         KdPrint2((PRINT_PREFIX
10097                                    "AtapiStartIo: bad_ldev -> IOCTL SRB rejected\n"));
10098                         // Indicate no device found at this address.
10099                         goto reject_srb;
10100                     }
10101                 }
10102 
10103                 /* check if queueing is necessary */
10104                 switch (AtaCtl->hdr.ControlCode) {
10105                 case  IOCTL_SCSI_MINIPORT_UNIATA_RESETBB:
10106                     if(!LunExt->nBadBlocks) {
10107                         break;
10108                     }
10109                     goto uata_ctl_queue;
10110                 case  IOCTL_SCSI_MINIPORT_UNIATA_SET_MAX_MODE:
10111                     if(len < pos+sizeof(AtaCtl->SetMode)) {
10112                         KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
10113                             pos+sizeof(AtaCtl->SetMode) ));
10114                         goto wrong_buffer_size;
10115                     }
10116                     if(!AtaCtl->SetMode.ApplyImmediately) {
10117                         break;
10118                     }
10119                     goto uata_ctl_queue;
10120                 case  IOCTL_SCSI_MINIPORT_UNIATA_FIND_DEVICES:
10121                 //case  IOCTL_SCSI_MINIPORT_UNIATA_RESET_DEVICE: reset must be processed immediately
10122 uata_ctl_queue:
10123                     KdPrint2((PRINT_PREFIX "put to queue (UNIATA)\n"));
10124                     PostReq = UniataNeedQueueing(deviceExtension, chan, TopLevel);
10125 
10126                     if(PostReq || TopLevel) {
10127                         UniataQueueRequest(chan, Srb);
10128                         AtaReq = (PATA_REQ)(Srb->SrbExtension);
10129                         AtaReq->ReqState = REQ_STATE_QUEUED;
10130                     }
10131                     if(PostReq) {
10132                         KdPrint2((PRINT_PREFIX "Non-empty queue (UNIATA)\n"));
10133                         status = SRB_STATUS_PENDING;
10134 
10135                         KdPrint2((PRINT_PREFIX "AtapiStartIo: Already have %d request(s)!\n", chan->queue_depth));
10136                         goto complete_req;
10137                     }
10138                 } // end switch (AtaCtl->hdr.ControlCode)
10139 
10140                 /* process request */
10141                 switch (AtaCtl->hdr.ControlCode) {
10142                 case  IOCTL_SCSI_MINIPORT_UNIATA_FIND_DEVICES:
10143 
10144                     KdPrint2((PRINT_PREFIX "AtapiStartIo: rescan bus\n"));
10145 
10146                     if(len < pos+sizeof(AtaCtl->FindDelDev)) {
10147                         KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
10148                             pos+sizeof(AtaCtl->FindDelDev) ));
10149                         goto wrong_buffer_size;
10150                     }
10151                     if(AtaCtl->FindDelDev.Flags & UNIATA_ADD_FLAGS_UNHIDE) {
10152                         KdPrint2((PRINT_PREFIX "AtapiStartIo: unhide from further detection\n"));
10153                         if(AtaCtl->addr.TargetId != 0xff) {
10154                             LunExt->DeviceFlags &= ~DFLAGS_HIDDEN;
10155                         } else {
10156                         }
10157                     }
10158 
10159                     for(i=0; i<AtaCtl->FindDelDev.WaitForPhysicalLink && i<30; i++) {
10160                         AtapiStallExecution(1000 * 1000);
10161                     }
10162 
10163                     FindDevices(HwDeviceExtension,
10164                                 ((AtaCtl->addr.TargetId == 0xff) && (AtaCtl->FindDelDev.Flags & UNIATA_ADD_FLAGS_UNHIDE))
10165                                      ? UNIATA_FIND_DEV_UNHIDE : 0,
10166                                 AtaCtl->addr.PathId);
10167                     status = SRB_STATUS_SUCCESS;
10168 
10169                     break;
10170 
10171                 case  IOCTL_SCSI_MINIPORT_UNIATA_DELETE_DEVICE: {
10172 
10173                     KdPrint2((PRINT_PREFIX "AtapiStartIo: remove %#x:%#x\n", AtaCtl->addr.PathId, AtaCtl->addr.TargetId));
10174 
10175                     if(len < pos+sizeof(AtaCtl->FindDelDev)) {
10176                         KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
10177                             pos+sizeof(AtaCtl->FindDelDev) ));
10178                         goto wrong_buffer_size;
10179                     }
10180                     LunExt->DeviceFlags = 0;
10181                     if(AtaCtl->FindDelDev.Flags & UNIATA_REMOVE_FLAGS_HIDE) {
10182                         KdPrint2((PRINT_PREFIX "AtapiStartIo: hide from further detection\n"));
10183                         //LunExt->DeviceFlags |= DFLAGS_HIDDEN;
10184                         UniataForgetDevice(LunExt);
10185                     }
10186 
10187                     for(i=0; i<AtaCtl->FindDelDev.WaitForPhysicalLink && i<30; i++) {
10188                         AtapiStallExecution(1000 * 1000);
10189                     }
10190 
10191                     status = SRB_STATUS_SUCCESS;
10192                     break;
10193                 }
10194                 case  IOCTL_SCSI_MINIPORT_UNIATA_SET_MAX_MODE: {
10195 
10196                     KdPrint2((PRINT_PREFIX "AtapiStartIo: Set transfer mode\n"));
10197 
10198                     if(len < pos+sizeof(AtaCtl->SetMode)) {
10199                         KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
10200                             pos+sizeof(AtaCtl->SetMode) ));
10201                         goto wrong_buffer_size;
10202                     }
10203                     if(AtaCtl->SetMode.OrigMode != IOMODE_NOT_SPECIFIED) {
10204                         LunExt->OrigTransferMode = (UCHAR)(AtaCtl->SetMode.OrigMode);
10205                     }
10206                     if(AtaCtl->SetMode.MaxMode != IOMODE_NOT_SPECIFIED) {
10207                         LunExt->LimitedTransferMode = (UCHAR)(AtaCtl->SetMode.MaxMode);
10208                         if(LunExt->LimitedTransferMode >
10209                            LunExt->OrigTransferMode) {
10210                             // check for incorrect value
10211                             LunExt->LimitedTransferMode =
10212                                 LunExt->OrigTransferMode;
10213                         }
10214                     }
10215                     LunExt->TransferMode = min(LunExt->LimitedTransferMode, LunExt->OrigTransferMode);
10216 
10217                     LunExt->DeviceFlags |= DFLAGS_REINIT_DMA;  // force PIO/DMA reinit
10218                     if(AtaCtl->SetMode.ApplyImmediately) {
10219                         AtapiDmaInit__(deviceExtension, LunExt);
10220                     }
10221 /*                    LunExt->TransferMode =
10222                     LunExt->LimitedTransferMode = (UCHAR)(setTransferMode->Mode);*/
10223                     status = SRB_STATUS_SUCCESS;
10224                     break;
10225                 }
10226                 case  IOCTL_SCSI_MINIPORT_UNIATA_GET_MODE: {
10227 
10228                     KdPrint2((PRINT_PREFIX "AtapiStartIo: Get transfer mode\n"));
10229 
10230                     if(len < pos+sizeof(AtaCtl->GetMode)) {
10231                         KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
10232                             pos+sizeof(AtaCtl->GetMode) ));
10233                         goto wrong_buffer_size;
10234                     }
10235                     AtaCtl->GetMode.OrigMode    = LunExt->OrigTransferMode;
10236                     AtaCtl->GetMode.MaxMode     = LunExt->LimitedTransferMode;
10237                     AtaCtl->GetMode.CurrentMode = LunExt->TransferMode;
10238                     AtaCtl->GetMode.PhyMode     = LunExt->PhyTransferMode;
10239 
10240                     status = SRB_STATUS_SUCCESS;
10241                     break;
10242                 }
10243                 case  IOCTL_SCSI_MINIPORT_UNIATA_GET_VERSION: {
10244 
10245                     KdPrint2((PRINT_PREFIX "AtapiStartIo: Get version\n"));
10246 
10247                     if(len < pos+sizeof(AtaCtl->Version)) {
10248                         KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
10249                             pos+sizeof(AtaCtl->Version) ));
10250                         goto wrong_buffer_size;
10251                     }
10252                     AtaCtl->Version.Length      = sizeof(GETDRVVERSION);
10253                     AtaCtl->Version.VersionMj   = UNIATA_VER_MJ;
10254                     AtaCtl->Version.VersionMn   = UNIATA_VER_MN;
10255                     AtaCtl->Version.SubVerMj    = UNIATA_VER_SUB_MJ;
10256                     AtaCtl->Version.SubVerMn    = UNIATA_VER_SUB_MN;
10257 
10258                     status = SRB_STATUS_SUCCESS;
10259                     break;
10260                 }
10261                 case  IOCTL_SCSI_MINIPORT_UNIATA_ADAPTER_INFO: {
10262 
10263                     KdPrint2((PRINT_PREFIX "AtapiStartIo: Get adapter info\n"));
10264 
10265                     if(len < pos+sizeof(AtaCtl->AdapterInfo)) {
10266                         KdPrint2((PRINT_PREFIX "AtapiStartIo: AtaCtl Buffer too small: %#x < %#x\n", len,
10267                             pos+sizeof(AtaCtl->AdapterInfo) ));
10268                         goto wrong_buffer_size;
10269                     }
10270                     AtaCtl->AdapterInfo.HeaderLength = sizeof(ADAPTERINFO);
10271 
10272                     AtaCtl->AdapterInfo.DevID      = deviceExtension->DevID;
10273                     AtaCtl->AdapterInfo.RevID      = deviceExtension->RevID;
10274                     AtaCtl->AdapterInfo.slotNumber = deviceExtension->slotNumber;
10275                     AtaCtl->AdapterInfo.SystemIoBusNumber = deviceExtension->SystemIoBusNumber;
10276                     AtaCtl->AdapterInfo.DevIndex   = deviceExtension->DevIndex;
10277                     AtaCtl->AdapterInfo.Channel    = deviceExtension->Channel;
10278                     AtaCtl->AdapterInfo.HbaCtrlFlags = deviceExtension->HbaCtrlFlags;
10279                     AtaCtl->AdapterInfo.simplexOnly= deviceExtension->simplexOnly;
10280                     AtaCtl->AdapterInfo.MemIo      = FALSE;/*deviceExtension->MemIo;*/
10281                     AtaCtl->AdapterInfo.UnknownDev = deviceExtension->UnknownDev;
10282                     AtaCtl->AdapterInfo.MasterDev  = deviceExtension->MasterDev;
10283                     AtaCtl->AdapterInfo.MaxTransferMode = deviceExtension->MaxTransferMode;
10284                     AtaCtl->AdapterInfo.HwFlags    = deviceExtension->HwFlags;
10285                     AtaCtl->AdapterInfo.OrigAdapterInterfaceType = deviceExtension->OrigAdapterInterfaceType;
10286                     AtaCtl->AdapterInfo.BusInterruptLevel = deviceExtension->BusInterruptLevel;
10287                     AtaCtl->AdapterInfo.InterruptMode = deviceExtension->InterruptMode;
10288                     AtaCtl->AdapterInfo.BusInterruptVector = deviceExtension->BusInterruptVector;
10289                     AtaCtl->AdapterInfo.NumberChannels = deviceExtension->NumberChannels;
10290                     AtaCtl->AdapterInfo.NumberLuns = (UCHAR)deviceExtension->NumberLuns;
10291                     AtaCtl->AdapterInfo.AdapterInterfaceType = deviceExtension->AdapterInterfaceType;
10292                     if(deviceExtension->FullDevName) {
10293                         strncpy(AtaCtl->AdapterInfo.DeviceName, deviceExtension->FullDevName, 64);
10294                     }
10295                     AtaCtl->AdapterInfo.ChanInfoValid = FALSE;
10296                     AtaCtl->AdapterInfo.LunInfoValid = FALSE;
10297                     AtaCtl->AdapterInfo.ChanHeaderLengthValid = TRUE;
10298 
10299                     pos += AtaCtl->AdapterInfo.HeaderLength;
10300 
10301                     // zero tail
10302                     RtlZeroMemory(((PCHAR)AtaCtl)+pos,
10303                         len-pos);
10304 
10305                     if(len >= pos+AtaCtl->AdapterInfo.NumberChannels*sizeof(CHANINFO)) {
10306                         PCHANINFO ChanInfo = (PCHANINFO)( ((PCHAR)AtaCtl)+pos );
10307                         PHW_CHANNEL cur_chan;
10308                         KdPrint2((PRINT_PREFIX "AtapiStartIo: Fill channel info\n"));
10309                         for(i=0;i<AtaCtl->AdapterInfo.NumberChannels;i++) {
10310                             KdPrint2((PRINT_PREFIX "chan[%d] %x\n", i, cur_chan));
10311                             cur_chan = &(deviceExtension->chan[i]);
10312                             ChanInfo->MaxTransferMode = cur_chan->MaxTransferMode;
10313                             ChanInfo->ChannelCtrlFlags = cur_chan->ChannelCtrlFlags;
10314                             RtlCopyMemory(&(ChanInfo->QueueStat), &(cur_chan->QueueStat), sizeof(ChanInfo->QueueStat));
10315                             ChanInfo->ReorderCount        = cur_chan->ReorderCount;
10316                             ChanInfo->IntersectCount      = cur_chan->IntersectCount;
10317                             ChanInfo->TryReorderCount     = cur_chan->TryReorderCount;
10318                             ChanInfo->TryReorderHeadCount = cur_chan->TryReorderHeadCount;
10319                             ChanInfo->TryReorderTailCount = cur_chan->TryReorderTailCount;
10320                             //ChanInfo->opt_MaxTransferMode = cur_chan->opt_MaxTransferMode;
10321                             ChanInfo++;
10322                         }
10323                         AtaCtl->AdapterInfo.ChanInfoValid = TRUE;
10324                         AtaCtl->AdapterInfo.ChanHeaderLength = sizeof(*ChanInfo);
10325                     }
10326 
10327                     status = SRB_STATUS_SUCCESS;
10328                     break;
10329                 }
10330                 case  IOCTL_SCSI_MINIPORT_UNIATA_RESETBB: {
10331 
10332                     KdPrint2((PRINT_PREFIX "AtapiStartIo: Forget BB list\n"));
10333 
10334                     ForgetBadBlocks(LunExt);
10335 
10336                     status = SRB_STATUS_SUCCESS;
10337                     break;
10338                 }
10339                 case  IOCTL_SCSI_MINIPORT_UNIATA_RESET_DEVICE: {
10340 
10341                     KdPrint2((PRINT_PREFIX "AtapiStartIo: Reset device\n"));
10342 
10343                     if(bad_ldev) {
10344                         goto do_bus_reset;
10345                     } else {
10346                         UniataUserDeviceReset(deviceExtension, LunExt, AtaCtl->addr.PathId);
10347                     }
10348 
10349                     status = SRB_STATUS_SUCCESS;
10350                     break;
10351                 }
10352                 default :
10353                     KdPrint2((PRINT_PREFIX "AtapiStartIo: invalid IoControl %#x for -UNIATA- signature\n",
10354                                 AtaCtl->hdr.ControlCode ));
10355                     status = SRB_STATUS_INVALID_REQUEST;
10356                     break;
10357                 }
10358 
10359             } else {
10360                 KdPrint2((PRINT_PREFIX "AtapiStartIo: IoControl signature incorrect. Send %s, expected %s or %s\n",
10361                             ((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature,
10362                             "SCSIDISK", "-UNIATA-"));
10363 
10364                 status = SRB_STATUS_INVALID_REQUEST;
10365                 break;
10366             }
10367 
10368             break;
10369         } // end SRB_FUNCTION_IO_CONTROL
10370         default:
10371 
10372             KdPrint2((PRINT_PREFIX "AtapiStartIo: Unknown IOCTL\n"));
10373             // Indicate unsupported command.
10374             status = SRB_STATUS_INVALID_REQUEST;
10375 
10376 //            break;
10377 
10378         } // end switch
10379 
10380 complete_req:
10381 
10382         PathId   = Srb->PathId;
10383         TargetId = Srb->TargetId;
10384         Lun      = Srb->Lun;
10385 
10386         if (status != SRB_STATUS_PENDING) {
10387 
10388             KdPrint2((PRINT_PREFIX
10389                        "AtapiStartIo: Srb %#x complete with status %#x\n",
10390                        Srb,
10391                        status));
10392 
10393             // Set status in SRB.
10394             Srb->SrbStatus = (UCHAR)status;
10395 
10396             if(chan && Srb) {
10397                 KdPrint2((PRINT_PREFIX "AtapiStartIo: AtapiDmaDBSync(%x, %x)\n", chan, Srb));
10398                 AtapiDmaDBSync(chan, Srb);
10399             }
10400             KdPrint2((PRINT_PREFIX "AtapiStartIo: UniataRemoveRequest(%x, %x)\n", chan, Srb));
10401             UniataRemoveRequest(chan, Srb);
10402             // Indicate command complete.
10403             KdPrint2((PRINT_PREFIX "AtapiStartIo: ScsiPortNotification\n"));
10404             ScsiPortNotification(RequestComplete,
10405                                  deviceExtension,
10406                                  Srb);
10407 
10408             KdPrint2((PRINT_PREFIX "AtapiStartIo: UniataGetCurRequest\n"));
10409             // Remove current Srb & get next one
10410             if((Srb = UniataGetCurRequest(chan))) {
10411                 AtaReq = (PATA_REQ)(Srb->SrbExtension);
10412                 if(AtaReq->ReqState > REQ_STATE_QUEUED) {
10413                     // current request is under precessing, thus
10414                     // we should do nothing here
10415                     Srb = NULL;
10416                 }
10417             }
10418             KdPrint2((PRINT_PREFIX "AtapiStartIo: chan %x, Src %x\n", chan, Srb));
10419             if(!chan) {
10420                 //ASSERT(TopLevel);
10421             }
10422         }
10423         KdPrint2((PRINT_PREFIX "AtapiStartIo: next Srb %x\n", Srb));
10424 
10425     } while (Srb && (status != SRB_STATUS_PENDING));
10426 
10427     KdPrint2((PRINT_PREFIX "AtapiStartIo: query PORT for next request\n"));
10428     // Indicate ready for next request.
10429     ScsiPortNotification(NextRequest,
10430                          deviceExtension,
10431                          NULL);
10432 
10433     ScsiPortNotification(NextLuRequest,
10434                          deviceExtension,
10435                          PathId,
10436                          TargetId,
10437                          Lun);
10438 
10439     return TRUE;
10440 
10441 } // end AtapiStartIo__()
10442 
10443 #if 0
10444 void
10445 NTAPI
10446 UniataInitAtaCommands()
10447 {
10448     int i;
10449     UCHAR command;
10450     UCHAR flags;
10451 
10452     KdPrint2((PRINT_PREFIX "UniataInitAtaCommands:\n"));
10453 
10454     for(i=0; i<256; i++) {
10455 
10456         flags = 0;
10457         command = i;
10458 
10459         //KdPrint2((PRINT_PREFIX "cmd %2.2x: ", command));
10460 
10461         switch(command) {
10462         case IDE_COMMAND_READ_DMA48:
10463         case IDE_COMMAND_READ_DMA_Q48:
10464         case IDE_COMMAND_READ_STREAM_DMA48:
10465         case IDE_COMMAND_READ_STREAM48:
10466         case IDE_COMMAND_WRITE_DMA48:
10467         case IDE_COMMAND_WRITE_DMA_Q48:
10468         case IDE_COMMAND_READ_DMA_Q:
10469         case IDE_COMMAND_READ_DMA:
10470         case IDE_COMMAND_WRITE_DMA:
10471         case IDE_COMMAND_WRITE_DMA_Q:
10472         case IDE_COMMAND_WRITE_STREAM_DMA48:
10473         case IDE_COMMAND_WRITE_STREAM48:
10474         case IDE_COMMAND_WRITE_FUA_DMA48:
10475         case IDE_COMMAND_WRITE_FUA_DMA_Q48:
10476         case IDE_COMMAND_READ_LOG_DMA48:
10477         case IDE_COMMAND_WRITE_LOG_DMA48:
10478         case IDE_COMMAND_TRUSTED_RCV_DMA:
10479         case IDE_COMMAND_TRUSTED_SEND_DMA:
10480         case IDE_COMMAND_DATA_SET_MGMT: // TRIM
10481             //KdPrint2((PRINT_PREFIX "DMA "));
10482             flags |= ATA_CMD_FLAG_DMA;
10483         }
10484 
10485         switch(command) {
10486         case IDE_COMMAND_WRITE_FUA_DMA48:
10487         case IDE_COMMAND_WRITE_FUA_DMA_Q48:
10488         case IDE_COMMAND_WRITE_MUL_FUA48:
10489 
10490             flags |= ATA_CMD_FLAG_FUA;
10491             /* FALL THROUGH */
10492 
10493         case IDE_COMMAND_READ48:
10494         case IDE_COMMAND_READ_DMA48:
10495         case IDE_COMMAND_READ_DMA_Q48:
10496         case IDE_COMMAND_READ_MUL48:
10497         case IDE_COMMAND_READ_STREAM_DMA48:
10498         case IDE_COMMAND_READ_STREAM48:
10499         case IDE_COMMAND_WRITE48:
10500         case IDE_COMMAND_WRITE_DMA48:
10501         case IDE_COMMAND_WRITE_DMA_Q48:
10502         case IDE_COMMAND_WRITE_MUL48:
10503         case IDE_COMMAND_WRITE_STREAM_DMA48:
10504         case IDE_COMMAND_WRITE_STREAM48:
10505         case IDE_COMMAND_FLUSH_CACHE48:
10506         case IDE_COMMAND_VERIFY48:
10507 
10508             //KdPrint2((PRINT_PREFIX "48 "));
10509             flags |= ATA_CMD_FLAG_48;
10510             /* FALL THROUGH */
10511 
10512         case IDE_COMMAND_READ:
10513         case IDE_COMMAND_READ_MULTIPLE:
10514         case IDE_COMMAND_READ_DMA:
10515         case IDE_COMMAND_READ_DMA_Q:
10516         case IDE_COMMAND_WRITE:
10517         case IDE_COMMAND_WRITE_MULTIPLE:
10518         case IDE_COMMAND_WRITE_DMA:
10519         case IDE_COMMAND_WRITE_DMA_Q:
10520         case IDE_COMMAND_FLUSH_CACHE:
10521         case IDE_COMMAND_VERIFY:
10522 
10523             //KdPrint2((PRINT_PREFIX "LBA "));
10524             flags |= ATA_CMD_FLAG_LBAIOsupp;
10525         }
10526 
10527         switch(command) {
10528         case IDE_COMMAND_READ_NATIVE_SIZE48:
10529         case IDE_COMMAND_SET_NATIVE_SIZE48:
10530             // we cannot set LBA flag for these commands to avoid BadBlock handling
10531             //flags |= ATA_CMD_FLAG_LBAIOsupp;
10532             flags |= ATA_CMD_FLAG_48;
10533 
10534         case IDE_COMMAND_READ_NATIVE_SIZE:
10535         case IDE_COMMAND_SET_NATIVE_SIZE:
10536 
10537             flags |= ATA_CMD_FLAG_LBAIOsupp | ATA_CMD_FLAG_FUA;
10538         }
10539 
10540         flags |= ATA_CMD_FLAG_48supp;
10541 
10542         switch (command) {
10543         case IDE_COMMAND_READ:
10544             command = IDE_COMMAND_READ48; break;
10545         case IDE_COMMAND_READ_MULTIPLE:
10546             command = IDE_COMMAND_READ_MUL48; break;
10547         case IDE_COMMAND_READ_DMA:
10548             command = IDE_COMMAND_READ_DMA48; break;
10549         case IDE_COMMAND_READ_DMA_Q:
10550             command = IDE_COMMAND_READ_DMA_Q48; break;
10551         case IDE_COMMAND_WRITE:
10552             command = IDE_COMMAND_WRITE48; break;
10553         case IDE_COMMAND_WRITE_MULTIPLE:
10554             command = IDE_COMMAND_WRITE_MUL48; break;
10555         case IDE_COMMAND_WRITE_DMA:
10556             command = IDE_COMMAND_WRITE_DMA48; break;
10557         case IDE_COMMAND_WRITE_DMA_Q:
10558             command = IDE_COMMAND_WRITE_DMA_Q48; break;
10559         case IDE_COMMAND_FLUSH_CACHE:
10560             command = IDE_COMMAND_FLUSH_CACHE48; break;
10561     //    case IDE_COMMAND_READ_NATIVE_SIZE:
10562     //            command = IDE_COMMAND_READ_NATIVE_SIZE48; break;
10563         case IDE_COMMAND_SET_NATIVE_SIZE:
10564             command = IDE_COMMAND_SET_NATIVE_SIZE48; break;
10565         case IDE_COMMAND_VERIFY:
10566             command = IDE_COMMAND_VERIFY48; break;
10567         default:
10568             //KdPrint2((PRINT_PREFIX "!28->48 "));
10569             flags &= ~ATA_CMD_FLAG_48supp;
10570         }
10571 
10572         switch (command) {
10573         case IDE_COMMAND_READ:
10574         case IDE_COMMAND_READ_MULTIPLE:
10575         case IDE_COMMAND_READ_DMA48:
10576         case IDE_COMMAND_READ_DMA_Q48:
10577         case IDE_COMMAND_READ_STREAM_DMA48:
10578         case IDE_COMMAND_READ_STREAM48:
10579         case IDE_COMMAND_READ_DMA_Q:
10580         case IDE_COMMAND_READ_DMA:
10581         case IDE_COMMAND_READ_LOG_DMA48:
10582         case IDE_COMMAND_TRUSTED_RCV_DMA:
10583         case IDE_COMMAND_IDENTIFY:
10584         case IDE_COMMAND_ATAPI_IDENTIFY:
10585             //KdPrint2((PRINT_PREFIX "RD "));
10586             flags |= ATA_CMD_FLAG_In;
10587             break;
10588         case IDE_COMMAND_WRITE:
10589         case IDE_COMMAND_WRITE_MULTIPLE:
10590         case IDE_COMMAND_WRITE_DMA48:
10591         case IDE_COMMAND_WRITE_DMA_Q48:
10592         case IDE_COMMAND_WRITE_DMA:
10593         case IDE_COMMAND_WRITE_DMA_Q:
10594         case IDE_COMMAND_WRITE_STREAM_DMA48:
10595         case IDE_COMMAND_WRITE_STREAM48:
10596         case IDE_COMMAND_WRITE_FUA_DMA48:
10597         case IDE_COMMAND_WRITE_FUA_DMA_Q48:
10598             //KdPrint2((PRINT_PREFIX "WR "));
10599             flags |= ATA_CMD_FLAG_Out;
10600             break;
10601         }
10602 
10603         //KdPrint2((PRINT_PREFIX "\t -> %2.2x (%2.2x)\n", command, flags));
10604         AtaCommands48[i]   = command;
10605         AtaCommandFlags[i] = flags;
10606     }
10607 } // end UniataInitAtaCommands()
10608 #endif
10609 
10610 /*++
10611 
10612 Routine Description:
10613 
10614     Installable driver initialization entry point for system.
10615 
10616 Arguments:
10617 
10618     Driver Object
10619 
10620 Return Value:
10621 
10622     Status from ScsiPortInitialize()
10623 
10624 --*/
10625 extern "C"
10626 ULONG
10627 NTAPI
10628 DriverEntry(
10629     IN PVOID DriverObject,
10630     IN PVOID Argument2
10631     )
10632 {
10633     HW_INITIALIZATION_DATA_COMMON hwInitializationData;
10634     ULONG                  adapterCount;
10635     ULONG                  i, c, alt, pref_alt;
10636     ULONG                  statusToReturn, newStatus;
10637     PUNICODE_STRING        RegistryPath = (PUNICODE_STRING)Argument2;
10638     BOOLEAN                ReEnter = FALSE;
10639 //    WCHAR                  a;
10640 #ifndef USE_REACTOS_DDK
10641     NTSTATUS               status;
10642 #endif
10643 
10644     PCONFIGURATION_INFORMATION GlobalConfig = IoGetConfigurationInformation();
10645     BOOLEAN PrimaryClaimed   = FALSE;
10646     BOOLEAN SecondaryClaimed = FALSE;
10647     BOOLEAN IgnoreIsaCompatiblePci = FALSE;
10648     BOOLEAN IgnoreNativePci = FALSE;
10649 
10650     LARGE_INTEGER t0, t1;
10651 
10652     KdPrint2((PRINT_PREFIX "%s", (PCCHAR)ver_string));
10653     //a = (WCHAR)strlen(ver_string);
10654 
10655     statusToReturn = 0xffffffff;
10656 
10657     // Zero out structure.
10658     RtlZeroMemory(((PCHAR)&hwInitializationData), sizeof(hwInitializationData));
10659 
10660     // Set size of hwInitializationData.
10661     hwInitializationData.comm.HwInitializationDataSize =
10662       sizeof(hwInitializationData.comm) +
10663 //      sizeof(hwInitializationData.nt4) +
10664       ((WinVer_Id() <= WinVer_NT) ? 0 : sizeof(hwInitializationData.w2k));
10665     KdPrint(("HwInitializationDataSize = %x\n", hwInitializationData.comm.HwInitializationDataSize));
10666 
10667     // Set entry points.
10668     hwInitializationData.comm.HwInitialize = (PHW_INITIALIZE)AtapiHwInitialize;
10669     hwInitializationData.comm.HwResetBus = (PHW_RESET_BUS)AtapiResetController;
10670     hwInitializationData.comm.HwStartIo = (PHW_STARTIO)AtapiStartIo;
10671     hwInitializationData.comm.HwInterrupt = (PHW_INTERRUPT)AtapiInterrupt;
10672 
10673     // Specify size of extensions.
10674     hwInitializationData.comm.DeviceExtensionSize     = sizeof(HW_DEVICE_EXTENSION);
10675     hwInitializationData.comm.SpecificLuExtensionSize = sizeof(HW_LU_EXTENSION);
10676     hwInitializationData.comm.SrbExtensionSize        = sizeof(ATA_REQ);
10677 
10678     // Indicate PIO device.
10679     hwInitializationData.comm.MapBuffers = TRUE;
10680 
10681     // Request and parse arument string.
10682     KdPrint2((PRINT_PREFIX "\n\nUniATA: parse ArgumentString\n"));
10683     // Zero out structure.
10684     hwInitializationData.comm.NumberOfAccessRanges = 2;
10685     hwInitializationData.comm.HwFindAdapter = AtapiReadArgumentString;
10686     ScsiPortInitialize(DriverObject,
10687                                     Argument2,
10688                                     &hwInitializationData.comm,
10689                                     &adapterCount);
10690 
10691     if(!g_Dump) {
10692         Connect_DbgPrint();
10693         g_opt_Verbose = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"PrintLogo", 0);
10694         if(g_opt_Verbose) {
10695             _PrintNtConsole("Universal ATA driver v 0." UNIATA_VER_STR "\n");
10696         }
10697         IgnoreIsaCompatiblePci = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreIsaCompatiblePci", IgnoreIsaCompatiblePci) ? TRUE : FALSE;
10698         IgnoreNativePci = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreNativePci", IgnoreNativePci) ? TRUE : FALSE;
10699     } else {
10700         KdPrint(("crashdump mode\n"));
10701     }
10702 
10703     if(!SavedDriverObject) {
10704         SavedDriverObject = (PDRIVER_OBJECT)DriverObject;
10705 #ifdef USE_REACTOS_DDK
10706         KdPrint(("UniATA Init: OS should be ReactOS\n"));
10707         MajorVersion=0x04;
10708         MinorVersion=0x01;
10709         BuildNumber=1;
10710         CPU_num = KeNumberProcessors;
10711 #else
10712         // we are here for the 1st time
10713         // init CrossNT and get OS version
10714         if(!NT_SUCCESS(status = CrNtInit(SavedDriverObject, RegistryPath))) {
10715             KdPrint(("UniATA Init: CrNtInit failed with status %#x\n", status));
10716             //HalDisplayString((PUCHAR)"DbgPrnHkInitialize: CrNtInit failed\n");
10717             return status;
10718         }
10719         CPU_num = *KeNumberProcessors;
10720 #endif // USE_REACTOS_DDK
10721         KdPrint(("UniATA Init: OS ver %x.%x (%d), %d CPU(s)\n", MajorVersion, MinorVersion, BuildNumber, CPU_num));
10722 
10723         KeQuerySystemTime(&t0);
10724         do {
10725             KeQuerySystemTime(&t1);
10726         } while(t0.QuadPart == t1.QuadPart);
10727         t0=t1;
10728         g_Perf=0;
10729         do {
10730             KeQuerySystemTime(&t1);
10731             g_Perf++;
10732         } while(t0.QuadPart == t1.QuadPart);
10733         g_PerfDt = (ULONG)((t1.QuadPart - t0.QuadPart)/10);
10734         KdPrint(("Performance calibration: dt=%d, counter=%I64d\n", g_PerfDt, g_Perf ));
10735     } else {
10736         KdPrint(("UniATA Init: ReEnter\n"));
10737         ReEnter = TRUE;
10738     }
10739 
10740     // (re)read bad block list
10741     InitBadBlocks(NULL);
10742 
10743     if(!ReEnter) {
10744         // init ATA command translation table
10745         //UniataInitAtaCommands();
10746 
10747         // get registry path to settings
10748         RtlCopyMemory(&SavedRegPath, RegistryPath, sizeof(UNICODE_STRING));
10749         SavedRegPath.Buffer = (PWCHAR)&SavedRegPathBuffer;
10750         SavedRegPath.Length = min(RegistryPath->Length, 255*sizeof(WCHAR));
10751         SavedRegPath.MaximumLength = 255*sizeof(WCHAR);
10752         RtlCopyMemory(SavedRegPath.Buffer, RegistryPath->Buffer, SavedRegPath.Length);
10753         SavedRegPath.Buffer[SavedRegPath.Length/sizeof(WCHAR)] = 0;
10754     }
10755 
10756     if(WinVer_Id() >= WinVer_2k) {
10757         if(AtapiRegCheckParameterValue(NULL, L"Paramaters\\PnpInterface", L"1", 0)) {
10758             KdPrint(("UniATA: Behave as WDM, mlia (1)\n"));
10759             WinVer_WDM_Model = TRUE;
10760         }
10761         if(AtapiRegCheckParameterValue(NULL, L"Paramaters\\PnpInterface", L"5", 0)) {
10762             KdPrint(("UniATA: Behave as WDM, mlia (5)\n"));
10763             WinVer_WDM_Model = TRUE;
10764         }
10765     }
10766 
10767     SkipRaids = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"SkipRaids", 1);
10768     ForceSimplex = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"ForceSimplex", 0);
10769 #ifdef _DEBUG
10770     g_LogToDisplay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"LogToDisplay", 0);
10771 #endif //_DEBUG
10772 
10773     // Set PnP-specific API
10774     if(WinVer_Id() > WinVer_NT) {
10775         KdPrint(("set NeedPhysicalAddresses = TRUE\n"));
10776         hwInitializationData.comm.NeedPhysicalAddresses = TRUE;
10777         KdPrint(("set AtapiAdapterControl() ptr\n"));
10778         hwInitializationData.w2k.HwAdapterControl = (PHW_ADAPTER_CONTROL)AtapiAdapterControl;
10779     }
10780 
10781     KdPrint2((PRINT_PREFIX "\n\nUniATA init... (%d)\n", ReEnter));
10782     if(!ReEnter) {
10783 
10784         g_opt_VirtualMachine = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"VirtualMachineType", g_opt_VirtualMachine);
10785         if(g_opt_VirtualMachine > VM_MAX_KNOWN) {
10786             g_opt_VirtualMachine = 0;
10787         }
10788         if(AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"VirtualBox", (g_opt_VirtualMachine == VM_VBOX))) {
10789             g_opt_VirtualMachine = VM_VBOX;
10790         }
10791         // Pre-scan PCI bus, also check if we are under VM
10792         // But do not perform scan if PCI bus is claimed as unused
10793         if(!IgnoreIsaCompatiblePci || !IgnoreNativePci) {
10794             KdPrint2((PRINT_PREFIX "\nATAPI IDE enum supported PCI BusMaster Devices\n"));
10795             UniataEnumBusMasterController(DriverObject, Argument2);
10796         }
10797 
10798         switch(g_opt_VirtualMachine) {
10799         case VM_VBOX:
10800             KdPrint2((PRINT_PREFIX "adjust options for VirtualBox\n"));
10801             // adjust options for VirtualBox
10802             g_opt_WaitBusyCount = 20000;
10803             g_opt_WaitBusyDelay = 150;
10804             g_opt_WaitDrqDelay  = 100;
10805             g_opt_WaitBusyLongCount = 20000;
10806             g_opt_MaxIsrWait = 200;
10807             g_opt_AtapiSendDisableIntr = FALSE;
10808             g_opt_AtapiDmaRawRead = FALSE;
10809             break;
10810         case VM_BOCHS:
10811             KdPrint2((PRINT_PREFIX "adjust options for Bochs\n"));
10812             g_opt_AtapiNoDma = TRUE;
10813         }
10814 
10815         if(!hasPCI) {
10816             KdPrint2((PRINT_PREFIX "old slow machine, adjust timings\n"));
10817             // old slow machine, adjust timings (us)
10818             g_opt_WaitBusyResetCount = 20000;
10819             g_opt_WaitBusyCount = 20000;
10820             g_opt_WaitBusyDelay = 150;
10821             g_opt_WaitDrqDelay  = 100;
10822             g_opt_WaitBusyLongCount = 20000;
10823             g_opt_MaxIsrWait = 200;
10824             g_opt_DriveSelectNanoDelay = 400;
10825         }
10826         if(g_opt_VirtualMachine > VM_NONE) {
10827             g_opt_DriveSelectNanoDelay = 0;
10828         }
10829         if(CPU_num > 1) {
10830             g_opt_AtapiSendDisableIntr = TRUE;
10831         }
10832 
10833         g_opt_WaitBusyCount = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyCount", g_opt_WaitBusyCount); // 200 vs 20000
10834         g_opt_WaitBusyDelay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyDelay", g_opt_WaitBusyDelay); // 10 vs 150
10835         g_opt_WaitDrqDelay  = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitDrqDelay",  g_opt_WaitDrqDelay);  // 10 vs 100
10836         g_opt_WaitBusyLongCount = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyLongCount", g_opt_WaitBusyLongCount); // 2000 vs 20000
10837         g_opt_WaitBusyLongDelay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"WaitBusyLongDelay", g_opt_WaitBusyLongDelay); // 250 vs 250
10838         g_opt_AtapiSendDisableIntr = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiSendDisableIntr",  g_opt_AtapiSendDisableIntr) ? TRUE : FALSE;  // 1 vs 0
10839         g_opt_AtapiDmaRawRead      = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiDmaRawRead",       g_opt_AtapiDmaRawRead) ? TRUE : FALSE;       // 1 vs 0
10840         g_opt_AtapiNoDma    = (BOOLEAN)AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"AtapiNoDma", g_opt_AtapiNoDma) ? TRUE : FALSE;       // 1 vs 0
10841         g_opt_MaxIsrWait    = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"MaxIsrWait", g_opt_MaxIsrWait);       // 40 vs xxx
10842         g_opt_DriveSelectNanoDelay = AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"DriveSelectNanoDelay", g_opt_DriveSelectNanoDelay);
10843     } // end !re-enter
10844 
10845     // Look for legacy ISA-bridged PCI IDE controller (onboard)
10846     KdPrint2((PRINT_PREFIX "\n\nATAPI IDE: Look for legacy ISA-bridged PCI IDE controller (onboard)\n"));
10847     KdPrint2((PRINT_PREFIX "\n\nATAPI IDE: BMListLen %d\n", BMListLen));
10848     for (i=0; i <BMListLen; i++) {
10849 
10850         if(!BMList[i].MasterDev) {
10851             KdPrint2((PRINT_PREFIX "!BMList[i].MasterDev\n"));
10852             break;
10853         }
10854         if(IgnoreIsaCompatiblePci) {
10855             break;
10856         }
10857         if(ReEnter) {
10858             KdPrint2((PRINT_PREFIX "ReEnter, skip it\n"));
10859             if(BMList[i].ChanInitOk & 0x03) {
10860                 KdPrint2((PRINT_PREFIX "Already initialized, skip it\n"));
10861                 statusToReturn =
10862                 newStatus = STATUS_SUCCESS;
10863             }
10864             continue;
10865         }
10866         //BMList[i].AltInitMasterDev = (UCHAR)0xff;
10867 
10868         if(GlobalConfig->AtDiskPrimaryAddressClaimed)
10869             PrimaryClaimed = TRUE;
10870         if(GlobalConfig->AtDiskSecondaryAddressClaimed)
10871             SecondaryClaimed = TRUE;
10872         pref_alt = 0;
10873 
10874         if(!WinVer_WDM_Model && !PrimaryClaimed && !SecondaryClaimed && !g_Dump &&
10875             !(BMList[i].ChanInitOk & 0x80)) {
10876 
10877             // We just want to claim our PCI device in compatible mode, since we shall not
10878             // tell system that we use it inside HwInitialize
10879             // Even more, we shall cheat system, that work with ISA
10880             // Note: this call may (but not 'must' or 'can') cause IO resource
10881             // reallocation and switch to native mode if HAL supports this
10882             newStatus = (ULONG)UniataClaimLegacyPCIIDE(i);
10883             // Special check for NT3.51/NT4 (not ReactOS !!!)
10884             if(((NTSTATUS)newStatus == STATUS_CONFLICTING_ADDRESSES) &&
10885                //(BMList[i].ChanInitOk & 0x40) &&
10886                /*CPU_num > 1 &&*/
10887                (WinVer_Id() <= WinVer_NT)) {
10888                 // Some NT3/4 SMP (but not only) HALs cannot reallocate IO resources of
10889                 // BusMaster PCI controller
10890                 // Since nobody claimed Primary/Secondary yet, try init and claim them
10891                 // However it is not 100% safe way, especially under ReactOS, which doesn't resolve
10892                 // conflicts yet.
10893                 // We relay on ScsiPort internal checks
10894                 KdPrint2((PRINT_PREFIX "Can't acquire PCI part of BusMaster on SMP NT3/4 system, try init anyway.\n"));
10895                 newStatus = STATUS_SUCCESS;
10896                 // Prefer alternative init method (try to change Isa -> PCI in ConfigInfo first)
10897                 pref_alt = 1;
10898             }
10899             if(newStatus != STATUS_SUCCESS) {
10900                 KdPrint2((PRINT_PREFIX "Can't acquire PCI part of BusMaster, try as pure ISA later.\n"));
10901                 break;
10902             }
10903         }
10904 
10905         if(g_opt_Verbose) {
10906             _PrintNtConsole("Init standard Dual-channel PCI ATA controller:");
10907         }
10908 
10909         for(alt = 0; alt < (ULONG)(WinVer_WDM_Model ? 1 : 2) ; alt++) {
10910 
10911             for(c=0; c<2; c++) {
10912                 // check is channel is manually excluded
10913                 if(AtapiRegCheckDevValue(NULL, c, DEVNUM_NOT_SPECIFIED, L"IgnoreIsaCompatiblePci", 0)) {
10914                     break;
10915                 }
10916                 if(c==0) {
10917                     if(PrimaryClaimed) {
10918                         KdPrint2((PRINT_PREFIX "Primary already claimed\n"));
10919                         continue;
10920                     }
10921                 } else
10922                 if(c==1) {
10923                     if(SecondaryClaimed) {
10924                         KdPrint2((PRINT_PREFIX "Secondary already claimed\n"));
10925                         continue;
10926                     }
10927                 }
10928 
10929                 if((WinVer_Id() < WinVer_2k)) {
10930                     // do not even try if already claimed
10931                     if(c==0) {
10932                         GlobalConfig->AtDiskPrimaryAddressClaimed = FALSE;
10933                     } else
10934                     if(c==1) {
10935                         GlobalConfig->AtDiskSecondaryAddressClaimed = FALSE;
10936                     }
10937                 }
10938                 if(!WinVer_WDM_Model) {
10939                     hwInitializationData.comm.HwFindAdapter = UniataFindBusMasterController;
10940                 } else {
10941                     // in WDM model things are different....
10942                     hwInitializationData.comm.HwFindAdapter = (c == 0) ?
10943                         UniataFindCompatBusMasterController1 : UniataFindCompatBusMasterController2;
10944                 }
10945                 hwInitializationData.comm.NumberOfAccessRanges = 6;
10946                 hwInitializationData.comm.AdapterInterfaceType = Isa;
10947 
10948                 if(!WinVer_WDM_Model) {
10949                     BMList[i].channel = (UCHAR)c;
10950                 }
10951 
10952                 KdPrint2((PRINT_PREFIX "Try init channel %d, method %d\n", c, alt));
10953                 newStatus = ScsiPortInitialize(DriverObject,
10954                                                Argument2,
10955                                                &hwInitializationData.comm,
10956                                                UlongToPtr(i | ((alt ^ pref_alt) ? 0x80000000 : 0)));
10957                 KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x\n", newStatus));
10958                 if (newStatus < statusToReturn) {
10959                     statusToReturn = newStatus;
10960                 }
10961                 if (newStatus == STATUS_SUCCESS) {
10962                     if(WinVer_Id() < WinVer_2k) {
10963                         // This should be done in HwInitialize under w2k+ to ensure that
10964                         // channel is actually initialized
10965                         BMList[i].ChanInitOk |= 0x01 << c;
10966                     } else {
10967                         if(BMList[i].ChanInitOk & (0x01 << c)) {
10968                             KdPrint2((PRINT_PREFIX "HwInit passed\n"));
10969                         }
10970                     }
10971 /*
10972                     if(BMList[i].MasterDev && (WinVer_Id() > WinVer_NT)) {
10973                         c = 1; // this will break our for()
10974                         BMList[i].ChanInitOk |= 0x01 << c;
10975                     }
10976 */
10977                 }
10978             }
10979 /*            if(WinVer_Id() >= WinVer_2k) {
10980                 // the following didn't work under higher OSes,
10981                 // until we move setting of FLAGS to HwInit
10982                 KdPrint2((PRINT_PREFIX "make still one attempt\n"));
10983                 continue;
10984             }*/
10985             if(BMList[i].ChanInitOk & 0x03) {
10986                 // Under NT we receive status immediately, so
10987                 // we can omit alternative init method if STATUS_SUCCESS returned.
10988                 // Under w2k+ we relay on flags, set in HwInitialize.
10989                 KdPrint2((PRINT_PREFIX "Ok, no more retries required\n"));
10990                 break;
10991             } else
10992             if(WinVer_Id() >= WinVer_2k) {
10993                 // try AltInit if HwInit was not called immediately under w2k+
10994                 KdPrint2((PRINT_PREFIX "make still one attempt w2k+\n"));
10995             } else {
10996                 // if (WinVer_Id() == WinVer_NT) and some error occured
10997                 // try alternative init method
10998                 KdPrint2((PRINT_PREFIX "make still one attempt w2k+\n"));
10999             }
11000         } // for(alt...)
11001         if(g_opt_Verbose) {
11002             if(BMList[i].ChanInitOk & 0x03) {
11003                 _PrintNtConsole("  OK\n");
11004             } else {
11005                 _PrintNtConsole("  failed\n");
11006             }
11007         }
11008 
11009     }
11010 
11011 /*    KeBugCheckEx(0xc000000e,
11012                  (i << 16) | BMList[0].ChanInitOk,
11013                  c,
11014                  newStatus, statusToReturn);*/
11015 
11016     // Look for PCI IDE controller
11017     KdPrint2((PRINT_PREFIX "\n\nATAPI IDE: Look for PCI IDE controller\n"));
11018     KdPrint2((PRINT_PREFIX "\n\nATAPI IDE: i %d, BMListLen %d\n", i, BMListLen));
11019     for (; i <BMListLen; i++) {
11020 
11021         if(IgnoreNativePci) {
11022             break;
11023         }
11024 /*        if(BMList[i].MasterDev)
11025             continue;*/
11026         if(g_opt_Verbose) {
11027             _PrintNtConsole("Init PCI ATA controller Vendor/Dev %4.4s//%4.4s at PCI Address %d:%d:%d",
11028                 BMList[i].VendorId, BMList[i].DeviceId,
11029                 BMList[i].busNumber,
11030                 BMList[i].slotNumber % PCI_MAX_FUNCTION,
11031                 (BMList[i].slotNumber / PCI_MAX_FUNCTION) % PCI_MAX_DEVICES);
11032         }
11033 
11034         hwInitializationData.comm.HwFindAdapter = UniataFindBusMasterController;
11035         hwInitializationData.comm.NumberOfAccessRanges = 6;
11036         hwInitializationData.comm.AdapterInterfaceType = PCIBus;
11037 
11038         hwInitializationData.comm.VendorId             = (PVOID)BMList[i].VendorId;
11039         hwInitializationData.comm.VendorIdLength       = (USHORT) BMList[i].VendorIdLength;
11040         hwInitializationData.comm.DeviceId             = (PVOID)BMList[i].DeviceId;
11041         hwInitializationData.comm.DeviceIdLength       = (USHORT) BMList[i].DeviceIdLength;
11042 
11043         BMList[i].channel = 0/*(UCHAR)c*/;
11044 
11045         KdPrint2((PRINT_PREFIX "Try init %4.4s %4.4s \n",
11046                                hwInitializationData.comm.VendorId,
11047                                hwInitializationData.comm.DeviceId));
11048         newStatus = ScsiPortInitialize(DriverObject,
11049                                        Argument2,
11050                                        &hwInitializationData.comm,
11051                                        UlongToPtr(i));
11052         KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x\n", newStatus));
11053         if(newStatus == (ULONG)STATUS_DEVICE_DOES_NOT_EXIST && BMList[i].NeedAltInit) {
11054             // Note: this is actually a BUG in scsiport.sys
11055             // It stops scanning PCI bus when reaches empty PCI Function inside Slot
11056             // However, this PCI Slot may have higher non-empty Functions
11057             // UniATA will perform all staff instead of ScsiPort under NT,
11058             // but for ReactOS it is better to patch ScsiPort.
11059             KdPrint2((PRINT_PREFIX "STATUS_DEVICE_DOES_NOT_EXIST, try workaround\n"));
11060             hwInitializationData.comm.AdapterInterfaceType = Isa;
11061             newStatus = ScsiPortInitialize(DriverObject,
11062                                            Argument2,
11063                                            &hwInitializationData.comm,
11064                                            UlongToPtr(i | 0x80000000));
11065             KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x (2)\n", newStatus));
11066         }
11067         if (newStatus < statusToReturn)
11068             statusToReturn = newStatus;
11069 
11070         if(g_opt_Verbose) {
11071             if(newStatus == STATUS_SUCCESS) {
11072                 _PrintNtConsole("  OK\n");
11073             } else {
11074                 _PrintNtConsole("  failed\n");
11075             }
11076         }
11077 
11078     }
11079 
11080 /*    KeBugCheckEx(0xc000000e,
11081                  i,
11082                  c,
11083                  newStatus, statusToReturn);*/
11084 
11085     // --------------
11086 
11087     hwInitializationData.comm.VendorId             = 0;
11088     hwInitializationData.comm.VendorIdLength       = 0;
11089     hwInitializationData.comm.DeviceId             = 0;
11090     hwInitializationData.comm.DeviceIdLength       = 0;
11091 
11092     if(!BMListLen) {
11093         hwInitializationData.comm.SrbExtensionSize        = //FIELD_OFFSET(ATA_REQ, ata);
11094                                                             sizeof(ATA_REQ);
11095         KdPrint2((PRINT_PREFIX "using AtaReq sz %x\n", hwInitializationData.comm.SrbExtensionSize));
11096     }
11097 
11098     // The adapter count is used by the find adapter routine to track how
11099     // which adapter addresses have been tested.
11100 
11101     // Indicate 2 access ranges and reset FindAdapter.
11102     hwInitializationData.comm.NumberOfAccessRanges = 2;
11103     hwInitializationData.comm.HwFindAdapter = AtapiFindIsaController;
11104 
11105     if(!AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreIsa", 0)) {
11106         // Indicate ISA bustype.
11107         hwInitializationData.comm.AdapterInterfaceType = Isa;
11108         adapterCount = 0;
11109 
11110         // Call initialization for ISA bustype.
11111         KdPrint2((PRINT_PREFIX "\n\nATAPI IDE: Look for ISA Controllers\n"));
11112         newStatus =  ScsiPortInitialize(DriverObject,
11113                                         Argument2,
11114                                         &hwInitializationData.comm,
11115                                         &adapterCount);
11116         KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x\n", newStatus));
11117         if (newStatus < statusToReturn)
11118             statusToReturn = newStatus;
11119     }
11120     if(!AtapiRegCheckDevValue(NULL, CHAN_NOT_SPECIFIED, DEVNUM_NOT_SPECIFIED, L"IgnoreMca", 0)) {
11121         // Set up for MCA
11122         KdPrint2((PRINT_PREFIX "\n\nATAPI IDE: Look for MCA Controllers\n"));
11123         hwInitializationData.comm.AdapterInterfaceType = MicroChannel;
11124         adapterCount = 0;
11125 
11126         newStatus =  ScsiPortInitialize(DriverObject,
11127                                         Argument2,
11128                                         &hwInitializationData.comm,
11129                                         &adapterCount);
11130         KdPrint2((PRINT_PREFIX "ScsiPortInitialize Status %#x\n", newStatus));
11131         if (newStatus < statusToReturn)
11132             statusToReturn = newStatus;
11133     }
11134     InDriverEntry = FALSE;
11135 
11136     KdPrint2((PRINT_PREFIX "\n\nLeave UNIATA MiniPort DriverEntry with status %#x\n", statusToReturn));
11137 
11138     return statusToReturn;
11139 
11140 } // end DriverEntry()
11141 
11142 
11143 PSCSI_REQUEST_BLOCK
11144 NTAPI
11145 BuildMechanismStatusSrb(
11146     IN PVOID HwDeviceExtension,
11147     IN PSCSI_REQUEST_BLOCK Srb
11148     )
11149 {
11150     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
11151     PSCSI_REQUEST_BLOCK srb;
11152     PCDB cdb;
11153     PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension);
11154 
11155     srb = &(deviceExtension->chan[GET_CHANNEL(Srb)].InternalSrb);
11156 
11157     RtlZeroMemory((PCHAR) srb, sizeof(SCSI_REQUEST_BLOCK));
11158 
11159     srb->PathId     = (UCHAR)(Srb->PathId);
11160     srb->TargetId   = (UCHAR)(Srb->TargetId);
11161     srb->Function   = SRB_FUNCTION_EXECUTE_SCSI;
11162     srb->Length     = sizeof(SCSI_REQUEST_BLOCK);
11163 
11164     // Set flags to disable synchronous negociation.
11165     srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
11166 
11167     // Set timeout to 4 seconds.
11168     srb->TimeOutValue = 4;
11169 
11170     srb->CdbLength          = 6;
11171     srb->DataBuffer         = &(deviceExtension->chan[GET_CHANNEL(Srb)].MechStatusData);
11172     srb->DataTransferLength = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER);
11173     srb->SrbExtension       = AtaReq;
11174 
11175     // Set CDB operation code.
11176     cdb = (PCDB)srb->Cdb;
11177     cdb->MECH_STATUS.OperationCode       = SCSIOP_MECHANISM_STATUS;
11178     cdb->MECH_STATUS.AllocationLength[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER);
11179 
11180     KdPrint2((PRINT_PREFIX " MechanismStatusSrb %#x\n", srb));
11181 
11182     return srb;
11183 } // end BuildMechanismStatusSrb()
11184 
11185 #endif //UNIATA_CORE
11186 
11187 PSCSI_REQUEST_BLOCK
11188 NTAPI
11189 BuildRequestSenseSrb (
11190     IN PVOID HwDeviceExtension,
11191     IN PSCSI_REQUEST_BLOCK Srb
11192     )
11193 {
11194     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
11195     PSCSI_REQUEST_BLOCK srb;
11196     PCDB cdb;
11197     PATA_REQ AtaReq = (PATA_REQ)(Srb->SrbExtension);
11198 
11199     srb = &(deviceExtension->chan[GET_CHANNEL(Srb)].InternalSrb);
11200 
11201     RtlZeroMemory((PCHAR) srb, sizeof(SCSI_REQUEST_BLOCK));
11202 
11203     srb->PathId     = (UCHAR)(Srb->PathId);
11204     srb->TargetId   = (UCHAR)(Srb->TargetId);
11205     srb->Function   = SRB_FUNCTION_EXECUTE_SCSI;
11206     srb->Length     = sizeof(SCSI_REQUEST_BLOCK);
11207 
11208     // Set flags to disable synchronous negociation.
11209     srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
11210 
11211     // Set timeout to 2 seconds.
11212     srb->TimeOutValue = 4;
11213 
11214     srb->CdbLength          = 6;
11215     srb->DataBuffer         = &(deviceExtension->chan[GET_CHANNEL(Srb)].MechStatusSense);
11216     srb->DataTransferLength = sizeof(SENSE_DATA);
11217     srb->SrbExtension       = AtaReq;
11218 
11219     // Set CDB operation code.
11220     cdb = (PCDB)srb->Cdb;
11221     cdb->CDB6INQUIRY.OperationCode    = SCSIOP_REQUEST_SENSE;
11222     cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA);
11223 
11224     KdPrint2((PRINT_PREFIX " RequestSenseSrb %#x\n", srb));
11225 
11226     return srb;
11227 } // end BuildRequestSenseSrb()
11228 
11229 #ifndef UNIATA_CORE
11230 
11231 ULONG
11232 NTAPI
11233 AtapiRegCheckDevLunValue(
11234     IN PVOID HwDeviceExtension,
11235     IN PCWCH NamePrefix,
11236     IN ULONG chan,
11237     IN ULONG dev,
11238     IN PCWSTR Name,
11239     IN ULONG Default
11240     )
11241 {
11242     WCHAR namex[160];
11243     ULONG val = Default;
11244 
11245     val = AtapiRegCheckParameterValue(
11246         HwDeviceExtension, NamePrefix, Name, val);
11247 
11248     if(chan != CHAN_NOT_SPECIFIED) {
11249         swprintf(namex, L"%s\\Chan_%1.1d", NamePrefix, chan);
11250         val = AtapiRegCheckParameterValue(
11251             HwDeviceExtension, namex, Name, val);
11252         if(dev != DEVNUM_NOT_SPECIFIED) {
11253             swprintf(namex, L"%s\\Chan_%1.1d\\%s", NamePrefix, chan, (dev & 0x01) ? L"Lun_1" : L"Lun_0");
11254             val = AtapiRegCheckParameterValue(
11255                 HwDeviceExtension, namex, Name, val);
11256         }
11257     }
11258     return val;
11259 } // end AtapiRegCheckDevLunValue()
11260 
11261 ULONG
11262 NTAPI
11263 EncodeVendorStr(
11264    OUT PWCHAR Buffer,
11265     IN PUCHAR Str,
11266     IN ULONG  Length
11267     )
11268 {
11269     ULONG i,j;
11270     WCHAR a;
11271 
11272     for(i=0, j=0; i<Length; i++, j++) {
11273         // fix byte-order
11274         a = Str[i ^ 0x01];
11275         if(!a) {
11276             Buffer[j] = 0;
11277             return j;
11278         } else
11279         if(a == ' ') {
11280             Buffer[j] = '_';
11281         } else
11282         if((a == '_') ||
11283            (a == '#') ||
11284            (a == '\\') ||
11285            (a == '\"') ||
11286            (a == '\'') ||
11287            (a <  ' ') ||
11288            (a >= 127)) {
11289             Buffer[j] = '#';
11290             j++;
11291             swprintf(Buffer+j, L"%2.2x", a);
11292             j++;
11293         } else {
11294             Buffer[j] = a;
11295         }
11296     }
11297     Buffer[j] = 0;
11298     return j;
11299 } // end EncodeVendorStr()
11300 
11301 ULONG
11302 NTAPI
11303 AtapiRegCheckDevValue(
11304     IN PVOID HwDeviceExtension,
11305     IN ULONG chan,
11306     IN ULONG dev,
11307     IN PCWSTR Name,
11308     IN ULONG Default
11309     )
11310 {
11311     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
11312 //    WCHAR name0[11];
11313 //    WCHAR name1[11+4+5];
11314 //    WCHAR name2[11+4+4+10];
11315 //    WCHAR name3[11+4+4+5+20];
11316 //    WCHAR name3[11+4+4+5+20+1];
11317     WCHAR namex[160];
11318 
11319     WCHAR namev[16];
11320     WCHAR named[16];
11321     WCHAR names[20];
11322 
11323     IN ULONG VendorID;
11324     IN ULONG DeviceID;
11325     IN ULONG SlotNumber;
11326     IN ULONG HwFlags;
11327 
11328     ULONG val = Default;
11329 
11330     KdPrint(( " Parameter %ws\n", Name));
11331 
11332     if(deviceExtension) {
11333         VendorID   =  deviceExtension->DevID        & 0xffff;
11334         DeviceID   = (deviceExtension->DevID >> 16) & 0xffff;
11335         SlotNumber = deviceExtension->slotNumber;
11336         HwFlags    = deviceExtension->HwFlags;
11337     } else {
11338         VendorID   = 0xffff;
11339         DeviceID   = 0xffff;
11340         SlotNumber = 0xffffffff;
11341         HwFlags    = 0;
11342     }
11343 
11344     val = AtapiRegCheckDevLunValue(
11345         HwDeviceExtension, L"Parameters", chan, dev, Name, val);
11346 
11347     if(deviceExtension) {
11348 
11349         if(HwFlags & UNIATA_SATA) {
11350             swprintf(namev, L"\\SATA");
11351             swprintf(namex, L"Parameters%s", namev);
11352             val = AtapiRegCheckDevLunValue(
11353                 HwDeviceExtension, namex, chan, dev, Name, val);
11354         }
11355         if(HwFlags & UNIATA_AHCI) {
11356             swprintf(namev, L"\\AHCI");
11357             swprintf(namex, L"Parameters%s", namev);
11358             val = AtapiRegCheckDevLunValue(
11359                 HwDeviceExtension, namex, chan, dev, Name, val);
11360         }
11361         if(!(HwFlags & (UNIATA_SATA | UNIATA_AHCI))) {
11362             swprintf(namev, L"\\PATA");
11363             swprintf(namex, L"Parameters%s", namev);
11364             val = AtapiRegCheckDevLunValue(
11365                 HwDeviceExtension, namex, chan, dev, Name, val);
11366         }
11367 
11368         if(deviceExtension->AdapterInterfaceType == PCIBus) {
11369             // PCI
11370             swprintf(namev, L"\\IDE_%d", deviceExtension->DevIndex);
11371             swprintf(namex, L"Parameters%s", namev);
11372             val = AtapiRegCheckDevLunValue(
11373                 HwDeviceExtension, namex, chan, dev, Name, val);
11374 
11375 
11376             swprintf(namev, L"\\Ven_%4.4x", VendorID);
11377             swprintf(named, L"\\Dev_%4.4x", DeviceID);
11378             swprintf(names, L"\\Slot_%8.8x", SlotNumber);
11379 
11380             swprintf(namex, L"Parameters%s", namev);
11381             val = AtapiRegCheckDevLunValue(
11382                 HwDeviceExtension, namex, chan, dev, Name, val);
11383 
11384             swprintf(namex, L"Parameters%s%s", namev, named);
11385             val = AtapiRegCheckDevLunValue(
11386                 HwDeviceExtension, namex, chan, dev, Name, val);
11387 
11388             swprintf(namex, L"Parameters%s%s%s", namev, named, names);
11389             val = AtapiRegCheckDevLunValue(
11390                 HwDeviceExtension, namex, chan, dev, Name, val);
11391         } else
11392         if(deviceExtension->AdapterInterfaceType == Isa) {
11393             // Isa
11394             swprintf(namev, L"\\IDE_%d", deviceExtension->DevIndex+BMListLen);
11395             swprintf(namex, L"Parameters%s", namev);
11396             val = AtapiRegCheckDevLunValue(
11397                 HwDeviceExtension, namex, chan, dev, Name, val);
11398 
11399             swprintf(namev, L"\\ISA_%d", deviceExtension->DevIndex);
11400             swprintf(namex, L"Parameters%s", namev);
11401             val = AtapiRegCheckDevLunValue(
11402                 HwDeviceExtension, namex, chan, dev, Name, val);
11403 
11404         } else
11405         if(deviceExtension->AdapterInterfaceType == MicroChannel) {
11406             // MicroChannel
11407             swprintf(namev, L"\\IDE_%d", deviceExtension->DevIndex+BMListLen+IsaCount);
11408             swprintf(namex, L"Parameters%s", namev);
11409             val = AtapiRegCheckDevLunValue(
11410                 HwDeviceExtension, namex, chan, dev, Name, val);
11411 
11412             swprintf(namev, L"\\MCA_%d", deviceExtension->DevIndex);
11413             swprintf(namex, L"Parameters%s", namev);
11414             val = AtapiRegCheckDevLunValue(
11415                 HwDeviceExtension, namex, chan, dev, Name, val);
11416 
11417         }
11418     }
11419 
11420     KdPrint(( " Parameter %ws = %#x\n", Name, val));
11421     return val;
11422 
11423 } // end AtapiRegCheckDevValue()
11424 
11425 /*
11426     The user must specify that Xxx is to run on the platform
11427     by setting the registry value HKEY_LOCAL_MACHINE\System\CurrentControlSet\
11428     Services\UniATA\Xxx:REG_DWORD:Zzz.
11429 
11430     The user can override the global setting to enable or disable Xxx on a
11431     specific cdrom device by setting the key HKEY_LOCAL_MACHINE\System\
11432     CurrentControlSet\Services\UniATA\Parameters\Device<N>\Xxx:REG_DWORD to one or zero.
11433 
11434     If this registry value does not exist or contains the value zero then
11435     the timer to check for media change does not run.
11436 
11437     Arguments:
11438 
11439     RegistryPath - pointer to the unicode string inside
11440                    ...\CurrentControlSet\Services\UniATA
11441     DeviceNumber - The number of the HBA device object
11442 
11443     Returns:    Registry Key value
11444  */
11445 ULONG
11446 NTAPI
11447 AtapiRegCheckParameterValue(
11448     IN PVOID HwDeviceExtension,
11449     IN PCWSTR PathSuffix,
11450     IN PCWSTR Name,
11451     IN ULONG Default
11452     )
11453 {
11454 #define ITEMS_TO_QUERY 2 // always 1 greater than what is searched
11455 
11456 //    PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
11457     NTSTATUS          status;
11458     LONG              zero = Default;
11459 
11460     RTL_QUERY_REGISTRY_TABLE parameters[ITEMS_TO_QUERY];
11461 
11462 //    LONG              tmp = 0;
11463     LONG              doRun = Default;
11464 
11465     PUNICODE_STRING   RegistryPath = &SavedRegPath;
11466 
11467     UNICODE_STRING    paramPath;
11468 
11469     if(g_Dump) {
11470         goto failed;
11471     }
11472 
11473     // <SavedRegPath>\<PathSuffix> -> <Name>
11474 //    KdPrint(( "AtapiCheckRegValue: %ws -> %ws\n", PathSuffix, Name));
11475 //    KdPrint(( "AtapiCheckRegValue: RegistryPath %ws\n", RegistryPath->Buffer));
11476 
11477     paramPath.Length = 0;
11478     paramPath.MaximumLength = RegistryPath->Length +
11479         (wcslen(PathSuffix)+2)*sizeof(WCHAR);
11480     paramPath.Buffer = (PWCHAR)ExAllocatePool(NonPagedPool, paramPath.MaximumLength);
11481     if(!paramPath.Buffer) {
11482         KdPrint(("AtapiCheckRegValue: couldn't allocate paramPath\n"));
11483         return Default;
11484     }
11485 
11486     RtlZeroMemory(paramPath.Buffer, paramPath.MaximumLength);
11487     RtlAppendUnicodeToString(&paramPath, RegistryPath->Buffer);
11488     RtlAppendUnicodeToString(&paramPath, L"\\");
11489     RtlAppendUnicodeToString(&paramPath, REGRTL_STR_PTYPE PathSuffix);
11490 
11491     // Check for the Xxx value.
11492     RtlZeroMemory(parameters, (sizeof(RTL_QUERY_REGISTRY_TABLE)*ITEMS_TO_QUERY));
11493 
11494     parameters[0].Flags         = RTL_QUERY_REGISTRY_DIRECT;
11495     parameters[0].Name          = REGRTL_STR_PTYPE Name;
11496     parameters[0].EntryContext  = &doRun;
11497     parameters[0].DefaultType   = REG_DWORD;
11498     parameters[0].DefaultData   = &zero;
11499     parameters[0].DefaultLength = sizeof(ULONG);
11500 
11501     status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE /*| RTL_REGISTRY_OPTIONAL*/,
11502                                     paramPath.Buffer, parameters, NULL, NULL);
11503     if(NT_SUCCESS(status)) {
11504         KdPrint(( "AtapiCheckRegValue: %ws -> %ws is %#x\n", PathSuffix, Name, doRun));
11505     }
11506 
11507     ExFreePool(paramPath.Buffer);
11508 
11509     if(!NT_SUCCESS(status)) {
11510 failed:
11511         doRun = Default;
11512     }
11513 
11514     return doRun;
11515 
11516 #undef ITEMS_TO_QUERY
11517 
11518 } // end AtapiRegCheckParameterValue()
11519 
11520 
11521 SCSI_ADAPTER_CONTROL_STATUS
11522 NTAPI
11523 AtapiAdapterControl(
11524     IN PVOID HwDeviceExtension,
11525     IN SCSI_ADAPTER_CONTROL_TYPE ControlType,
11526     IN PVOID Parameters
11527     )
11528 {
11529     PHW_DEVICE_EXTENSION deviceExtension = (PHW_DEVICE_EXTENSION)HwDeviceExtension;
11530     PSCSI_SUPPORTED_CONTROL_TYPE_LIST pControlTypeList;
11531     ULONG                numberChannels  = deviceExtension->NumberChannels;
11532     ULONG c;
11533     NTSTATUS status;
11534 
11535     KdPrint(( "AtapiAdapterControl: %#x\n", ControlType));
11536 
11537     switch(ControlType) {
11538         case ScsiQuerySupportedControlTypes: {
11539             BOOLEAN supportedTypes[ScsiAdapterControlMax] = {
11540                 TRUE,       // ScsiQuerySupportedControlTypes
11541                 TRUE,       // ScsiStopAdapter
11542                 TRUE,       // ScsiRestartAdapter
11543                 FALSE,      // ScsiSetBootConfig
11544                 FALSE       // ScsiSetRunningConfig
11545             };
11546 
11547             ULONG lim = ScsiAdapterControlMax;
11548             ULONG i;
11549 
11550             pControlTypeList = (PSCSI_SUPPORTED_CONTROL_TYPE_LIST) Parameters;
11551 
11552             if(pControlTypeList->MaxControlType < lim) {
11553                 lim = pControlTypeList->MaxControlType;
11554             }
11555 
11556             for(i = 0; i < lim; i++) {
11557                 pControlTypeList->SupportedTypeList[i] = supportedTypes[i];
11558             }
11559 
11560             break;
11561 
11562         }
11563         case ScsiStopAdapter: {
11564 
11565             KdPrint(( "AtapiAdapterControl: ScsiStopAdapter\n"));
11566             // Shut down all interrupts on the adapter.  They'll get re-enabled
11567             // by the initialization routines.
11568             for (c = 0; c < numberChannels; c++) {
11569                 AtapiResetController(deviceExtension, c);
11570                 AtapiDisableInterrupts(deviceExtension, c);
11571             }
11572             if(deviceExtension->AdapterInterfaceType == PCIBus) {
11573                 // we must never get here for non-PCI
11574                 /*status =*/ UniataDisconnectIntr2(HwDeviceExtension);
11575                 BMList[deviceExtension->DevIndex].Isr2Enable = FALSE;
11576             }
11577             break;
11578         }
11579         case ScsiRestartAdapter: {
11580 
11581             KdPrint(( "AtapiAdapterControl: ScsiRestartAdapter\n"));
11582             // Enable all the interrupts on the adapter while port driver call
11583             // for power up an HBA that was shut down for power management
11584 
11585             AtapiChipInit(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, CHAN_NOT_SPECIFIED);
11586             status = UniataConnectIntr2(HwDeviceExtension);
11587             if(NT_SUCCESS(status)) {
11588                 for (c = 0; c < numberChannels; c++) {
11589                     AtapiChipInit(HwDeviceExtension, DEVNUM_NOT_SPECIFIED, c);
11590                     FindDevices(HwDeviceExtension, 0, c);
11591                     AtapiEnableInterrupts(deviceExtension, c);
11592                     AtapiHwInitialize__(deviceExtension, c);
11593                 }
11594                 if(deviceExtension->Isr2DevObj) {
11595                     // we must never get here for non-PCI
11596                     BMList[deviceExtension->DevIndex].Isr2Enable = TRUE;
11597                 }
11598             }
11599 
11600             break;
11601         }
11602 
11603         default: {
11604             KdPrint(( "AtapiAdapterControl: default => return ScsiAdapterControlUnsuccessful\n"));
11605             return ScsiAdapterControlUnsuccessful;
11606         }
11607     }
11608 
11609     return ScsiAdapterControlSuccess;
11610 } // end AtapiAdapterControl()
11611 
11612 #endif //UNIATA_CORE
11613 
11614 extern "C"
11615 NTHALAPI
11616 VOID
11617 NTAPI
11618 HalDisplayString (
11619     PUCHAR String
11620     );
11621 
11622 #define DEBUG_MSG_BUFFER_SIZE   512
11623 
11624 extern "C"
11625 VOID
11626 _cdecl
11627 _PrintNtConsole(
11628     PCCH DebugMessage,
11629     ...
11630     )
11631 {
11632     //int len;
11633     UCHAR dbg_print_tmp_buff[DEBUG_MSG_BUFFER_SIZE];
11634 //    UNICODE_STRING msgBuff;
11635     va_list ap;
11636     va_start(ap, DebugMessage);
11637 
11638     /*len =*/ _vsnprintf((PCHAR)&dbg_print_tmp_buff[0], DEBUG_MSG_BUFFER_SIZE-1, DebugMessage, ap);
11639 
11640     dbg_print_tmp_buff[DEBUG_MSG_BUFFER_SIZE-1] = 0;
11641 
11642     //DbgPrint(((PCHAR)&(dbg_print_tmp_buff[0]))); // already done in KdPrint macro
11643     HalDisplayString(dbg_print_tmp_buff);
11644 
11645 #ifdef _DEBUG
11646     if(g_LogToDisplay > 1) {
11647         AtapiStallExecution(g_LogToDisplay*1000);
11648     }
11649 #endif // _DEBUG
11650 
11651     va_end(ap);
11652 
11653 } // end PrintNtConsole()
11654 
11655