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.
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>
51 #include <ddk/ntddscsi.h>
58 #define VERSION "0.0.1"
61 // ------------------------------------------------------- File Static Data
63 // ATAPI_MINIPORT_EXTENSION
66 // Extension to be placed in each port device object
69 // Allocated from NON-PAGED POOL
70 // Available at any IRQL
73 typedef struct _ATAPI_MINIPORT_EXTENSION
75 IDE_DRIVE_IDENTIFY DeviceParams[2];
76 BOOLEAN DevicePresent[2];
77 BOOLEAN DeviceAtapi[2];
79 ULONG CommandPortBase;
80 ULONG ControlPortBase;
81 ULONG BusMasterRegisterBase;
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 DPRINT("ATAPI Driver %s\n", VERSION);
258 DPRINT("RegistryPath: '%wZ'\n", RegistryPath);
260 /* Initialize data structure */
261 RtlZeroMemory(&InitData,
262 sizeof(HW_INITIALIZATION_DATA));
263 InitData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
264 InitData.HwInitialize = AtapiInitialize;
265 InitData.HwResetBus = AtapiResetBus;
266 InitData.HwStartIo = AtapiStartIo;
267 InitData.HwInterrupt = AtapiInterrupt;
269 InitData.DeviceExtensionSize = sizeof(ATAPI_MINIPORT_EXTENSION);
270 InitData.SpecificLuExtensionSize = sizeof(UNIT_EXTENSION);
272 InitData.MapBuffers = TRUE;
274 /* Search the PCI bus for compatibility mode ide controllers */
276 InitData.HwFindAdapter = AtapiFindCompatiblePciController;
277 InitData.NumberOfAccessRanges = 3;
278 InitData.AdapterInterfaceType = PCIBus;
280 InitData.VendorId = NULL;
281 InitData.VendorIdLength = 0;
282 InitData.DeviceId = NULL;
283 InitData.DeviceIdLength = 0;
285 Status = ScsiPortInitialize(DriverObject,
289 // if (newStatus < statusToReturn)
290 // statusToReturn = newStatus;
293 /* Search the ISA bus for ide controllers */
295 InitData.HwFindAdapter = AtapiFindIsaBusController;
296 InitData.NumberOfAccessRanges = 2;
297 InitData.AdapterInterfaceType = Isa;
299 InitData.VendorId = NULL;
300 InitData.VendorIdLength = 0;
301 InitData.DeviceId = NULL;
302 InitData.DeviceIdLength = 0;
304 Status = ScsiPortInitialize(DriverObject,
308 // if (newStatus < statusToReturn)
309 // statusToReturn = newStatus;
312 /* Search the PCI bus for native mode ide controllers */
314 InitData.HwFindAdapter = AtapiFindNativePciController;
315 InitData.NumberOfAccessRanges = 2;
316 InitData.AdapterInterfaceType = PCIBus;
318 InitData.VendorId = NULL;
319 InitData.VendorIdLength = 0;
320 InitData.DeviceId = NULL;
321 InitData.DeviceIdLength = 0;
323 Status = ScsiPortInitialize(DriverObject,
327 // if (newStatus < statusToReturn)
328 // statusToReturn = newStatus;
331 DPRINT("Returning from DriverEntry\n");
338 AtapiFindCompatiblePciController(PVOID DeviceExtension,
340 PVOID BusInformation,
341 PCHAR ArgumentString,
342 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
345 PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
346 PCI_SLOT_NUMBER SlotNumber;
347 PCI_COMMON_CONFIG PciConfig;
349 ULONG FunctionNumber;
350 BOOLEAN ChannelFound;
353 DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
354 ConfigInfo->SystemIoBusNumber,
355 ConfigInfo->SlotNumber);
359 /* both channels were claimed: exit */
360 if (ConfigInfo->AtdiskPrimaryClaimed == TRUE &&
361 ConfigInfo->AtdiskSecondaryClaimed == TRUE)
362 return(SP_RETURN_NOT_FOUND);
365 SlotNumber.u.AsULONG = 0;
366 for (FunctionNumber = 0 /*ConfigInfo->SlotNumber*/; FunctionNumber < 256; FunctionNumber++)
368 SlotNumber.u.AsULONG = FunctionNumber;
370 ChannelFound = FALSE;
373 DataSize = ScsiPortGetBusData(DeviceExtension,
376 SlotNumber.u.AsULONG,
378 sizeof(PCI_COMMON_CONFIG));
379 // if (DataSize != sizeof(PCI_COMMON_CONFIG) ||
380 // PciConfig.VendorID == PCI_INVALID_VENDORID)
383 // if ((SlotNumber.u.AsULONG & 0x07) == 0)
384 // return(SP_RETURN_ERROR); /* No bus found */
387 // return(SP_RETURN_ERROR);
390 if (PciConfig.BaseClass == 0x01 &&
391 PciConfig.SubClass == 0x01) // &&
392 // (PciConfig.ProgIf & 0x05) == 0)
394 /* both channels are in compatibility mode */
395 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
396 ConfigInfo->SystemIoBusNumber,
397 SlotNumber.u.bits.DeviceNumber,
398 SlotNumber.u.bits.FunctionNumber,
401 DPRINT("ProgIF 0x%02hx\n", PciConfig.ProgIf);
403 DPRINT("Found IDE controller in compatibility mode!\n");
405 ConfigInfo->NumberOfBuses = 1;
406 ConfigInfo->MaximumNumberOfTargets = 2;
407 ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
409 if (PciConfig.ProgIf & 0x80)
411 DPRINT("Found IDE Bus Master controller!\n");
412 if (PciConfig.u.type0.BaseAddresses[4] & 0x00000001)
414 DPRINT(" IDE Bus Master Registers at IO %lx\n",
415 PciConfig.u.type0.BaseAddresses[4] & ~0x00000003);
419 if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
421 /* Both channels unclaimed: Claim primary channel */
422 DPRINT("Primary channel!\n");
424 DevExt->CommandPortBase = 0x01F0;
425 DevExt->ControlPortBase = 0x03F6;
427 ConfigInfo->BusInterruptLevel = 14;
428 ConfigInfo->BusInterruptVector = 14;
429 ConfigInfo->InterruptMode = LevelSensitive;
431 ConfigInfo->AccessRanges[0].RangeStart =
432 ScsiPortConvertUlongToPhysicalAddress(0x01F0);
433 ConfigInfo->AccessRanges[0].RangeLength = 8;
434 ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
436 ConfigInfo->AccessRanges[1].RangeStart =
437 ScsiPortConvertUlongToPhysicalAddress(0x03F6);
438 ConfigInfo->AccessRanges[1].RangeLength = 1;
439 ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
441 /* Claim bus master registers */
442 if (PciConfig.ProgIf & 0x80)
444 DevExt->BusMasterRegisterBase =
445 PciConfig.u.type0.BaseAddresses[4] & ~0x00000003;
447 ConfigInfo->AccessRanges[2].RangeStart =
448 ScsiPortConvertUlongToPhysicalAddress(DevExt->BusMasterRegisterBase);
449 ConfigInfo->AccessRanges[2].RangeLength = 8;
450 ConfigInfo->AccessRanges[2].RangeInMemory = FALSE;
453 ConfigInfo->AtdiskPrimaryClaimed = TRUE;
457 else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
459 /* Primary channel already claimed: claim secondary channel */
460 DPRINT("Secondary channel!\n");
462 DevExt->CommandPortBase = 0x0170;
463 DevExt->ControlPortBase = 0x0376;
465 ConfigInfo->BusInterruptLevel = 15;
466 ConfigInfo->BusInterruptVector = 15;
467 ConfigInfo->InterruptMode = LevelSensitive;
469 ConfigInfo->AccessRanges[0].RangeStart =
470 ScsiPortConvertUlongToPhysicalAddress(0x0170);
471 ConfigInfo->AccessRanges[0].RangeLength = 8;
472 ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
474 ConfigInfo->AccessRanges[1].RangeStart =
475 ScsiPortConvertUlongToPhysicalAddress(0x0376);
476 ConfigInfo->AccessRanges[1].RangeLength = 1;
477 ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
479 /* Claim bus master registers */
480 if (PciConfig.ProgIf & 0x80)
482 DevExt->BusMasterRegisterBase =
483 (PciConfig.u.type0.BaseAddresses[4] & ~0x00000003) + 8;
485 ConfigInfo->AccessRanges[2].RangeStart =
486 ScsiPortConvertUlongToPhysicalAddress(DevExt->BusMasterRegisterBase);
487 ConfigInfo->AccessRanges[2].RangeLength = 8;
488 ConfigInfo->AccessRanges[2].RangeInMemory = FALSE;
491 ConfigInfo->AtdiskSecondaryClaimed = TRUE;
496 /* Find attached devices */
497 if (ChannelFound == TRUE)
499 DeviceFound = AtapiFindDevices(DevExt,
502 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
503 return(SP_RETURN_FOUND);
507 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
509 return(SP_RETURN_NOT_FOUND);
514 AtapiFindIsaBusController(PVOID DeviceExtension,
516 PVOID BusInformation,
517 PCHAR ArgumentString,
518 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
521 PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
522 BOOLEAN ChannelFound = FALSE;
523 BOOLEAN DeviceFound = FALSE;
525 DPRINT("AtapiFindIsaBusController() called!\n");
529 ConfigInfo->NumberOfBuses = 1;
530 ConfigInfo->MaximumNumberOfTargets = 2;
531 ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
533 if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
535 /* Both channels unclaimed: Claim primary channel */
536 DPRINT("Primary channel!\n");
538 DevExt->CommandPortBase = 0x01F0;
539 DevExt->ControlPortBase = 0x03F6;
541 ConfigInfo->BusInterruptLevel = 14;
542 ConfigInfo->BusInterruptVector = 14;
543 ConfigInfo->InterruptMode = LevelSensitive;
545 ConfigInfo->AccessRanges[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x01F0);
546 ConfigInfo->AccessRanges[0].RangeLength = 8;
547 ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
549 ConfigInfo->AccessRanges[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x03F6);
550 ConfigInfo->AccessRanges[1].RangeLength = 1;
551 ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
553 ConfigInfo->AtdiskPrimaryClaimed = TRUE;
555 *Again = FALSE/*TRUE*/;
557 else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
559 /* Primary channel already claimed: claim secondary channel */
560 DPRINT("Secondary channel!\n");
562 DevExt->CommandPortBase = 0x0170;
563 DevExt->ControlPortBase = 0x0376;
565 ConfigInfo->BusInterruptLevel = 15;
566 ConfigInfo->BusInterruptVector = 15;
567 ConfigInfo->InterruptMode = LevelSensitive;
569 ConfigInfo->AccessRanges[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x0170);
570 ConfigInfo->AccessRanges[0].RangeLength = 8;
571 ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
573 ConfigInfo->AccessRanges[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x0376);
574 ConfigInfo->AccessRanges[1].RangeLength = 1;
575 ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
577 ConfigInfo->AtdiskSecondaryClaimed = TRUE;
583 DPRINT("AtapiFindIsaBusController() both channels claimed. Returns: SP_RETURN_NOT_FOUND\n");
585 return(SP_RETURN_NOT_FOUND);
588 /* Find attached devices */
591 DeviceFound = AtapiFindDevices(DevExt,
595 DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
596 return(SP_RETURN_FOUND);
601 AtapiFindNativePciController(PVOID DeviceExtension,
603 PVOID BusInformation,
604 PCHAR ArgumentString,
605 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
608 PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
610 DPRINT("AtapiFindNativePciController() called!\n");
614 DPRINT("AtapiFindNativePciController() done!\n");
616 return(SP_RETURN_NOT_FOUND);
620 static BOOLEAN STDCALL
621 AtapiInitialize(IN PVOID DeviceExtension)
627 static BOOLEAN STDCALL
628 AtapiResetBus(IN PVOID DeviceExtension,
635 static BOOLEAN STDCALL
636 AtapiStartIo(IN PVOID DeviceExtension,
637 IN PSCSI_REQUEST_BLOCK Srb)
639 PATAPI_MINIPORT_EXTENSION DevExt;
642 DPRINT("AtapiStartIo() called\n");
644 DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
646 switch (Srb->Function)
648 case SRB_FUNCTION_EXECUTE_SCSI:
649 DevExt->CurrentSrb = Srb;
650 if (DevExt->DeviceAtapi[Srb->TargetId] == TRUE)
652 Result = AtapiSendAtapiCommand(DevExt,
657 Result = AtapiSendIdeCommand(DevExt,
664 Srb->SrbStatus = Result;
667 if (Result != SRB_STATUS_PENDING)
669 DevExt->CurrentSrb = NULL;
670 Srb->SrbStatus = (UCHAR)Result;
672 ScsiPortNotification(RequestComplete,
675 ScsiPortNotification(NextRequest,
681 DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
684 DPRINT("AtapiStartIo() done\n");
690 static BOOLEAN STDCALL
691 AtapiInterrupt(IN PVOID DeviceExtension)
693 PATAPI_MINIPORT_EXTENSION DevExt;
694 PSCSI_REQUEST_BLOCK Srb;
695 ULONG CommandPortBase;
696 ULONG ControlPortBase;
702 PUCHAR TargetAddress;
706 DPRINT("AtapiInterrupt() called!\n");
708 DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
709 if (DevExt->ExpectingInterrupt == FALSE)
711 DPRINT("AtapiInterrupt(): Unexpected interrupt\n");
715 Srb = DevExt->CurrentSrb;
716 DPRINT("Srb: %p\n", Srb);
718 CommandPortBase = DevExt->CommandPortBase;
719 ControlPortBase = DevExt->ControlPortBase;
720 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", CommandPortBase, ControlPortBase);
722 IsAtapi = DevExt->DeviceAtapi[Srb->TargetId];
723 DPRINT("IsAtapi == %s\n", (IsAtapi) ? "TRUE" : "FALSE");
727 DeviceStatus = IDEReadStatus(CommandPortBase);
728 DPRINT("DeviceStatus: %x\n", DeviceStatus);
730 if (DeviceStatus & IDE_SR_BUSY)
732 /* Wait for BUSY to drop */
733 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
735 DeviceStatus = IDEReadStatus(CommandPortBase);
736 if (!(DeviceStatus & IDE_SR_BUSY))
740 ScsiPortStallExecution(10);
742 if (Retries >= IDE_MAX_BUSY_RETRIES)
744 DPRINT1("Drive is BUSY for too long\n");
745 /* FIXME: handle timeout */
749 if ((DeviceStatus & IDE_SR_ERR) &&
750 (Srb->Cdb[0] != SCSIOP_REQUEST_SENSE))
752 /* Report error condition */
753 Srb->SrbStatus = SRB_STATUS_ERROR;
758 if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
760 DPRINT("Read data\n");
762 /* Update controller/device state variables */
763 TargetAddress = Srb->DataBuffer;
767 TransferSize = IDEReadCylinderLow(CommandPortBase);
768 TransferSize += IDEReadCylinderHigh(CommandPortBase) << 8;
772 TransferSize = DevExt->DeviceParams[Srb->TargetId].BytesPerSector;
775 DPRINT("TransferLength: %lu\n", Srb->DataTransferLength);
776 DPRINT("TransferSize: %lu\n", TransferSize);
778 if (Srb->DataTransferLength <= TransferSize)
780 Srb->DataTransferLength = 0;
785 Srb->DataTransferLength -= TransferSize;
788 Srb->DataBuffer += TransferSize;
789 DPRINT("IsLastBlock == %s\n", (IsLastBlock) ? "TRUE" : "FALSE");
791 /* Wait for DRQ assertion */
792 for (Retries = 0; Retries < IDE_MAX_DRQ_RETRIES &&
793 !(IDEReadStatus(CommandPortBase) & IDE_SR_DRQ);
796 KeStallExecutionProcessor(10);
799 /* Copy the block of data */
800 IDEReadBlock(CommandPortBase,
807 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
808 (IDEReadStatus(CommandPortBase) & IDE_SR_BUSY);
811 KeStallExecutionProcessor(10);
814 /* Check for data overrun */
815 if (IDEReadStatus(CommandPortBase) & IDE_SR_DRQ)
817 /* FIXME: Handle error! */
818 DPRINT1("AtapiInterrupt(): data overrun error!");
822 Srb->SrbStatus = SRB_STATUS_SUCCESS;
824 else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
826 DPRINT("Write data\n");
828 if (Srb->DataTransferLength == 0)
831 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
832 (IDEReadStatus(CommandPortBase) & IDE_SR_BUSY);
835 KeStallExecutionProcessor(10);
838 /* Check for data overrun */
839 if (IDEReadStatus(CommandPortBase) & IDE_SR_DRQ)
841 /* FIXME: Handle error! */
842 DPRINT1("AtapiInterrupt(): data overrun error!");
845 DevExt->ExpectingInterrupt = FALSE;
850 /* Update SRB data */
851 SectorSize = DevExt->DeviceParams[Srb->TargetId].BytesPerSector;
853 TargetAddress = Srb->DataBuffer;
854 Srb->DataBuffer += SectorSize;
855 Srb->DataTransferLength -= SectorSize;
857 /* Write the sector */
858 IDEWriteBlock(CommandPortBase,
863 Srb->SrbStatus = SRB_STATUS_SUCCESS;
867 DPRINT1("Unspecified transfer direction!\n");
868 Srb->SrbStatus = SRB_STATUS_SUCCESS; // SRB_STATUS_ERROR;
874 if (Srb->SrbStatus == SRB_STATUS_ERROR)
876 Srb->SrbStatus = AtapiErrorToScsi(DeviceExtension,
881 /* complete this packet */
884 DevExt->ExpectingInterrupt = FALSE;
886 ScsiPortNotification(RequestComplete,
890 ScsiPortNotification(NextRequest,
895 DPRINT("AtapiInterrupt() done!\n");
905 // ---------------------------------------------------- Discardable statics
908 /**********************************************************************
913 * Searches for devices on the given port.
920 * Port device specific information.
923 * Port configuration information.
926 * TRUE: At least one device is attached to the port.
927 * FALSE: No device is attached to the port.
931 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
932 PPORT_CONFIGURATION_INFORMATION ConfigInfo)
934 BOOLEAN DeviceFound = FALSE;
935 ULONG CommandPortBase;
936 ULONG ControlPortBase;
941 DPRINT("AtapiFindDevices() called\n");
943 CommandPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[0].RangeStart);
944 DPRINT(" CommandPortBase: %x\n", CommandPortBase);
946 ControlPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[1].RangeStart);
947 DPRINT(" ControlPortBase: %x\n", ControlPortBase);
949 for (UnitNumber = 0; UnitNumber < 2; UnitNumber++)
952 IDEWriteDriveHead(CommandPortBase,
953 IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
954 ScsiPortStallExecution(500);
956 /* Disable interrupts */
957 IDEWriteDriveControl(ControlPortBase,
959 ScsiPortStallExecution(500);
961 IDEWriteCylinderHigh(CommandPortBase, 0);
962 IDEWriteCylinderLow(CommandPortBase, 0);
963 IDEWriteCommand(CommandPortBase, IDE_CMD_RESET);
965 for (Retries = 0; Retries < 20000; Retries++)
967 if (!(IDEReadStatus(CommandPortBase) & IDE_SR_BUSY))
971 ScsiPortStallExecution(150);
973 if (Retries >= 20000)
975 DPRINT("Timeout on drive %lu\n", UnitNumber);
976 DeviceExtension->DevicePresent[UnitNumber] = FALSE;
980 High = IDEReadCylinderHigh(CommandPortBase);
981 Low = IDEReadCylinderLow(CommandPortBase);
983 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
988 if (High == 0xEB && Low == 0x14)
990 if (AtapiIdentifyDevice(CommandPortBase,
994 &DeviceExtension->DeviceParams[UnitNumber]))
996 DPRINT(" ATAPI drive found!\n");
997 DeviceExtension->DevicePresent[UnitNumber] = TRUE;
998 DeviceExtension->DeviceAtapi[UnitNumber] = TRUE;
1003 DPRINT(" No ATAPI drive found!\n");
1008 if (AtapiIdentifyDevice(CommandPortBase,
1012 &DeviceExtension->DeviceParams[UnitNumber]))
1014 DPRINT(" IDE drive found!\n");
1015 DeviceExtension->DevicePresent[UnitNumber] = TRUE;
1016 DeviceExtension->DeviceAtapi[UnitNumber] = FALSE;
1021 DPRINT(" No IDE drive found!\n");
1027 DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound) ? "TRUE" : "FALSE");
1029 return(DeviceFound);
1033 // AtapiResetController
1036 // Reset the controller and report completion status
1042 // IN WORD CommandPort The address of the command port
1043 // IN WORD ControlPort The address of the control port
1049 AtapiResetController(IN ULONG CommandPort,
1050 IN ULONG ControlPort)
1054 /* Assert drive reset line */
1055 IDEWriteDriveControl(ControlPort, IDE_DC_SRST);
1057 /* Wait for min. 25 microseconds */
1058 ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH);
1060 /* Negate drive reset line */
1061 IDEWriteDriveControl(ControlPort, 0);
1063 /* Wait for BUSY negation */
1064 for (Retries = 0; Retries < IDE_RESET_BUSY_TIMEOUT * 1000; Retries++)
1066 if (!(IDEReadStatus(CommandPort) & IDE_SR_BUSY))
1070 ScsiPortStallExecution(10);
1073 if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
1078 // return TRUE if controller came back to life. and
1079 // the registers are initialized correctly
1080 return(IDEReadError(CommandPort) == 1);
1084 * AtapiIdentifyDevice
1087 * Get the identification block from the drive
1094 * Address of the command port
1096 * Address of the control port
1098 * The drive index (0,1)
1100 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1102 * Address to write drive ident block
1105 * TRUE: The drive identification block was retrieved successfully
1106 * FALSE: an error ocurred
1110 AtapiIdentifyDevice(IN ULONG CommandPort,
1111 IN ULONG ControlPort,
1114 OUT PIDE_DRIVE_IDENTIFY DrvParms)
1118 /* Get the Drive Identify block from drive or die */
1119 if (AtapiPolledRead(CommandPort,
1126 (DriveNum ? IDE_DH_DRV1 : 0),
1127 (Atapi ? IDE_CMD_IDENT_ATAPI_DRV : IDE_CMD_IDENT_ATA_DRV),
1128 (BYTE *)DrvParms) != 0)
1130 DPRINT("IDEPolledRead() failed\n");
1134 /* Report on drive parameters if debug mode */
1135 IDESwapBytePairs(DrvParms->SerialNumber, 20);
1136 IDESwapBytePairs(DrvParms->FirmwareRev, 8);
1137 IDESwapBytePairs(DrvParms->ModelNumber, 40);
1138 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1139 DrvParms->ConfigBits,
1140 DrvParms->LogicalCyls,
1141 DrvParms->LogicalHeads,
1142 DrvParms->SectorsPerTrack,
1143 DrvParms->InterSectorGap,
1144 DrvParms->InterSectorGapSize);
1145 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1146 DrvParms->BytesInPLO,
1147 DrvParms->VendorUniqueCnt,
1148 DrvParms->SerialNumber);
1149 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1150 DrvParms->ControllerType,
1151 DrvParms->BufferSize * IDE_SECTOR_BUF_SZ,
1152 DrvParms->ECCByteCnt,
1153 DrvParms->FirmwareRev);
1154 DPRINT("Model:[%.40s]\n", DrvParms->ModelNumber);
1155 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1156 (DrvParms->RWMultImplemented) & 0xff,
1157 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0,
1158 (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
1159 DrvParms->MinPIOTransTime,
1160 DrvParms->MinDMATransTime);
1161 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1162 DrvParms->TMCylinders,
1164 DrvParms->TMSectorsPerTrk,
1165 (ULONG)(DrvParms->TMCapacityLo + (DrvParms->TMCapacityHi << 16)));
1166 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1167 DrvParms->TMSectorCountHi,
1168 DrvParms->TMSectorCountLo,
1169 (ULONG)((DrvParms->TMSectorCountHi << 16) + DrvParms->TMSectorCountLo));
1171 DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
1172 if (DrvParms->BytesPerSector == 0)
1174 DrvParms->BytesPerSector = 512;
1178 for (i = 15; i >= 0; i--)
1180 if (DrvParms->BytesPerSector & (1 << i))
1182 DrvParms->BytesPerSector = 1 << i;
1187 DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
1196 // Read a sector of data from the drive in a polled fashion.
1202 // IN WORD Address Address of command port for drive
1203 // IN BYTE PreComp Value to write to precomp register
1204 // IN BYTE SectorCnt Value to write to sectorCnt register
1205 // IN BYTE SectorNum Value to write to sectorNum register
1206 // IN BYTE CylinderLow Value to write to CylinderLow register
1207 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1208 // IN BYTE DrvHead Value to write to Drive/Head register
1209 // IN BYTE Command Value to write to Command register
1210 // OUT BYTE *Buffer Buffer for output data
1213 // int 0 is success, non 0 is an error code
1217 AtapiPolledRead(IN ULONG CommandPort,
1218 IN ULONG ControlPort,
1222 IN BYTE CylinderLow,
1223 IN BYTE CylinderHigh,
1228 ULONG SectorCount = 0;
1230 BOOLEAN Junk = FALSE;
1235 /* Wait for BUSY to clear */
1236 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1238 Status = IDEReadStatus(CommandPort);
1239 if (!(Status & IDE_SR_BUSY))
1243 ScsiPortStallExecution(10);
1245 DPRINT("status=%02x\n", Status);
1246 DPRINT("waited %ld usecs for busy to clear\n", RetryCount * 10);
1247 if (RetryCount >= IDE_MAX_BUSY_RETRIES)
1249 DPRINT("Drive is BUSY for too long\n");
1250 return(IDE_ER_ABRT);
1254 /* Write Drive/Head to select drive */
1255 IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
1256 ScsiPortStallExecution(500);
1258 /* Disable interrupts */
1259 Control = IDEReadAltStatus(ControlPort);
1260 IDEWriteDriveControl(ControlPort, Control | IDE_DC_nIEN);
1261 ScsiPortStallExecution(500);
1264 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1265 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1267 Status = IDEReadStatus(CommandPort);
1268 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1272 ScsiPortStallExecution(10);
1274 if (RetryCount >= IDE_MAX_BUSY_RETRIES)
1280 /* Issue command to drive */
1281 if (DrvHead & IDE_DH_LBA)
1283 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1284 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1285 ((DrvHead & 0x0f) << 24) + (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
1291 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1292 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1301 /* Setup command parameters */
1302 IDEWritePrecomp(CommandPort, PreComp);
1303 IDEWriteSectorCount(CommandPort, SectorCnt);
1304 IDEWriteSectorNum(CommandPort, SectorNum);
1305 IDEWriteCylinderHigh(CommandPort, CylinderHigh);
1306 IDEWriteCylinderLow(CommandPort, CylinderLow);
1307 IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
1309 /* Issue the command */
1310 IDEWriteCommand(CommandPort, Command);
1311 ScsiPortStallExecution(50);
1313 /* wait for DRQ or error */
1314 for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
1316 Status = IDEReadStatus(CommandPort);
1317 if (!(Status & IDE_SR_BUSY))
1319 if (Status & IDE_SR_ERR)
1321 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1322 return(IDE_ER_ABRT);
1324 if (Status & IDE_SR_DRQ)
1330 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1331 return(IDE_ER_ABRT);
1334 ScsiPortStallExecution(10);
1338 if (RetryCount >= IDE_MAX_POLL_RETRIES)
1340 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1341 return(IDE_ER_ABRT);
1346 /* Read data into buffer */
1349 IDEReadBlock(CommandPort, Buffer, IDE_SECTOR_BUF_SZ);
1350 Buffer += IDE_SECTOR_BUF_SZ;
1354 UCHAR JunkBuffer[IDE_SECTOR_BUF_SZ];
1355 IDEReadBlock(CommandPort, JunkBuffer, IDE_SECTOR_BUF_SZ);
1359 /* Check for error or more sectors to read */
1360 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1362 Status = IDEReadStatus(CommandPort);
1363 if (!(Status & IDE_SR_BUSY))
1365 if (Status & IDE_SR_ERR)
1367 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1368 return(IDE_ER_ABRT);
1370 if (Status & IDE_SR_DRQ)
1372 if (SectorCount >= SectorCnt)
1374 DPRINT("Buffer size exceeded!\n");
1381 if (SectorCount > SectorCnt)
1383 DPRINT("Read %lu sectors of junk!\n",
1384 SectorCount - SectorCnt);
1386 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1395 // ------------------------------------------- Nondiscardable statics
1398 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1399 IN PSCSI_REQUEST_BLOCK Srb)
1401 UCHAR ByteCountHigh;
1407 DPRINT("AtapiSendAtapiCommand() called!\n");
1409 if (Srb->PathId != 0)
1411 Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
1412 return(SRB_STATUS_INVALID_PATH_ID);
1415 if (Srb->TargetId > 1)
1417 Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
1418 return(SRB_STATUS_INVALID_TARGET_ID);
1423 Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
1424 return(SRB_STATUS_INVALID_LUN);
1427 if (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE)
1429 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1430 return(SRB_STATUS_NO_DEVICE);
1433 DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
1436 if (Srb->Cdb[0] == SCSIOP_INQUIRY)
1437 return(AtapiInquiry(DeviceExtension,
1440 /* Set pointer to data buffer. */
1441 DeviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer;
1442 DeviceExtension->CurrentSrb = Srb;
1444 /* Wait for BUSY to clear */
1445 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1447 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1448 if (!(Status & IDE_SR_BUSY))
1452 ScsiPortStallExecution(10);
1454 DPRINT("status=%02x\n", Status);
1455 DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
1456 if (Retries >= IDE_MAX_BUSY_RETRIES)
1458 DPRINT("Drive is BUSY for too long\n");
1459 return(SRB_STATUS_BUSY);
1462 /* Select the desired drive */
1463 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
1464 IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
1466 /* Wait a little while */
1467 ScsiPortStallExecution(50);
1470 /* Wait for BUSY to clear and DRDY to assert */
1471 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1473 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1474 if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1478 ScsiPortStallExecution(10);
1480 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
1481 if (Retries >= IDE_MAX_BUSY_RETRIES)
1483 DPRINT("Drive is BUSY for too long after drive select\n");
1484 return(SRB_STATUS_BUSY);
1488 if (Srb->DataTransferLength < 0x10000)
1490 ByteCountLow = (UCHAR)(Srb->DataTransferLength & 0xFF);
1491 ByteCountHigh = (UCHAR)(Srb->DataTransferLength >> 8);
1495 ByteCountLow = 0xFF;
1496 ByteCountHigh = 0xFF;
1499 /* Set feature register */
1500 IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
1502 /* Set command packet length */
1503 IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, ByteCountHigh);
1504 IDEWriteCylinderLow(DeviceExtension->CommandPortBase, ByteCountLow);
1506 /* Issue command to drive */
1507 IDEWriteCommand(DeviceExtension->CommandPortBase, 0xA0); /* Packet command */
1509 /* Wait for DRQ to assert */
1510 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1512 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1513 if ((Status & IDE_SR_DRQ))
1517 ScsiPortStallExecution(10);
1520 CdbSize = (DeviceExtension->DeviceParams[Srb->TargetId].ConfigBits & 0x3 == 1) ? 16 : 12;
1521 DPRINT("CdbSize: %lu\n", CdbSize);
1523 /* Write command packet */
1524 IDEWriteBlock(DeviceExtension->CommandPortBase,
1528 DeviceExtension->ExpectingInterrupt = TRUE;
1530 DPRINT("AtapiSendAtapiCommand() done\n");
1532 return(SRB_STATUS_PENDING);
1537 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1538 IN PSCSI_REQUEST_BLOCK Srb)
1540 ULONG SrbStatus = SRB_STATUS_SUCCESS;
1542 DPRINT("AtapiSendIdeCommand() called!\n");
1544 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1549 switch (Srb->Cdb[0])
1551 case SCSIOP_INQUIRY:
1552 SrbStatus = AtapiInquiry(DeviceExtension,
1556 case SCSIOP_READ_CAPACITY:
1557 SrbStatus = AtapiReadCapacity(DeviceExtension,
1563 SrbStatus = AtapiReadWrite(DeviceExtension,
1567 case SCSIOP_MODE_SENSE:
1568 case SCSIOP_TEST_UNIT_READY:
1570 case SCSIOP_START_STOP_UNIT:
1571 case SCSIOP_REQUEST_SENSE:
1575 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1577 SrbStatus = SRB_STATUS_INVALID_REQUEST;
1581 DPRINT("AtapiSendIdeCommand() done!\n");
1588 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1589 PSCSI_REQUEST_BLOCK Srb)
1591 PIDE_DRIVE_IDENTIFY DeviceParams;
1592 PINQUIRYDATA InquiryData;
1595 DPRINT("SCSIOP_INQUIRY: DeviceExtension %p TargetId: %lu\n",
1596 DeviceExtension, Srb->TargetId);
1598 if (Srb->PathId != 0)
1600 Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
1601 return(SRB_STATUS_INVALID_PATH_ID);
1604 if (Srb->TargetId > 1)
1606 Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
1607 return(SRB_STATUS_INVALID_TARGET_ID);
1612 Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
1613 return(SRB_STATUS_INVALID_LUN);
1616 if (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE)
1618 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1619 return(SRB_STATUS_NO_DEVICE);
1622 InquiryData = Srb->DataBuffer;
1623 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1626 for (i = 0; i < Srb->DataTransferLength; i++)
1628 ((PUCHAR)Srb->DataBuffer)[i] = 0;
1631 /* set device class */
1632 if (DeviceExtension->DeviceAtapi[Srb->TargetId] == FALSE)
1635 InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
1639 /* get it from the ATAPI configuration word */
1640 InquiryData->DeviceType = (DeviceParams->ConfigBits >> 8) & 0x1F;
1641 DPRINT("Device class: %u\n", InquiryData->DeviceType);
1644 DPRINT("ConfigBits: 0x%x\n", DeviceParams->ConfigBits);
1645 if (DeviceParams->ConfigBits & 0x80)
1647 DPRINT("Removable media!\n");
1648 InquiryData->RemovableMedia = 1;
1651 for (i = 0; i < 20; i += 2)
1653 InquiryData->VendorId[i] =
1654 ((PUCHAR)DeviceParams->ModelNumber)[i];
1655 InquiryData->VendorId[i+1] =
1656 ((PUCHAR)DeviceParams->ModelNumber)[i+1];
1659 for (i = 0; i < 4; i++)
1661 InquiryData->ProductId[12+i] = ' ';
1664 for (i = 0; i < 4; i += 2)
1666 InquiryData->ProductRevisionLevel[i] =
1667 ((PUCHAR)DeviceParams->FirmwareRev)[i];
1668 InquiryData->ProductRevisionLevel[i+1] =
1669 ((PUCHAR)DeviceParams->FirmwareRev)[i+1];
1672 DPRINT("VendorId: '%.20s'\n", InquiryData->VendorId);
1674 Srb->SrbStatus = SRB_STATUS_SUCCESS;
1675 return(SRB_STATUS_SUCCESS);
1680 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1681 PSCSI_REQUEST_BLOCK Srb)
1683 PREAD_CAPACITY_DATA CapacityData;
1684 PIDE_DRIVE_IDENTIFY DeviceParams;
1687 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb->TargetId);
1689 if (Srb->PathId != 0)
1691 Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
1692 return(SRB_STATUS_INVALID_PATH_ID);
1695 if (Srb->TargetId > 1)
1697 Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
1698 return(SRB_STATUS_INVALID_TARGET_ID);
1703 Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
1704 return(SRB_STATUS_INVALID_LUN);
1707 if (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE)
1709 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1710 return(SRB_STATUS_NO_DEVICE);
1713 CapacityData = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
1714 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1716 /* Set sector (block) size to 512 bytes (big-endian). */
1717 CapacityData->BytesPerBlock = 0x20000;
1719 /* Calculate last sector (big-endian). */
1720 if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
1722 LastSector = (ULONG)((DeviceParams->TMSectorCountHi << 16) +
1723 DeviceParams->TMSectorCountLo) - 1;
1727 LastSector = (ULONG)(DeviceParams->LogicalCyls *
1728 DeviceParams->LogicalHeads *
1729 DeviceParams->SectorsPerTrack)-1;
1732 CapacityData->LogicalBlockAddress = (((PUCHAR)&LastSector)[0] << 24) |
1733 (((PUCHAR)&LastSector)[1] << 16) |
1734 (((PUCHAR)&LastSector)[2] << 8) |
1735 ((PUCHAR)&LastSector)[3];
1737 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
1740 CapacityData->LogicalBlockAddress);
1742 Srb->SrbStatus = SRB_STATUS_SUCCESS;
1743 return(SRB_STATUS_SUCCESS);
1748 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1749 PSCSI_REQUEST_BLOCK Srb)
1751 PIDE_DRIVE_IDENTIFY DeviceParams;
1752 ULONG StartingSector;
1762 DPRINT("AtapiReadWrite() called!\n");
1764 if (Srb->PathId != 0)
1766 Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
1767 return(SRB_STATUS_INVALID_PATH_ID);
1770 if (Srb->TargetId > 1)
1772 Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
1773 return(SRB_STATUS_INVALID_TARGET_ID);
1778 Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
1779 return(SRB_STATUS_INVALID_LUN);
1782 if (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE)
1784 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1785 return(SRB_STATUS_NO_DEVICE);
1788 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
1791 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1793 /* Get starting sector number from CDB. */
1794 StartingSector = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
1795 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
1796 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
1797 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
1799 SectorCount = (Srb->DataTransferLength + DeviceParams->BytesPerSector - 1) /
1800 DeviceParams->BytesPerSector;
1802 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
1804 Srb->DataTransferLength,
1807 if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
1809 SectorNumber = StartingSector & 0xff;
1810 CylinderLow = (StartingSector >> 8) & 0xff;
1811 CylinderHigh = (StartingSector >> 16) & 0xff;
1812 DrvHead = ((StartingSector >> 24) & 0x0f) |
1813 (Srb->TargetId ? IDE_DH_DRV1 : 0) |
1818 SectorNumber = (StartingSector % DeviceParams->SectorsPerTrack) + 1;
1819 StartingSector /= DeviceParams->SectorsPerTrack;
1820 DrvHead = (StartingSector % DeviceParams->LogicalHeads) |
1821 (Srb->TargetId ? IDE_DH_DRV1 : 0);
1822 StartingSector /= DeviceParams->LogicalHeads;
1823 CylinderLow = StartingSector & 0xff;
1824 CylinderHigh = StartingSector >> 8;
1828 if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
1830 Command = IDE_CMD_READ;
1834 Command = IDE_CMD_WRITE;
1837 if (DrvHead & IDE_DH_LBA)
1839 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1840 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
1841 DeviceExtension->CommandPortBase,
1842 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1843 ((DrvHead & 0x0f) << 24) +
1844 (CylinderHigh << 16) + (CylinderLow << 8) + SectorNumber,
1850 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1851 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
1852 DeviceExtension->CommandPortBase,
1853 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1862 /* Set pointer to data buffer. */
1863 DeviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer;
1865 DeviceExtension->CurrentSrb = Srb;
1866 DeviceExtension->ExpectingInterrupt = TRUE;
1870 /* wait for BUSY to clear */
1871 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1873 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1874 if (!(Status & IDE_SR_BUSY))
1878 ScsiPortStallExecution(10);
1880 DPRINT("status=%02x\n", Status);
1881 DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
1882 if (Retries >= IDE_MAX_BUSY_RETRIES)
1884 DPRINT ("Drive is BUSY for too long\n");
1885 return(SRB_STATUS_BUSY);
1887 if (++ControllerExtension->Retries > IDE_MAX_CMD_RETRIES)
1889 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1890 Irp = ControllerExtension->CurrentIrp;
1891 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1892 Irp->IoStatus.Information = 0;
1898 DPRINT ("Beginning drive reset sequence\n");
1899 IDEBeginControllerReset(ControllerExtension);
1906 /* Select the desired drive */
1907 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
1908 IDE_DH_FIXED | DrvHead);
1910 ScsiPortStallExecution(10);
1912 /* wait for BUSY to clear and DRDY to assert */
1913 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1915 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1916 if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1920 ScsiPortStallExecution(10);
1922 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
1923 if (Retries >= IDE_MAX_BUSY_RETRIES)
1925 DPRINT("Drive is BUSY for too long after drive select\n");
1926 return(SRB_STATUS_BUSY);
1928 if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1930 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1931 Irp = ControllerExtension->CurrentIrp;
1932 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1933 Irp->IoStatus.Information = 0;
1939 DPRINT("Beginning drive reset sequence\n");
1940 IDEBeginControllerReset(ControllerExtension);
1948 /* Indicate expecting an interrupt. */
1949 DeviceExtension->ExpectingInterrupt = TRUE;
1951 /* Setup command parameters */
1952 IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
1953 IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount);
1954 IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber);
1955 IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh);
1956 IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow);
1957 IDEWriteDriveHead(DeviceExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
1959 /* Issue command to drive */
1960 IDEWriteCommand(DeviceExtension->CommandPortBase, Command);
1962 /* Write data block */
1963 if (Command == IDE_CMD_WRITE)
1965 PUCHAR TargetAddress;
1968 /* Wait for controller ready */
1969 for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
1971 BYTE Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1972 if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
1976 KeStallExecutionProcessor(10);
1978 if (Retries >= IDE_MAX_BUSY_RETRIES)
1980 DPRINT("Drive is BUSY for too long after sending write command\n");
1981 return(SRB_STATUS_BUSY);
1983 if (DeviceExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1985 Irp = ControllerExtension->CurrentIrp;
1986 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1987 Irp->IoStatus.Information = 0;
1993 IDEBeginControllerReset(ControllerExtension);
2000 /* Update SRB data */
2001 SectorSize = DeviceExtension->DeviceParams[Srb->TargetId].BytesPerSector;
2002 TargetAddress = Srb->DataBuffer;
2003 Srb->DataBuffer += SectorSize;
2004 Srb->DataTransferLength -= SectorSize;
2006 /* Write data block */
2007 IDEWriteBlock(DeviceExtension->CommandPortBase,
2013 DPRINT("AtapiReadWrite() done!\n");
2015 /* Wait for interrupt. */
2016 return(SRB_STATUS_PENDING);
2021 AtapiErrorToScsi(PVOID DeviceExtension,
2022 PSCSI_REQUEST_BLOCK Srb)
2024 PATAPI_MINIPORT_EXTENSION DevExt;
2025 ULONG CommandPortBase;
2026 ULONG ControlPortBase;
2031 DPRINT("AtapiErrorToScsi() called\n");
2033 DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
2035 CommandPortBase = DevExt->CommandPortBase;
2036 ControlPortBase = DevExt->ControlPortBase;
2038 ErrorReg = IDEReadError(CommandPortBase);
2040 if (DevExt->DeviceAtapi[Srb->TargetId])
2042 switch (ErrorReg >> 4)
2044 case SCSI_SENSE_NO_SENSE:
2045 DPRINT("ATAPI error: SCSI_SENSE_NO_SENSE\n");
2046 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2047 SrbStatus = SRB_STATUS_ERROR;
2050 case SCSI_SENSE_RECOVERED_ERROR:
2051 DPRINT("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
2053 SrbStatus = SRB_STATUS_SUCCESS;
2056 case SCSI_SENSE_NOT_READY:
2057 DPRINT("ATAPI error: SCSI_SENSE_NOT_READY\n");
2058 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2059 SrbStatus = SRB_STATUS_ERROR;
2062 case SCSI_SENSE_MEDIUM_ERROR:
2063 DPRINT("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
2064 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2065 SrbStatus = SRB_STATUS_ERROR;
2068 case SCSI_SENSE_HARDWARE_ERROR:
2069 DPRINT("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
2070 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2071 SrbStatus = SRB_STATUS_ERROR;
2074 case SCSI_SENSE_ILLEGAL_REQUEST:
2075 DPRINT("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
2076 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2077 SrbStatus = SRB_STATUS_ERROR;
2080 case SCSI_SENSE_UNIT_ATTENTION:
2081 DPRINT("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
2082 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2083 SrbStatus = SRB_STATUS_ERROR;
2086 case SCSI_SENSE_DATA_PROTECT:
2087 DPRINT("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
2088 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2089 SrbStatus = SRB_STATUS_ERROR;
2092 case SCSI_SENSE_BLANK_CHECK:
2093 DPRINT("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
2094 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2095 SrbStatus = SRB_STATUS_ERROR;
2098 case SCSI_SENSE_ABORTED_COMMAND:
2099 DPRINT("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
2100 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2101 SrbStatus = SRB_STATUS_ERROR;
2105 DPRINT("ATAPI error: Invalid sense key\n");
2107 SrbStatus = SRB_STATUS_ERROR;
2113 DPRINT1("IDE error: %02x\n", ErrorReg);
2116 SrbStatus = SRB_STATUS_ERROR;
2119 UCHAR SectorCount, SectorNum, CylinderLow, CylinderHigh;
2122 CylinderLow = IDEReadCylinderLow(CommandPortBase);
2123 CylinderHigh = IDEReadCylinderHigh(CommandPortBase);
2124 DriveHead = IDEReadDriveHead(CommandPortBase);
2125 SectorCount = IDEReadSectorCount(CommandPortBase);
2126 SectorNum = IDEReadSectorNum(CommandPortBase);
2128 DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
2139 Srb->ScsiStatus = ScsiStatus;
2141 DPRINT("AtapiErrorToScsi() done\n");