c42d750ba6061542321bf19c9f5ad80a0e992fdc
[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_NATIVE_PCI
45 #define ENABLE_ISA
46
47 //  -------------------------------------------------------------------------
48
49 #include <ddk/ntddk.h>
50 #include <ddk/srb.h>
51 #include <ddk/scsi.h>
52 #include <ddk/ntddscsi.h>
53
54 #include "atapi.h"
55
56 #define NDEBUG
57 #include <debug.h>
58
59 #define VERSION  "0.0.1"
60
61
62 //  -------------------------------------------------------  File Static Data
63
64 //    ATAPI_MINIPORT_EXTENSION
65 //
66 //  DESCRIPTION:
67 //    Extension to be placed in each port device object
68 //
69 //  ACCESS:
70 //    Allocated from NON-PAGED POOL
71 //    Available at any IRQL
72 //
73
74 typedef struct _ATAPI_MINIPORT_EXTENSION
75 {
76   IDE_DRIVE_IDENTIFY DeviceParams[2];
77   ULONG DeviceFlags[2];
78   ULONG TransferSize[2];
79
80   ULONG CommandPortBase;
81   ULONG ControlPortBase;
82   ULONG BusMasterRegisterBase;
83
84   BOOLEAN ExpectingInterrupt;
85   PSCSI_REQUEST_BLOCK CurrentSrb;
86
87
88   PUCHAR DataBuffer;
89   ULONG DataTransferLength;
90 } ATAPI_MINIPORT_EXTENSION, *PATAPI_MINIPORT_EXTENSION;
91
92 /* DeviceFlags */
93 #define DEVICE_PRESENT           0x00000001
94 #define DEVICE_ATAPI             0x00000002
95 #define DEVICE_MULTI_SECTOR_CMD  0x00000004
96 #define DEVICE_DWORD_IO          0x00000008
97 #define DEVICE_48BIT_ADDRESS     0x00000010
98 #define DEVICE_MEDIA_STATUS      0x00000020
99
100
101 typedef struct _UNIT_EXTENSION
102 {
103   ULONG Dummy;
104 } UNIT_EXTENSION, *PUNIT_EXTENSION;
105
106 PCI_SLOT_NUMBER LastSlotNumber;
107
108 #ifdef ENABLE_NATIVE_PCI
109 typedef struct _PCI_NATIVE_CONTROLLER 
110 {
111   USHORT VendorID;
112   USHORT DeviceID;
113 }
114 PCI_NATIVE_CONTROLLER, *PPCI_NATIVE_CONTROLLER;
115
116 PCI_NATIVE_CONTROLLER const PciNativeController[] = 
117 {
118     {
119         0x105A,             // Promise 
120         0x4D68,             // PDC20268, Ultra100TX2
121     },
122     {
123         0x105A,             // Promise 
124         0x4D30,             // PDC20267, Ultra100
125     }
126 };
127 #endif
128
129
130 //  -----------------------------------------------  Discardable Declarations
131
132 #ifdef  ALLOC_PRAGMA
133
134 //  make the initialization routines discardable, so that they 
135 //  don't waste space
136
137 #pragma  alloc_text(init, DriverEntry)
138 #pragma  alloc_text(init, IDECreateController)
139 #pragma  alloc_text(init, IDEPolledRead)
140
141 //  make the PASSIVE_LEVEL routines pageable, so that they don't
142 //  waste nonpaged memory
143
144 #pragma  alloc_text(page, IDEShutdown)
145 #pragma  alloc_text(page, IDEDispatchOpenClose)
146 #pragma  alloc_text(page, IDEDispatchRead)
147 #pragma  alloc_text(page, IDEDispatchWrite)
148
149 #endif  /*  ALLOC_PRAGMA  */
150
151 //  ---------------------------------------------------- Forward Declarations
152
153 static ULONG STDCALL
154 AtapiFindCompatiblePciController(PVOID DeviceExtension,
155                                  PVOID HwContext,
156                                  PVOID BusInformation,
157                                  PCHAR ArgumentString,
158                                  PPORT_CONFIGURATION_INFORMATION ConfigInfo,
159                                  PBOOLEAN Again);
160
161 static ULONG STDCALL
162 AtapiFindIsaBusController(PVOID DeviceExtension,
163                           PVOID HwContext,
164                           PVOID BusInformation,
165                           PCHAR ArgumentString,
166                           PPORT_CONFIGURATION_INFORMATION ConfigInfo,
167                           PBOOLEAN Again);
168
169 static ULONG STDCALL
170 AtapiFindNativePciController(PVOID DeviceExtension,
171                              PVOID HwContext,
172                              PVOID BusInformation,
173                              PCHAR ArgumentString,
174                              PPORT_CONFIGURATION_INFORMATION ConfigInfo,
175                              PBOOLEAN Again);
176
177 static BOOLEAN STDCALL
178 AtapiInitialize(IN PVOID DeviceExtension);
179
180 static BOOLEAN STDCALL
181 AtapiResetBus(IN PVOID DeviceExtension,
182               IN ULONG PathId);
183
184 static BOOLEAN STDCALL
185 AtapiStartIo(IN PVOID DeviceExtension,
186              IN PSCSI_REQUEST_BLOCK Srb);
187
188 static BOOLEAN STDCALL
189 AtapiInterrupt(IN PVOID DeviceExtension);
190
191 static BOOLEAN
192 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
193                  PPORT_CONFIGURATION_INFORMATION ConfigInfo);
194
195 static BOOLEAN
196 AtapiIdentifyDevice(IN ULONG CommandPort,
197                     IN ULONG ControlPort,
198                     IN ULONG DriveNum,
199                     IN BOOLEAN Atapi,
200                     OUT PIDE_DRIVE_IDENTIFY DrvParms);
201
202 static BOOLEAN
203 IDEResetController(IN ULONG CommandPort,
204                    IN ULONG ControlPort);
205
206 static int
207 AtapiPolledRead(IN ULONG CommandPort,
208                 IN ULONG ControlPort,
209                 IN BYTE PreComp,
210                 IN BYTE SectorCnt,
211                 IN BYTE SectorNum,
212                 IN BYTE CylinderLow,
213                 IN BYTE CylinderHigh,
214                 IN BYTE DrvHead,
215                 IN BYTE Command,
216                 OUT BYTE *Buffer);
217
218
219
220 static ULONG
221 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
222                       IN PSCSI_REQUEST_BLOCK Srb);
223
224 static ULONG
225 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
226                     IN PSCSI_REQUEST_BLOCK Srb);
227
228 static ULONG
229 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
230              IN PSCSI_REQUEST_BLOCK Srb);
231
232 static ULONG
233 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
234                   IN PSCSI_REQUEST_BLOCK Srb);
235
236 static ULONG
237 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
238                IN PSCSI_REQUEST_BLOCK Srb);
239
240 static ULONG
241 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension,
242                 PSCSI_REQUEST_BLOCK Srb);
243
244 static ULONG
245 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension,
246                    PSCSI_REQUEST_BLOCK Srb);
247
248 static UCHAR
249 AtapiErrorToScsi(PVOID DeviceExtension,
250                  PSCSI_REQUEST_BLOCK Srb);
251
252 static VOID
253 AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb);
254
255 //  ----------------------------------------------------------------  Inlines
256
257 void
258 IDESwapBytePairs(char *Buf,
259                  int Cnt)
260 {
261   char  t;
262   int   i;
263
264   for (i = 0; i < Cnt; i += 2)
265     {
266       t = Buf[i];
267       Buf[i] = Buf[i+1];
268       Buf[i+1] = t;
269     }
270 }
271
272
273 //  -------------------------------------------------------  Public Interface
274
275 //    DriverEntry
276 //
277 //  DESCRIPTION:
278 //    This function initializes the driver, locates and claims 
279 //    hardware resources, and creates various NT objects needed
280 //    to process I/O requests.
281 //
282 //  RUN LEVEL:
283 //    PASSIVE_LEVEL
284 //
285 //  ARGUMENTS:
286 //    IN  PDRIVER_OBJECT   DriverObject  System allocated Driver Object
287 //                                       for this driver
288 //    IN  PUNICODE_STRING  RegistryPath  Name of registry driver service 
289 //                                       key
290 //
291 //  RETURNS:
292 //    NTSTATUS
293
294 STDCALL NTSTATUS
295 DriverEntry(IN PDRIVER_OBJECT DriverObject,
296             IN PUNICODE_STRING RegistryPath)
297 {
298   HW_INITIALIZATION_DATA InitData;
299   NTSTATUS Status;
300
301   DPRINT("ATAPI Driver %s\n", VERSION);
302   DPRINT("RegistryPath: '%wZ'\n", RegistryPath);
303
304   /* Initialize data structure */
305   RtlZeroMemory(&InitData,
306                 sizeof(HW_INITIALIZATION_DATA));
307   InitData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
308   InitData.HwInitialize = AtapiInitialize;
309   InitData.HwResetBus = AtapiResetBus;
310   InitData.HwStartIo = AtapiStartIo;
311   InitData.HwInterrupt = AtapiInterrupt;
312
313   InitData.DeviceExtensionSize = sizeof(ATAPI_MINIPORT_EXTENSION);
314   InitData.SpecificLuExtensionSize = sizeof(UNIT_EXTENSION);
315
316   InitData.MapBuffers = TRUE;
317
318
319   /* Search the PCI bus for compatibility mode ide controllers */
320 #ifdef ENABLE_PCI
321   InitData.HwFindAdapter = AtapiFindCompatiblePciController;
322   InitData.NumberOfAccessRanges = 3;
323   InitData.AdapterInterfaceType = PCIBus;
324
325   InitData.VendorId = NULL;
326   InitData.VendorIdLength = 0;
327   InitData.DeviceId = NULL;
328   InitData.DeviceIdLength = 0;
329
330   Status = ScsiPortInitialize(DriverObject,
331                               RegistryPath,
332                               &InitData,
333                               NULL);
334 //  if (newStatus < statusToReturn)
335 //    statusToReturn = newStatus;
336 #endif
337
338   /* Search the PCI bus for all ide controllers */
339 #ifdef ENABLE_NATIVE_PCI
340
341   InitData.HwFindAdapter = AtapiFindNativePciController;
342   InitData.NumberOfAccessRanges = 3;
343   InitData.AdapterInterfaceType = PCIBus;
344
345   InitData.VendorId = 0;
346   InitData.VendorIdLength = 0;
347   InitData.DeviceId = 0;
348   InitData.DeviceIdLength = 0;
349
350   LastSlotNumber.u.AsULONG = 0xFFFFFFFF;
351
352   Status = ScsiPortInitialize(DriverObject,
353                               RegistryPath,
354                               &InitData,
355                               NULL);
356 //  if (newStatus < statusToReturn)
357 //    statusToReturn = newStatus;
358 #endif
359
360   /* Search the ISA bus for ide controllers */
361 #ifdef ENABLE_ISA
362   InitData.HwFindAdapter = AtapiFindIsaBusController;
363   InitData.NumberOfAccessRanges = 2;
364   InitData.AdapterInterfaceType = Isa;
365
366   InitData.VendorId = NULL;
367   InitData.VendorIdLength = 0;
368   InitData.DeviceId = NULL;
369   InitData.DeviceIdLength = 0;
370
371   Status = ScsiPortInitialize(DriverObject,
372                               RegistryPath,
373                               &InitData,
374                               NULL);
375 //      if (newStatus < statusToReturn)
376 //        statusToReturn = newStatus;
377 #endif
378
379   DPRINT("Returning from DriverEntry\n");
380
381   return(Status);
382 }
383
384
385 BOOLEAN
386 AtapiClaimHwResources(PATAPI_MINIPORT_EXTENSION DevExt,
387                       PPORT_CONFIGURATION_INFORMATION ConfigInfo,
388                       INTERFACE_TYPE InterfaceType,
389                       ULONG CommandPortBase,
390                       ULONG ControlPortBase,
391                       ULONG BusMasterPortBase,
392                       ULONG InterruptVector)
393 {
394    SCSI_PHYSICAL_ADDRESS IoAddress;
395    PVOID IoBase;
396    
397    IoAddress = ScsiPortConvertUlongToPhysicalAddress(CommandPortBase);
398    IoBase = ScsiPortGetDeviceBase((PVOID)DevExt,
399                                   InterfaceType,
400                                   ConfigInfo->SystemIoBusNumber,
401                                   IoAddress,
402                                   8,
403                                   TRUE);
404    if (IoBase == NULL)
405    {
406       return FALSE;
407    }
408    DevExt->CommandPortBase = (ULONG)IoBase;
409    ConfigInfo->AccessRanges[0].RangeStart = IoAddress;
410    ConfigInfo->AccessRanges[0].RangeLength = 8;
411    ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
412
413    if (ControlPortBase)
414    {
415       IoAddress = ScsiPortConvertUlongToPhysicalAddress(ControlPortBase + 2);
416       IoBase = ScsiPortGetDeviceBase((PVOID)DevExt,
417                                      InterfaceType,
418                                      ConfigInfo->SystemIoBusNumber,
419                                      IoAddress,
420                                      1,
421                                      TRUE);
422       if (IoBase == NULL)
423       {
424          ScsiPortFreeDeviceBase((PVOID)DevExt,
425                                 (PVOID)DevExt->CommandPortBase);
426          return FALSE;
427       }
428       DevExt->ControlPortBase = (ULONG)IoBase;
429       ConfigInfo->AccessRanges[1].RangeStart = IoAddress;
430       ConfigInfo->AccessRanges[1].RangeLength = 1;
431       ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
432    }
433    if (BusMasterPortBase)
434    {
435       IoAddress = ScsiPortConvertUlongToPhysicalAddress(BusMasterPortBase);
436       IoBase = ScsiPortGetDeviceBase((PVOID)DevExt,
437                                      InterfaceType,
438                                      ConfigInfo->SystemIoBusNumber,
439                                      IoAddress,
440                                      8,
441                                      TRUE);
442       if (IoBase == NULL)
443       {
444          ScsiPortFreeDeviceBase((PVOID)DevExt, (PVOID)DevExt->CommandPortBase);
445          ScsiPortFreeDeviceBase((PVOID)DevExt, (PVOID)DevExt->ControlPortBase);
446          return FALSE;
447       }
448       ConfigInfo->AccessRanges[2].RangeStart = IoAddress;
449       ConfigInfo->AccessRanges[2].RangeLength = 8;
450       ConfigInfo->AccessRanges[2].RangeInMemory = FALSE;
451    }
452    ConfigInfo->BusInterruptLevel = InterruptVector;
453    ConfigInfo->BusInterruptVector = InterruptVector;
454    ConfigInfo->InterruptMode = (InterfaceType == Isa) ? Latched : LevelSensitive;
455
456    if ((CommandPortBase == 0x1F0 || ControlPortBase == 0x3F4) && !ConfigInfo->AtdiskPrimaryClaimed)
457    {
458       ConfigInfo->AtdiskPrimaryClaimed = TRUE;
459    }
460    if ((CommandPortBase == 0x170 || ControlPortBase == 0x374) && !ConfigInfo->AtdiskSecondaryClaimed)
461    {
462       ConfigInfo->AtdiskSecondaryClaimed = TRUE;
463    }
464    return TRUE;
465 }
466
467
468 #ifdef ENABLE_PCI
469 static ULONG STDCALL
470 AtapiFindCompatiblePciController(PVOID DeviceExtension,
471                                  PVOID HwContext,
472                                  PVOID BusInformation,
473                                  PCHAR ArgumentString,
474                                  PPORT_CONFIGURATION_INFORMATION ConfigInfo,
475                                  PBOOLEAN Again)
476 {
477   PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
478   PCI_SLOT_NUMBER SlotNumber;
479   PCI_COMMON_CONFIG PciConfig;
480   ULONG DataSize;
481   ULONG StartDeviceNumber;
482   ULONG DeviceNumber;
483   ULONG StartFunctionNumber;
484   ULONG FunctionNumber;
485   BOOLEAN ChannelFound;
486   BOOLEAN DeviceFound;
487   ULONG BusMasterBasePort = 0;
488
489   DPRINT("AtapiFindCompatiblePciController() Bus: %lu  Slot: %lu\n",
490           ConfigInfo->SystemIoBusNumber,
491           ConfigInfo->SlotNumber);
492
493   *Again = FALSE;
494
495   /* both channels were claimed: exit */
496   if (ConfigInfo->AtdiskPrimaryClaimed == TRUE &&
497       ConfigInfo->AtdiskSecondaryClaimed == TRUE)
498     return(SP_RETURN_NOT_FOUND);
499
500   SlotNumber.u.AsULONG = ConfigInfo->SlotNumber;
501   StartDeviceNumber = SlotNumber.u.bits.DeviceNumber;
502   StartFunctionNumber = SlotNumber.u.bits.FunctionNumber;
503   for (DeviceNumber = StartDeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
504   {
505      SlotNumber.u.bits.DeviceNumber = DeviceNumber;
506      for (FunctionNumber = StartFunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
507      {
508         SlotNumber.u.bits.FunctionNumber = FunctionNumber;
509         ChannelFound = FALSE;
510         DeviceFound = FALSE;
511
512         DataSize = ScsiPortGetBusData(DeviceExtension,
513                                       PCIConfiguration,
514                                       ConfigInfo->SystemIoBusNumber,
515                                       SlotNumber.u.AsULONG,
516                                       &PciConfig,
517                                       PCI_COMMON_HDR_LENGTH);
518         if (DataSize != PCI_COMMON_HDR_LENGTH)
519         {
520            if (FunctionNumber == 0)
521            {
522               break;
523            }
524            else
525            {
526               continue;
527            }
528         }
529           
530         DPRINT("%x %x\n", PciConfig.BaseClass, PciConfig.SubClass);
531         if (PciConfig.BaseClass == 0x01 &&
532             PciConfig.SubClass == 0x01) // &&
533 //          (PciConfig.ProgIf & 0x05) == 0)
534         {
535            /* both channels are in compatibility mode */
536            DPRINT("Bus %1lu  Device %2lu  Func %1lu  VenID 0x%04hx  DevID 0x%04hx\n",
537                   ConfigInfo->SystemIoBusNumber,
538                   SlotNumber.u.bits.DeviceNumber,
539                   SlotNumber.u.bits.FunctionNumber,
540                   PciConfig.VendorID,
541                   PciConfig.DeviceID);
542            DPRINT("ProgIF 0x%02hx\n", PciConfig.ProgIf);
543
544            DPRINT("Found IDE controller in compatibility mode!\n");
545
546            ConfigInfo->NumberOfBuses = 1;
547            ConfigInfo->MaximumNumberOfTargets = 2;
548            ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
549
550            if (PciConfig.ProgIf & 0x80)
551            {
552               DPRINT("Found IDE Bus Master controller!\n");
553               if (PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_SPACE)
554               {
555                   BusMasterBasePort = PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_ADDRESS_MASK;
556                   DPRINT("  IDE Bus Master Registers at IO %lx\n", BusMasterBasePort);
557               }
558            }
559            if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
560            {
561               /* Both channels unclaimed: Claim primary channel */
562               DPRINT("Primary channel!\n");
563               ChannelFound = AtapiClaimHwResources(DevExt,
564                                                    ConfigInfo,
565                                                    PCIBus,
566                                                    0x1F0,
567                                                    0x3F4,
568                                                    BusMasterBasePort,
569                                                    14);
570               *Again = TRUE;
571            }
572            else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
573            {
574               /* Primary channel already claimed: claim secondary channel */
575               DPRINT("Secondary channel!\n");
576
577               ChannelFound = AtapiClaimHwResources(DevExt,
578                                                    ConfigInfo,
579                                                    PCIBus,
580                                                    0x170,
581                                                    0x374,
582                                                    BusMasterBasePort ? BusMasterBasePort + 8 : 0,
583                                                    15);
584               *Again = FALSE;
585            }
586            /* Find attached devices */
587            if (ChannelFound)
588            {
589               DeviceFound = AtapiFindDevices(DevExt, ConfigInfo);
590               ConfigInfo->SlotNumber = SlotNumber.u.AsULONG;
591               DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
592               return(SP_RETURN_FOUND);
593            }
594         }
595         if (FunctionNumber == 0 && !(PciConfig.HeaderType & PCI_MULTIFUNCTION))
596         {
597            break;
598         }
599      }  
600      StartFunctionNumber = 0;
601   }
602   DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
603
604   return(SP_RETURN_NOT_FOUND);
605 }
606 #endif
607
608
609 #ifdef ENABLE_ISA
610 static ULONG STDCALL
611 AtapiFindIsaBusController(PVOID DeviceExtension,
612                           PVOID HwContext,
613                           PVOID BusInformation,
614                           PCHAR ArgumentString,
615                           PPORT_CONFIGURATION_INFORMATION ConfigInfo,
616                           PBOOLEAN Again)
617 {
618   PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
619   BOOLEAN ChannelFound = FALSE;
620   BOOLEAN DeviceFound = FALSE;
621
622   DPRINT("AtapiFindIsaBusController() called!\n");
623
624   *Again = FALSE;
625
626   ConfigInfo->NumberOfBuses = 1;
627   ConfigInfo->MaximumNumberOfTargets = 2;
628   ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
629
630   if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
631     {
632       /* Both channels unclaimed: Claim primary channel */
633       DPRINT("Primary channel!\n");
634
635       ChannelFound = AtapiClaimHwResources(DevExt,
636                                            ConfigInfo,
637                                            Isa,
638                                            0x1F0,
639                                            0x3F4,
640                                            0,
641                                            14);
642       *Again = TRUE;
643     }
644   else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
645     {
646       /* Primary channel already claimed: claim secondary channel */
647       DPRINT("Secondary channel!\n");
648
649       ChannelFound = AtapiClaimHwResources(DevExt,
650                                            ConfigInfo,
651                                            Isa,
652                                            0x170,
653                                            0x374,
654                                            0,
655                                            15);
656       *Again = FALSE;
657     }
658   else
659     {
660       DPRINT("AtapiFindIsaBusController() both channels claimed. Returns: SP_RETURN_NOT_FOUND\n");
661       *Again = FALSE;
662       return(SP_RETURN_NOT_FOUND);
663     }
664
665   /* Find attached devices */
666   if (ChannelFound)
667     {
668       DeviceFound = AtapiFindDevices(DevExt,
669                                      ConfigInfo);
670       DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
671       return(SP_RETURN_FOUND);
672     }
673   *Again = FALSE;
674   return SP_RETURN_NOT_FOUND;
675 }
676 #endif
677
678
679 #ifdef ENABLE_NATIVE_PCI
680 static ULONG STDCALL
681 AtapiFindNativePciController(PVOID DeviceExtension,
682                              PVOID HwContext,
683                              PVOID BusInformation,
684                              PCHAR ArgumentString,
685                              PPORT_CONFIGURATION_INFORMATION ConfigInfo,
686                              PBOOLEAN Again)
687 {
688   PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
689   PCI_COMMON_CONFIG PciConfig;
690   PCI_SLOT_NUMBER SlotNumber;
691   ULONG DataSize;
692   ULONG DeviceNumber;
693   ULONG StartDeviceNumber;
694   ULONG FunctionNumber;
695   ULONG StartFunctionNumber;
696   ULONG BusMasterBasePort;
697   ULONG Count;
698   BOOLEAN ChannelFound;
699
700   DPRINT("AtapiFindNativePciController() called!\n");
701
702   SlotNumber.u.AsULONG = ConfigInfo->SlotNumber;
703   StartDeviceNumber = SlotNumber.u.bits.DeviceNumber;
704   StartFunctionNumber = SlotNumber.u.bits.FunctionNumber;
705   for (DeviceNumber = StartDeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
706   {
707      SlotNumber.u.bits.DeviceNumber = DeviceNumber;
708      for (FunctionNumber = StartFunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
709      {
710         SlotNumber.u.bits.FunctionNumber = FunctionNumber;
711         DataSize = ScsiPortGetBusData(DeviceExtension,
712                                       PCIConfiguration,
713                                       ConfigInfo->SystemIoBusNumber,
714                                       SlotNumber.u.AsULONG,
715                                       &PciConfig,
716                                       PCI_COMMON_HDR_LENGTH);
717         if (DataSize != PCI_COMMON_HDR_LENGTH)
718         {
719            break;
720         }
721         for (Count = 0; Count < sizeof(PciNativeController)/sizeof(PCI_NATIVE_CONTROLLER); Count++)
722         {
723            if (PciConfig.VendorID == PciNativeController[Count].VendorID &&
724                PciConfig.DeviceID == PciNativeController[Count].DeviceID)
725            {
726               break;
727            }
728         }
729         if (Count < sizeof(PciNativeController)/sizeof(PCI_NATIVE_CONTROLLER)) 
730         {
731            /* We have found a known native pci ide controller */
732            if ((PciConfig.ProgIf & 0x80) && (PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_SPACE))
733            {
734               DPRINT("Found IDE Bus Master controller!\n");
735               BusMasterBasePort = PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_ADDRESS_MASK;
736               DPRINT("  IDE Bus Master Registers at IO %lx\n", BusMasterBasePort);
737            }
738            else
739            {
740               BusMasterBasePort = 0;
741            }
742
743            DPRINT("VendorID: %04x, DeviceID: %04x\n", PciConfig.VendorID, PciConfig.DeviceID);
744            ConfigInfo->NumberOfBuses = 1;
745            ConfigInfo->MaximumNumberOfTargets = 2;
746            ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
747
748            /* FIXME:
749                 We must not store and use the last tested slot number. If there is a recall
750                 to the some device and we will claim the primary channel again than the call
751                 to ScsiPortGetDeviceBase in AtapiClaimHwResource will fail and we can try to
752                 claim the secondary channel. 
753             */
754            ChannelFound = FALSE;
755            if (LastSlotNumber.u.AsULONG != SlotNumber.u.AsULONG)
756            {
757               /* try to claim primary channel */
758               if ((PciConfig.u.type0.BaseAddresses[0] & PCI_ADDRESS_IO_SPACE) &&
759                   (PciConfig.u.type0.BaseAddresses[1] & PCI_ADDRESS_IO_SPACE))
760               {
761                  /* primary channel is enabled */
762                  ChannelFound = AtapiClaimHwResources(DevExt,
763                                                       ConfigInfo,
764                                                       PCIBus,
765                                                       PciConfig.u.type0.BaseAddresses[0] & PCI_ADDRESS_IO_ADDRESS_MASK,
766                                                       PciConfig.u.type0.BaseAddresses[1] & PCI_ADDRESS_IO_ADDRESS_MASK,
767                                                       BusMasterBasePort,
768                                                       PciConfig.u.type0.InterruptLine);
769                  if (ChannelFound)
770                  {
771                     AtapiFindDevices(DevExt, ConfigInfo);
772                     *Again = TRUE;
773                     ConfigInfo->SlotNumber = LastSlotNumber.u.AsULONG = SlotNumber.u.AsULONG;
774                     return SP_RETURN_FOUND;
775                  }
776               }
777            }
778            if (!ChannelFound)
779            {
780               /* try to claim secondary channel */
781               if ((PciConfig.u.type0.BaseAddresses[2] & PCI_ADDRESS_IO_SPACE) &&
782                   (PciConfig.u.type0.BaseAddresses[3] & PCI_ADDRESS_IO_SPACE))
783               {
784                  /* secondary channel is enabled */
785                  ChannelFound = AtapiClaimHwResources(DevExt,
786                                                       ConfigInfo,
787                                                       PCIBus,
788                                                       PciConfig.u.type0.BaseAddresses[2] & PCI_ADDRESS_IO_ADDRESS_MASK,
789                                                       PciConfig.u.type0.BaseAddresses[3] & PCI_ADDRESS_IO_ADDRESS_MASK,
790                                                       BusMasterBasePort ? BusMasterBasePort + 8 : 0,
791                                                       PciConfig.u.type0.InterruptLine);
792                  if (ChannelFound)
793                  {
794                     AtapiFindDevices(DevExt, ConfigInfo);
795                     *Again = FALSE;
796                     LastSlotNumber.u.AsULONG = 0xFFFFFFFF;
797                     return SP_RETURN_FOUND;
798                  }
799               }
800            }
801         }
802      }
803      StartFunctionNumber = 0;
804   }
805   *Again = FALSE;
806   LastSlotNumber.u.AsULONG = 0xFFFFFFFF;
807   DPRINT("AtapiFindNativePciController() done!\n");
808
809   return(SP_RETURN_NOT_FOUND);
810 }
811 #endif
812
813
814 static BOOLEAN STDCALL
815 AtapiInitialize(IN PVOID DeviceExtension)
816 {
817   return(TRUE);
818 }
819
820
821 static BOOLEAN STDCALL
822 AtapiResetBus(IN PVOID DeviceExtension,
823               IN ULONG PathId)
824 {
825   return(TRUE);
826 }
827
828
829 static BOOLEAN STDCALL
830 AtapiStartIo(IN PVOID DeviceExtension,
831              IN PSCSI_REQUEST_BLOCK Srb)
832 {
833   PATAPI_MINIPORT_EXTENSION DevExt;
834   ULONG Result;
835
836   DPRINT("AtapiStartIo() called\n");
837
838   DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
839
840   switch (Srb->Function)
841     {
842       case SRB_FUNCTION_EXECUTE_SCSI:
843         DevExt->CurrentSrb = Srb;
844         if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
845           {
846             Result = AtapiSendAtapiCommand(DevExt,
847                                            Srb);
848           }
849         else
850           {
851             Result = AtapiSendIdeCommand(DevExt,
852                                          Srb);
853           }
854         break;
855
856       case SRB_FUNCTION_ABORT_COMMAND:
857         if (DevExt->CurrentSrb != NULL)
858           {
859             Result = SRB_STATUS_ABORT_FAILED;
860           }
861         else
862           {
863             Result = SRB_STATUS_SUCCESS;
864           }
865         break;
866
867       default:
868         Result = SRB_STATUS_INVALID_REQUEST;
869         break;
870     }
871
872   Srb->SrbStatus = Result;
873
874
875   if (Result != SRB_STATUS_PENDING)
876     {
877       DevExt->CurrentSrb = NULL;
878       Srb->SrbStatus = (UCHAR)Result;
879
880       ScsiPortNotification(RequestComplete,
881                            DeviceExtension,
882                            Srb);
883       ScsiPortNotification(NextRequest,
884                            DeviceExtension,
885                            NULL);
886     }
887   else
888     {
889       DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
890     }
891
892   DPRINT("AtapiStartIo() done\n");
893
894   return(TRUE);
895 }
896
897
898 static BOOLEAN STDCALL
899 AtapiInterrupt(IN PVOID DeviceExtension)
900 {
901   PATAPI_MINIPORT_EXTENSION DevExt;
902   PSCSI_REQUEST_BLOCK Srb;
903   ULONG CommandPortBase;
904   ULONG ControlPortBase;
905   UCHAR DeviceStatus;
906   BOOLEAN IsLastBlock;
907   BOOLEAN IsAtapi;
908   ULONG Retries;
909   PUCHAR TargetAddress;
910   ULONG TransferSize;
911   ULONG JunkSize;
912   USHORT Junk;
913
914   DPRINT("AtapiInterrupt() called!\n");
915
916   DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
917
918   CommandPortBase = DevExt->CommandPortBase;
919   ControlPortBase = DevExt->ControlPortBase;
920
921   if (DevExt->ExpectingInterrupt == FALSE)
922     {
923       DeviceStatus = IDEReadStatus(CommandPortBase);
924       DPRINT("AtapiInterrupt(): Unexpected interrupt (port=%x)\n", CommandPortBase);
925       return(FALSE);
926     }
927
928   /* check if it was our irq */
929   if ((DeviceStatus = IDEReadAltStatus(ControlPortBase)) & IDE_SR_BUSY)
930   {
931      ScsiPortStallExecution(1);
932      if ((DeviceStatus = IDEReadAltStatus(ControlPortBase) & IDE_SR_BUSY))
933      {
934         DPRINT("AtapiInterrupt(): Unexpected interrupt (port=%x)\n", CommandPortBase);
935         return(FALSE);
936      }
937   }
938
939   Srb = DevExt->CurrentSrb;
940   DPRINT("Srb: %p\n", Srb);
941
942   DPRINT("CommandPortBase: %lx  ControlPortBase: %lx\n", CommandPortBase, ControlPortBase);
943
944   IsAtapi = (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI);
945   DPRINT("IsAtapi == %s\n", (IsAtapi) ? "TRUE" : "FALSE");
946
947   IsLastBlock = FALSE;
948
949   DeviceStatus = IDEReadStatus(CommandPortBase);
950   DPRINT("DeviceStatus: %x\n", DeviceStatus);
951
952   if ((DeviceStatus & IDE_SR_ERR) &&
953       (Srb->Cdb[0] != SCSIOP_REQUEST_SENSE))
954     {
955       /* Report error condition */
956       Srb->SrbStatus = SRB_STATUS_ERROR;
957       IsLastBlock = TRUE;
958     }
959   else
960     {
961       if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
962         {
963           DPRINT("Read data\n");
964
965           /* Update controller/device state variables */
966           TargetAddress = DevExt->DataBuffer;
967
968           if (IsAtapi)
969             {
970               TransferSize = IDEReadCylinderLow(CommandPortBase);
971               TransferSize += IDEReadCylinderHigh(CommandPortBase) << 8;
972             }
973           else
974             {
975               TransferSize = DevExt->TransferSize[Srb->TargetId];
976             }
977
978           DPRINT("TransferLength: %lu\n", Srb->DataTransferLength);
979           DPRINT("TransferSize: %lu\n", TransferSize);
980
981           if (DevExt->DataTransferLength <= TransferSize)
982             {
983               JunkSize = TransferSize - DevExt->DataTransferLength;
984               TransferSize = DevExt->DataTransferLength;
985
986 #ifndef NDEBUG
987               if (JunkSize > 0)
988                 {
989                   DPRINT1("Junk data: %lu bytes\n", JunkSize);
990                 }
991 #endif
992
993               DevExt->DataTransferLength = 0;
994               IsLastBlock = TRUE;
995             }
996           else
997             {
998               DevExt->DataTransferLength -= TransferSize;
999               IsLastBlock = FALSE;
1000             }
1001           DevExt->DataBuffer += TransferSize;
1002           DPRINT("IsLastBlock == %s\n", (IsLastBlock) ? "TRUE" : "FALSE");
1003
1004           /* Wait for DRQ assertion */
1005           for (Retries = 0; Retries < IDE_MAX_DRQ_RETRIES &&
1006                !(IDEReadStatus(CommandPortBase) & IDE_SR_DRQ);
1007                Retries++)
1008             {
1009               KeStallExecutionProcessor(10);
1010             }
1011
1012           /* Copy the block of data */
1013           if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
1014             {
1015               IDEReadBlock32(CommandPortBase,
1016                              TargetAddress,
1017                              TransferSize);
1018             }
1019           else
1020             {
1021               IDEReadBlock(CommandPortBase,
1022                            TargetAddress,
1023                            TransferSize);
1024             }
1025
1026           /* check DRQ */
1027           if (IsLastBlock)
1028             {
1029               /* Read remaining junk from device */
1030               while (JunkSize > 0)
1031                 {
1032                   IDEReadBlock(CommandPortBase,
1033                                &Junk,
1034                                2);
1035                   JunkSize -= 2;
1036                 }
1037
1038               for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
1039                    (IDEReadStatus(CommandPortBase) & IDE_SR_BUSY);
1040                    Retries++)
1041                 {
1042                   KeStallExecutionProcessor(10);
1043                 }
1044
1045               /* Check for data overrun */
1046               while (IDEReadStatus(CommandPortBase) & IDE_SR_DRQ)
1047                 {
1048                   DPRINT1("AtapiInterrupt(): reading overrun data!\n");
1049                   IDEReadWord(CommandPortBase);
1050                 }
1051             }
1052
1053           Srb->SrbStatus = SRB_STATUS_SUCCESS;
1054         }
1055       else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
1056         {
1057           DPRINT("Write data\n");
1058
1059           if (DevExt->DataTransferLength == 0)
1060             {
1061               /* Check for data overrun */
1062               if (DeviceStatus & IDE_SR_DRQ)
1063                 {
1064                   /* FIXME: Handle error! */
1065                   /* This can occure if the irq is shared with an other and if the 
1066                      ide controller has a write buffer. We have write the last sectors
1067                      and the other device has a irq before ours. The isr is called but 
1068                      we haven't a interrupt. The controller writes the sector buffer 
1069                      and the status register shows DRQ because the write is not ended. */
1070                   DPRINT("AtapiInterrupt(): data overrun error!\n");
1071                 }
1072               IsLastBlock = TRUE;
1073             }
1074           else
1075             {
1076               /* Update DevExt data */
1077               TransferSize = DevExt->TransferSize[Srb->TargetId];
1078               if (DevExt->DataTransferLength < TransferSize)
1079                 {
1080                   TransferSize = DevExt->DataTransferLength;
1081                 }
1082
1083               TargetAddress = DevExt->DataBuffer;
1084               DevExt->DataBuffer += TransferSize;
1085               DevExt->DataTransferLength -= TransferSize;
1086
1087               /* Write the sector */
1088               if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
1089                 {
1090                   IDEWriteBlock32(CommandPortBase,
1091                                   TargetAddress,
1092                                   TransferSize);
1093                 }
1094               else
1095                 {
1096                   IDEWriteBlock(CommandPortBase,
1097                                 TargetAddress,
1098                                 TransferSize);
1099                 }
1100             }
1101
1102           Srb->SrbStatus = SRB_STATUS_SUCCESS;
1103         }
1104       else
1105         {
1106           DPRINT("Unspecified transfer direction!\n");
1107           Srb->SrbStatus = SRB_STATUS_SUCCESS;
1108           IsLastBlock = TRUE;
1109         }
1110     }
1111
1112
1113   if (Srb->SrbStatus == SRB_STATUS_ERROR)
1114     {
1115       Srb->SrbStatus = AtapiErrorToScsi(DeviceExtension,
1116                                         Srb);
1117     }
1118
1119
1120   /* complete this packet */
1121   if (IsLastBlock)
1122     {
1123       DevExt->ExpectingInterrupt = FALSE;
1124
1125       ScsiPortNotification(RequestComplete,
1126                            DeviceExtension,
1127                            Srb);
1128
1129       ScsiPortNotification(NextRequest,
1130                            DeviceExtension,
1131                            NULL);
1132     }
1133
1134   DPRINT("AtapiInterrupt() done!\n");
1135
1136   return(TRUE);
1137 }
1138
1139 //  ----------------------------------------------------  Discardable statics
1140
1141
1142 /**********************************************************************
1143  * NAME                                                 INTERNAL
1144  *      AtapiFindDevices
1145  *
1146  * DESCRIPTION
1147  *      Searches for devices on the given port.
1148  *
1149  * RUN LEVEL
1150  *      PASSIVE_LEVEL
1151  *
1152  * ARGUMENTS
1153  *      DeviceExtension
1154  *              Port device specific information.
1155  *
1156  *      ConfigInfo
1157  *              Port configuration information.
1158  *
1159  * RETURN VALUE
1160  *      TRUE: At least one device is attached to the port.
1161  *      FALSE: No device is attached to the port.
1162  */
1163
1164 static BOOLEAN
1165 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1166                  PPORT_CONFIGURATION_INFORMATION ConfigInfo)
1167 {
1168   BOOLEAN DeviceFound = FALSE;
1169   ULONG CommandPortBase;
1170   ULONG ControlPortBase;
1171   ULONG UnitNumber;
1172   ULONG Retries;
1173   BYTE High, Low;
1174
1175   DPRINT("AtapiFindDevices() called\n");
1176
1177   CommandPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[0].RangeStart);
1178   DPRINT("  CommandPortBase: %x\n", CommandPortBase);
1179
1180   ControlPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[1].RangeStart);
1181   DPRINT("  ControlPortBase: %x\n", ControlPortBase);
1182
1183   for (UnitNumber = 0; UnitNumber < 2; UnitNumber++)
1184     {
1185       /* Select drive */
1186       IDEWriteDriveHead(CommandPortBase,
1187                         IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
1188       ScsiPortStallExecution(500);
1189
1190       /* Disable interrupts */
1191       IDEWriteDriveControl(ControlPortBase,
1192                            IDE_DC_nIEN);
1193       ScsiPortStallExecution(500);
1194
1195       /* Check if a device is attached to the interface */
1196       IDEWriteCylinderHigh(CommandPortBase, 0xaa);
1197       IDEWriteCylinderLow(CommandPortBase, 0x55);
1198
1199       High = IDEReadCylinderHigh(CommandPortBase);
1200       Low = IDEReadCylinderLow(CommandPortBase);
1201
1202       IDEWriteCylinderHigh(CommandPortBase, 0);
1203       IDEWriteCylinderLow(CommandPortBase, 0);
1204
1205       if (Low != 0x55 || High != 0xaa)
1206       {
1207          DPRINT("No Drive found. UnitNumber %d CommandPortBase %x\n", UnitNumber, CommandPortBase);
1208          continue;
1209       }
1210
1211       IDEWriteCommand(CommandPortBase, IDE_CMD_RESET);
1212
1213       for (Retries = 0; Retries < 20000; Retries++)
1214         {
1215           if (!(IDEReadStatus(CommandPortBase) & IDE_SR_BUSY))
1216             {
1217               break;
1218             }
1219           ScsiPortStallExecution(150);
1220         }
1221       if (Retries >= 20000)
1222         {
1223           DPRINT("Timeout on drive %lu\n", UnitNumber);
1224           DeviceExtension->DeviceFlags[UnitNumber] &= ~DEVICE_PRESENT;
1225           continue;
1226         }
1227
1228       High = IDEReadCylinderHigh(CommandPortBase);
1229       Low = IDEReadCylinderLow(CommandPortBase);
1230
1231       DPRINT("  Check drive %lu: High 0x%x Low 0x%x\n",
1232              UnitNumber,
1233              High,
1234              Low);
1235
1236       if (High == 0xEB && Low == 0x14)
1237         {
1238           if (AtapiIdentifyDevice(CommandPortBase,
1239                                   ControlPortBase,
1240                                   UnitNumber,
1241                                   TRUE,
1242                                   &DeviceExtension->DeviceParams[UnitNumber]))
1243             {
1244               DPRINT("  ATAPI drive found!\n");
1245               DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_PRESENT;
1246               DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_ATAPI;
1247               DeviceExtension->TransferSize[UnitNumber] =
1248                 DeviceExtension->DeviceParams[UnitNumber].BytesPerSector;
1249               DeviceFound = TRUE;
1250             }
1251           else
1252             {
1253               DPRINT("  No ATAPI drive found!\n");
1254             }
1255         }
1256       else
1257         {
1258           if (AtapiIdentifyDevice(CommandPortBase,
1259                                   ControlPortBase,
1260                                   UnitNumber,
1261                                   FALSE,
1262                                   &DeviceExtension->DeviceParams[UnitNumber]))
1263             {
1264               DPRINT("  IDE drive found!\n");
1265               DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_PRESENT;
1266               DeviceExtension->TransferSize[UnitNumber] = DeviceExtension->DeviceParams[UnitNumber].BytesPerSector;
1267               if ((DeviceExtension->DeviceParams[UnitNumber].RWMultImplemented & 0x8000) && 
1268                   (DeviceExtension->DeviceParams[UnitNumber].RWMultImplemented & 0xff) &&
1269                   (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0x100) &&
1270                   (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0xff))
1271                 {
1272                   DeviceExtension->TransferSize[UnitNumber] *= (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0xff);
1273                   DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_MULTI_SECTOR_CMD;
1274                 }
1275
1276               if (DeviceExtension->DeviceParams[UnitNumber].DWordIo)
1277                 {
1278                   DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DWORD_IO;
1279                 }
1280
1281               DeviceFound = TRUE;
1282             }
1283           else
1284             {
1285               DPRINT("  No IDE drive found!\n");
1286             }
1287         }
1288     }
1289
1290   /* Reset pending interrupts */
1291   IDEReadStatus(CommandPortBase);
1292   /* Reenable interrupts */
1293   IDEWriteDriveControl(ControlPortBase, 0);
1294   ScsiPortStallExecution(500);
1295   /* Return with drive 0 selected */
1296   IDEWriteDriveHead(CommandPortBase, IDE_DH_FIXED);
1297   ScsiPortStallExecution(500);
1298
1299   DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound) ? "TRUE" : "FALSE");
1300
1301   return(DeviceFound);
1302 }
1303
1304
1305 //    AtapiResetController
1306 //
1307 //  DESCRIPTION:
1308 //    Reset the controller and report completion status
1309 //
1310 //  RUN LEVEL:
1311 //    PASSIVE_LEVEL
1312 //
1313 //  ARGUMENTS:
1314 //    IN  WORD  CommandPort  The address of the command port
1315 //    IN  WORD  ControlPort  The address of the control port
1316 //
1317 //  RETURNS:
1318 //
1319
1320 static BOOLEAN
1321 AtapiResetController(IN ULONG CommandPort,
1322                      IN ULONG ControlPort)
1323 {
1324   int Retries;
1325
1326   /* Assert drive reset line */
1327   IDEWriteDriveControl(ControlPort, IDE_DC_SRST);
1328
1329   /* Wait for min. 25 microseconds */
1330   ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH);
1331
1332   /* Negate drive reset line */
1333   IDEWriteDriveControl(ControlPort, 0);
1334
1335   /* Wait for BUSY negation */
1336   for (Retries = 0; Retries < IDE_RESET_BUSY_TIMEOUT * 1000; Retries++)
1337     {
1338       if (!(IDEReadStatus(CommandPort) & IDE_SR_BUSY))
1339         {
1340           break;
1341         }
1342       ScsiPortStallExecution(10);
1343     }
1344
1345   if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
1346     {
1347       return(FALSE);
1348     }
1349
1350     //  return TRUE if controller came back to life. and
1351     //  the registers are initialized correctly
1352   return(IDEReadError(CommandPort) == 1);
1353 }
1354
1355 /*
1356  *  AtapiIdentifyDevice
1357  *
1358  *  DESCRIPTION:
1359  *      Get the identification block from the drive
1360  *
1361  *  RUN LEVEL:
1362  *      PASSIVE_LEVEL
1363  *
1364  *  ARGUMENTS:
1365  *      CommandPort
1366  *              Address of the command port
1367  *      ControlPort
1368  *              Address of the control port
1369  *      DriveNum
1370  *              The drive index (0,1)
1371  *      Atapi
1372  *              Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1373  *      DrvParms
1374  *              Address to write drive ident block
1375  *
1376  *  RETURNS:
1377  *      TRUE: The drive identification block was retrieved successfully
1378  *      FALSE: an error ocurred
1379  */
1380
1381 static BOOLEAN
1382 AtapiIdentifyDevice(IN ULONG CommandPort,
1383                     IN ULONG ControlPort,
1384                     IN ULONG DriveNum,
1385                     IN BOOLEAN Atapi,
1386                     OUT PIDE_DRIVE_IDENTIFY DrvParms)
1387 {
1388   LONG i;
1389
1390   /*  Get the Drive Identify block from drive or die  */
1391   if (AtapiPolledRead(CommandPort,
1392                       ControlPort,
1393                       0,
1394                       1,
1395                       0,
1396                       0,
1397                       0,
1398                       (DriveNum ? IDE_DH_DRV1 : 0),
1399                       (Atapi ? IDE_CMD_IDENT_ATAPI_DRV : IDE_CMD_IDENT_ATA_DRV),
1400                       (BYTE *)DrvParms) != 0)
1401     {
1402       DPRINT("IDEPolledRead() failed\n");
1403       return(FALSE);
1404     }
1405
1406   /*  Report on drive parameters if debug mode  */
1407   IDESwapBytePairs(DrvParms->SerialNumber, 20);
1408   IDESwapBytePairs(DrvParms->FirmwareRev, 8);
1409   IDESwapBytePairs(DrvParms->ModelNumber, 40);
1410   DPRINT("Config:%04x  Cyls:%5d  Heads:%2d  Sectors/Track:%3d  Gaps:%02d %02d\n",
1411          DrvParms->ConfigBits,
1412          DrvParms->LogicalCyls,
1413          DrvParms->LogicalHeads,
1414          DrvParms->SectorsPerTrack,
1415          DrvParms->InterSectorGap,
1416          DrvParms->InterSectorGapSize);
1417   DPRINT("Bytes/PLO:%3d  Vendor Cnt:%2d  Serial number:[%.20s]\n",
1418          DrvParms->BytesInPLO,
1419          DrvParms->VendorUniqueCnt,
1420          DrvParms->SerialNumber);
1421   DPRINT("Cntlr type:%2d  BufSiz:%5d  ECC bytes:%3d  Firmware Rev:[%.8s]\n",
1422          DrvParms->ControllerType,
1423          DrvParms->BufferSize * IDE_SECTOR_BUF_SZ,
1424          DrvParms->ECCByteCnt,
1425          DrvParms->FirmwareRev);
1426   DPRINT("Model:[%.40s]\n", DrvParms->ModelNumber);
1427   DPRINT("RWMultMax?:%04x  RWMult?:%02x  LBA:%d  DMA:%d  MinPIO:%d ns  MinDMA:%d ns\n",
1428          (DrvParms->RWMultImplemented),
1429          (DrvParms->RWMultCurrent) & 0xff,
1430          (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0,
1431          (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
1432          DrvParms->MinPIOTransTime,
1433          DrvParms->MinDMATransTime);
1434   DPRINT("TM:Cyls:%d  Heads:%d  Sectors/Trk:%d Capacity:%ld\n",
1435          DrvParms->TMCylinders,
1436          DrvParms->TMHeads,
1437          DrvParms->TMSectorsPerTrk,
1438          (ULONG)(DrvParms->TMCapacityLo + (DrvParms->TMCapacityHi << 16)));
1439   DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1440          DrvParms->TMSectorCountHi,
1441          DrvParms->TMSectorCountLo,
1442          (ULONG)((DrvParms->TMSectorCountHi << 16) + DrvParms->TMSectorCountLo));
1443
1444   if (! Atapi && 0 != (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED))
1445     {
1446       /* LBA ATA drives always have a sector size of 512 */
1447       DrvParms->BytesPerSector = 512;
1448     }
1449   else
1450     {
1451       DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
1452       if (DrvParms->BytesPerSector == 0)
1453         {
1454           DrvParms->BytesPerSector = 512;
1455         }
1456       else
1457         {
1458           for (i = 15; i >= 0; i--)
1459             {
1460               if (DrvParms->BytesPerSector & (1 << i))
1461                 {
1462                   DrvParms->BytesPerSector = 1 << i;
1463                   break;
1464                 }
1465             }
1466         }
1467     }
1468   DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
1469
1470   return(TRUE);
1471 }
1472
1473
1474 //    AtapiPolledRead
1475 //
1476 //  DESCRIPTION:
1477 //    Read a sector of data from the drive in a polled fashion.
1478 //
1479 //  RUN LEVEL:
1480 //    PASSIVE_LEVEL
1481 //
1482 //  ARGUMENTS:
1483 //    IN   WORD  Address       Address of command port for drive
1484 //    IN   BYTE  PreComp       Value to write to precomp register
1485 //    IN   BYTE  SectorCnt     Value to write to sectorCnt register
1486 //    IN   BYTE  SectorNum     Value to write to sectorNum register
1487 //    IN   BYTE  CylinderLow   Value to write to CylinderLow register
1488 //    IN   BYTE  CylinderHigh  Value to write to CylinderHigh register
1489 //    IN   BYTE  DrvHead       Value to write to Drive/Head register
1490 //    IN   BYTE  Command       Value to write to Command register
1491 //    OUT  BYTE  *Buffer       Buffer for output data
1492 //
1493 //  RETURNS:
1494 //    int  0 is success, non 0 is an error code
1495 //
1496
1497 static int
1498 AtapiPolledRead(IN ULONG CommandPort,
1499                 IN ULONG ControlPort,
1500                 IN BYTE PreComp,
1501                 IN BYTE SectorCnt,
1502                 IN BYTE SectorNum,
1503                 IN BYTE CylinderLow,
1504                 IN BYTE CylinderHigh,
1505                 IN BYTE DrvHead,
1506                 IN BYTE Command,
1507                 OUT BYTE *Buffer)
1508 {
1509   ULONG SectorCount = 0;
1510   ULONG RetryCount;
1511   BOOLEAN Junk = FALSE;
1512   UCHAR Status;
1513
1514 //#if 0
1515   /* Wait for BUSY to clear */
1516   for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1517     {
1518       Status = IDEReadStatus(CommandPort);
1519       if (!(Status & IDE_SR_BUSY))
1520         {
1521           break;
1522         }
1523       ScsiPortStallExecution(10);
1524     }
1525   DPRINT("status=%02x\n", Status);
1526   DPRINT("waited %ld usecs for busy to clear\n", RetryCount * 10);
1527   if (RetryCount >= IDE_MAX_BUSY_RETRIES)
1528     {
1529       DPRINT("Drive is BUSY for too long\n");
1530       return(IDE_ER_ABRT);
1531     }
1532 //#endif
1533
1534   /*  Write Drive/Head to select drive  */
1535   IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
1536   ScsiPortStallExecution(500);
1537
1538   /* Disable interrupts */
1539   IDEWriteDriveControl(ControlPort, IDE_DC_nIEN);
1540   ScsiPortStallExecution(500);
1541
1542 #if 0
1543   /*  Wait for STATUS.BUSY and STATUS.DRQ to clear  */
1544   for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1545     {
1546       Status = IDEReadStatus(CommandPort);
1547       if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1548         {
1549           break;
1550         }
1551       ScsiPortStallExecution(10);
1552     }
1553   if (RetryCount >= IDE_MAX_BUSY_RETRIES)
1554     {
1555       return IDE_ER_ABRT;
1556     }
1557 #endif
1558
1559   /*  Issue command to drive  */
1560   if (DrvHead & IDE_DH_LBA)
1561     {
1562       DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1563              DrvHead & IDE_DH_DRV1 ? 1 : 0,
1564              ((DrvHead & 0x0f) << 24) + (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
1565              SectorCnt,
1566              Command);
1567     }
1568   else
1569     {
1570       DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1571              DrvHead & IDE_DH_DRV1 ? 1 : 0,
1572              CylinderHigh,
1573              CylinderLow,
1574              DrvHead & 0x0f,
1575              SectorNum,
1576              SectorCnt,
1577              Command);
1578     }
1579
1580   /*  Setup command parameters  */
1581   IDEWritePrecomp(CommandPort, PreComp);
1582   IDEWriteSectorCount(CommandPort, SectorCnt);
1583   IDEWriteSectorNum(CommandPort, SectorNum);
1584   IDEWriteCylinderHigh(CommandPort, CylinderHigh);
1585   IDEWriteCylinderLow(CommandPort, CylinderLow);
1586   IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
1587
1588   /*  Issue the command  */
1589   IDEWriteCommand(CommandPort, Command);
1590   ScsiPortStallExecution(50);
1591
1592   /*  wait for DRQ or error  */
1593   for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
1594     {
1595       Status = IDEReadStatus(CommandPort);
1596       if (!(Status & IDE_SR_BUSY))
1597         {
1598           if (Status & IDE_SR_ERR)
1599             {
1600               IDEWriteDriveControl(ControlPort, 0);
1601               ScsiPortStallExecution(50);
1602               IDEReadStatus(CommandPort);
1603
1604               return(IDE_ER_ABRT);
1605             }
1606           if (Status & IDE_SR_DRQ)
1607             {
1608               break;
1609             }
1610           else
1611             {
1612               IDEWriteDriveControl(ControlPort, 0);
1613               ScsiPortStallExecution(50);
1614               IDEReadStatus(CommandPort);
1615
1616               return(IDE_ER_ABRT);
1617             }
1618         }
1619       ScsiPortStallExecution(10);
1620     }
1621
1622   /*  timed out  */
1623   if (RetryCount >= IDE_MAX_POLL_RETRIES)
1624     {
1625       IDEWriteDriveControl(ControlPort, 0);
1626       ScsiPortStallExecution(50);
1627       IDEReadStatus(CommandPort);
1628
1629       return(IDE_ER_ABRT);
1630     }
1631
1632   while (1)
1633     {
1634       /*  Read data into buffer  */
1635       if (Junk == FALSE)
1636         {
1637           IDEReadBlock(CommandPort, Buffer, IDE_SECTOR_BUF_SZ);
1638           Buffer += IDE_SECTOR_BUF_SZ;
1639         }
1640       else
1641         {
1642           UCHAR JunkBuffer[IDE_SECTOR_BUF_SZ];
1643           IDEReadBlock(CommandPort, JunkBuffer, IDE_SECTOR_BUF_SZ);
1644         }
1645       SectorCount++;
1646
1647       /*  Check for error or more sectors to read  */
1648       for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1649         {
1650           Status = IDEReadStatus(CommandPort);
1651           if (!(Status & IDE_SR_BUSY))
1652             {
1653               if (Status & IDE_SR_ERR)
1654                 {
1655                   IDEWriteDriveControl(ControlPort, 0);
1656                   ScsiPortStallExecution(50);
1657                   IDEReadStatus(CommandPort);
1658
1659                   return(IDE_ER_ABRT);
1660                 }
1661               if (Status & IDE_SR_DRQ)
1662                 {
1663                   if (SectorCount >= SectorCnt)
1664                     {
1665                       DPRINT("Buffer size exceeded!\n");
1666                       Junk = TRUE;
1667                     }
1668                   break;
1669                 }
1670               else
1671                 {
1672                   if (SectorCount > SectorCnt)
1673                     {
1674                       DPRINT("Read %lu sectors of junk!\n",
1675                              SectorCount - SectorCnt);
1676                     }
1677                   IDEWriteDriveControl(ControlPort, 0);
1678                   ScsiPortStallExecution(50);
1679                   IDEReadStatus(CommandPort);
1680
1681                   return(0);
1682                 }
1683             }
1684         }
1685     }
1686 }
1687
1688
1689 //  -------------------------------------------  Nondiscardable statics
1690
1691 static ULONG
1692 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1693                       IN PSCSI_REQUEST_BLOCK Srb)
1694 {
1695   UCHAR ByteCountHigh;
1696   UCHAR ByteCountLow;
1697   ULONG Retries;
1698   ULONG CdbSize;
1699   UCHAR Status;
1700
1701   DPRINT("AtapiSendAtapiCommand() called!\n");
1702
1703   if (Srb->PathId != 0)
1704     {
1705       Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
1706       return(SRB_STATUS_INVALID_PATH_ID);
1707     }
1708
1709   if (Srb->TargetId > 1)
1710     {
1711       Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
1712       return(SRB_STATUS_INVALID_TARGET_ID);
1713     }
1714
1715   if (Srb->Lun != 0)
1716     {
1717       Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
1718       return(SRB_STATUS_INVALID_LUN);
1719     }
1720
1721   if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_PRESENT))
1722     {
1723       Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1724       return(SRB_STATUS_NO_DEVICE);
1725     }
1726
1727   DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
1728          Srb->TargetId);
1729
1730   if (Srb->Cdb[0] == SCSIOP_INQUIRY)
1731     return(AtapiInquiry(DeviceExtension,
1732                         Srb));
1733
1734   /* Set pointer to data buffer. */
1735   DeviceExtension->DataBuffer = (PUCHAR)Srb->DataBuffer;
1736   DeviceExtension->DataTransferLength = Srb->DataTransferLength;
1737   DeviceExtension->CurrentSrb = Srb;
1738
1739   /* Wait for BUSY to clear */
1740   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1741     {
1742       Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1743       if (!(Status & IDE_SR_BUSY))
1744         {
1745           break;
1746         }
1747       ScsiPortStallExecution(10);
1748     }
1749   DPRINT("status=%02x\n", Status);
1750   DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
1751   if (Retries >= IDE_MAX_BUSY_RETRIES)
1752     {
1753       DPRINT("Drive is BUSY for too long\n");
1754       return(SRB_STATUS_BUSY);
1755     }
1756
1757   /* Select the desired drive */
1758   IDEWriteDriveHead(DeviceExtension->CommandPortBase,
1759                     IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
1760
1761   /* Wait a little while */
1762   ScsiPortStallExecution(50);
1763
1764 #if 0
1765   /* Wait for BUSY to clear and DRDY to assert */
1766   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1767     {
1768       Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1769       if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1770         {
1771           break;
1772         }
1773       ScsiPortStallExecution(10);
1774     }
1775   DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
1776   if (Retries >= IDE_MAX_BUSY_RETRIES)
1777     {
1778       DPRINT("Drive is BUSY for too long after drive select\n");
1779       return(SRB_STATUS_BUSY);
1780     }
1781 #endif
1782
1783   if (DeviceExtension->DataTransferLength < 0x10000)
1784     {
1785       ByteCountLow = (UCHAR)(DeviceExtension->DataTransferLength & 0xFF);
1786       ByteCountHigh = (UCHAR)(DeviceExtension->DataTransferLength >> 8);
1787     }
1788   else
1789     {
1790       ByteCountLow = 0xFF;
1791       ByteCountHigh = 0xFF;
1792     }
1793
1794   /* Set feature register */
1795   IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
1796
1797   /* Set command packet length */
1798   IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, ByteCountHigh);
1799   IDEWriteCylinderLow(DeviceExtension->CommandPortBase, ByteCountLow);
1800
1801   /* Issue command to drive */
1802   IDEWriteCommand(DeviceExtension->CommandPortBase, IDE_CMD_PACKET);
1803
1804   /* Wait for DRQ to assert */
1805   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1806     {
1807       Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1808       if ((Status & IDE_SR_DRQ))
1809         {
1810           break;
1811         }
1812       ScsiPortStallExecution(10);
1813     }
1814
1815   /* Convert special SCSI SRBs to ATAPI format */
1816   switch (Srb->Cdb[0])
1817     {
1818       case SCSIOP_FORMAT_UNIT:
1819       case SCSIOP_MODE_SELECT:
1820       case SCSIOP_MODE_SENSE:
1821         AtapiScsiSrbToAtapi (Srb);
1822         break;
1823     }
1824
1825   CdbSize = (DeviceExtension->DeviceParams[Srb->TargetId].ConfigBits & 0x3 == 1) ? 16 : 12;
1826   DPRINT("CdbSize: %lu\n", CdbSize);
1827
1828   /* Write command packet */
1829   IDEWriteBlock(DeviceExtension->CommandPortBase,
1830                 (PUSHORT)Srb->Cdb,
1831                 CdbSize);
1832
1833   DeviceExtension->ExpectingInterrupt = TRUE;
1834
1835   DPRINT("AtapiSendAtapiCommand() done\n");
1836
1837   return(SRB_STATUS_PENDING);
1838 }
1839
1840
1841 static ULONG
1842 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1843                     IN PSCSI_REQUEST_BLOCK Srb)
1844 {
1845   ULONG SrbStatus = SRB_STATUS_SUCCESS;
1846
1847   DPRINT("AtapiSendIdeCommand() called!\n");
1848
1849   DPRINT("PathId: %lu  TargetId: %lu  Lun: %lu\n",
1850          Srb->PathId,
1851          Srb->TargetId,
1852          Srb->Lun);
1853
1854   if (Srb->PathId != 0)
1855     {
1856       Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
1857       return(SRB_STATUS_INVALID_PATH_ID);
1858     }
1859
1860   if (Srb->TargetId > 1)
1861     {
1862       Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
1863       return(SRB_STATUS_INVALID_TARGET_ID);
1864     }
1865
1866   if (Srb->Lun != 0)
1867     {
1868       Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
1869       return(SRB_STATUS_INVALID_LUN);
1870     }
1871
1872   if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_PRESENT))
1873     {
1874       Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1875       return(SRB_STATUS_NO_DEVICE);
1876     }
1877
1878   switch (Srb->Cdb[0])
1879     {
1880       case SCSIOP_INQUIRY:
1881         SrbStatus = AtapiInquiry(DeviceExtension,
1882                                  Srb);
1883         break;
1884
1885       case SCSIOP_READ_CAPACITY:
1886         SrbStatus = AtapiReadCapacity(DeviceExtension,
1887                                       Srb);
1888         break;
1889
1890       case SCSIOP_READ:
1891       case SCSIOP_WRITE:
1892         SrbStatus = AtapiReadWrite(DeviceExtension,
1893                                    Srb);
1894         break;
1895
1896       case SCSIOP_SYNCHRONIZE_CACHE:
1897         SrbStatus = AtapiFlushCache(DeviceExtension,
1898                                     Srb);
1899         break;
1900
1901       case SCSIOP_TEST_UNIT_READY:
1902         SrbStatus = AtapiTestUnitReady(DeviceExtension,
1903                                        Srb);
1904         break;
1905
1906       case SCSIOP_MODE_SENSE:
1907
1908       case SCSIOP_VERIFY:
1909       case SCSIOP_START_STOP_UNIT:
1910       case SCSIOP_REQUEST_SENSE:
1911         break;
1912
1913      default:
1914         DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1915                  Srb->Cdb[0]);
1916         SrbStatus = SRB_STATUS_INVALID_REQUEST;
1917         break;
1918     }
1919
1920   DPRINT("AtapiSendIdeCommand() done!\n");
1921
1922   return(SrbStatus);
1923 }
1924
1925
1926 static ULONG
1927 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1928              PSCSI_REQUEST_BLOCK Srb)
1929 {
1930   PIDE_DRIVE_IDENTIFY DeviceParams;
1931   PINQUIRYDATA InquiryData;
1932   ULONG i;
1933
1934   DPRINT("SCSIOP_INQUIRY: DeviceExtension %p  TargetId: %lu\n",
1935          DeviceExtension, Srb->TargetId);
1936
1937   InquiryData = Srb->DataBuffer;
1938   DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1939
1940   /* clear buffer */
1941   for (i = 0; i < Srb->DataTransferLength; i++)
1942     {
1943       ((PUCHAR)Srb->DataBuffer)[i] = 0;
1944     }
1945
1946   /* set device class */
1947   if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
1948     {
1949       /* get it from the ATAPI configuration word */
1950       InquiryData->DeviceType = (DeviceParams->ConfigBits >> 8) & 0x1F;
1951       DPRINT("Device class: %u\n", InquiryData->DeviceType);
1952     }
1953   else
1954     {
1955       /* hard-disk */
1956       InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
1957     }
1958
1959   DPRINT("ConfigBits: 0x%x\n", DeviceParams->ConfigBits);
1960   if (DeviceParams->ConfigBits & 0x80)
1961     {
1962       DPRINT("Removable media!\n");
1963       InquiryData->RemovableMedia = 1;
1964     }
1965
1966   for (i = 0; i < 20; i += 2)
1967     {
1968       InquiryData->VendorId[i] =
1969         ((PUCHAR)DeviceParams->ModelNumber)[i];
1970       InquiryData->VendorId[i+1] =
1971         ((PUCHAR)DeviceParams->ModelNumber)[i+1];
1972     }
1973
1974   for (i = 0; i < 4; i++)
1975     {
1976       InquiryData->ProductId[12+i] = ' ';
1977     }
1978
1979   for (i = 0; i < 4; i += 2)
1980     {
1981       InquiryData->ProductRevisionLevel[i] =
1982         ((PUCHAR)DeviceParams->FirmwareRev)[i];
1983       InquiryData->ProductRevisionLevel[i+1] =
1984         ((PUCHAR)DeviceParams->FirmwareRev)[i+1];
1985     }
1986
1987   DPRINT("VendorId: '%.20s'\n", InquiryData->VendorId);
1988
1989   Srb->SrbStatus = SRB_STATUS_SUCCESS;
1990   return(SRB_STATUS_SUCCESS);
1991 }
1992
1993
1994 static ULONG
1995 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1996                   PSCSI_REQUEST_BLOCK Srb)
1997 {
1998   PREAD_CAPACITY_DATA CapacityData;
1999   PIDE_DRIVE_IDENTIFY DeviceParams;
2000   ULONG LastSector;
2001
2002   DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb->TargetId);
2003   CapacityData = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
2004   DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
2005
2006   /* Set sector (block) size to 512 bytes (big-endian). */
2007   CapacityData->BytesPerBlock = 0x20000;
2008
2009   /* Calculate last sector (big-endian). */
2010   if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
2011     {
2012       LastSector = (ULONG)((DeviceParams->TMSectorCountHi << 16) +
2013                             DeviceParams->TMSectorCountLo) - 1;
2014     }
2015   else
2016     {
2017       LastSector = (ULONG)(DeviceParams->LogicalCyls *
2018                            DeviceParams->LogicalHeads *
2019                            DeviceParams->SectorsPerTrack)-1;
2020     }
2021
2022   CapacityData->LogicalBlockAddress = (((PUCHAR)&LastSector)[0] << 24) |
2023                                       (((PUCHAR)&LastSector)[1] << 16) |
2024                                       (((PUCHAR)&LastSector)[2] << 8) |
2025                                       ((PUCHAR)&LastSector)[3];
2026
2027   DPRINT("LastCount: %lu (%08lx / %08lx)\n",
2028          LastSector,
2029          LastSector,
2030          CapacityData->LogicalBlockAddress);
2031
2032   Srb->SrbStatus = SRB_STATUS_SUCCESS;
2033   return(SRB_STATUS_SUCCESS);
2034 }
2035
2036
2037 static ULONG
2038 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
2039                PSCSI_REQUEST_BLOCK Srb)
2040 {
2041   PIDE_DRIVE_IDENTIFY DeviceParams;
2042   ULONG StartingSector;
2043   ULONG SectorCount;
2044   UCHAR CylinderHigh;
2045   UCHAR CylinderLow;
2046   UCHAR DrvHead;
2047   UCHAR SectorNumber;
2048   UCHAR Command;
2049   ULONG Retries;
2050   UCHAR Status;
2051
2052   DPRINT("AtapiReadWrite() called!\n");
2053   DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
2054          Srb->TargetId);
2055
2056   DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
2057
2058   /* Get starting sector number from CDB. */
2059   StartingSector = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
2060                    ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
2061                    ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
2062                    ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
2063
2064   SectorCount = (Srb->DataTransferLength + DeviceParams->BytesPerSector - 1) /
2065                 DeviceParams->BytesPerSector;
2066
2067   DPRINT("Starting sector %lu  Number of bytes %lu  Sectors %lu\n",
2068          StartingSector,
2069          Srb->DataTransferLength,
2070          SectorCount);
2071
2072   if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
2073     {
2074       SectorNumber = StartingSector & 0xff;
2075       CylinderLow = (StartingSector >> 8) & 0xff;
2076       CylinderHigh = (StartingSector >> 16) & 0xff;
2077       DrvHead = ((StartingSector >> 24) & 0x0f) | 
2078           (Srb->TargetId ? IDE_DH_DRV1 : 0) |
2079           IDE_DH_LBA;
2080     }
2081   else
2082     {
2083       SectorNumber = (StartingSector % DeviceParams->SectorsPerTrack) + 1;
2084       StartingSector /= DeviceParams->SectorsPerTrack;
2085       DrvHead = (StartingSector % DeviceParams->LogicalHeads) | 
2086           (Srb->TargetId ? IDE_DH_DRV1 : 0);
2087       StartingSector /= DeviceParams->LogicalHeads;
2088       CylinderLow = StartingSector & 0xff;
2089       CylinderHigh = StartingSector >> 8;
2090     }
2091
2092
2093   if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
2094     {
2095       Command = (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_MULTI_SECTOR_CMD) ? IDE_CMD_READ_MULTIPLE : IDE_CMD_READ;
2096     }
2097   else
2098     {
2099       Command = (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_MULTI_SECTOR_CMD) ? IDE_CMD_WRITE_MULTIPLE : IDE_CMD_WRITE;
2100     }
2101
2102   if (DrvHead & IDE_DH_LBA)
2103     {
2104       DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
2105              (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
2106              DeviceExtension->CommandPortBase,
2107              DrvHead & IDE_DH_DRV1 ? 1 : 0,
2108              ((DrvHead & 0x0f) << 24) +
2109                (CylinderHigh << 16) + (CylinderLow << 8) + SectorNumber,
2110              SectorCount,
2111              Command);
2112     }
2113   else
2114     {
2115       DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
2116              (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
2117              DeviceExtension->CommandPortBase,
2118              DrvHead & IDE_DH_DRV1 ? 1 : 0, 
2119              CylinderHigh,
2120              CylinderLow,
2121              DrvHead & 0x0f,
2122              SectorNumber,
2123              SectorCount,
2124              Command);
2125     }
2126
2127   /* Set pointer to data buffer. */
2128   DeviceExtension->DataBuffer = (PUCHAR)Srb->DataBuffer;
2129   DeviceExtension->DataTransferLength = Srb->DataTransferLength;
2130
2131   DeviceExtension->CurrentSrb = Srb;
2132
2133   /*  wait for BUSY to clear  */
2134   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
2135     {
2136       Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2137       if (!(Status & IDE_SR_BUSY))
2138         {
2139           break;
2140         }
2141       ScsiPortStallExecution(10);
2142     }
2143   DPRINT("status=%02x\n", Status);
2144   DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
2145   if (Retries >= IDE_MAX_BUSY_RETRIES)
2146     {
2147       DPRINT ("Drive is BUSY for too long\n");
2148       return(SRB_STATUS_BUSY);
2149     }
2150
2151   /*  Select the desired drive  */
2152   IDEWriteDriveHead(DeviceExtension->CommandPortBase,
2153                     IDE_DH_FIXED | DrvHead);
2154
2155   ScsiPortStallExecution(10);
2156 #if 0
2157   /*  wait for BUSY to clear and DRDY to assert */
2158   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
2159     {
2160       Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2161       if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
2162         {
2163           break;
2164         }
2165       ScsiPortStallExecution(10);
2166     }
2167   DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
2168   if (Retries >= IDE_MAX_BUSY_RETRIES)
2169     {
2170       DPRINT("Drive is BUSY for too long after drive select\n");
2171       return(SRB_STATUS_BUSY);
2172     }
2173 #endif
2174
2175   /* Setup command parameters */
2176   IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
2177   IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount);
2178   IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber);
2179   IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh);
2180   IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow);
2181   IDEWriteDriveHead(DeviceExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
2182
2183   /* Indicate expecting an interrupt. */
2184   DeviceExtension->ExpectingInterrupt = TRUE;
2185
2186   /* Issue command to drive */
2187   IDEWriteCommand(DeviceExtension->CommandPortBase, Command);
2188
2189   /* Write data block */
2190   if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
2191     {
2192       PUCHAR TargetAddress;
2193       ULONG TransferSize;
2194
2195       /* Wait for controller ready */
2196       for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
2197         {
2198           BYTE  Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2199           if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
2200             {
2201               break;
2202             }
2203           KeStallExecutionProcessor(10);
2204         }
2205       if (Retries >= IDE_MAX_WRITE_RETRIES)
2206         {
2207           DPRINT1("Drive is BUSY for too long after sending write command\n");
2208           return(SRB_STATUS_BUSY);
2209         }
2210
2211       /* Update DeviceExtension data */
2212       TransferSize = DeviceExtension->TransferSize[Srb->TargetId];
2213       if (DeviceExtension->DataTransferLength < TransferSize)
2214         {
2215           TransferSize = DeviceExtension->DataTransferLength;
2216         }
2217
2218       TargetAddress = DeviceExtension->DataBuffer;
2219       DeviceExtension->DataBuffer += TransferSize;
2220       DeviceExtension->DataTransferLength -= TransferSize;
2221
2222       /* Write data block */
2223       if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
2224         {
2225           IDEWriteBlock32(DeviceExtension->CommandPortBase,
2226                           TargetAddress,
2227                           TransferSize);
2228         }
2229       else
2230         {
2231           IDEWriteBlock(DeviceExtension->CommandPortBase,
2232                         TargetAddress,
2233                         TransferSize);
2234         }
2235     }
2236
2237   DPRINT("AtapiReadWrite() done!\n");
2238
2239   /* Wait for interrupt. */
2240   return(SRB_STATUS_PENDING);
2241 }
2242
2243
2244 static ULONG
2245 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension,
2246                 PSCSI_REQUEST_BLOCK Srb)
2247 {
2248   ULONG Retries;
2249   UCHAR Status;
2250
2251   DPRINT("AtapiFlushCache() called!\n");
2252   DPRINT("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
2253          Srb->TargetId);
2254
2255   /* Wait for BUSY to clear */
2256   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
2257     {
2258       Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2259       if (!(Status & IDE_SR_BUSY))
2260         {
2261           break;
2262         }
2263       ScsiPortStallExecution(10);
2264     }
2265   DPRINT("Status=%02x\n", Status);
2266   DPRINT("Waited %ld usecs for busy to clear\n", Retries * 10);
2267   if (Retries >= IDE_MAX_BUSY_RETRIES)
2268     {
2269       DPRINT1("Drive is BUSY for too long\n");
2270       return(SRB_STATUS_BUSY);
2271     }
2272
2273   /* Select the desired drive */
2274   IDEWriteDriveHead(DeviceExtension->CommandPortBase,
2275                     IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
2276   ScsiPortStallExecution(10);
2277
2278   /* Issue command to drive */
2279   IDEWriteCommand(DeviceExtension->CommandPortBase, IDE_CMD_FLUSH_CACHE);
2280
2281   /* Wait for controller ready */
2282   for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
2283     {
2284       BYTE  Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2285       if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
2286         {
2287           break;
2288         }
2289       KeStallExecutionProcessor(10);
2290     }
2291   if (Retries >= IDE_MAX_WRITE_RETRIES)
2292     {
2293       DPRINT1("Drive is BUSY for too long after sending write command\n");
2294       return(SRB_STATUS_BUSY);
2295     }
2296
2297   /* Indicate expecting an interrupt. */
2298   DeviceExtension->ExpectingInterrupt = TRUE;
2299
2300   DPRINT("AtapiFlushCache() done!\n");
2301
2302   /* Wait for interrupt. */
2303   return(SRB_STATUS_PENDING);
2304 }
2305
2306
2307 static ULONG
2308 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension,
2309                    PSCSI_REQUEST_BLOCK Srb)
2310 {
2311   ULONG Retries;
2312   UCHAR Status;
2313   UCHAR Error;
2314
2315   DPRINT1("AtapiTestUnitReady() called!\n");
2316
2317   DPRINT1("SCSIOP_TEST_UNIT_READY: TargetId: %lu\n",
2318          Srb->TargetId);
2319
2320   /* Return success if media status is not supported */
2321   if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_MEDIA_STATUS))
2322     {
2323       Srb->SrbStatus = SRB_STATUS_SUCCESS;
2324       return(SRB_STATUS_SUCCESS);
2325     }
2326
2327   /* Wait for BUSY to clear */
2328   for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
2329     {
2330       Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2331       if (!(Status & IDE_SR_BUSY))
2332         {
2333           break;
2334         }
2335       ScsiPortStallExecution(10);
2336     }
2337   DPRINT1("Status=%02x\n", Status);
2338   DPRINT1("Waited %ld usecs for busy to clear\n", Retries * 10);
2339   if (Retries >= IDE_MAX_BUSY_RETRIES)
2340     {
2341       DPRINT1("Drive is BUSY for too long\n");
2342       return(SRB_STATUS_BUSY);
2343     }
2344
2345   /* Select the desired drive */
2346   IDEWriteDriveHead(DeviceExtension->CommandPortBase,
2347                     IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
2348   ScsiPortStallExecution(10);
2349
2350   /* Issue command to drive */
2351   IDEWriteCommand(DeviceExtension->CommandPortBase, IDE_CMD_GET_MEDIA_STATUS);
2352
2353   /* Wait for controller ready */
2354   for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
2355     {
2356       Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2357       if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
2358         {
2359           break;
2360         }
2361       KeStallExecutionProcessor(10);
2362     }
2363   if (Retries >= IDE_MAX_WRITE_RETRIES)
2364     {
2365       DPRINT1("Drive is BUSY for too long after sending write command\n");
2366       return(SRB_STATUS_BUSY);
2367     }
2368
2369   if (Status & IDE_SR_ERR)
2370     {
2371       Error = IDEReadError(DeviceExtension->CommandPortBase);
2372       if (Error == IDE_ER_UNC)
2373         {
2374 CHECKPOINT1;
2375           /* Handle write protection 'error' */
2376           Srb->SrbStatus = SRB_STATUS_SUCCESS;
2377           return(SRB_STATUS_SUCCESS);
2378         }
2379       else
2380         {
2381 CHECKPOINT1;
2382           /* Indicate expecting an interrupt. */
2383           DeviceExtension->ExpectingInterrupt = TRUE;
2384           return(SRB_STATUS_PENDING);
2385         }
2386     }
2387
2388   DPRINT1("AtapiTestUnitReady() done!\n");
2389
2390   Srb->SrbStatus = SRB_STATUS_SUCCESS;
2391   return(SRB_STATUS_SUCCESS);
2392 }
2393
2394
2395 static UCHAR
2396 AtapiErrorToScsi(PVOID DeviceExtension,
2397                  PSCSI_REQUEST_BLOCK Srb)
2398 {
2399   PATAPI_MINIPORT_EXTENSION DevExt;
2400   ULONG CommandPortBase;
2401   ULONG ControlPortBase;
2402   UCHAR ErrorReg;
2403   UCHAR ScsiStatus;
2404   UCHAR SrbStatus;
2405
2406   DPRINT("AtapiErrorToScsi() called\n");
2407
2408   DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
2409
2410   CommandPortBase = DevExt->CommandPortBase;
2411   ControlPortBase = DevExt->ControlPortBase;
2412
2413   ErrorReg = IDEReadError(CommandPortBase);
2414
2415   if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
2416     {
2417       switch (ErrorReg >> 4)
2418         {
2419           case SCSI_SENSE_NO_SENSE:
2420             DPRINT("ATAPI error: SCSI_SENSE_NO_SENSE\n");
2421             ScsiStatus = SCSISTAT_CHECK_CONDITION;
2422             SrbStatus = SRB_STATUS_ERROR;
2423             break;
2424
2425           case SCSI_SENSE_RECOVERED_ERROR:
2426             DPRINT("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
2427             ScsiStatus = 0;
2428             SrbStatus = SRB_STATUS_SUCCESS;
2429             break;
2430
2431           case SCSI_SENSE_NOT_READY:
2432             DPRINT("ATAPI error: SCSI_SENSE_NOT_READY\n");
2433             ScsiStatus = SCSISTAT_CHECK_CONDITION;
2434             SrbStatus = SRB_STATUS_ERROR;
2435             break;
2436
2437           case SCSI_SENSE_MEDIUM_ERROR:
2438             DPRINT("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
2439             ScsiStatus = SCSISTAT_CHECK_CONDITION;
2440             SrbStatus = SRB_STATUS_ERROR;
2441             break;
2442
2443           case SCSI_SENSE_HARDWARE_ERROR:
2444             DPRINT("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
2445             ScsiStatus = SCSISTAT_CHECK_CONDITION;
2446             SrbStatus = SRB_STATUS_ERROR;
2447             break;
2448
2449           case SCSI_SENSE_ILLEGAL_REQUEST:
2450             DPRINT("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
2451             ScsiStatus = SCSISTAT_CHECK_CONDITION;
2452             SrbStatus = SRB_STATUS_ERROR;
2453             break;
2454
2455           case SCSI_SENSE_UNIT_ATTENTION:
2456             DPRINT("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
2457             ScsiStatus = SCSISTAT_CHECK_CONDITION;
2458             SrbStatus = SRB_STATUS_ERROR;
2459             break;
2460
2461           case SCSI_SENSE_DATA_PROTECT:
2462             DPRINT("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
2463             ScsiStatus = SCSISTAT_CHECK_CONDITION;
2464             SrbStatus = SRB_STATUS_ERROR;
2465             break;
2466
2467           case SCSI_SENSE_BLANK_CHECK:
2468             DPRINT("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
2469             ScsiStatus = SCSISTAT_CHECK_CONDITION;
2470             SrbStatus = SRB_STATUS_ERROR;
2471             break;
2472
2473           case SCSI_SENSE_ABORTED_COMMAND:
2474             DPRINT("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
2475             ScsiStatus = SCSISTAT_CHECK_CONDITION;
2476             SrbStatus = SRB_STATUS_ERROR;
2477             break;
2478
2479           default:
2480             DPRINT("ATAPI error: Invalid sense key\n");
2481             ScsiStatus = 0;
2482             SrbStatus = SRB_STATUS_ERROR;
2483             break;
2484         }
2485     }
2486   else
2487     {
2488       DPRINT1("IDE error: %02x\n", ErrorReg);
2489
2490       ScsiStatus = 0;
2491       SrbStatus = SRB_STATUS_ERROR;
2492
2493 #if 0
2494       UCHAR SectorCount, SectorNum, CylinderLow, CylinderHigh;
2495       UCHAR DriveHead;
2496
2497       CylinderLow = IDEReadCylinderLow(CommandPortBase);
2498       CylinderHigh = IDEReadCylinderHigh(CommandPortBase);
2499       DriveHead = IDEReadDriveHead(CommandPortBase);
2500       SectorCount = IDEReadSectorCount(CommandPortBase);
2501       SectorNum = IDEReadSectorNum(CommandPortBase);
2502
2503       DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
2504               ErrorReg,
2505               CylinderLow,
2506               CylinderHigh,
2507               SectorCount,
2508               SectorNum);
2509 #endif
2510     }
2511
2512
2513
2514   Srb->ScsiStatus = ScsiStatus;
2515
2516   DPRINT("AtapiErrorToScsi() done\n");
2517
2518   return(SrbStatus);
2519 }
2520
2521
2522 static VOID
2523 AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb)
2524 {
2525   DPRINT("AtapiConvertScsiToAtapi() called\n");
2526
2527   Srb->CdbLength = 12;
2528
2529   switch (Srb->Cdb[0])
2530     {
2531       case SCSIOP_FORMAT_UNIT:
2532         Srb->Cdb[0] = ATAPI_FORMAT_UNIT;
2533         break;
2534
2535       case SCSIOP_MODE_SELECT:
2536           {
2537             PATAPI_MODE_SELECT12 AtapiModeSelect;
2538             UCHAR Length;
2539
2540             AtapiModeSelect = (PATAPI_MODE_SELECT12)Srb->Cdb;
2541             Length = ((PCDB)Srb->Cdb)->MODE_SELECT.ParameterListLength;
2542
2543             RtlZeroMemory (Srb->Cdb,
2544                            MAXIMUM_CDB_SIZE);
2545             AtapiModeSelect->OperationCode = ATAPI_MODE_SELECT;
2546             AtapiModeSelect->PFBit = 1;
2547             AtapiModeSelect->ParameterListLengthMsb = 0;
2548             AtapiModeSelect->ParameterListLengthLsb = Length;
2549           }
2550         break;
2551
2552       case SCSIOP_MODE_SENSE:
2553           {
2554             PATAPI_MODE_SENSE12 AtapiModeSense;
2555             UCHAR PageCode;
2556             UCHAR Length;
2557
2558             AtapiModeSense = (PATAPI_MODE_SENSE12)Srb->Cdb;
2559             PageCode = ((PCDB)Srb->Cdb)->MODE_SENSE.PageCode;
2560             Length = ((PCDB)Srb->Cdb)->MODE_SENSE.AllocationLength;
2561
2562             RtlZeroMemory (Srb->Cdb,
2563                            MAXIMUM_CDB_SIZE);
2564             AtapiModeSense->OperationCode = ATAPI_MODE_SENSE;
2565             AtapiModeSense->PageCode = PageCode;
2566             AtapiModeSense->ParameterListLengthMsb = 0;
2567             AtapiModeSense->ParameterListLengthLsb = Length;
2568           }
2569         break;
2570     }
2571 }
2572
2573 /* EOF */