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