3 * Copyright (C) 2001, 2002 ReactOS Team
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.
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.
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.
19 /* $Id: atapi.c,v 1.19 2002/04/10 17:01:47 ekohl Exp $
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)
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.
39 * - implement sending of atapi commands
40 * - handle removable atapi non-cdrom drives
46 // -------------------------------------------------------------------------
48 #include <ddk/ntddk.h>
50 #include "../include/srb.h"
51 #include "../include/scsi.h"
52 #include "../include/ntddscsi.h"
59 #define VERSION "0.0.1"
62 // ------------------------------------------------------- File Static Data
64 // ATAPI_MINIPORT_EXTENSION
67 // Extension to be placed in each port device object
70 // Allocated from NON-PAGED POOL
71 // Available at any IRQL
74 typedef struct _ATAPI_MINIPORT_EXTENSION
76 IDE_DRIVE_IDENTIFY DeviceParams
[2];
77 BOOLEAN DevicePresent
[2];
78 BOOLEAN DeviceAtapi
[2];
80 ULONG CommandPortBase
;
81 ULONG ControlPortBase
;
83 BOOLEAN ExpectingInterrupt
;
84 PSCSI_REQUEST_BLOCK CurrentSrb
;
87 } ATAPI_MINIPORT_EXTENSION
, *PATAPI_MINIPORT_EXTENSION
;
90 typedef struct _UNIT_EXTENSION
93 } UNIT_EXTENSION
, *PUNIT_EXTENSION
;
96 // ----------------------------------------------- Discardable Declarations
100 // make the initialization routines discardable, so that they
103 #pragma alloc_text(init, DriverEntry)
104 #pragma alloc_text(init, IDECreateController)
105 #pragma alloc_text(init, IDEPolledRead)
107 // make the PASSIVE_LEVEL routines pageable, so that they don't
108 // waste nonpaged memory
110 #pragma alloc_text(page, IDEShutdown)
111 #pragma alloc_text(page, IDEDispatchOpenClose)
112 #pragma alloc_text(page, IDEDispatchRead)
113 #pragma alloc_text(page, IDEDispatchWrite)
115 #endif /* ALLOC_PRAGMA */
117 // ---------------------------------------------------- Forward Declarations
120 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
122 PVOID BusInformation
,
123 PCHAR ArgumentString
,
124 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
128 AtapiFindIsaBusController(PVOID DeviceExtension
,
130 PVOID BusInformation
,
131 PCHAR ArgumentString
,
132 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
136 AtapiFindNativePciController(PVOID DeviceExtension
,
138 PVOID BusInformation
,
139 PCHAR ArgumentString
,
140 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
143 static BOOLEAN STDCALL
144 AtapiInitialize(IN PVOID DeviceExtension
);
146 static BOOLEAN STDCALL
147 AtapiResetBus(IN PVOID DeviceExtension
,
150 static BOOLEAN STDCALL
151 AtapiStartIo(IN PVOID DeviceExtension
,
152 IN PSCSI_REQUEST_BLOCK Srb
);
154 static BOOLEAN STDCALL
155 AtapiInterrupt(IN PVOID DeviceExtension
);
158 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
159 PPORT_CONFIGURATION_INFORMATION ConfigInfo
);
162 AtapiIdentifyDevice(IN ULONG CommandPort
,
163 IN ULONG ControlPort
,
166 OUT PIDE_DRIVE_IDENTIFY DrvParms
);
169 IDEResetController(IN ULONG CommandPort
,
170 IN ULONG ControlPort
);
173 AtapiPolledRead(IN ULONG CommandPort
,
174 IN ULONG ControlPort
,
179 IN BYTE CylinderHigh
,
187 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
188 IN PSCSI_REQUEST_BLOCK Srb
);
191 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
192 IN PSCSI_REQUEST_BLOCK Srb
);
195 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
196 IN PSCSI_REQUEST_BLOCK Srb
);
199 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
200 IN PSCSI_REQUEST_BLOCK Srb
);
203 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
204 IN PSCSI_REQUEST_BLOCK Srb
);
208 AtapiErrorToScsi(PVOID DeviceExtension
,
209 PSCSI_REQUEST_BLOCK Srb
);
211 // ---------------------------------------------------------------- Inlines
214 IDESwapBytePairs(char *Buf
,
220 for (i
= 0; i
< Cnt
; i
+= 2)
229 // ------------------------------------------------------- Public Interface
234 // This function initializes the driver, locates and claims
235 // hardware resources, and creates various NT objects needed
236 // to process I/O requests.
242 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
244 // IN PUNICODE_STRING RegistryPath Name of registry driver service
251 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
252 IN PUNICODE_STRING RegistryPath
)
254 HW_INITIALIZATION_DATA InitData
;
257 DbgPrint("ATAPI Driver %s\n", VERSION
);
259 /* Initialize data structure */
260 RtlZeroMemory(&InitData
,
261 sizeof(HW_INITIALIZATION_DATA
));
262 InitData
.HwInitializationDataSize
= sizeof(HW_INITIALIZATION_DATA
);
263 InitData
.HwInitialize
= AtapiInitialize
;
264 InitData
.HwResetBus
= AtapiResetBus
;
265 InitData
.HwStartIo
= AtapiStartIo
;
266 InitData
.HwInterrupt
= AtapiInterrupt
;
268 InitData
.DeviceExtensionSize
= sizeof(ATAPI_MINIPORT_EXTENSION
);
269 InitData
.SpecificLuExtensionSize
= sizeof(UNIT_EXTENSION
);
271 InitData
.MapBuffers
= TRUE
;
273 /* Search the PCI bus for compatibility mode ide controllers */
275 InitData
.HwFindAdapter
= AtapiFindCompatiblePciController
;
276 InitData
.NumberOfAccessRanges
= 2;
277 InitData
.AdapterInterfaceType
= PCIBus
;
279 InitData
.VendorId
= NULL
;
280 InitData
.VendorIdLength
= 0;
281 InitData
.DeviceId
= NULL
;
282 InitData
.DeviceIdLength
= 0;
284 Status
= ScsiPortInitialize(DriverObject
,
288 // if (newStatus < statusToReturn)
289 // statusToReturn = newStatus;
292 /* Search the ISA bus for ide controllers */
294 InitData
.HwFindAdapter
= AtapiFindIsaBusController
;
295 InitData
.NumberOfAccessRanges
= 2;
296 InitData
.AdapterInterfaceType
= Isa
;
298 InitData
.VendorId
= NULL
;
299 InitData
.VendorIdLength
= 0;
300 InitData
.DeviceId
= NULL
;
301 InitData
.DeviceIdLength
= 0;
303 Status
= ScsiPortInitialize(DriverObject
,
307 // if (newStatus < statusToReturn)
308 // statusToReturn = newStatus;
311 /* Search the PCI bus for native mode ide controllers */
313 InitData
.HwFindAdapter
= AtapiFindNativePciController
;
314 InitData
.NumberOfAccessRanges
= 2;
315 InitData
.AdapterInterfaceType
= PCIBus
;
317 InitData
.VendorId
= NULL
;
318 InitData
.VendorIdLength
= 0;
319 InitData
.DeviceId
= NULL
;
320 InitData
.DeviceIdLength
= 0;
322 Status
= ScsiPortInitialize(DriverObject
,
326 // if (newStatus < statusToReturn)
327 // statusToReturn = newStatus;
330 DPRINT( "Returning from DriverEntry\n" );
337 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
339 PVOID BusInformation
,
340 PCHAR ArgumentString
,
341 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
344 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
345 PCI_SLOT_NUMBER SlotNumber
;
346 PCI_COMMON_CONFIG PciConfig
;
348 ULONG FunctionNumber
;
349 BOOLEAN ChannelFound
;
352 DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
353 ConfigInfo
->SystemIoBusNumber
,
354 ConfigInfo
->SlotNumber
);
358 /* both channels were claimed: exit */
359 if (ConfigInfo
->AtdiskPrimaryClaimed
== TRUE
&&
360 ConfigInfo
->AtdiskSecondaryClaimed
== TRUE
)
361 return(SP_RETURN_NOT_FOUND
);
364 SlotNumber
.u
.AsULONG
= 0;
365 for (FunctionNumber
= 0 /*ConfigInfo->SlotNumber*/; FunctionNumber
< 256; FunctionNumber
++)
367 // SlotNumber.u.bits.FunctionNumber = FunctionNumber;
368 // SlotNumber.u.AsULONG = (FunctionNumber & 0x07);
369 SlotNumber
.u
.AsULONG
= FunctionNumber
;
371 ChannelFound
= FALSE
;
374 DataSize
= ScsiPortGetBusData(DeviceExtension
,
377 SlotNumber
.u
.AsULONG
,
379 sizeof(PCI_COMMON_CONFIG
));
380 // if (DataSize != sizeof(PCI_COMMON_CONFIG) ||
381 // PciConfig.VendorID == PCI_INVALID_VENDORID)
384 // if ((SlotNumber.u.AsULONG & 0x07) == 0)
385 // return(SP_RETURN_ERROR); /* No bus found */
388 // return(SP_RETURN_ERROR);
391 if (PciConfig
.BaseClass
== 0x01 &&
392 PciConfig
.SubClass
== 0x01) // &&
393 // (PciConfig.ProgIf & 0x05) == 0)
395 /* both channels are in compatibility mode */
396 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
397 ConfigInfo
->SystemIoBusNumber
,
398 SlotNumber
.u
.bits
.DeviceNumber
,
399 SlotNumber
.u
.bits
.FunctionNumber
,
402 DPRINT("ProgIF 0x%02hx\n", PciConfig
.ProgIf
);
404 DPRINT("Found IDE controller in compatibility mode!\n");
406 ConfigInfo
->NumberOfBuses
= 1;
407 ConfigInfo
->MaximumNumberOfTargets
= 2;
408 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
410 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
412 /* Both channels unclaimed: Claim primary channel */
413 DPRINT("Primary channel!\n");
415 DevExt
->CommandPortBase
= 0x01F0;
416 DevExt
->ControlPortBase
= 0x03F6;
418 ConfigInfo
->BusInterruptLevel
= 14;
419 ConfigInfo
->BusInterruptVector
= 14;
420 ConfigInfo
->InterruptMode
= LevelSensitive
;
422 ConfigInfo
->AccessRanges
[0].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x01F0);
423 ConfigInfo
->AccessRanges
[0].RangeLength
= 8;
424 ConfigInfo
->AccessRanges
[0].RangeInMemory
= FALSE
;
426 ConfigInfo
->AccessRanges
[1].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x03F6);
427 ConfigInfo
->AccessRanges
[1].RangeLength
= 1;
428 ConfigInfo
->AccessRanges
[1].RangeInMemory
= FALSE
;
430 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
434 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
436 /* Primary channel already claimed: claim secondary channel */
437 DPRINT("Secondary channel!\n");
439 DevExt
->CommandPortBase
= 0x0170;
440 DevExt
->ControlPortBase
= 0x0376;
442 ConfigInfo
->BusInterruptLevel
= 15;
443 ConfigInfo
->BusInterruptVector
= 15;
444 ConfigInfo
->InterruptMode
= LevelSensitive
;
446 ConfigInfo
->AccessRanges
[0].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x0170);
447 ConfigInfo
->AccessRanges
[0].RangeLength
= 8;
448 ConfigInfo
->AccessRanges
[0].RangeInMemory
= FALSE
;
450 ConfigInfo
->AccessRanges
[1].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x0376);
451 ConfigInfo
->AccessRanges
[1].RangeLength
= 1;
452 ConfigInfo
->AccessRanges
[1].RangeInMemory
= FALSE
;
454 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
459 /* Find attached devices */
460 if (ChannelFound
== TRUE
)
462 DeviceFound
= AtapiFindDevices(DevExt
,
465 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
466 return(SP_RETURN_FOUND
);
470 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
472 return(SP_RETURN_NOT_FOUND
);
477 AtapiFindIsaBusController(PVOID DeviceExtension
,
479 PVOID BusInformation
,
480 PCHAR ArgumentString
,
481 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
484 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
485 BOOLEAN ChannelFound
= FALSE
;
486 BOOLEAN DeviceFound
= FALSE
;
488 DPRINT("AtapiFindIsaBusController() called!\n");
492 ConfigInfo
->NumberOfBuses
= 1;
493 ConfigInfo
->MaximumNumberOfTargets
= 2;
494 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
496 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
498 /* Both channels unclaimed: Claim primary channel */
499 DPRINT1("Primary channel!\n");
501 DevExt
->CommandPortBase
= 0x01F0;
502 DevExt
->ControlPortBase
= 0x03F6;
504 ConfigInfo
->BusInterruptLevel
= 14;
505 ConfigInfo
->BusInterruptVector
= 14;
506 ConfigInfo
->InterruptMode
= LevelSensitive
;
508 ConfigInfo
->AccessRanges
[0].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x01F0);
509 ConfigInfo
->AccessRanges
[0].RangeLength
= 8;
510 ConfigInfo
->AccessRanges
[0].RangeInMemory
= FALSE
;
512 ConfigInfo
->AccessRanges
[1].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x03F6);
513 ConfigInfo
->AccessRanges
[1].RangeLength
= 1;
514 ConfigInfo
->AccessRanges
[1].RangeInMemory
= FALSE
;
516 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
518 *Again
= FALSE
/*TRUE*/;
520 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
522 /* Primary channel already claimed: claim secondary channel */
523 DPRINT1("Secondary channel!\n");
525 DevExt
->CommandPortBase
= 0x0170;
526 DevExt
->ControlPortBase
= 0x0376;
528 ConfigInfo
->BusInterruptLevel
= 15;
529 ConfigInfo
->BusInterruptVector
= 15;
530 ConfigInfo
->InterruptMode
= LevelSensitive
;
532 ConfigInfo
->AccessRanges
[0].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x0170);
533 ConfigInfo
->AccessRanges
[0].RangeLength
= 8;
534 ConfigInfo
->AccessRanges
[0].RangeInMemory
= FALSE
;
536 ConfigInfo
->AccessRanges
[1].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x0376);
537 ConfigInfo
->AccessRanges
[1].RangeLength
= 1;
538 ConfigInfo
->AccessRanges
[1].RangeInMemory
= FALSE
;
540 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
546 DPRINT("AtapiFindIsaBusController() both channels claimed. Returns: SP_RETURN_NOT_FOUND\n");
548 return(SP_RETURN_NOT_FOUND
);
551 /* Find attached devices */
554 DeviceFound
= AtapiFindDevices(DevExt
,
558 DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
559 return(SP_RETURN_FOUND
);
564 AtapiFindNativePciController(PVOID DeviceExtension
,
566 PVOID BusInformation
,
567 PCHAR ArgumentString
,
568 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
571 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
573 DPRINT("AtapiFindNativePciController() called!\n");
577 DPRINT("AtapiFindNativePciController() done!\n");
579 return(SP_RETURN_NOT_FOUND
);
583 static BOOLEAN STDCALL
584 AtapiInitialize(IN PVOID DeviceExtension
)
590 static BOOLEAN STDCALL
591 AtapiResetBus(IN PVOID DeviceExtension
,
598 static BOOLEAN STDCALL
599 AtapiStartIo(IN PVOID DeviceExtension
,
600 IN PSCSI_REQUEST_BLOCK Srb
)
602 PATAPI_MINIPORT_EXTENSION DevExt
;
605 DPRINT("AtapiStartIo() called\n");
607 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
609 switch (Srb
->Function
)
611 case SRB_FUNCTION_EXECUTE_SCSI
:
612 DevExt
->CurrentSrb
= Srb
;
613 if (DevExt
->DeviceAtapi
[Srb
->TargetId
] == TRUE
)
615 Result
= AtapiSendAtapiCommand(DevExt
,
620 Result
= AtapiSendIdeCommand(DevExt
,
627 Srb
->SrbStatus
= Result
;
630 if (Result
!= SRB_STATUS_PENDING
)
632 DevExt
->CurrentSrb
= NULL
;
633 Srb
->SrbStatus
= (UCHAR
)Result
;
635 ScsiPortNotification(RequestComplete
,
638 ScsiPortNotification(NextRequest
,
644 DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
647 DPRINT("AtapiStartIo() done\n");
653 static BOOLEAN STDCALL
654 AtapiInterrupt(IN PVOID DeviceExtension
)
656 PATAPI_MINIPORT_EXTENSION DevExt
;
657 PSCSI_REQUEST_BLOCK Srb
;
658 ULONG CommandPortBase
;
659 ULONG ControlPortBase
;
665 PUCHAR TargetAddress
;
670 DPRINT("AtapiInterrupt() called!\n");
672 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
673 if (DevExt
->ExpectingInterrupt
== FALSE
)
675 DPRINT1("AtapiInterrupt(): Unexpected interrupt\n");
679 Srb
= DevExt
->CurrentSrb
;
680 DPRINT("Srb: %p\n", Srb
);
682 CommandPortBase
= DevExt
->CommandPortBase
;
683 ControlPortBase
= DevExt
->ControlPortBase
;
684 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", CommandPortBase
, ControlPortBase
);
686 IsAtapi
= DevExt
->DeviceAtapi
[Srb
->TargetId
];
687 DPRINT("IsAtapi == %s\n", (IsAtapi
) ? "TRUE" : "FALSE");
691 DeviceStatus
= IDEReadStatus(CommandPortBase
);
693 if ((DeviceStatus
& IDE_SR_ERR
) &&
694 (Srb
->Cdb
[0] != SCSIOP_REQUEST_SENSE
))
696 /* Report error condition */
697 Srb
->SrbStatus
= SRB_STATUS_ERROR
;
702 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
704 DPRINT("Read data\n");
706 /* Update controller/device state variables */
707 TargetAddress
= Srb
->DataBuffer
;
711 TransferSize
= IDEReadCylinderLow(CommandPortBase
);
712 TransferSize
+= IDEReadCylinderHigh(CommandPortBase
) << 8;
716 TransferSize
= DevExt
->DeviceParams
[Srb
->TargetId
].BytesPerSector
;
719 DPRINT("TransferLength: %lu\n", Srb
->DataTransferLength
);
720 DPRINT("TransferSize: %lu\n", TransferSize
);
722 if (Srb
->DataTransferLength
<= TransferSize
)
724 Srb
->DataTransferLength
= 0;
729 Srb
->DataTransferLength
-= TransferSize
;
732 Srb
->DataBuffer
+= TransferSize
;
733 DPRINT("IsLastBlock == %s\n", (IsLastBlock
) ? "TRUE" : "FALSE");
735 /* Wait for DRQ assertion */
736 for (Retries
= 0; Retries
< IDE_MAX_DRQ_RETRIES
&&
737 !(IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
);
740 KeStallExecutionProcessor(10);
743 /* Copy the block of data */
744 IDEReadBlock(CommandPortBase
,
751 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
752 (IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
);
755 KeStallExecutionProcessor(10);
758 /* Check for data overrun */
759 if (IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
)
761 /* FIXME: Handle error! */
762 DPRINT1("AtapiInterrupt(): data overrun error!");
766 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
768 else if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
770 DPRINT("Write data\n");
772 if (Srb
->DataTransferLength
== 0)
775 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
776 (IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
);
779 KeStallExecutionProcessor(10);
782 /* Check for data overrun */
783 if (IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
)
785 /* FIXME: Handle error! */
786 DPRINT1("AtapiInterrupt(): data overrun error!");
789 DevExt
->ExpectingInterrupt
= FALSE
;
794 /* Update SRB data */
795 SectorSize
= DevExt
->DeviceParams
[Srb
->TargetId
].BytesPerSector
;
797 TargetAddress
= Srb
->DataBuffer
;
798 Srb
->DataBuffer
+= SectorSize
;
799 Srb
->DataTransferLength
-= SectorSize
;
801 /* Write the sector */
802 IDEWriteBlock(CommandPortBase
,
807 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
811 DPRINT1("Unspecified transfer direction!\n");
812 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
; // SRB_STATUS_ERROR;
818 if (Srb
->SrbStatus
== SRB_STATUS_ERROR
)
820 Srb
->SrbStatus
= AtapiErrorToScsi(DeviceExtension
,
825 /* complete this packet */
828 DevExt
->ExpectingInterrupt
= FALSE
;
830 ScsiPortNotification(RequestComplete
,
834 ScsiPortNotification(NextRequest
,
839 DPRINT("AtapiInterrupt() done!\n");
849 // ---------------------------------------------------- Discardable statics
852 /**********************************************************************
857 * Searches for devices on the given port.
864 * Port device specific information.
867 * Port configuration information.
870 * TRUE: At least one device is attached to the port.
871 * FALSE: No device is attached to the port.
875 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
876 PPORT_CONFIGURATION_INFORMATION ConfigInfo
)
878 BOOLEAN DeviceFound
= FALSE
;
879 ULONG CommandPortBase
;
880 ULONG ControlPortBase
;
885 DPRINT("AtapiFindDevices() called\n");
887 // CommandPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
888 CommandPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[0].RangeStart
);
889 DPRINT(" CommandPortBase: %x\n", CommandPortBase
);
891 // ControlPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[1].RangeStart);
892 ControlPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[1].RangeStart
);
893 DPRINT(" ControlPortBase: %x\n", ControlPortBase
);
895 for (UnitNumber
= 0; UnitNumber
< 2; UnitNumber
++)
898 IDEWriteDriveHead(CommandPortBase
,
899 IDE_DH_FIXED
| (UnitNumber
? IDE_DH_DRV1
: 0));
900 ScsiPortStallExecution(500);
902 /* Disable interrupts */
903 IDEWriteDriveControl(ControlPortBase
,
905 ScsiPortStallExecution(500);
907 IDEWriteCylinderHigh(CommandPortBase
, 0);
908 IDEWriteCylinderLow(CommandPortBase
, 0);
909 IDEWriteCommand(CommandPortBase
, IDE_CMD_RESET
);
911 for (Retries
= 0; Retries
< 20000; Retries
++)
913 if (!(IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
))
917 ScsiPortStallExecution(150);
919 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
921 DbgPrint("Timeout on drive %lu\n", UnitNumber
);
925 High
= IDEReadCylinderHigh(CommandPortBase
);
926 Low
= IDEReadCylinderLow(CommandPortBase
);
928 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
933 if (High
== 0xEB && Low
== 0x14)
935 if (AtapiIdentifyDevice(CommandPortBase
,
939 &DeviceExtension
->DeviceParams
[UnitNumber
]))
941 DPRINT(" ATAPI drive found!\n");
942 DeviceExtension
->DevicePresent
[UnitNumber
] = TRUE
;
943 DeviceExtension
->DeviceAtapi
[UnitNumber
] = TRUE
;
948 DPRINT(" No ATAPI drive found!\n");
953 if (AtapiIdentifyDevice(CommandPortBase
,
957 &DeviceExtension
->DeviceParams
[UnitNumber
]))
959 DPRINT(" IDE drive found!\n");
960 DeviceExtension
->DevicePresent
[UnitNumber
] = TRUE
;
961 DeviceExtension
->DeviceAtapi
[UnitNumber
] = FALSE
;
966 DPRINT(" No IDE drive found!\n");
971 DPRINT("AtapiFindDrives() done\n");
977 // AtapiResetController
980 // Reset the controller and report completion status
986 // IN WORD CommandPort The address of the command port
987 // IN WORD ControlPort The address of the control port
993 AtapiResetController(IN ULONG CommandPort
,
994 IN ULONG ControlPort
)
998 /* Assert drive reset line */
999 IDEWriteDriveControl(ControlPort
, IDE_DC_SRST
);
1001 /* Wait for min. 25 microseconds */
1002 ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH
);
1004 /* Negate drive reset line */
1005 IDEWriteDriveControl(ControlPort
, 0);
1007 /* Wait for BUSY negation */
1008 for (Retries
= 0; Retries
< IDE_RESET_BUSY_TIMEOUT
* 1000; Retries
++)
1010 if (!(IDEReadStatus(CommandPort
) & IDE_SR_BUSY
))
1014 ScsiPortStallExecution(10);
1018 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
1025 // return TRUE if controller came back to life. and
1026 // the registers are initialized correctly
1027 return(IDEReadError(CommandPort
) == 1);
1031 * AtapiIdentifyDevice
1034 * Get the identification block from the drive
1041 * Address of the command port
1043 * Address of the control port
1045 * The drive index (0,1)
1047 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1049 * Address to write drive ident block
1052 * TRUE: The drive identification block was retrieved successfully
1053 * FALSE: an error ocurred
1057 AtapiIdentifyDevice(IN ULONG CommandPort
,
1058 IN ULONG ControlPort
,
1061 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
1063 /* Get the Drive Identify block from drive or die */
1064 if (AtapiPolledRead(CommandPort
,
1071 (DriveNum
? IDE_DH_DRV1
: 0),
1072 (Atapi
? IDE_CMD_IDENT_ATAPI_DRV
: IDE_CMD_IDENT_ATA_DRV
),
1073 (BYTE
*)DrvParms
) != 0)
1075 DPRINT1("IDEPolledRead() failed\n");
1079 /* Report on drive parameters if debug mode */
1080 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
1081 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
1082 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
1083 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1084 DrvParms
->ConfigBits
,
1085 DrvParms
->LogicalCyls
,
1086 DrvParms
->LogicalHeads
,
1087 DrvParms
->SectorsPerTrack
,
1088 DrvParms
->InterSectorGap
,
1089 DrvParms
->InterSectorGapSize
);
1090 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1091 DrvParms
->BytesInPLO
,
1092 DrvParms
->VendorUniqueCnt
,
1093 DrvParms
->SerialNumber
);
1094 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1095 DrvParms
->ControllerType
,
1096 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
1097 DrvParms
->ECCByteCnt
,
1098 DrvParms
->FirmwareRev
);
1099 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
1100 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1101 (DrvParms
->RWMultImplemented
) & 0xff,
1102 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
1103 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
1104 DrvParms
->MinPIOTransTime
,
1105 DrvParms
->MinDMATransTime
);
1106 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1107 DrvParms
->TMCylinders
,
1109 DrvParms
->TMSectorsPerTrk
,
1110 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
1111 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1112 DrvParms
->TMSectorCountHi
,
1113 DrvParms
->TMSectorCountLo
,
1114 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
1116 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1117 if (DrvParms
->BytesPerSector
== 0)
1118 DrvParms
->BytesPerSector
= 512;
1126 // Read a sector of data from the drive in a polled fashion.
1132 // IN WORD Address Address of command port for drive
1133 // IN BYTE PreComp Value to write to precomp register
1134 // IN BYTE SectorCnt Value to write to sectorCnt register
1135 // IN BYTE SectorNum Value to write to sectorNum register
1136 // IN BYTE CylinderLow Value to write to CylinderLow register
1137 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1138 // IN BYTE DrvHead Value to write to Drive/Head register
1139 // IN BYTE Command Value to write to Command register
1140 // OUT BYTE *Buffer Buffer for output data
1143 // int 0 is success, non 0 is an error code
1147 AtapiPolledRead(IN ULONG CommandPort
,
1148 IN ULONG ControlPort
,
1152 IN BYTE CylinderLow
,
1153 IN BYTE CylinderHigh
,
1158 ULONG SectorCount
= 0;
1160 BOOLEAN Junk
= FALSE
;
1164 /* Write Drive/Head to select drive */
1165 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1166 ScsiPortStallExecution(500);
1168 /* Disable interrupts */
1169 Control
= IDEReadAltStatus(ControlPort
);
1170 IDEWriteDriveControl(ControlPort
, Control
| IDE_DC_nIEN
);
1171 ScsiPortStallExecution(500);
1173 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1174 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1176 Status
= IDEReadStatus(CommandPort
);
1177 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1181 ScsiPortStallExecution(10);
1183 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1185 return(IDE_ER_ABRT
);
1188 /* Write Drive/Head to select drive */
1189 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1191 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1192 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1194 Status
= IDEReadStatus(CommandPort
);
1195 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1199 ScsiPortStallExecution(10);
1201 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1206 /* Issue command to drive */
1207 if (DrvHead
& IDE_DH_LBA
)
1209 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1210 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1211 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1217 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1218 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1227 /* Setup command parameters */
1228 IDEWritePrecomp(CommandPort
, PreComp
);
1229 IDEWriteSectorCount(CommandPort
, SectorCnt
);
1230 IDEWriteSectorNum(CommandPort
, SectorNum
);
1231 IDEWriteCylinderHigh(CommandPort
, CylinderHigh
);
1232 IDEWriteCylinderLow(CommandPort
, CylinderLow
);
1233 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1235 /* Issue the command */
1236 IDEWriteCommand(CommandPort
, Command
);
1237 ScsiPortStallExecution(50);
1239 /* wait for DRQ or error */
1240 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1242 Status
= IDEReadStatus(CommandPort
);
1243 if (!(Status
& IDE_SR_BUSY
))
1245 if (Status
& IDE_SR_ERR
)
1247 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1248 return(IDE_ER_ABRT
);
1250 if (Status
& IDE_SR_DRQ
)
1256 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1257 return(IDE_ER_ABRT
);
1260 ScsiPortStallExecution(10);
1264 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1266 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1267 return(IDE_ER_ABRT
);
1272 /* Read data into buffer */
1275 IDEReadBlock(CommandPort
, Buffer
, IDE_SECTOR_BUF_SZ
);
1276 Buffer
+= IDE_SECTOR_BUF_SZ
;
1280 UCHAR JunkBuffer
[IDE_SECTOR_BUF_SZ
];
1281 IDEReadBlock(CommandPort
, JunkBuffer
, IDE_SECTOR_BUF_SZ
);
1285 /* Check for error or more sectors to read */
1286 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1288 Status
= IDEReadStatus(CommandPort
);
1289 if (!(Status
& IDE_SR_BUSY
))
1291 if (Status
& IDE_SR_ERR
)
1293 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1294 return(IDE_ER_ABRT
);
1296 if (Status
& IDE_SR_DRQ
)
1298 if (SectorCount
>= SectorCnt
)
1300 DPRINT("Buffer size exceeded!\n");
1307 if (SectorCount
> SectorCnt
)
1309 DPRINT("Read %lu sectors of junk!\n",
1310 SectorCount
- SectorCnt
);
1312 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1321 // ------------------------------------------- Nondiscardable statics
1324 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1325 IN PSCSI_REQUEST_BLOCK Srb
)
1327 UCHAR ByteCountHigh
;
1333 DPRINT("AtapiSendAtapiCommand() called!\n");
1335 if ((Srb
->PathId
!= 0) ||
1336 (Srb
->TargetId
> 1) ||
1338 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1340 return(SRB_STATUS_SELECTION_TIMEOUT
);
1343 DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
1346 if (Srb
->Cdb
[0] == SCSIOP_INQUIRY
)
1347 return(AtapiInquiry(DeviceExtension
,
1350 /* Set pointer to data buffer. */
1351 DeviceExtension
->DataBuffer
= (PUSHORT
)Srb
->DataBuffer
;
1352 DeviceExtension
->CurrentSrb
= Srb
;
1354 /* wait for BUSY to clear */
1355 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1357 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1358 if (!(Status
& IDE_SR_BUSY
))
1362 ScsiPortStallExecution(10);
1364 DPRINT("status=%02x\n", Status
);
1365 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
1366 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1368 DPRINT("Drive is BUSY for too long\n");
1369 return(SRB_STATUS_BUSY
);
1371 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
1373 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1374 Irp
= ControllerExtension
->CurrentIrp
;
1375 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1376 Irp
->IoStatus
.Information
= 0;
1382 DPRINT ("Beginning drive reset sequence\n");
1383 IDEBeginControllerReset(ControllerExtension
);
1390 /* Select the desired drive */
1391 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
1392 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
1394 /* wait for BUSY to clear and DRDY to assert */
1395 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1397 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1398 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1402 ScsiPortStallExecution(10);
1404 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1405 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1407 DPRINT("Drive is BUSY for too long after drive select\n");
1408 return(SRB_STATUS_BUSY
);
1410 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1412 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1413 Irp
= ControllerExtension
->CurrentIrp
;
1414 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1415 Irp
->IoStatus
.Information
= 0;
1421 DPRINT("Beginning drive reset sequence\n");
1422 IDEBeginControllerReset(ControllerExtension
);
1429 if (Srb
->DataTransferLength
< 0x10000)
1431 ByteCountLow
= (UCHAR
)(Srb
->DataTransferLength
& 0xFF);
1432 ByteCountHigh
= (UCHAR
)(Srb
->DataTransferLength
>> 8);
1436 ByteCountLow
= 0xFF;
1437 ByteCountHigh
= 0xFF;
1440 /* Set feature register */
1441 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
1443 /* Set command packet length */
1444 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, ByteCountHigh
);
1445 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, ByteCountLow
);
1447 /* Issue command to drive */
1448 IDEWriteCommand(DeviceExtension
->CommandPortBase
, 0xA0); /* Packet command */
1451 /* Wait for DRQ to assert */
1452 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1454 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1455 if ((Status
& IDE_SR_DRQ
))
1459 ScsiPortStallExecution(10);
1462 CdbSize
= (DeviceExtension
->DeviceParams
[Srb
->TargetId
].ConfigBits
& 0x3 == 1) ? 16 : 12;
1463 DPRINT("CdbSize: %lu\n", CdbSize
);
1465 /* Write command packet */
1466 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
1470 DeviceExtension
->ExpectingInterrupt
= TRUE
;
1472 DPRINT("AtapiSendAtapiCommand() done\n");
1474 return(SRB_STATUS_PENDING
);
1479 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1480 IN PSCSI_REQUEST_BLOCK Srb
)
1482 ULONG SrbStatus
= SRB_STATUS_SUCCESS
;
1484 DPRINT("AtapiSendIdeCommand() called!\n");
1486 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1491 switch (Srb
->Cdb
[0])
1493 case SCSIOP_INQUIRY
:
1494 SrbStatus
= AtapiInquiry(DeviceExtension
,
1498 case SCSIOP_READ_CAPACITY
:
1499 SrbStatus
= AtapiReadCapacity(DeviceExtension
,
1505 SrbStatus
= AtapiReadWrite(DeviceExtension
,
1509 case SCSIOP_MODE_SENSE
:
1510 case SCSIOP_TEST_UNIT_READY
:
1512 case SCSIOP_START_STOP_UNIT
:
1513 case SCSIOP_REQUEST_SENSE
:
1517 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1519 SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1523 DPRINT("AtapiSendIdeCommand() done!\n");
1530 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1531 PSCSI_REQUEST_BLOCK Srb
)
1533 PIDE_DRIVE_IDENTIFY DeviceParams
;
1534 PINQUIRYDATA InquiryData
;
1537 DPRINT1("SCSIOP_INQUIRY: DeviceExtension %p TargetId: %lu\n",
1538 DeviceExtension
, Srb
->TargetId
);
1540 if ((Srb
->PathId
!= 0) ||
1541 (Srb
->TargetId
> 1) ||
1543 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1545 return(SRB_STATUS_SELECTION_TIMEOUT
);
1548 InquiryData
= Srb
->DataBuffer
;
1549 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1552 for (i
= 0; i
< Srb
->DataTransferLength
; i
++)
1554 ((PUCHAR
)Srb
->DataBuffer
)[i
] = 0;
1557 /* set device class */
1558 if (DeviceExtension
->DeviceAtapi
[Srb
->TargetId
] == FALSE
)
1561 InquiryData
->DeviceType
= DIRECT_ACCESS_DEVICE
;
1565 /* get it from the ATAPI configuration word */
1566 InquiryData
->DeviceType
= (DeviceParams
->ConfigBits
>> 8) & 0x1F;
1567 DPRINT("Device class: %u\n", InquiryData
->DeviceType
);
1570 DPRINT("ConfigBits: 0x%x\n", DeviceParams
->ConfigBits
);
1571 if (DeviceParams
->ConfigBits
& 0x80)
1573 DPRINT("Removable media!\n");
1574 InquiryData
->RemovableMedia
= 1;
1577 for (i
= 0; i
< 20; i
+= 2)
1579 InquiryData
->VendorId
[i
] =
1580 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
];
1581 InquiryData
->VendorId
[i
+1] =
1582 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
+1];
1585 for (i
= 0; i
< 4; i
++)
1587 InquiryData
->ProductId
[12+i
] = ' ';
1590 for (i
= 0; i
< 4; i
+= 2)
1592 InquiryData
->ProductRevisionLevel
[i
] =
1593 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
];
1594 InquiryData
->ProductRevisionLevel
[i
+1] =
1595 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
+1];
1598 DPRINT1("VendorId: '%.20s'\n", InquiryData
->VendorId
);
1600 return(SRB_STATUS_SUCCESS
);
1605 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1606 PSCSI_REQUEST_BLOCK Srb
)
1608 PREAD_CAPACITY_DATA CapacityData
;
1609 PIDE_DRIVE_IDENTIFY DeviceParams
;
1612 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb
->TargetId
);
1614 if ((Srb
->PathId
!= 0) ||
1615 (Srb
->TargetId
> 1) ||
1617 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1619 return(SRB_STATUS_SELECTION_TIMEOUT
);
1623 CapacityData
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
1624 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1626 /* Set sector (block) size to 512 bytes (big-endian). */
1627 CapacityData
->BytesPerBlock
= 0x20000;
1629 /* Calculate last sector (big-endian). */
1630 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1632 LastSector
= (ULONG
)((DeviceParams
->TMSectorCountHi
<< 16) +
1633 DeviceParams
->TMSectorCountLo
) - 1;
1637 LastSector
= (ULONG
)(DeviceParams
->LogicalCyls
*
1638 DeviceParams
->LogicalHeads
*
1639 DeviceParams
->SectorsPerTrack
)-1;
1642 CapacityData
->LogicalBlockAddress
= (((PUCHAR
)&LastSector
)[0] << 24) |
1643 (((PUCHAR
)&LastSector
)[1] << 16) |
1644 (((PUCHAR
)&LastSector
)[2] << 8) |
1645 ((PUCHAR
)&LastSector
)[3];
1647 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
1650 CapacityData
->LogicalBlockAddress
);
1652 return(SRB_STATUS_SUCCESS
);
1657 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1658 PSCSI_REQUEST_BLOCK Srb
)
1660 PIDE_DRIVE_IDENTIFY DeviceParams
;
1661 ULONG StartingSector
;
1671 DPRINT("AtapiReadWrite() called!\n");
1673 if ((Srb
->PathId
!= 0) ||
1674 (Srb
->TargetId
> 1) ||
1676 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1678 return(SRB_STATUS_SELECTION_TIMEOUT
);
1681 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
1684 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1686 /* Get starting sector number from CDB. */
1687 StartingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
1688 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
1689 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
1690 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
1692 SectorCount
= (Srb
->DataTransferLength
+ DeviceParams
->BytesPerSector
- 1) /
1693 DeviceParams
->BytesPerSector
;
1695 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
1697 Srb
->DataTransferLength
,
1700 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1702 SectorNumber
= StartingSector
& 0xff;
1703 CylinderLow
= (StartingSector
>> 8) & 0xff;
1704 CylinderHigh
= (StartingSector
>> 16) & 0xff;
1705 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
1706 (Srb
->TargetId
? IDE_DH_DRV1
: 0) |
1711 SectorNumber
= (StartingSector
% DeviceParams
->SectorsPerTrack
) + 1;
1712 StartingSector
/= DeviceParams
->SectorsPerTrack
;
1713 DrvHead
= (StartingSector
% DeviceParams
->LogicalHeads
) |
1714 (Srb
->TargetId
? IDE_DH_DRV1
: 0);
1715 StartingSector
/= DeviceParams
->LogicalHeads
;
1716 CylinderLow
= StartingSector
& 0xff;
1717 CylinderHigh
= StartingSector
>> 8;
1721 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
1723 Command
= IDE_CMD_READ
;
1727 Command
= IDE_CMD_WRITE
;
1730 if (DrvHead
& IDE_DH_LBA
)
1732 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1733 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
1734 DeviceExtension
->CommandPortBase
,
1735 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1736 ((DrvHead
& 0x0f) << 24) +
1737 (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNumber
,
1743 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1744 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
1745 DeviceExtension
->CommandPortBase
,
1746 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1755 /* Set pointer to data buffer. */
1756 DeviceExtension
->DataBuffer
= (PUSHORT
)Srb
->DataBuffer
;
1758 DeviceExtension
->CurrentSrb
= Srb
;
1759 DeviceExtension
->ExpectingInterrupt
= TRUE
;
1763 /* wait for BUSY to clear */
1764 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1766 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1767 if (!(Status
& IDE_SR_BUSY
))
1771 ScsiPortStallExecution(10);
1773 DPRINT("status=%02x\n", Status
);
1774 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
1775 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1777 DPRINT ("Drive is BUSY for too long\n");
1778 return(SRB_STATUS_BUSY
);
1780 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
1782 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1783 Irp
= ControllerExtension
->CurrentIrp
;
1784 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1785 Irp
->IoStatus
.Information
= 0;
1791 DPRINT ("Beginning drive reset sequence\n");
1792 IDEBeginControllerReset(ControllerExtension
);
1799 /* Select the desired drive */
1800 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
1801 IDE_DH_FIXED
| DrvHead
);
1803 /* wait for BUSY to clear and DRDY to assert */
1804 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1806 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1807 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1811 ScsiPortStallExecution(10);
1813 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1814 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1816 DPRINT("Drive is BUSY for too long after drive select\n");
1817 return(SRB_STATUS_BUSY
);
1819 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1821 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1822 Irp
= ControllerExtension
->CurrentIrp
;
1823 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1824 Irp
->IoStatus
.Information
= 0;
1830 DPRINT("Beginning drive reset sequence\n");
1831 IDEBeginControllerReset(ControllerExtension
);
1838 /* Indicate expecting an interrupt. */
1839 DeviceExtension
->ExpectingInterrupt
= TRUE
;
1841 /* Setup command parameters */
1842 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
1843 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
);
1844 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
);
1845 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
);
1846 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
);
1847 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1849 /* Issue command to drive */
1850 IDEWriteCommand(DeviceExtension
->CommandPortBase
, Command
);
1852 /* Write data block */
1853 if (Command
== IDE_CMD_WRITE
)
1855 PUCHAR TargetAddress
;
1858 /* Wait for controller ready */
1859 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
1861 BYTE Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1862 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
1866 KeStallExecutionProcessor(10);
1868 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1870 DPRINT("Drive is BUSY for too long after sending write command\n");
1871 return(SRB_STATUS_BUSY
);
1873 if (DeviceExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1875 Irp
= ControllerExtension
->CurrentIrp
;
1876 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1877 Irp
->IoStatus
.Information
= 0;
1883 IDEBeginControllerReset(ControllerExtension
);
1890 /* Update SRB data */
1891 SectorSize
= DeviceExtension
->DeviceParams
[Srb
->TargetId
].BytesPerSector
;
1892 TargetAddress
= Srb
->DataBuffer
;
1893 Srb
->DataBuffer
+= SectorSize
;
1894 Srb
->DataTransferLength
-= SectorSize
;
1896 /* Write data block */
1897 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
1903 DPRINT("AtapiReadWrite() done!\n");
1905 /* Wait for interrupt. */
1906 return(SRB_STATUS_PENDING
);
1911 AtapiErrorToScsi(PVOID DeviceExtension
,
1912 PSCSI_REQUEST_BLOCK Srb
)
1914 PATAPI_MINIPORT_EXTENSION DevExt
;
1915 ULONG CommandPortBase
;
1916 ULONG ControlPortBase
;
1921 DPRINT1("AtapiErrorToScsi() called\n");
1923 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
1925 CommandPortBase
= DevExt
->CommandPortBase
;
1926 ControlPortBase
= DevExt
->ControlPortBase
;
1928 ErrorReg
= IDEReadError(CommandPortBase
);
1930 if (DevExt
->DeviceAtapi
[Srb
->TargetId
])
1932 switch (ErrorReg
>> 4)
1934 case SCSI_SENSE_NO_SENSE
:
1935 DPRINT1("ATAPI error: SCSI_SENSE_NO_SENSE\n");
1936 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
1937 SrbStatus
= SRB_STATUS_ERROR
;
1940 case SCSI_SENSE_RECOVERED_ERROR
:
1941 DPRINT1("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
1943 SrbStatus
= SRB_STATUS_SUCCESS
;
1946 case SCSI_SENSE_NOT_READY
:
1947 DPRINT1("ATAPI error: SCSI_SENSE_NOT_READY\n");
1948 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
1949 SrbStatus
= SRB_STATUS_ERROR
;
1952 case SCSI_SENSE_MEDIUM_ERROR
:
1953 DPRINT1("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
1954 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
1955 SrbStatus
= SRB_STATUS_ERROR
;
1958 case SCSI_SENSE_HARDWARE_ERROR
:
1959 DPRINT1("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
1960 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
1961 SrbStatus
= SRB_STATUS_ERROR
;
1964 case SCSI_SENSE_ILLEGAL_REQUEST
:
1965 DPRINT1("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
1966 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
1967 SrbStatus
= SRB_STATUS_ERROR
;
1970 case SCSI_SENSE_UNIT_ATTENTION
:
1971 DPRINT1("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
1972 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
1973 SrbStatus
= SRB_STATUS_ERROR
;
1976 case SCSI_SENSE_DATA_PROTECT
:
1977 DPRINT1("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
1978 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
1979 SrbStatus
= SRB_STATUS_ERROR
;
1982 case SCSI_SENSE_BLANK_CHECK
:
1983 DPRINT1("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
1984 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
1985 SrbStatus
= SRB_STATUS_ERROR
;
1988 case SCSI_SENSE_ABORTED_COMMAND
:
1989 DPRINT1("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
1990 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
1991 SrbStatus
= SRB_STATUS_ERROR
;
1995 DPRINT1("ATAPI error: Invalid sense key\n");
1997 SrbStatus
= SRB_STATUS_ERROR
;
2003 DPRINT1("IDE error: %02x\n", ErrorReg
);
2006 SrbStatus
= SRB_STATUS_ERROR
;
2009 UCHAR SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
2012 CylinderLow
= IDEReadCylinderLow(CommandPortBase
);
2013 CylinderHigh
= IDEReadCylinderHigh(CommandPortBase
);
2014 DriveHead
= IDEReadDriveHead(CommandPortBase
);
2015 SectorCount
= IDEReadSectorCount(CommandPortBase
);
2016 SectorNum
= IDEReadSectorNum(CommandPortBase
);
2018 DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
2029 Srb
->ScsiStatus
= ScsiStatus
;
2031 DPRINT1("AtapiErrorToScsi() done\n");