:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / storage / atapi / atapi.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2001, 2002 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /* $Id$
20  *
21  * COPYRIGHT:   See COPYING in the top level directory
22  * PROJECT:     ReactOS ATAPI miniport driver
23  * FILE:        services/storage/atapi/atapi.c
24  * PURPOSE:     ATAPI miniport driver
25  * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de)
26  * REVISIONS:
27  *              09-09-2001 Created
28  */
29
30 /*
31  * Note:
32  *   This driver is derived from Rex Jolliff's ide driver. Lots of his
33  *   routines are still in here although they belong into the higher level
34  *   drivers. They will be moved away as soon as possible.
35  */
36
37 /*
38  * TODO:
39  *      - implement sending of atapi commands
40  *      - handle removable atapi non-cdrom drives
41  */
42
43 #define ENABLE_PCI
44 #define ENABLE_ISA
45
46 //  -------------------------------------------------------------------------
47
48 #include <ddk/ntddk.h>
49 #include <ddk/srb.h>
50 #include <ddk/scsi.h>
51 #include <ddk/ntddscsi.h>
52
53 #include "atapi.h"
54
55 #define NDEBUG
56 #include <debug.h>
57
58 #define VERSION  "0.0.1"
59
60
61 //  -------------------------------------------------------  File Static Data
62
63 //    ATAPI_MINIPORT_EXTENSION
64 //
65 //  DESCRIPTION:
66 //    Extension to be placed in each port device object
67 //
68 //  ACCESS:
69 //    Allocated from NON-PAGED POOL
70 //    Available at any IRQL
71 //
72
73 typedef struct _ATAPI_MINIPORT_EXTENSION
74 {
75   IDE_DRIVE_IDENTIFY DeviceParams[2];
76   BOOLEAN DevicePresent[2];
77   BOOLEAN DeviceAtapi[2];
78
79   ULONG CommandPortBase;
80   ULONG ControlPortBase;
81   ULONG BusMasterRegisterBase;
82
83   BOOLEAN ExpectingInterrupt;
84   PSCSI_REQUEST_BLOCK CurrentSrb;
85
86   PUSHORT DataBuffer;
87 } ATAPI_MINIPORT_EXTENSION, *PATAPI_MINIPORT_EXTENSION;
88
89
90 typedef struct _UNIT_EXTENSION
91 {
92   ULONG Dummy;
93 } UNIT_EXTENSION, *PUNIT_EXTENSION;
94
95
96 //  -----------------------------------------------  Discardable Declarations
97
98 #ifdef  ALLOC_PRAGMA
99
100 //  make the initialization routines discardable, so that they 
101 //  don't waste space
102
103 #pragma  alloc_text(init, DriverEntry)
104 #pragma  alloc_text(init, IDECreateController)
105 #pragma  alloc_text(init, IDEPolledRead)
106
107 //  make the PASSIVE_LEVEL routines pageable, so that they don't
108 //  waste nonpaged memory
109
110 #pragma  alloc_text(page, IDEShutdown)
111 #pragma  alloc_text(page, IDEDispatchOpenClose)
112 #pragma  alloc_text(page, IDEDispatchRead)
113 #pragma  alloc_text(page, IDEDispatchWrite)
114
115 #endif  /*  ALLOC_PRAGMA  */
116
117 //  ---------------------------------------------------- Forward Declarations
118
119 static ULONG STDCALL
120 AtapiFindCompatiblePciController(PVOID DeviceExtension,
121                                  PVOID HwContext,
122                                  PVOID BusInformation,
123                                  PCHAR ArgumentString,
124                                  PPORT_CONFIGURATION_INFORMATION ConfigInfo,
125                                  PBOOLEAN Again);
126
127 static ULONG STDCALL
128 AtapiFindIsaBusController(PVOID DeviceExtension,
129                           PVOID HwContext,
130                           PVOID BusInformation,
131                           PCHAR ArgumentString,
132                           PPORT_CONFIGURATION_INFORMATION ConfigInfo,
133                           PBOOLEAN Again);
134
135 static ULONG STDCALL
136 AtapiFindNativePciController(PVOID DeviceExtension,
137                              PVOID HwContext,
138                              PVOID BusInformation,
139                              PCHAR ArgumentString,
140                              PPORT_CONFIGURATION_INFORMATION ConfigInfo,
141                              PBOOLEAN Again);
142
143 static BOOLEAN STDCALL
144 AtapiInitialize(IN PVOID DeviceExtension);
145
146 static BOOLEAN STDCALL
147 AtapiResetBus(IN PVOID DeviceExtension,
148               IN ULONG PathId);
149
150 static BOOLEAN STDCALL
151 AtapiStartIo(IN PVOID DeviceExtension,
152              IN PSCSI_REQUEST_BLOCK Srb);
153
154 static BOOLEAN STDCALL
155 AtapiInterrupt(IN PVOID DeviceExtension);
156
157 static BOOLEAN
158 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
159                  PPORT_CONFIGURATION_INFORMATION ConfigInfo);
160
161 static BOOLEAN
162 AtapiIdentifyDevice(IN ULONG CommandPort,
163                     IN ULONG ControlPort,
164                     IN ULONG DriveNum,
165                     IN BOOLEAN Atapi,
166                     OUT PIDE_DRIVE_IDENTIFY DrvParms);
167
168 static BOOLEAN
169 IDEResetController(IN ULONG CommandPort,
170                    IN ULONG ControlPort);
171
172 static int
173 AtapiPolledRead(IN ULONG CommandPort,
174                 IN ULONG ControlPort,
175                 IN BYTE PreComp,
176                 IN BYTE SectorCnt,
177                 IN BYTE SectorNum,
178                 IN BYTE CylinderLow,
179                 IN BYTE CylinderHigh,
180                 IN BYTE DrvHead,
181                 IN BYTE Command,
182                 OUT BYTE *Buffer);
183
184
185
186 static ULONG
187 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
188                       IN PSCSI_REQUEST_BLOCK Srb);
189
190 static ULONG
191 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
192                     IN PSCSI_REQUEST_BLOCK Srb);
193
194 static ULONG
195 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
196              IN PSCSI_REQUEST_BLOCK Srb);
197
198 static ULONG
199 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
200                   IN PSCSI_REQUEST_BLOCK Srb);
201
202 static ULONG
203 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
204                IN PSCSI_REQUEST_BLOCK Srb);
205
206
207 static UCHAR
208 AtapiErrorToScsi(PVOID DeviceExtension,
209                  PSCSI_REQUEST_BLOCK Srb);
210
211 //  ----------------------------------------------------------------  Inlines
212
213 void
214 IDESwapBytePairs(char *Buf,
215                  int Cnt)
216 {
217   char  t;
218   int   i;
219
220   for (i = 0; i < Cnt; i += 2)
221     {
222       t = Buf[i];
223       Buf[i] = Buf[i+1];
224       Buf[i+1] = t;
225     }
226 }
227
228
229 //  -------------------------------------------------------  Public Interface
230
231 //    DriverEntry
232 //
233 //  DESCRIPTION:
234 //    This function initializes the driver, locates and claims 
235 //    hardware resources, and creates various NT objects needed
236 //    to process I/O requests.
237 //
238 //  RUN LEVEL:
239 //    PASSIVE_LEVEL
240 //
241 //  ARGUMENTS:
242 //    IN  PDRIVER_OBJECT   DriverObject  System allocated Driver Object
243 //                                       for this driver
244 //    IN  PUNICODE_STRING  RegistryPath  Name of registry driver service 
245 //                                       key
246 //
247 //  RETURNS:
248 //    NTSTATUS
249
250 STDCALL NTSTATUS
251 DriverEntry(IN PDRIVER_OBJECT DriverObject,
252             IN PUNICODE_STRING RegistryPath)
253 {
254   HW_INITIALIZATION_DATA InitData;
255   NTSTATUS Status;
256
257   DPRINT("ATAPI Driver %s\n", VERSION);
258   DPRINT("RegistryPath: '%wZ'\n", RegistryPath);
259
260   /* Initialize data structure */
261   RtlZeroMemory(&InitData,
262                 sizeof(HW_INITIALIZATION_DATA));
263   InitData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
264   InitData.HwInitialize = AtapiInitialize;
265   InitData.HwResetBus = AtapiResetBus;
266   InitData.HwStartIo = AtapiStartIo;
267   InitData.HwInterrupt = AtapiInterrupt;
268
269   InitData.DeviceExtensionSize = sizeof(ATAPI_MINIPORT_EXTENSION);
270   InitData.SpecificLuExtensionSize = sizeof(UNIT_EXTENSION);
271
272   InitData.MapBuffers = TRUE;
273
274   /* Search the PCI bus for compatibility mode ide controllers */
275 #ifdef ENABLE_PCI
276   InitData.HwFindAdapter = AtapiFindCompatiblePciController;
277   InitData.NumberOfAccessRanges = 3;
278   InitData.AdapterInterfaceType = PCIBus;
279
280   InitData.VendorId = NULL;
281   InitData.VendorIdLength = 0;
282   InitData.DeviceId = NULL;
283   InitData.DeviceIdLength = 0;
284
285   Status = ScsiPortInitialize(DriverObject,
286                               RegistryPath,
287                               &InitData,
288                               NULL);
289 //  if (newStatus < statusToReturn)
290 //    statusToReturn = newStatus;
291 #endif
292
293   /* Search the ISA bus for ide controllers */
294 #ifdef ENABLE_ISA
295   InitData.HwFindAdapter = AtapiFindIsaBusController;
296   InitData.NumberOfAccessRanges = 2;
297   InitData.AdapterInterfaceType = Isa;
298
299   InitData.VendorId = NULL;
300   InitData.VendorIdLength = 0;
301   InitData.DeviceId = NULL;
302   InitData.DeviceIdLength = 0;
303
304   Status = ScsiPortInitialize(DriverObject,
305                               RegistryPath,
306                               &InitData,
307                               NULL);
308 //      if (newStatus < statusToReturn)
309 //        statusToReturn = newStatus;
310 #endif
311
312   /* Search the PCI bus for native mode ide controllers */
313 #if 0
314   InitData.HwFindAdapter = AtapiFindNativePciController;
315   InitData.NumberOfAccessRanges = 2;
316   InitData.AdapterInterfaceType = PCIBus;
317
318   InitData.VendorId = NULL;
319   InitData.VendorIdLength = 0;
320   InitData.DeviceId = NULL;
321   InitData.DeviceIdLength = 0;
322
323   Status = ScsiPortInitialize(DriverObject,
324                               RegistryPath,
325                               &InitData,
326                               (PVOID)i);
327 //  if (newStatus < statusToReturn)
328 //    statusToReturn = newStatus;
329 #endif
330
331   DPRINT("Returning from DriverEntry\n");
332
333   return(Status);
334 }
335
336
337 static ULONG STDCALL
338 AtapiFindCompatiblePciController(PVOID DeviceExtension,
339                                  PVOID HwContext,
340                                  PVOID BusInformation,
341                                  PCHAR ArgumentString,
342                                  PPORT_CONFIGURATION_INFORMATION ConfigInfo,
343                                  PBOOLEAN Again)
344 {
345   PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
346   PCI_SLOT_NUMBER SlotNumber;
347   PCI_COMMON_CONFIG PciConfig;
348   ULONG DataSize;
349   ULONG FunctionNumber;
350   BOOLEAN ChannelFound;
351   BOOLEAN DeviceFound;
352
353   DPRINT("AtapiFindCompatiblePciController() Bus: %lu  Slot: %lu\n",
354           ConfigInfo->SystemIoBusNumber,
355           ConfigInfo->SlotNumber);
356
357   *Again = FALSE;
358
359   /* both channels were claimed: exit */
360   if (ConfigInfo->AtdiskPrimaryClaimed == TRUE &&
361       ConfigInfo->AtdiskSecondaryClaimed == TRUE)
362     return(SP_RETURN_NOT_FOUND);
363
364
365   SlotNumber.u.AsULONG = 0;
366   for (FunctionNumber = 0 /*ConfigInfo->SlotNumber*/; FunctionNumber < 256; FunctionNumber++)
367     {
368       SlotNumber.u.AsULONG = FunctionNumber;
369
370       ChannelFound = FALSE;
371       DeviceFound = FALSE;
372
373       DataSize = ScsiPortGetBusData(DeviceExtension,
374                                     PCIConfiguration,
375                                     0,
376                                     SlotNumber.u.AsULONG,
377                                     &PciConfig,
378                                     sizeof(PCI_COMMON_CONFIG));
379 //      if (DataSize != sizeof(PCI_COMMON_CONFIG) ||
380 //        PciConfig.VendorID == PCI_INVALID_VENDORID)
381       if (DataSize == 0)
382         {
383 //        if ((SlotNumber.u.AsULONG & 0x07) == 0)
384 //          return(SP_RETURN_ERROR); /* No bus found */
385
386           continue;
387 //        return(SP_RETURN_ERROR);
388         }
389
390       if (PciConfig.BaseClass == 0x01 &&
391           PciConfig.SubClass == 0x01) // &&
392 //        (PciConfig.ProgIf & 0x05) == 0)
393         {
394           /* both channels are in compatibility mode */
395           DPRINT("Bus %1lu  Device %2lu  Func %1lu  VenID 0x%04hx  DevID 0x%04hx\n",
396                  ConfigInfo->SystemIoBusNumber,
397                  SlotNumber.u.bits.DeviceNumber,
398                  SlotNumber.u.bits.FunctionNumber,
399                  PciConfig.VendorID,
400                  PciConfig.DeviceID);
401           DPRINT("ProgIF 0x%02hx\n", PciConfig.ProgIf);
402
403           DPRINT("Found IDE controller in compatibility mode!\n");
404
405           ConfigInfo->NumberOfBuses = 1;
406           ConfigInfo->MaximumNumberOfTargets = 2;
407           ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
408
409           if (PciConfig.ProgIf & 0x80)
410             {
411               DPRINT("Found IDE Bus Master controller!\n");
412               if (PciConfig.u.type0.BaseAddresses[4] & 0x00000001)
413                 {
414                   DPRINT("  IDE Bus Master Registers at IO %lx\n",
415                           PciConfig.u.type0.BaseAddresses[4] & ~0x00000003);
416                 }
417             }
418
419           if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
420             {
421               /* Both channels unclaimed: Claim primary channel */
422               DPRINT("Primary channel!\n");
423
424               DevExt->CommandPortBase = 0x01F0;
425               DevExt->ControlPortBase = 0x03F6;
426
427               ConfigInfo->BusInterruptLevel = 14;
428               ConfigInfo->BusInterruptVector = 14;
429               ConfigInfo->InterruptMode = LevelSensitive;
430
431               ConfigInfo->AccessRanges[0].RangeStart =
432                 ScsiPortConvertUlongToPhysicalAddress(0x01F0);
433               ConfigInfo->AccessRanges[0].RangeLength = 8;
434               ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
435
436               ConfigInfo->AccessRanges[1].RangeStart =
437                 ScsiPortConvertUlongToPhysicalAddress(0x03F6);
438               ConfigInfo->AccessRanges[1].RangeLength = 1;
439               ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
440
441               /* Claim bus master registers */
442               if (PciConfig.ProgIf & 0x80)
443                 {
444                   DevExt->BusMasterRegisterBase =
445                     PciConfig.u.type0.BaseAddresses[4] & ~0x00000003;
446
447                   ConfigInfo->AccessRanges[2].RangeStart =
448                     ScsiPortConvertUlongToPhysicalAddress(DevExt->BusMasterRegisterBase);
449                   ConfigInfo->AccessRanges[2].RangeLength = 8;
450                   ConfigInfo->AccessRanges[2].RangeInMemory = FALSE;
451                 }
452
453               ConfigInfo->AtdiskPrimaryClaimed = TRUE;
454               ChannelFound = TRUE;
455               *Again = TRUE;
456             }
457           else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
458             {
459               /* Primary channel already claimed: claim secondary channel */
460               DPRINT("Secondary channel!\n");
461
462               DevExt->CommandPortBase = 0x0170;
463               DevExt->ControlPortBase = 0x0376;
464
465               ConfigInfo->BusInterruptLevel = 15;
466               ConfigInfo->BusInterruptVector = 15;
467               ConfigInfo->InterruptMode = LevelSensitive;
468
469               ConfigInfo->AccessRanges[0].RangeStart =
470                 ScsiPortConvertUlongToPhysicalAddress(0x0170);
471               ConfigInfo->AccessRanges[0].RangeLength = 8;
472               ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
473
474               ConfigInfo->AccessRanges[1].RangeStart =
475                 ScsiPortConvertUlongToPhysicalAddress(0x0376);
476               ConfigInfo->AccessRanges[1].RangeLength = 1;
477               ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
478
479               /* Claim bus master registers */
480               if (PciConfig.ProgIf & 0x80)
481                 {
482                   DevExt->BusMasterRegisterBase =
483                     (PciConfig.u.type0.BaseAddresses[4] & ~0x00000003) + 8;
484
485                   ConfigInfo->AccessRanges[2].RangeStart =
486                     ScsiPortConvertUlongToPhysicalAddress(DevExt->BusMasterRegisterBase);
487                   ConfigInfo->AccessRanges[2].RangeLength = 8;
488                   ConfigInfo->AccessRanges[2].RangeInMemory = FALSE;
489                 }
490
491               ConfigInfo->AtdiskSecondaryClaimed = TRUE;
492               ChannelFound = TRUE;
493               *Again = FALSE;
494             }
495
496           /* Find attached devices */
497           if (ChannelFound == TRUE)
498             {
499               DeviceFound = AtapiFindDevices(DevExt,
500                                              ConfigInfo);
501             }
502           DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
503           return(SP_RETURN_FOUND);
504         }
505     }
506
507   DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
508
509   return(SP_RETURN_NOT_FOUND);
510 }
511
512
513 static ULONG STDCALL
514 AtapiFindIsaBusController(PVOID DeviceExtension,
515                           PVOID HwContext,
516                           PVOID BusInformation,
517                           PCHAR ArgumentString,
518                           PPORT_CONFIGURATION_INFORMATION ConfigInfo,
519                           PBOOLEAN Again)
520 {
521   PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
522   BOOLEAN ChannelFound = FALSE;
523   BOOLEAN DeviceFound = FALSE;
524
525   DPRINT("AtapiFindIsaBusController() called!\n");
526
527   *Again = FALSE;
528
529   ConfigInfo->NumberOfBuses = 1;
530   ConfigInfo->MaximumNumberOfTargets = 2;
531   ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
532
533   if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
534     {
535       /* Both channels unclaimed: Claim primary channel */
536       DPRINT("Primary channel!\n");
537
538       DevExt->CommandPortBase = 0x01F0;
539       DevExt->ControlPortBase = 0x03F6;
540
541       ConfigInfo->BusInterruptLevel = 14;
542       ConfigInfo->BusInterruptVector = 14;
543       ConfigInfo->InterruptMode = LevelSensitive;
544
545       ConfigInfo->AccessRanges[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x01F0);
546       ConfigInfo->AccessRanges[0].RangeLength = 8;
547       ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
548
549       ConfigInfo->AccessRanges[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x03F6);
550       ConfigInfo->AccessRanges[1].RangeLength = 1;
551       ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
552
553       ConfigInfo->AtdiskPrimaryClaimed = TRUE;
554       ChannelFound = TRUE;
555       *Again = FALSE/*TRUE*/;
556     }
557   else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
558     {
559       /* Primary channel already claimed: claim secondary channel */
560       DPRINT("Secondary channel!\n");
561
562       DevExt->CommandPortBase = 0x0170;
563       DevExt->ControlPortBase = 0x0376;
564
565       ConfigInfo->BusInterruptLevel = 15;
566       ConfigInfo->BusInterruptVector = 15;
567       ConfigInfo->InterruptMode = LevelSensitive;
568
569       ConfigInfo->AccessRanges[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x0170);
570       ConfigInfo->AccessRanges[0].RangeLength = 8;
571       ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
572
573       ConfigInfo->AccessRanges[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x0376);
574       ConfigInfo->AccessRanges[1].RangeLength = 1;
575       ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
576
577       ConfigInfo->AtdiskSecondaryClaimed = TRUE;
578       ChannelFound = TRUE;
579       *Again = FALSE;
580     }
581   else
582     {
583       DPRINT("AtapiFindIsaBusController() both channels claimed. Returns: SP_RETURN_NOT_FOUND\n");
584       *Again = FALSE;
585       return(SP_RETURN_NOT_FOUND);
586     }
587
588   /* Find attached devices */
589   if (ChannelFound)
590     {
591       DeviceFound = AtapiFindDevices(DevExt,
592                                      ConfigInfo);
593     }
594
595   DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
596   return(SP_RETURN_FOUND);
597 }
598
599
600 static ULONG STDCALL
601 AtapiFindNativePciController(PVOID DeviceExtension,
602                              PVOID HwContext,
603                              PVOID BusInformation,
604                              PCHAR ArgumentString,
605                              PPORT_CONFIGURATION_INFORMATION ConfigInfo,
606                              PBOOLEAN Again)
607 {
608   PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
609
610   DPRINT("AtapiFindNativePciController() called!\n");
611
612   *Again = FALSE;
613
614   DPRINT("AtapiFindNativePciController() done!\n");
615
616   return(SP_RETURN_NOT_FOUND);
617 }
618
619
620 static BOOLEAN STDCALL
621 AtapiInitialize(IN PVOID DeviceExtension)
622 {
623   return(TRUE);
624 }
625
626
627 static BOOLEAN STDCALL
628 AtapiResetBus(IN PVOID DeviceExtension,
629               IN ULONG PathId)
630 {
631   return(TRUE);
632 }
633
634
635 static BOOLEAN STDCALL
636 AtapiStartIo(IN PVOID DeviceExtension,
637              IN PSCSI_REQUEST_BLOCK Srb)
638 {
639   PATAPI_MINIPORT_EXTENSION DevExt;
640   ULONG Result;
641
642   DPRINT("AtapiStartIo() called\n");
643
644   DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
645
646   switch (Srb->Function)
647     {
648       case SRB_FUNCTION_EXECUTE_SCSI:
649         DevExt->CurrentSrb = Srb;
650         if (DevExt->DeviceAtapi[Srb->TargetId] == TRUE)
651           {
652             Result = AtapiSendAtapiCommand(DevExt,
653                                            Srb);
654           }
655         else
656           {
657             Result = AtapiSendIdeCommand(DevExt,
658                                          Srb);
659           }
660         break;
661
662     }
663
664   Srb->SrbStatus = Result;
665
666
667   if (Result != SRB_STATUS_PENDING)
668     {
669       DevExt->CurrentSrb = NULL;
670       Srb->SrbStatus = (UCHAR)Result;
671
672       ScsiPortNotification(RequestComplete,
673                            DeviceExtension,
674                            Srb);
675       ScsiPortNotification(NextRequest,
676                            DeviceExtension,
677                            NULL);
678     }
679   else
680     {
681       DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
682     }
683
684   DPRINT("AtapiStartIo() done\n");
685
686   return(TRUE);
687 }
688
689
690 static BOOLEAN STDCALL
691 AtapiInterrupt(IN PVOID DeviceExtension)
692 {
693   PATAPI_MINIPORT_EXTENSION DevExt;
694   PSCSI_REQUEST_BLOCK Srb;
695   ULONG CommandPortBase;
696   ULONG ControlPortBase;
697
698   UCHAR DeviceStatus;
699   BOOLEAN IsLastBlock;
700   BOOLEAN IsAtapi;
701   ULONG Retries;
702   PUCHAR TargetAddress;
703   ULONG SectorSize;
704   ULONG TransferSize;
705
706   DPRINT("AtapiInterrupt() called!\n");
707
708   DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
709   if (DevExt->ExpectingInterrupt == FALSE)
710     {
711       DPRINT("AtapiInterrupt(): Unexpected interrupt\n");
712       return(FALSE);
713     }
714
715   Srb = DevExt->CurrentSrb;
716   DPRINT("Srb: %p\n", Srb);
717
718   CommandPortBase = DevExt->CommandPortBase;
719   ControlPortBase = DevExt->ControlPortBase;
720   DPRINT("CommandPortBase: %lx  ControlPortBase: %lx\n", CommandPortBase, ControlPortBase);
721
722   IsAtapi = DevExt->DeviceAtapi[Srb->TargetId];
723   DPRINT("IsAtapi == %s\n", (IsAtapi) ? "TRUE" : "FALSE");
724
725   IsLastBlock = FALSE;
726
727   DeviceStatus = IDEReadStatus(CommandPortBase);
728   DPRINT("DeviceStatus: %x\n", DeviceStatus);
729
730   if (DeviceStatus & IDE_SR_BUSY)
731     {
732       /* Wait for BUSY to drop */
733       for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
734         {
735           DeviceStatus = IDEReadStatus(CommandPortBase);
736           if (!(DeviceStatus & IDE_SR_BUSY))
737             {
738               break;
739             }
740           ScsiPortStallExecution(10);
741         }
742       if (Retries >= IDE_MAX_BUSY_RETRIES)
743         {
744           DPRINT1("Drive is BUSY for too long\n");
745           /* FIXME: handle timeout */
746         }
747     }
748
749   if ((DeviceStatus & IDE_SR_ERR) &&
750       (Srb->Cdb[0] != SCSIOP_REQUEST_SENSE))
751     {
752       /* Report error condition */
753       Srb->SrbStatus = SRB_STATUS_ERROR;
754       IsLastBlock = TRUE;
755     }
756   else
757     {
758       if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
759         {
760           DPRINT("Read data\n");
761
762           /* Update controller/device state variables */
763           TargetAddress = Srb->DataBuffer;
764
765           if (IsAtapi)
766             {
767               TransferSize = IDEReadCylinderLow(CommandPortBase);
768               TransferSize += IDEReadCylinderHigh(CommandPortBase) << 8;
769             }
770           else
771             {
772               TransferSize = DevExt->DeviceParams[Srb->TargetId].BytesPerSector;
773             }
774
775           DPRINT("TransferLength: %lu\n", Srb->DataTransferLength);
776           DPRINT("TransferSize: %lu\n", TransferSize);
777
778           if (Srb->DataTransferLength <= TransferSize)
779             {
780               Srb->DataTransferLength = 0;
781               IsLastBlock = TRUE;
782             }
783           else
784             {
785               Srb->DataTransferLength -= TransferSize;
786               IsLastBlock = FALSE;
787             }
788           Srb->DataBuffer += TransferSize;
789           DPRINT("IsLastBlock == %s\n", (IsLastBlock) ? "TRUE" : "FALSE");
790
791           /* Wait for DRQ assertion */
792           for (Retries = 0; Retries < IDE_MAX_DRQ_RETRIES &&
793                !(IDEReadStatus(CommandPortBase) & IDE_SR_DRQ);
794                Retries++)
795             {
796                 KeStallExecutionProcessor(10);
797             }
798
799           /* Copy the block of data */
800           IDEReadBlock(CommandPortBase,
801                        TargetAddress,
802                        TransferSize);
803
804           /* check DRQ */
805           if (IsLastBlock)
806             {
807               for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
808                    (IDEReadStatus(CommandPortBase) & IDE_SR_BUSY);
809                    Retries++)
810                 {
811                   KeStallExecutionProcessor(10);
812                 }
813
814               /* Check for data overrun */
815               if (IDEReadStatus(CommandPortBase) & IDE_SR_DRQ)
816                 {
817                   /* FIXME: Handle error! */
818                   DPRINT1("AtapiInterrupt(): data overrun error!");
819                 }
820             }
821
822           Srb->SrbStatus = SRB_STATUS_SUCCESS;
823         }
824       else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
825         {
826           DPRINT("Write data\n");
827
828           if (Srb->DataTransferLength == 0)
829             {
830
831               for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
832                    (IDEReadStatus(CommandPortBase) & IDE_SR_BUSY);
833                    Retries++)
834                 {
835                   KeStallExecutionProcessor(10);
836                 }
837
838               /* Check for data overrun */
839               if (IDEReadStatus(CommandPortBase) & IDE_SR_DRQ)
840                 {
841                   /* FIXME: Handle error! */
842                   DPRINT1("AtapiInterrupt(): data overrun error!");
843                 }
844
845               DevExt->ExpectingInterrupt = FALSE;
846               IsLastBlock = TRUE;
847             }
848           else
849             {
850               /* Update SRB data */
851               SectorSize = DevExt->DeviceParams[Srb->TargetId].BytesPerSector;
852
853               TargetAddress = Srb->DataBuffer;
854               Srb->DataBuffer += SectorSize;
855               Srb->DataTransferLength -= SectorSize;
856
857               /* Write the sector */
858               IDEWriteBlock(CommandPortBase,
859                             TargetAddress,
860                             SectorSize);
861             }
862
863           Srb->SrbStatus = SRB_STATUS_SUCCESS;
864         }
865       else
866         {
867           DPRINT1("Unspecified transfer direction!\n");
868           Srb->SrbStatus = SRB_STATUS_SUCCESS; // SRB_STATUS_ERROR;
869           IsLastBlock = TRUE;
870         }
871     }
872
873
874   if (Srb->SrbStatus == SRB_STATUS_ERROR)
875     {
876       Srb->SrbStatus = AtapiErrorToScsi(DeviceExtension,
877                                         Srb);
878     }
879
880
881   /* complete this packet */
882   if (IsLastBlock)
883     {
884       DevExt->ExpectingInterrupt = FALSE;
885
886       ScsiPortNotification(RequestComplete,
887                            DeviceExtension,
888                            Srb);
889
890       ScsiPortNotification(NextRequest,
891                            DeviceExtension,
892                            NULL);
893     }
894
895   DPRINT("AtapiInterrupt() done!\n");
896
897   return(TRUE);
898 }
899
900
901
902
903
904
905 //  ----------------------------------------------------  Discardable statics
906
907
908 /**********************************************************************
909  * NAME                                                 INTERNAL
910  *      AtapiFindDevices
911  *
912  * DESCRIPTION
913  *      Searches for devices on the given port.
914  *
915  * RUN LEVEL
916  *      PASSIVE_LEVEL
917  *
918  * ARGUMENTS
919  *      DeviceExtension
920  *              Port device specific information.
921  *
922  *      ConfigInfo
923  *              Port configuration information.
924  *
925  * RETURN VALUE
926  *      TRUE: At least one device is attached to the port.
927  *      FALSE: No device is attached to the port.
928  */
929
930 static BOOLEAN
931 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
932                  PPORT_CONFIGURATION_INFORMATION ConfigInfo)
933 {
934   BOOLEAN DeviceFound = FALSE;
935   ULONG CommandPortBase;
936   ULONG ControlPortBase;
937   ULONG UnitNumber;
938   ULONG Retries;
939   BYTE High, Low;
940
941   DPRINT("AtapiFindDevices() called\n");
942
943   CommandPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[0].RangeStart);
944   DPRINT("  CommandPortBase: %x\n", CommandPortBase);
945
946   ControlPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[1].RangeStart);
947   DPRINT("  ControlPortBase: %x\n", ControlPortBase);
948
949   for (UnitNumber = 0; UnitNumber < 2; UnitNumber++)
950     {
951       /* Select drive */
952       IDEWriteDriveHead(CommandPortBase,
953                         IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
954       ScsiPortStallExecution(500);
955
956       /* Disable interrupts */
957       IDEWriteDriveControl(ControlPortBase,
958                            IDE_DC_nIEN);
959       ScsiPortStallExecution(500);
960
961       IDEWriteCylinderHigh(CommandPortBase, 0);
962       IDEWriteCylinderLow(CommandPortBase, 0);
963       IDEWriteCommand(CommandPortBase, IDE_CMD_RESET);
964
965       for (Retries = 0; Retries < 20000; Retries++)
966         {
967           if (!(IDEReadStatus(CommandPortBase) & IDE_SR_BUSY))
968             {
969               break;
970             }
971           ScsiPortStallExecution(150);
972         }
973       if (Retries >= 20000)
974         {
975           DPRINT("Timeout on drive %lu\n", UnitNumber);
976           DeviceExtension->DevicePresent[UnitNumber] = FALSE;
977           continue;
978         }
979
980       High = IDEReadCylinderHigh(CommandPortBase);
981       Low = IDEReadCylinderLow(CommandPortBase);
982
983       DPRINT("  Check drive %lu: High 0x%x Low 0x%x\n",
984              UnitNumber,
985              High,
986              Low);
987
988       if (High == 0xEB && Low == 0x14)
989         {
990           if (AtapiIdentifyDevice(CommandPortBase,
991                                   ControlPortBase,
992                                   UnitNumber,
993                                   TRUE,
994                                   &DeviceExtension->DeviceParams[UnitNumber]))
995             {
996               DPRINT("  ATAPI drive found!\n");
997               DeviceExtension->DevicePresent[UnitNumber] = TRUE;
998               DeviceExtension->DeviceAtapi[UnitNumber] = TRUE;
999               DeviceFound = TRUE;
1000             }
1001           else
1002             {
1003               DPRINT("  No ATAPI drive found!\n");
1004             }
1005         }
1006       else
1007         {
1008           if (AtapiIdentifyDevice(CommandPortBase,
1009                                   ControlPortBase,
1010                                   UnitNumber,
1011                                   FALSE,
1012                                   &DeviceExtension->DeviceParams[UnitNumber]))
1013             {
1014               DPRINT("  IDE drive found!\n");
1015               DeviceExtension->DevicePresent[UnitNumber] = TRUE;
1016               DeviceExtension->DeviceAtapi[UnitNumber] = FALSE;
1017               DeviceFound = TRUE;
1018             }
1019           else
1020             {
1021               DPRINT("  No IDE drive found!\n");
1022             }
1023         }
1024     }
1025
1026
1027   DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound) ? "TRUE" : "FALSE");
1028
1029   return(DeviceFound);
1030 }
1031
1032
1033 //    AtapiResetController
1034 //
1035 //  DESCRIPTION:
1036 //    Reset the controller and report completion status
1037 //
1038 //  RUN LEVEL:
1039 //    PASSIVE_LEVEL
1040 //
1041 //  ARGUMENTS:
1042 //    IN  WORD  CommandPort  The address of the command port
1043 //    IN  WORD  ControlPort  The address of the control port
1044 //
1045 //  RETURNS:
1046 //
1047
1048 static BOOLEAN
1049 AtapiResetController(IN ULONG CommandPort,
1050                      IN ULONG ControlPort)
1051 {
1052   int Retries;
1053
1054   /* Assert drive reset line */
1055   IDEWriteDriveControl(ControlPort, IDE_DC_SRST);
1056
1057   /* Wait for min. 25 microseconds */
1058   ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH);
1059
1060   /* Negate drive reset line */
1061   IDEWriteDriveControl(ControlPort, 0);
1062
1063   /* Wait for BUSY negation */
1064   for (Retries = 0; Retries < IDE_RESET_BUSY_TIMEOUT * 1000; Retries++)
1065     {
1066       if (!(IDEReadStatus(CommandPort) & IDE_SR_BUSY))
1067         {
1068           break;
1069         }
1070       ScsiPortStallExecution(10);
1071     }
1072
1073   if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
1074     {
1075       return(FALSE);
1076     }
1077
1078     //  return TRUE if controller came back to life. and
1079     //  the registers are initialized correctly
1080   return(IDEReadError(CommandPort) == 1);
1081 }
1082
1083 /*
1084  *  AtapiIdentifyDevice
1085  *
1086  *  DESCRIPTION:
1087  *      Get the identification block from the drive
1088  *
1089  *  RUN LEVEL:
1090  *      PASSIVE_LEVEL
1091  *
1092  *  ARGUMENTS:
1093  *      CommandPort
1094  *              Address of the command port
1095  *      ControlPort
1096  *              Address of the control port
1097  *      DriveNum
1098  *              The drive index (0,1)
1099  *      Atapi
1100  *              Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1101  *      DrvParms
1102  *              Address to write drive ident block
1103  *
1104  *  RETURNS:
1105  *      TRUE: The drive identification block was retrieved successfully
1106  *      FALSE: an error ocurred
1107  */
1108
1109 static BOOLEAN
1110 AtapiIdentifyDevice(IN ULONG CommandPort,
1111                     IN ULONG ControlPort,
1112                     IN ULONG DriveNum,
1113                     IN BOOLEAN Atapi,
1114                     OUT PIDE_DRIVE_IDENTIFY DrvParms)
1115 {
1116   LONG i;
1117
1118   /*  Get the Drive Identify block from drive or die  */
1119   if (AtapiPolledRead(CommandPort,
1120                       ControlPort,
1121                       0,
1122                       1,
1123                       0,
1124                       0,
1125                       0,
1126                       (DriveNum ? IDE_DH_DRV1 : 0),
1127                       (Atapi ? IDE_CMD_IDENT_ATAPI_DRV : IDE_CMD_IDENT_ATA_DRV),
1128                       (BYTE *)DrvParms) != 0)
1129     {
1130       DPRINT("IDEPolledRead() failed\n");
1131       return(FALSE);
1132     }
1133
1134   /*  Report on drive parameters if debug mode  */
1135   IDESwapBytePairs(DrvParms->SerialNumber, 20);
1136   IDESwapBytePairs(DrvParms->FirmwareRev, 8);
1137   IDESwapBytePairs(DrvParms->ModelNumber, 40);
1138   DPRINT("Config:%04x  Cyls:%5d  Heads:%2d  Sectors/Track:%3d  Gaps:%02d %02d\n",
1139          DrvParms->ConfigBits,
1140          DrvParms->LogicalCyls,
1141          DrvParms->LogicalHeads,
1142          DrvParms->SectorsPerTrack,
1143          DrvParms->InterSectorGap,
1144          DrvParms->InterSectorGapSize);
1145   DPRINT("Bytes/PLO:%3d  Vendor Cnt:%2d  Serial number:[%.20s]\n",
1146          DrvParms->BytesInPLO,
1147          DrvParms->VendorUniqueCnt,
1148          DrvParms->SerialNumber);
1149   DPRINT("Cntlr type:%2d  BufSiz:%5d  ECC bytes:%3d  Firmware Rev:[%.8s]\n",
1150          DrvParms->ControllerType,
1151          DrvParms->BufferSize * IDE_SECTOR_BUF_SZ,
1152          DrvParms->ECCByteCnt,
1153          DrvParms->FirmwareRev);
1154   DPRINT("Model:[%.40s]\n", DrvParms->ModelNumber);
1155   DPRINT("RWMult?:%02x  LBA:%d  DMA:%d  MinPIO:%d ns  MinDMA:%d ns\n",
1156          (DrvParms->RWMultImplemented) & 0xff,
1157          (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0,
1158          (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
1159          DrvParms->MinPIOTransTime,
1160          DrvParms->MinDMATransTime);
1161   DPRINT("TM:Cyls:%d  Heads:%d  Sectors/Trk:%d Capacity:%ld\n",
1162          DrvParms->TMCylinders,
1163          DrvParms->TMHeads,
1164          DrvParms->TMSectorsPerTrk,
1165          (ULONG)(DrvParms->TMCapacityLo + (DrvParms->TMCapacityHi << 16)));
1166   DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1167          DrvParms->TMSectorCountHi,
1168          DrvParms->TMSectorCountLo,
1169          (ULONG)((DrvParms->TMSectorCountHi << 16) + DrvParms->TMSectorCountLo));
1170
1171   DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
1172   if (DrvParms->BytesPerSector == 0)
1173     {
1174       DrvParms->BytesPerSector = 512;
1175     }
1176   else
1177     {
1178       for (i = 15; i >= 0; i--)
1179         {
1180           if (DrvParms->BytesPerSector & (1 << i))
1181             {
1182               DrvParms->BytesPerSector = 1 << i;
1183               break;
1184             }
1185         }
1186     }
1187   DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
1188
1189   return(TRUE);
1190 }
1191
1192
1193 //    AtapiPolledRead
1194 //
1195 //  DESCRIPTION:
1196 //    Read a sector of data from the drive in a polled fashion.
1197 //
1198 //  RUN LEVEL:
1199 //    PASSIVE_LEVEL
1200 //
1201 //  ARGUMENTS:
1202 //    IN   WORD  Address       Address of command port for drive
1203 //    IN   BYTE  PreComp       Value to write to precomp register
1204 //    IN   BYTE  SectorCnt     Value to write to sectorCnt register
1205 //    IN   BYTE  SectorNum     Value to write to sectorNum register
1206 //    IN   BYTE  CylinderLow   Value to write to CylinderLow register
1207 //    IN   BYTE  CylinderHigh  Value to write to CylinderHigh register
1208 //    IN   BYTE  DrvHead       Value to write to Drive/Head register
1209 //    IN   BYTE  Command       Value to write to Command register
1210 //    OUT  BYTE  *Buffer       Buffer for output data
1211 //
1212 //  RETURNS:
1213 //    int  0 is success, non 0 is an error code
1214 //
1215
1216 static int
1217 AtapiPolledRead(IN ULONG CommandPort,
1218                 IN ULONG ControlPort,
1219                 IN BYTE PreComp,
1220                 IN BYTE SectorCnt,
1221                 IN BYTE SectorNum,
1222                 IN BYTE CylinderLow,
1223                 IN BYTE CylinderHigh,
1224                 IN BYTE DrvHead,
1225                 IN BYTE Command,
1226                 OUT BYTE *Buffer)
1227 {
1228   ULONG SectorCount = 0;
1229   ULONG RetryCount;
1230   BOOLEAN Junk = FALSE;
1231   UCHAR Status;
1232   UCHAR Control;
1233
1234 //#if 0
1235   /* Wait for BUSY to clear */
1236   for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1237     {
1238       Status = IDEReadStatus(CommandPort);
1239       if (!(Status & IDE_SR_BUSY))
1240         {
1241           break;
1242         }
1243       ScsiPortStallExecution(10);
1244     }
1245   DPRINT("status=%02x\n", Status);
1246   DPRINT("waited %ld usecs for busy to clear\n", RetryCount * 10);
1247   if (RetryCount >= IDE_MAX_BUSY_RETRIES)
1248     {
1249       DPRINT("Drive is BUSY for too long\n");
1250       return(IDE_ER_ABRT);
1251     }
1252 //#endif
1253
1254   /*  Write Drive/Head to select drive  */
1255   IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
1256   ScsiPortStallExecution(500);
1257
1258   /* Disable interrupts */
1259   Control = IDEReadAltStatus(ControlPort);
1260   IDEWriteDriveControl(ControlPort, Control | IDE_DC_nIEN);
1261   ScsiPortStallExecution(500);
1262
1263 #if 0
1264   /*  Wait for STATUS.BUSY and STATUS.DRQ to clear  */
1265   for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1266     {
1267       Status = IDEReadStatus(CommandPort);
1268       if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1269         {
1270           break;
1271         }
1272       ScsiPortStallExecution(10);
1273     }
1274   if (RetryCount >= IDE_MAX_BUSY_RETRIES)
1275     {
1276       return IDE_ER_ABRT;
1277     }
1278 #endif
1279
1280   /*  Issue command to drive  */
1281   if (DrvHead & IDE_DH_LBA)
1282     {
1283       DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1284              DrvHead & IDE_DH_DRV1 ? 1 : 0,
1285              ((DrvHead & 0x0f) << 24) + (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
1286              SectorCnt,
1287              Command);
1288     }
1289   else
1290     {
1291       DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1292              DrvHead & IDE_DH_DRV1 ? 1 : 0,
1293              CylinderHigh,
1294              CylinderLow,
1295              DrvHead & 0x0f,
1296              SectorNum,
1297              SectorCnt,
1298              Command);
1299     }
1300
1301   /*  Setup command parameters  */
1302   IDEWritePrecomp(CommandPort, PreComp);
1303   IDEWriteSectorCount(CommandPort, SectorCnt);
1304   IDEWriteSectorNum(CommandPort, SectorNum);
1305   IDEWriteCylinderHigh(CommandPort, CylinderHigh);
1306   IDEWriteCylinderLow(CommandPort, CylinderLow);
1307   IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
1308
1309   /*  Issue the command  */
1310   IDEWriteCommand(CommandPort, Command);
1311   ScsiPortStallExecution(50);
1312
1313   /*  wait for DRQ or error  */
1314   for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
1315     {
1316       Status = IDEReadStatus(CommandPort);
1317       if (!(Status & IDE_SR_BUSY))
1318         {
1319           if (Status & IDE_SR_ERR)
1320             {
1321               IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1322               return(IDE_ER_ABRT);
1323             }
1324           if (Status & IDE_SR_DRQ)
1325             {
1326               break;
1327             }
1328           else
1329             {
1330               IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1331               return(IDE_ER_ABRT);
1332             }
1333         }
1334       ScsiPortStallExecution(10);
1335     }
1336
1337   /*  timed out  */
1338   if (RetryCount >= IDE_MAX_POLL_RETRIES)
1339     {
1340       IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1341       return(IDE_ER_ABRT);
1342     }
1343
1344   while (1)
1345     {
1346       /*  Read data into buffer  */
1347       if (Junk == FALSE)
1348         {
1349           IDEReadBlock(CommandPort, Buffer, IDE_SECTOR_BUF_SZ);
1350           Buffer += IDE_SECTOR_BUF_SZ;
1351         }
1352       else
1353         {
1354           UCHAR JunkBuffer[IDE_SECTOR_BUF_SZ];
1355           IDEReadBlock(CommandPort, JunkBuffer, IDE_SECTOR_BUF_SZ);
1356         }
1357       SectorCount++;
1358
1359       /*  Check for error or more sectors to read  */
1360       for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1361         {
1362           Status = IDEReadStatus(CommandPort);
1363           if (!(Status & IDE_SR_BUSY))
1364             {
1365               if (Status & IDE_SR_ERR)
1366                 {
1367                   IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1368                   return(IDE_ER_ABRT);
1369                 }
1370               if (Status & IDE_SR_DRQ)
1371                 {
1372                   if (SectorCount >= SectorCnt)
1373                     {
1374                       DPRINT("Buffer size exceeded!\n");
1375                       Junk = TRUE;
1376                     }
1377                   break;
1378                 }
1379               else
1380                 {
1381                   if (SectorCount > SectorCnt)
1382                     {
1383                       DPRINT("Read %lu sectors of junk!\n",
1384                              SectorCount - SectorCnt);
1385                     }
1386                   IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1387                   return(0);
1388                 }
1389             }
1390         }
1391     }
1392 }
1393
1394
1395 //  -------------------------------------------  Nondiscardable statics
1396
1397 static ULONG
1398 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1399                       IN PSCSI_REQUEST_BLOCK Srb)
1400 {
1401   UCHAR ByteCountHigh;
1402   UCHAR ByteCountLow;
1403   ULONG Retries;
1404   ULONG CdbSize;
1405   UCHAR Status;
1406
1407   DPRINT("AtapiSendAtapiCommand() called!\n");
1408
1409   if (Srb->PathId != 0)
1410     {
1411       Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
1412       return(SRB_STATUS_INVALID_PATH_ID);
1413     }
1414
1415   if (Srb->TargetId > 1)
1416     {
1417       Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
1418       return(SRB_STATUS_INVALID_TARGET_ID);
1419     }
1420
1421   if (Srb->Lun != 0)
1422     {
1423       Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
1424       return(SRB_STATUS_INVALID_LUN);
1425     }
1426
1427   if (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE)
1428     {
1429       Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1430       return(SRB_STATUS_NO_DEVICE);
1431     }
1432
1433   DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
1434          Srb->TargetId);
1435
1436   if (Srb->Cdb[0] == SCSIOP_INQUIRY)
1437     return(AtapiInquiry(DeviceExtension,
1438                         Srb));
1439
1440   /* Set pointer to data buffer. */
1441   DeviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer;
1442   DeviceExtension->CurrentSrb = Srb;
1443
1444   /* Wait for BUSY to clear */
1445   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1446     {
1447       Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1448       if (!(Status & IDE_SR_BUSY))
1449         {
1450           break;
1451         }
1452       ScsiPortStallExecution(10);
1453     }
1454   DPRINT("status=%02x\n", Status);
1455   DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
1456   if (Retries >= IDE_MAX_BUSY_RETRIES)
1457     {
1458       DPRINT("Drive is BUSY for too long\n");
1459       return(SRB_STATUS_BUSY);
1460     }
1461
1462   /* Select the desired drive */
1463   IDEWriteDriveHead(DeviceExtension->CommandPortBase,
1464                     IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
1465
1466   /* Wait a little while */
1467   ScsiPortStallExecution(50);
1468
1469 #if 0
1470   /* Wait for BUSY to clear and DRDY to assert */
1471   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1472     {
1473       Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1474       if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1475         {
1476           break;
1477         }
1478       ScsiPortStallExecution(10);
1479     }
1480   DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
1481   if (Retries >= IDE_MAX_BUSY_RETRIES)
1482     {
1483       DPRINT("Drive is BUSY for too long after drive select\n");
1484       return(SRB_STATUS_BUSY);
1485     }
1486 #endif
1487
1488   if (Srb->DataTransferLength < 0x10000)
1489     {
1490       ByteCountLow = (UCHAR)(Srb->DataTransferLength & 0xFF);
1491       ByteCountHigh = (UCHAR)(Srb->DataTransferLength >> 8);
1492     }
1493   else
1494     {
1495       ByteCountLow = 0xFF;
1496       ByteCountHigh = 0xFF;
1497     }
1498
1499   /* Set feature register */
1500   IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
1501
1502   /* Set command packet length */
1503   IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, ByteCountHigh);
1504   IDEWriteCylinderLow(DeviceExtension->CommandPortBase, ByteCountLow);
1505
1506   /* Issue command to drive */
1507   IDEWriteCommand(DeviceExtension->CommandPortBase, 0xA0); /* Packet command */
1508
1509   /* Wait for DRQ to assert */
1510   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1511     {
1512       Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1513       if ((Status & IDE_SR_DRQ))
1514         {
1515           break;
1516         }
1517       ScsiPortStallExecution(10);
1518     }
1519
1520   CdbSize = (DeviceExtension->DeviceParams[Srb->TargetId].ConfigBits & 0x3 == 1) ? 16 : 12;
1521   DPRINT("CdbSize: %lu\n", CdbSize);
1522
1523   /* Write command packet */
1524   IDEWriteBlock(DeviceExtension->CommandPortBase,
1525                 (PUSHORT)Srb->Cdb,
1526                 CdbSize);
1527
1528   DeviceExtension->ExpectingInterrupt = TRUE;
1529
1530   DPRINT("AtapiSendAtapiCommand() done\n");
1531
1532   return(SRB_STATUS_PENDING);
1533 }
1534
1535
1536 static ULONG
1537 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1538                     IN PSCSI_REQUEST_BLOCK Srb)
1539 {
1540   ULONG SrbStatus = SRB_STATUS_SUCCESS;
1541
1542   DPRINT("AtapiSendIdeCommand() called!\n");
1543
1544   DPRINT("PathId: %lu  TargetId: %lu  Lun: %lu\n",
1545          Srb->PathId,
1546          Srb->TargetId,
1547          Srb->Lun);
1548
1549   switch (Srb->Cdb[0])
1550     {
1551       case SCSIOP_INQUIRY:
1552         SrbStatus = AtapiInquiry(DeviceExtension,
1553                                  Srb);
1554         break;
1555
1556       case SCSIOP_READ_CAPACITY:
1557         SrbStatus = AtapiReadCapacity(DeviceExtension,
1558                                       Srb);
1559         break;
1560
1561       case SCSIOP_READ:
1562       case SCSIOP_WRITE:
1563         SrbStatus = AtapiReadWrite(DeviceExtension,
1564                                    Srb);
1565         break;
1566
1567       case SCSIOP_MODE_SENSE:
1568       case SCSIOP_TEST_UNIT_READY:
1569       case SCSIOP_VERIFY:
1570       case SCSIOP_START_STOP_UNIT:
1571       case SCSIOP_REQUEST_SENSE:
1572         break;
1573
1574      default:
1575         DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1576                  Srb->Cdb[0]);
1577         SrbStatus = SRB_STATUS_INVALID_REQUEST;
1578         break;
1579     }
1580
1581   DPRINT("AtapiSendIdeCommand() done!\n");
1582
1583   return(SrbStatus);
1584 }
1585
1586
1587 static ULONG
1588 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1589              PSCSI_REQUEST_BLOCK Srb)
1590 {
1591   PIDE_DRIVE_IDENTIFY DeviceParams;
1592   PINQUIRYDATA InquiryData;
1593   ULONG i;
1594
1595   DPRINT("SCSIOP_INQUIRY: DeviceExtension %p  TargetId: %lu\n",
1596          DeviceExtension, Srb->TargetId);
1597
1598   if (Srb->PathId != 0)
1599     {
1600       Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
1601       return(SRB_STATUS_INVALID_PATH_ID);
1602     }
1603
1604   if (Srb->TargetId > 1)
1605     {
1606       Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
1607       return(SRB_STATUS_INVALID_TARGET_ID);
1608     }
1609
1610   if (Srb->Lun != 0)
1611     {
1612       Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
1613       return(SRB_STATUS_INVALID_LUN);
1614     }
1615
1616   if (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE)
1617     {
1618       Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1619       return(SRB_STATUS_NO_DEVICE);
1620     }
1621
1622   InquiryData = Srb->DataBuffer;
1623   DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1624
1625   /* clear buffer */
1626   for (i = 0; i < Srb->DataTransferLength; i++)
1627     {
1628       ((PUCHAR)Srb->DataBuffer)[i] = 0;
1629     }
1630
1631   /* set device class */
1632   if (DeviceExtension->DeviceAtapi[Srb->TargetId] == FALSE)
1633     {
1634       /* hard-disk */
1635       InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
1636     }
1637   else
1638     {
1639       /* get it from the ATAPI configuration word */
1640       InquiryData->DeviceType = (DeviceParams->ConfigBits >> 8) & 0x1F;
1641       DPRINT("Device class: %u\n", InquiryData->DeviceType);
1642     }
1643
1644   DPRINT("ConfigBits: 0x%x\n", DeviceParams->ConfigBits);
1645   if (DeviceParams->ConfigBits & 0x80)
1646     {
1647       DPRINT("Removable media!\n");
1648       InquiryData->RemovableMedia = 1;
1649     }
1650
1651   for (i = 0; i < 20; i += 2)
1652     {
1653       InquiryData->VendorId[i] =
1654         ((PUCHAR)DeviceParams->ModelNumber)[i];
1655       InquiryData->VendorId[i+1] =
1656         ((PUCHAR)DeviceParams->ModelNumber)[i+1];
1657     }
1658
1659   for (i = 0; i < 4; i++)
1660     {
1661       InquiryData->ProductId[12+i] = ' ';
1662     }
1663
1664   for (i = 0; i < 4; i += 2)
1665     {
1666       InquiryData->ProductRevisionLevel[i] =
1667         ((PUCHAR)DeviceParams->FirmwareRev)[i];
1668       InquiryData->ProductRevisionLevel[i+1] =
1669         ((PUCHAR)DeviceParams->FirmwareRev)[i+1];
1670     }
1671
1672   DPRINT("VendorId: '%.20s'\n", InquiryData->VendorId);
1673
1674   Srb->SrbStatus = SRB_STATUS_SUCCESS;
1675   return(SRB_STATUS_SUCCESS);
1676 }
1677
1678
1679 static ULONG
1680 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1681                   PSCSI_REQUEST_BLOCK Srb)
1682 {
1683   PREAD_CAPACITY_DATA CapacityData;
1684   PIDE_DRIVE_IDENTIFY DeviceParams;
1685   ULONG LastSector;
1686
1687   DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb->TargetId);
1688
1689   if (Srb->PathId != 0)
1690     {
1691       Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
1692       return(SRB_STATUS_INVALID_PATH_ID);
1693     }
1694
1695   if (Srb->TargetId > 1)
1696     {
1697       Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
1698       return(SRB_STATUS_INVALID_TARGET_ID);
1699     }
1700
1701   if (Srb->Lun != 0)
1702     {
1703       Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
1704       return(SRB_STATUS_INVALID_LUN);
1705     }
1706
1707   if (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE)
1708     {
1709       Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1710       return(SRB_STATUS_NO_DEVICE);
1711     }
1712
1713   CapacityData = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
1714   DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1715
1716   /* Set sector (block) size to 512 bytes (big-endian). */
1717   CapacityData->BytesPerBlock = 0x20000;
1718
1719   /* Calculate last sector (big-endian). */
1720   if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
1721     {
1722       LastSector = (ULONG)((DeviceParams->TMSectorCountHi << 16) +
1723                             DeviceParams->TMSectorCountLo) - 1;
1724     }
1725   else
1726     {
1727       LastSector = (ULONG)(DeviceParams->LogicalCyls *
1728                            DeviceParams->LogicalHeads *
1729                            DeviceParams->SectorsPerTrack)-1;
1730     }
1731
1732   CapacityData->LogicalBlockAddress = (((PUCHAR)&LastSector)[0] << 24) |
1733                                       (((PUCHAR)&LastSector)[1] << 16) |
1734                                       (((PUCHAR)&LastSector)[2] << 8) |
1735                                       ((PUCHAR)&LastSector)[3];
1736
1737   DPRINT("LastCount: %lu (%08lx / %08lx)\n",
1738          LastSector,
1739          LastSector,
1740          CapacityData->LogicalBlockAddress);
1741
1742   Srb->SrbStatus = SRB_STATUS_SUCCESS;
1743   return(SRB_STATUS_SUCCESS);
1744 }
1745
1746
1747 static ULONG
1748 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1749                PSCSI_REQUEST_BLOCK Srb)
1750 {
1751   PIDE_DRIVE_IDENTIFY DeviceParams;
1752   ULONG StartingSector;
1753   ULONG SectorCount;
1754   UCHAR CylinderHigh;
1755   UCHAR CylinderLow;
1756   UCHAR DrvHead;
1757   UCHAR SectorNumber;
1758   UCHAR Command;
1759   ULONG Retries;
1760   UCHAR Status;
1761
1762   DPRINT("AtapiReadWrite() called!\n");
1763
1764   if (Srb->PathId != 0)
1765     {
1766       Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
1767       return(SRB_STATUS_INVALID_PATH_ID);
1768     }
1769
1770   if (Srb->TargetId > 1)
1771     {
1772       Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
1773       return(SRB_STATUS_INVALID_TARGET_ID);
1774     }
1775
1776   if (Srb->Lun != 0)
1777     {
1778       Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
1779       return(SRB_STATUS_INVALID_LUN);
1780     }
1781
1782   if (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE)
1783     {
1784       Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1785       return(SRB_STATUS_NO_DEVICE);
1786     }
1787
1788   DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
1789          Srb->TargetId);
1790
1791   DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1792
1793   /* Get starting sector number from CDB. */
1794   StartingSector = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
1795                    ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
1796                    ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
1797                    ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
1798
1799   SectorCount = (Srb->DataTransferLength + DeviceParams->BytesPerSector - 1) /
1800                 DeviceParams->BytesPerSector;
1801
1802   DPRINT("Starting sector %lu  Number of bytes %lu  Sectors %lu\n",
1803          StartingSector,
1804          Srb->DataTransferLength,
1805          SectorCount);
1806
1807   if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
1808     {
1809       SectorNumber = StartingSector & 0xff;
1810       CylinderLow = (StartingSector >> 8) & 0xff;
1811       CylinderHigh = (StartingSector >> 16) & 0xff;
1812       DrvHead = ((StartingSector >> 24) & 0x0f) | 
1813           (Srb->TargetId ? IDE_DH_DRV1 : 0) |
1814           IDE_DH_LBA;
1815     }
1816   else
1817     {
1818       SectorNumber = (StartingSector % DeviceParams->SectorsPerTrack) + 1;
1819       StartingSector /= DeviceParams->SectorsPerTrack;
1820       DrvHead = (StartingSector % DeviceParams->LogicalHeads) | 
1821           (Srb->TargetId ? IDE_DH_DRV1 : 0);
1822       StartingSector /= DeviceParams->LogicalHeads;
1823       CylinderLow = StartingSector & 0xff;
1824       CylinderHigh = StartingSector >> 8;
1825     }
1826
1827
1828   if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
1829     {
1830       Command = IDE_CMD_READ;
1831     }
1832   else
1833     {
1834       Command = IDE_CMD_WRITE;
1835     }
1836
1837   if (DrvHead & IDE_DH_LBA)
1838     {
1839       DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1840              (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
1841              DeviceExtension->CommandPortBase,
1842              DrvHead & IDE_DH_DRV1 ? 1 : 0,
1843              ((DrvHead & 0x0f) << 24) +
1844                (CylinderHigh << 16) + (CylinderLow << 8) + SectorNumber,
1845              SectorCount,
1846              Command);
1847     }
1848   else
1849     {
1850       DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1851              (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
1852              DeviceExtension->CommandPortBase,
1853              DrvHead & IDE_DH_DRV1 ? 1 : 0, 
1854              CylinderHigh,
1855              CylinderLow,
1856              DrvHead & 0x0f,
1857              SectorNumber,
1858              SectorCount,
1859              Command);
1860     }
1861
1862   /* Set pointer to data buffer. */
1863   DeviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer;
1864
1865   DeviceExtension->CurrentSrb = Srb;
1866   DeviceExtension->ExpectingInterrupt = TRUE;
1867
1868
1869
1870   /*  wait for BUSY to clear  */
1871   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1872     {
1873       Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1874       if (!(Status & IDE_SR_BUSY))
1875         {
1876           break;
1877         }
1878       ScsiPortStallExecution(10);
1879     }
1880   DPRINT("status=%02x\n", Status);
1881   DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
1882   if (Retries >= IDE_MAX_BUSY_RETRIES)
1883     {
1884       DPRINT ("Drive is BUSY for too long\n");
1885       return(SRB_STATUS_BUSY);
1886 #if 0
1887       if (++ControllerExtension->Retries > IDE_MAX_CMD_RETRIES)
1888         {
1889           DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1890           Irp = ControllerExtension->CurrentIrp;
1891           Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1892           Irp->IoStatus.Information = 0;
1893
1894           return FALSE;
1895         }
1896       else
1897         {
1898           DPRINT ("Beginning drive reset sequence\n");
1899           IDEBeginControllerReset(ControllerExtension);
1900
1901           return TRUE;
1902         }
1903 #endif
1904     }
1905
1906   /*  Select the desired drive  */
1907   IDEWriteDriveHead(DeviceExtension->CommandPortBase,
1908                     IDE_DH_FIXED | DrvHead);
1909
1910   ScsiPortStallExecution(10);
1911 #if 0
1912   /*  wait for BUSY to clear and DRDY to assert */
1913   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1914     {
1915       Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1916       if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1917         {
1918           break;
1919         }
1920       ScsiPortStallExecution(10);
1921     }
1922   DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
1923   if (Retries >= IDE_MAX_BUSY_RETRIES)
1924     {
1925       DPRINT("Drive is BUSY for too long after drive select\n");
1926       return(SRB_STATUS_BUSY);
1927 #if 0
1928       if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1929         {
1930           DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1931           Irp = ControllerExtension->CurrentIrp;
1932           Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1933           Irp->IoStatus.Information = 0;
1934
1935           return FALSE;
1936         }
1937       else
1938         {
1939           DPRINT("Beginning drive reset sequence\n");
1940           IDEBeginControllerReset(ControllerExtension);
1941
1942           return TRUE;
1943         }
1944 #endif
1945     }
1946 #endif
1947
1948   /* Indicate expecting an interrupt. */
1949   DeviceExtension->ExpectingInterrupt = TRUE;
1950
1951   /* Setup command parameters */
1952   IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
1953   IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount);
1954   IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber);
1955   IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh);
1956   IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow);
1957   IDEWriteDriveHead(DeviceExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
1958
1959   /* Issue command to drive */
1960   IDEWriteCommand(DeviceExtension->CommandPortBase, Command);
1961
1962   /* Write data block */
1963   if (Command == IDE_CMD_WRITE)
1964     {
1965       PUCHAR TargetAddress;
1966       ULONG SectorSize;
1967
1968       /* Wait for controller ready */
1969       for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
1970         {
1971           BYTE  Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1972           if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
1973             {
1974               break;
1975             }
1976           KeStallExecutionProcessor(10);
1977         }
1978       if (Retries >= IDE_MAX_BUSY_RETRIES)
1979         {
1980           DPRINT("Drive is BUSY for too long after sending write command\n");
1981           return(SRB_STATUS_BUSY);
1982 #if 0
1983           if (DeviceExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1984             {
1985               Irp = ControllerExtension->CurrentIrp;
1986               Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1987               Irp->IoStatus.Information = 0;
1988
1989               return FALSE;
1990             }
1991           else
1992             {
1993               IDEBeginControllerReset(ControllerExtension);
1994
1995               return TRUE;
1996             }
1997 #endif
1998         }
1999
2000       /* Update SRB data */
2001       SectorSize = DeviceExtension->DeviceParams[Srb->TargetId].BytesPerSector;
2002       TargetAddress = Srb->DataBuffer;
2003       Srb->DataBuffer += SectorSize;
2004       Srb->DataTransferLength -= SectorSize;
2005
2006       /* Write data block */
2007       IDEWriteBlock(DeviceExtension->CommandPortBase,
2008                     TargetAddress,
2009                     SectorSize);
2010     }
2011
2012
2013   DPRINT("AtapiReadWrite() done!\n");
2014
2015   /* Wait for interrupt. */
2016   return(SRB_STATUS_PENDING);
2017 }
2018
2019
2020 static UCHAR
2021 AtapiErrorToScsi(PVOID DeviceExtension,
2022                  PSCSI_REQUEST_BLOCK Srb)
2023 {
2024   PATAPI_MINIPORT_EXTENSION DevExt;
2025   ULONG CommandPortBase;
2026   ULONG ControlPortBase;
2027   UCHAR ErrorReg;
2028   UCHAR ScsiStatus;
2029   UCHAR SrbStatus;
2030
2031   DPRINT("AtapiErrorToScsi() called\n");
2032
2033   DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
2034
2035   CommandPortBase = DevExt->CommandPortBase;
2036   ControlPortBase = DevExt->ControlPortBase;
2037
2038   ErrorReg = IDEReadError(CommandPortBase);
2039
2040   if (DevExt->DeviceAtapi[Srb->TargetId])
2041     {
2042       switch (ErrorReg >> 4)
2043         {
2044           case SCSI_SENSE_NO_SENSE:
2045             DPRINT("ATAPI error: SCSI_SENSE_NO_SENSE\n");
2046             ScsiStatus = SCSISTAT_CHECK_CONDITION;
2047             SrbStatus = SRB_STATUS_ERROR;
2048             break;
2049
2050           case SCSI_SENSE_RECOVERED_ERROR:
2051             DPRINT("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
2052             ScsiStatus = 0;
2053             SrbStatus = SRB_STATUS_SUCCESS;
2054             break;
2055
2056           case SCSI_SENSE_NOT_READY:
2057             DPRINT("ATAPI error: SCSI_SENSE_NOT_READY\n");
2058             ScsiStatus = SCSISTAT_CHECK_CONDITION;
2059             SrbStatus = SRB_STATUS_ERROR;
2060             break;
2061
2062           case SCSI_SENSE_MEDIUM_ERROR:
2063             DPRINT("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
2064             ScsiStatus = SCSISTAT_CHECK_CONDITION;
2065             SrbStatus = SRB_STATUS_ERROR;
2066             break;
2067
2068           case SCSI_SENSE_HARDWARE_ERROR:
2069             DPRINT("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
2070             ScsiStatus = SCSISTAT_CHECK_CONDITION;
2071             SrbStatus = SRB_STATUS_ERROR;
2072             break;
2073
2074           case SCSI_SENSE_ILLEGAL_REQUEST:
2075             DPRINT("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
2076             ScsiStatus = SCSISTAT_CHECK_CONDITION;
2077             SrbStatus = SRB_STATUS_ERROR;
2078             break;
2079
2080           case SCSI_SENSE_UNIT_ATTENTION:
2081             DPRINT("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
2082             ScsiStatus = SCSISTAT_CHECK_CONDITION;
2083             SrbStatus = SRB_STATUS_ERROR;
2084             break;
2085
2086           case SCSI_SENSE_DATA_PROTECT:
2087             DPRINT("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
2088             ScsiStatus = SCSISTAT_CHECK_CONDITION;
2089             SrbStatus = SRB_STATUS_ERROR;
2090             break;
2091
2092           case SCSI_SENSE_BLANK_CHECK:
2093             DPRINT("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
2094             ScsiStatus = SCSISTAT_CHECK_CONDITION;
2095             SrbStatus = SRB_STATUS_ERROR;
2096             break;
2097
2098           case SCSI_SENSE_ABORTED_COMMAND:
2099             DPRINT("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
2100             ScsiStatus = SCSISTAT_CHECK_CONDITION;
2101             SrbStatus = SRB_STATUS_ERROR;
2102             break;
2103
2104           default:
2105             DPRINT("ATAPI error: Invalid sense key\n");
2106             ScsiStatus = 0;
2107             SrbStatus = SRB_STATUS_ERROR;
2108             break;
2109         }
2110     }
2111   else
2112     {
2113       DPRINT1("IDE error: %02x\n", ErrorReg);
2114
2115       ScsiStatus = 0;
2116       SrbStatus = SRB_STATUS_ERROR;
2117
2118 #if 0
2119       UCHAR SectorCount, SectorNum, CylinderLow, CylinderHigh;
2120       UCHAR DriveHead;
2121
2122       CylinderLow = IDEReadCylinderLow(CommandPortBase);
2123       CylinderHigh = IDEReadCylinderHigh(CommandPortBase);
2124       DriveHead = IDEReadDriveHead(CommandPortBase);
2125       SectorCount = IDEReadSectorCount(CommandPortBase);
2126       SectorNum = IDEReadSectorNum(CommandPortBase);
2127
2128       DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
2129               ErrorReg,
2130               CylinderLow,
2131               CylinderHigh,
2132               SectorCount,
2133               SectorNum);
2134 #endif
2135     }
2136
2137
2138
2139   Srb->ScsiStatus = ScsiStatus;
2140
2141   DPRINT("AtapiErrorToScsi() done\n");
2142
2143   return(SrbStatus);
2144 }
2145
2146 /* EOF */