005f6b3d1dd306cdafa273ba7d98704c8de1be01
[reactos.git] / reactos / drivers / storage / atapi / atapi.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2001, 2002, 2003, 2004, 2005 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS ATAPI miniport driver
23 * FILE: drivers/storage/atapi/atapi.c
24 * PURPOSE: ATAPI miniport driver
25 * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de)
26 * Hartmut Birr
27 * REVISIONS:
28 * 09-09-2001 Created
29 */
30
31 /*
32 * Note:
33 * This driver is derived from Rex Jolliff's ide driver. Lots of his
34 * routines are still in here although they belong into the higher level
35 * drivers. They will be moved away as soon as possible.
36 */
37
38 /*
39 * TODO:
40 * - implement sending of atapi commands
41 * - handle removable atapi non-cdrom drives
42 */
43
44 #define ENABLE_PCI
45 #define ENABLE_NATIVE_PCI
46 #define ENABLE_ISA
47 #define ENABLE_DMA
48
49 // -------------------------------------------------------------------------
50
51 #include <ddk/ntddk.h>
52 #include <ddk/srb.h>
53 #include <ddk/scsi.h>
54 #include <ddk/ntddscsi.h>
55 #include <ddk/ntdddisk.h>
56 #include <ddk/ntddstor.h>
57
58 #include "atapi.h"
59
60 #define NDEBUG
61 #include <debug.h>
62
63 #define VERSION "0.0.1"
64
65
66 // ------------------------------------------------------- File Static Data
67
68 #ifdef ENABLE_DMA
69 typedef struct _PRD
70 {
71 ULONG PhysAddress;
72 ULONG Length;
73 } PRD, *PPRD;
74 #endif
75
76 // ATAPI_MINIPORT_EXTENSION
77 //
78 // DESCRIPTION:
79 // Extension to be placed in each port device object
80 //
81 // ACCESS:
82 // Allocated from NON-PAGED POOL
83 // Available at any IRQL
84 //
85
86 typedef struct _ATAPI_MINIPORT_EXTENSION
87 {
88 IDE_DRIVE_IDENTIFY DeviceParams[2];
89 ULONG DeviceFlags[2];
90 ULONG TransferSize[2];
91
92 ULONG CommandPortBase;
93 ULONG ControlPortBase;
94 ULONG BusMasterRegisterBase;
95
96 PSCSI_REQUEST_BLOCK CurrentSrb;
97
98 PUCHAR DataBuffer;
99 ULONG DataTransferLength;
100
101 BOOLEAN FASTCALL (*Handler)(IN struct _ATAPI_MINIPORT_EXTENSION* DevExt);
102 #ifdef ENABLE_DMA
103 BOOL UseDma;
104 ULONG PRDCount;
105 ULONG PRDMaxCount;
106 PPRD PRDTable;
107 SCSI_PHYSICAL_ADDRESS PRDTablePhysicalAddress;
108 #endif
109 } ATAPI_MINIPORT_EXTENSION, *PATAPI_MINIPORT_EXTENSION;
110
111 /* DeviceFlags */
112 #define DEVICE_PRESENT 0x00000001
113 #define DEVICE_ATAPI 0x00000002
114 #define DEVICE_MULTI_SECTOR_CMD 0x00000004
115 #define DEVICE_DWORD_IO 0x00000008
116 #define DEVICE_48BIT_ADDRESS 0x00000010
117 #define DEVICE_MEDIA_STATUS 0x00000020
118 #define DEVICE_DMA_CMD 0x00000040
119 #define DEVICE_NO_FLUSH 0x00000080
120
121
122 typedef struct _UNIT_EXTENSION
123 {
124 ULONG Dummy;
125 } UNIT_EXTENSION, *PUNIT_EXTENSION;
126
127 PCI_SLOT_NUMBER LastSlotNumber;
128
129 #ifdef ENABLE_NATIVE_PCI
130 typedef struct _PCI_NATIVE_CONTROLLER
131 {
132 USHORT VendorID;
133 USHORT DeviceID;
134 }
135 PCI_NATIVE_CONTROLLER, *PPCI_NATIVE_CONTROLLER;
136
137 PCI_NATIVE_CONTROLLER const PciNativeController[] =
138 {
139 {
140 0x105A, // Promise
141 0x4D68, // PDC20268, Ultra100TX2
142 },
143 {
144 0x105A, // Promise
145 0x4D30, // PDC20267, Ultra100
146 }
147 };
148 #endif
149
150
151 // ----------------------------------------------- Discardable Declarations
152
153 #ifdef ALLOC_PRAGMA
154
155 // make the initialization routines discardable, so that they
156 // don't waste space
157
158 #pragma alloc_text(init, DriverEntry)
159
160 // make the PASSIVE_LEVEL routines pageable, so that they don't
161 // waste nonpaged memory
162
163 #endif /* ALLOC_PRAGMA */
164
165 // ---------------------------------------------------- Forward Declarations
166
167 #ifdef ENABLE_DMA
168 static BOOLEAN
169 AtapiInitDma(PATAPI_MINIPORT_EXTENSION DevExt,
170 PSCSI_REQUEST_BLOCK Srb,
171 BYTE cmd);
172 #endif
173
174 static ULONG STDCALL
175 AtapiFindCompatiblePciController(PVOID DeviceExtension,
176 PVOID HwContext,
177 PVOID BusInformation,
178 PCHAR ArgumentString,
179 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
180 PBOOLEAN Again);
181
182 static ULONG STDCALL
183 AtapiFindIsaBusController(PVOID DeviceExtension,
184 PVOID HwContext,
185 PVOID BusInformation,
186 PCHAR ArgumentString,
187 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
188 PBOOLEAN Again);
189
190 static ULONG STDCALL
191 AtapiFindNativePciController(PVOID DeviceExtension,
192 PVOID HwContext,
193 PVOID BusInformation,
194 PCHAR ArgumentString,
195 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
196 PBOOLEAN Again);
197
198 static BOOLEAN STDCALL
199 AtapiInitialize(IN PVOID DeviceExtension);
200
201 static BOOLEAN STDCALL
202 AtapiResetBus(IN PVOID DeviceExtension,
203 IN ULONG PathId);
204
205 static BOOLEAN STDCALL
206 AtapiStartIo(IN PVOID DeviceExtension,
207 IN PSCSI_REQUEST_BLOCK Srb);
208
209 static VOID
210 AtapiExecuteCommand(PATAPI_MINIPORT_EXTENSION DevExt,
211 BYTE command,
212 BOOLEAN FASTCALL (*Handler)(PATAPI_MINIPORT_EXTENSION));
213
214 static BOOLEAN STDCALL
215 AtapiInterrupt(IN PVOID DeviceExtension);
216
217 static BOOLEAN FASTCALL
218 AtapiNoDataInterrupt(PATAPI_MINIPORT_EXTENSION DevExt);
219
220 static BOOLEAN FASTCALL
221 AtapiPacketInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt);
222
223 static BOOLEAN FASTCALL
224 AtapiReadInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt);
225
226 #ifdef ENABLE_DMA
227 static BOOLEAN FASTCALL
228 AtapiDmaPacketInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt);
229
230 static BOOLEAN FASTCALL
231 AtapiDmaInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt);
232 #endif
233
234 static BOOLEAN FASTCALL
235 AtapiWriteInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt);
236
237 static BOOLEAN
238 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
239 PPORT_CONFIGURATION_INFORMATION ConfigInfo);
240
241 static BOOLEAN
242 AtapiIdentifyDevice(IN ULONG CommandPort,
243 IN ULONG ControlPort,
244 IN ULONG DriveNum,
245 IN BOOLEAN Atapi,
246 OUT PIDE_DRIVE_IDENTIFY DrvParms);
247
248 static BOOLEAN
249 AtapiPolledRead(IN ULONG CommandPort,
250 IN ULONG ControlPort,
251 IN UCHAR PreComp,
252 IN UCHAR SectorCnt,
253 IN UCHAR SectorNum,
254 IN UCHAR CylinderLow,
255 IN UCHAR CylinderHigh,
256 IN UCHAR DrvHead,
257 IN UCHAR Command,
258 OUT PUCHAR Buffer);
259
260 static ULONG
261 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
262 IN PSCSI_REQUEST_BLOCK Srb);
263
264 static ULONG
265 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
266 IN PSCSI_REQUEST_BLOCK Srb);
267
268 static ULONG
269 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
270 IN PSCSI_REQUEST_BLOCK Srb);
271
272 static ULONG
273 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
274 IN PSCSI_REQUEST_BLOCK Srb);
275
276 static ULONG
277 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
278 IN PSCSI_REQUEST_BLOCK Srb);
279
280 static ULONG
281 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension,
282 PSCSI_REQUEST_BLOCK Srb);
283
284 static ULONG
285 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension,
286 PSCSI_REQUEST_BLOCK Srb);
287
288 static UCHAR
289 AtapiErrorToScsi(PVOID DeviceExtension,
290 PSCSI_REQUEST_BLOCK Srb);
291
292 static VOID
293 AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb);
294
295 // ---------------------------------------------------------------- Inlines
296
297 void
298 IDESwapBytePairs(UCHAR *Buf,
299 int Cnt)
300 {
301 UCHAR t;
302 int i;
303
304 for (i = 0; i < Cnt; i += 2)
305 {
306 t = Buf[i];
307 Buf[i] = Buf[i+1];
308 Buf[i+1] = t;
309 }
310 }
311
312
313 // ------------------------------------------------------- Public Interface
314
315 // DriverEntry
316 //
317 // DESCRIPTION:
318 // This function initializes the driver, locates and claims
319 // hardware resources, and creates various NT objects needed
320 // to process I/O requests.
321 //
322 // RUN LEVEL:
323 // PASSIVE_LEVEL
324 //
325 // ARGUMENTS:
326 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
327 // for this driver
328 // IN PUNICODE_STRING RegistryPath Name of registry driver service
329 // key
330 //
331 // RETURNS:
332 // NTSTATUS
333
334 STDCALL NTSTATUS
335 DriverEntry(IN PDRIVER_OBJECT DriverObject,
336 IN PUNICODE_STRING RegistryPath)
337 {
338 HW_INITIALIZATION_DATA InitData;
339 NTSTATUS Status;
340
341 DPRINT("ATAPI Driver %s\n", VERSION);
342 DPRINT("RegistryPath: '%wZ'\n", RegistryPath);
343
344 /* Initialize data structure */
345 RtlZeroMemory(&InitData,
346 sizeof(HW_INITIALIZATION_DATA));
347 InitData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
348 InitData.HwInitialize = AtapiInitialize;
349 InitData.HwResetBus = AtapiResetBus;
350 InitData.HwStartIo = AtapiStartIo;
351 InitData.HwInterrupt = AtapiInterrupt;
352
353 InitData.DeviceExtensionSize = sizeof(ATAPI_MINIPORT_EXTENSION);
354 InitData.SpecificLuExtensionSize = sizeof(UNIT_EXTENSION);
355
356 InitData.MapBuffers = TRUE;
357
358 /* Search the PCI bus for compatibility mode ide controllers */
359 #ifdef ENABLE_PCI
360 InitData.NeedPhysicalAddresses = TRUE;
361
362 InitData.HwFindAdapter = AtapiFindCompatiblePciController;
363 InitData.NumberOfAccessRanges = 3;
364 InitData.AdapterInterfaceType = PCIBus;
365
366 InitData.VendorId = NULL;
367 InitData.VendorIdLength = 0;
368 InitData.DeviceId = NULL;
369 InitData.DeviceIdLength = 0;
370
371 Status = ScsiPortInitialize(DriverObject,
372 RegistryPath,
373 &InitData,
374 NULL);
375 // if (newStatus < statusToReturn)
376 // statusToReturn = newStatus;
377 #endif
378
379 /* Search the PCI bus for all ide controllers */
380 #ifdef ENABLE_NATIVE_PCI
381 InitData.NeedPhysicalAddresses = TRUE;
382
383 InitData.HwFindAdapter = AtapiFindNativePciController;
384 InitData.NumberOfAccessRanges = 3;
385 InitData.AdapterInterfaceType = PCIBus;
386
387 InitData.VendorId = 0;
388 InitData.VendorIdLength = 0;
389 InitData.DeviceId = 0;
390 InitData.DeviceIdLength = 0;
391
392 LastSlotNumber.u.AsULONG = 0xFFFFFFFF;
393
394 Status = ScsiPortInitialize(DriverObject,
395 RegistryPath,
396 &InitData,
397 NULL);
398 // if (newStatus < statusToReturn)
399 // statusToReturn = newStatus;
400 #endif
401
402 /* Search the ISA bus for ide controllers */
403 #ifdef ENABLE_ISA
404 InitData.HwFindAdapter = AtapiFindIsaBusController;
405 InitData.NumberOfAccessRanges = 2;
406 InitData.AdapterInterfaceType = Isa;
407
408 InitData.VendorId = NULL;
409 InitData.VendorIdLength = 0;
410 InitData.DeviceId = NULL;
411 InitData.DeviceIdLength = 0;
412
413 Status = ScsiPortInitialize(DriverObject,
414 RegistryPath,
415 &InitData,
416 NULL);
417 // if (newStatus < statusToReturn)
418 // statusToReturn = newStatus;
419 #endif
420
421 DPRINT("Returning from DriverEntry\n");
422
423 return(Status);
424 }
425
426
427 BOOLEAN
428 AtapiClaimHwResources(PATAPI_MINIPORT_EXTENSION DevExt,
429 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
430 INTERFACE_TYPE InterfaceType,
431 ULONG CommandPortBase,
432 ULONG ControlPortBase,
433 ULONG BusMasterPortBase,
434 ULONG InterruptVector)
435 {
436 SCSI_PHYSICAL_ADDRESS IoAddress;
437 PVOID IoBase;
438 #ifdef ENABLE_DMA
439 ULONG Length;
440 #endif
441 IoAddress = ScsiPortConvertUlongToPhysicalAddress(CommandPortBase);
442 IoBase = ScsiPortGetDeviceBase((PVOID)DevExt,
443 InterfaceType,
444 ConfigInfo->SystemIoBusNumber,
445 IoAddress,
446 8,
447 TRUE);
448 if (IoBase == NULL)
449 {
450 return FALSE;
451 }
452 DevExt->Handler = NULL;
453 DevExt->CommandPortBase = (ULONG)IoBase;
454 (*ConfigInfo->AccessRanges)[0].RangeStart = IoAddress;
455 (*ConfigInfo->AccessRanges)[0].RangeLength = 8;
456 (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
457
458 if (ControlPortBase)
459 {
460 IoAddress = ScsiPortConvertUlongToPhysicalAddress(ControlPortBase + 2);
461 IoBase = ScsiPortGetDeviceBase((PVOID)DevExt,
462 InterfaceType,
463 ConfigInfo->SystemIoBusNumber,
464 IoAddress,
465 1,
466 TRUE);
467 if (IoBase == NULL)
468 {
469 ScsiPortFreeDeviceBase((PVOID)DevExt,
470 (PVOID)DevExt->CommandPortBase);
471 return FALSE;
472 }
473 DevExt->ControlPortBase = (ULONG)IoBase;
474 (*ConfigInfo->AccessRanges)[1].RangeStart = IoAddress;
475 (*ConfigInfo->AccessRanges)[1].RangeLength = 1;
476 (*ConfigInfo->AccessRanges)[1].RangeInMemory = FALSE;
477 }
478 if (BusMasterPortBase)
479 {
480 IoAddress = ScsiPortConvertUlongToPhysicalAddress(BusMasterPortBase);
481 IoBase = ScsiPortGetDeviceBase((PVOID)DevExt,
482 InterfaceType,
483 ConfigInfo->SystemIoBusNumber,
484 IoAddress,
485 8,
486 TRUE);
487 if (IoBase == NULL)
488 {
489 ScsiPortFreeDeviceBase((PVOID)DevExt, (PVOID)DevExt->CommandPortBase);
490 ScsiPortFreeDeviceBase((PVOID)DevExt, (PVOID)DevExt->ControlPortBase);
491 return FALSE;
492 }
493 DevExt->BusMasterRegisterBase = (ULONG)IoBase;
494 (*ConfigInfo->AccessRanges)[2].RangeStart = IoAddress;
495 (*ConfigInfo->AccessRanges)[2].RangeLength = 8;
496 (*ConfigInfo->AccessRanges)[2].RangeInMemory = FALSE;
497 #ifdef ENABLE_DMA
498 // ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
499 // ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
500 ConfigInfo->DmaWidth = Width32Bits;
501 // ConfigInfo->DmaSpeed = Compatible;
502 ConfigInfo->ScatterGather = TRUE;
503 ConfigInfo->Master = TRUE;
504 ConfigInfo->NumberOfPhysicalBreaks = 0x10000 / PAGE_SIZE + 1;
505 ConfigInfo->Dma32BitAddresses = TRUE;
506 ConfigInfo->NeedPhysicalAddresses = TRUE;
507 ConfigInfo->MapBuffers = TRUE;
508
509 DevExt->PRDMaxCount = PAGE_SIZE / sizeof(PRD);
510 DevExt->PRDTable = ScsiPortGetUncachedExtension(DevExt, ConfigInfo, sizeof(PRD) * DevExt->PRDMaxCount);
511 if (DevExt->PRDTable != NULL)
512 {
513 DevExt->PRDTablePhysicalAddress = ScsiPortGetPhysicalAddress(DevExt, NULL, DevExt->PRDTable, &Length);
514 }
515 if (DevExt->PRDTable == NULL ||
516 DevExt->PRDTablePhysicalAddress.QuadPart == 0LL ||
517 Length < sizeof(PRD) * DevExt->PRDMaxCount)
518 {
519 ScsiPortFreeDeviceBase((PVOID)DevExt, (PVOID)DevExt->CommandPortBase);
520 ScsiPortFreeDeviceBase((PVOID)DevExt, (PVOID)DevExt->ControlPortBase);
521 ScsiPortFreeDeviceBase((PVOID)DevExt, (PVOID)DevExt->BusMasterRegisterBase);
522 return FALSE;
523 }
524 #endif
525 }
526 ConfigInfo->BusInterruptLevel = InterruptVector;
527 ConfigInfo->BusInterruptVector = InterruptVector;
528 ConfigInfo->InterruptMode = (InterfaceType == Isa) ? Latched : LevelSensitive;
529
530 if ((CommandPortBase == 0x1F0 || ControlPortBase == 0x3F4) && !ConfigInfo->AtdiskPrimaryClaimed)
531 {
532 ConfigInfo->AtdiskPrimaryClaimed = TRUE;
533 }
534 if ((CommandPortBase == 0x170 || ControlPortBase == 0x374) && !ConfigInfo->AtdiskSecondaryClaimed)
535 {
536 ConfigInfo->AtdiskSecondaryClaimed = TRUE;
537 }
538 return TRUE;
539 }
540
541
542 #ifdef ENABLE_PCI
543 static ULONG STDCALL
544 AtapiFindCompatiblePciController(PVOID DeviceExtension,
545 PVOID HwContext,
546 PVOID BusInformation,
547 PCHAR ArgumentString,
548 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
549 PBOOLEAN Again)
550 {
551 PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
552 PCI_SLOT_NUMBER SlotNumber;
553 PCI_COMMON_CONFIG PciConfig;
554 ULONG DataSize;
555 ULONG StartDeviceNumber;
556 ULONG DeviceNumber;
557 ULONG StartFunctionNumber;
558 ULONG FunctionNumber;
559 BOOLEAN ChannelFound;
560 BOOLEAN DeviceFound;
561 ULONG BusMasterBasePort = 0;
562
563 DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
564 ConfigInfo->SystemIoBusNumber,
565 ConfigInfo->SlotNumber);
566
567 *Again = FALSE;
568
569 /* both channels were claimed: exit */
570 if (ConfigInfo->AtdiskPrimaryClaimed == TRUE &&
571 ConfigInfo->AtdiskSecondaryClaimed == TRUE)
572 return(SP_RETURN_NOT_FOUND);
573
574 SlotNumber.u.AsULONG = ConfigInfo->SlotNumber;
575 StartDeviceNumber = SlotNumber.u.bits.DeviceNumber;
576 StartFunctionNumber = SlotNumber.u.bits.FunctionNumber;
577 for (DeviceNumber = StartDeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
578 {
579 SlotNumber.u.bits.DeviceNumber = DeviceNumber;
580 for (FunctionNumber = StartFunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
581 {
582 SlotNumber.u.bits.FunctionNumber = FunctionNumber;
583 ChannelFound = FALSE;
584 DeviceFound = FALSE;
585
586 DataSize = ScsiPortGetBusData(DeviceExtension,
587 PCIConfiguration,
588 ConfigInfo->SystemIoBusNumber,
589 SlotNumber.u.AsULONG,
590 &PciConfig,
591 PCI_COMMON_HDR_LENGTH);
592 if (DataSize != PCI_COMMON_HDR_LENGTH)
593 {
594 if (FunctionNumber == 0)
595 {
596 break;
597 }
598 else
599 {
600 continue;
601 }
602 }
603
604 DPRINT("%x %x\n", PciConfig.BaseClass, PciConfig.SubClass);
605 if (PciConfig.BaseClass == 0x01 &&
606 PciConfig.SubClass == 0x01) // &&
607 // (PciConfig.ProgIf & 0x05) == 0)
608 {
609 /* both channels are in compatibility mode */
610 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
611 ConfigInfo->SystemIoBusNumber,
612 SlotNumber.u.bits.DeviceNumber,
613 SlotNumber.u.bits.FunctionNumber,
614 PciConfig.VendorID,
615 PciConfig.DeviceID);
616 DPRINT("ProgIF 0x%02hx\n", PciConfig.ProgIf);
617
618 DPRINT("Found IDE controller in compatibility mode!\n");
619
620 ConfigInfo->NumberOfBuses = 1;
621 ConfigInfo->MaximumNumberOfTargets = 2;
622 ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
623
624 if (PciConfig.ProgIf & 0x80)
625 {
626 DPRINT("Found IDE Bus Master controller!\n");
627 if (PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_SPACE)
628 {
629 BusMasterBasePort = PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_ADDRESS_MASK;
630 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort);
631 }
632 }
633 if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
634 {
635 /* Both channels unclaimed: Claim primary channel */
636 DPRINT("Primary channel!\n");
637 ChannelFound = AtapiClaimHwResources(DevExt,
638 ConfigInfo,
639 PCIBus,
640 0x1F0,
641 0x3F4,
642 BusMasterBasePort,
643 14);
644 *Again = TRUE;
645 }
646 else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
647 {
648 /* Primary channel already claimed: claim secondary channel */
649 DPRINT("Secondary channel!\n");
650
651 ChannelFound = AtapiClaimHwResources(DevExt,
652 ConfigInfo,
653 PCIBus,
654 0x170,
655 0x374,
656 BusMasterBasePort ? BusMasterBasePort + 8 : 0,
657 15);
658 *Again = FALSE;
659 }
660 /* Find attached devices */
661 if (ChannelFound)
662 {
663 DeviceFound = AtapiFindDevices(DevExt, ConfigInfo);
664 ConfigInfo->SlotNumber = SlotNumber.u.AsULONG;
665 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
666 return(SP_RETURN_FOUND);
667 }
668 }
669 if (FunctionNumber == 0 && !(PciConfig.HeaderType & PCI_MULTIFUNCTION))
670 {
671 break;
672 }
673 }
674 StartFunctionNumber = 0;
675 }
676 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
677
678 return(SP_RETURN_NOT_FOUND);
679 }
680 #endif
681
682
683 #ifdef ENABLE_ISA
684 static ULONG STDCALL
685 AtapiFindIsaBusController(PVOID DeviceExtension,
686 PVOID HwContext,
687 PVOID BusInformation,
688 PCHAR ArgumentString,
689 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
690 PBOOLEAN Again)
691 {
692 PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
693 BOOLEAN ChannelFound = FALSE;
694 BOOLEAN DeviceFound = FALSE;
695
696 DPRINT("AtapiFindIsaBusController() called!\n");
697
698 *Again = FALSE;
699
700 ConfigInfo->NumberOfBuses = 1;
701 ConfigInfo->MaximumNumberOfTargets = 2;
702 ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
703
704 if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
705 {
706 /* Both channels unclaimed: Claim primary channel */
707 DPRINT("Primary channel!\n");
708
709 ChannelFound = AtapiClaimHwResources(DevExt,
710 ConfigInfo,
711 Isa,
712 0x1F0,
713 0x3F4,
714 0,
715 14);
716 *Again = TRUE;
717 }
718 else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
719 {
720 /* Primary channel already claimed: claim secondary channel */
721 DPRINT("Secondary channel!\n");
722
723 ChannelFound = AtapiClaimHwResources(DevExt,
724 ConfigInfo,
725 Isa,
726 0x170,
727 0x374,
728 0,
729 15);
730 *Again = FALSE;
731 }
732 else
733 {
734 DPRINT("AtapiFindIsaBusController() both channels claimed. Returns: SP_RETURN_NOT_FOUND\n");
735 *Again = FALSE;
736 return(SP_RETURN_NOT_FOUND);
737 }
738
739 /* Find attached devices */
740 if (ChannelFound)
741 {
742 DeviceFound = AtapiFindDevices(DevExt,
743 ConfigInfo);
744 DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
745 return(SP_RETURN_FOUND);
746 }
747 *Again = FALSE;
748 return SP_RETURN_NOT_FOUND;
749 }
750 #endif
751
752
753 #ifdef ENABLE_NATIVE_PCI
754 static ULONG STDCALL
755 AtapiFindNativePciController(PVOID DeviceExtension,
756 PVOID HwContext,
757 PVOID BusInformation,
758 PCHAR ArgumentString,
759 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
760 PBOOLEAN Again)
761 {
762 PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
763 PCI_COMMON_CONFIG PciConfig;
764 PCI_SLOT_NUMBER SlotNumber;
765 ULONG DataSize;
766 ULONG DeviceNumber;
767 ULONG StartDeviceNumber;
768 ULONG FunctionNumber;
769 ULONG StartFunctionNumber;
770 ULONG BusMasterBasePort;
771 ULONG Count;
772 BOOLEAN ChannelFound;
773
774 DPRINT("AtapiFindNativePciController() called!\n");
775
776 SlotNumber.u.AsULONG = ConfigInfo->SlotNumber;
777 StartDeviceNumber = SlotNumber.u.bits.DeviceNumber;
778 StartFunctionNumber = SlotNumber.u.bits.FunctionNumber;
779 for (DeviceNumber = StartDeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
780 {
781 SlotNumber.u.bits.DeviceNumber = DeviceNumber;
782 for (FunctionNumber = StartFunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
783 {
784 SlotNumber.u.bits.FunctionNumber = FunctionNumber;
785 DataSize = ScsiPortGetBusData(DeviceExtension,
786 PCIConfiguration,
787 ConfigInfo->SystemIoBusNumber,
788 SlotNumber.u.AsULONG,
789 &PciConfig,
790 PCI_COMMON_HDR_LENGTH);
791 if (DataSize != PCI_COMMON_HDR_LENGTH)
792 {
793 break;
794 }
795 for (Count = 0; Count < sizeof(PciNativeController)/sizeof(PCI_NATIVE_CONTROLLER); Count++)
796 {
797 if (PciConfig.VendorID == PciNativeController[Count].VendorID &&
798 PciConfig.DeviceID == PciNativeController[Count].DeviceID)
799 {
800 break;
801 }
802 }
803 if (Count < sizeof(PciNativeController)/sizeof(PCI_NATIVE_CONTROLLER))
804 {
805 /* We have found a known native pci ide controller */
806 if ((PciConfig.ProgIf & 0x80) && (PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_SPACE))
807 {
808 DPRINT("Found IDE Bus Master controller!\n");
809 BusMasterBasePort = PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_ADDRESS_MASK;
810 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort);
811 }
812 else
813 {
814 BusMasterBasePort = 0;
815 }
816
817 DPRINT("VendorID: %04x, DeviceID: %04x\n", PciConfig.VendorID, PciConfig.DeviceID);
818 ConfigInfo->NumberOfBuses = 1;
819 ConfigInfo->MaximumNumberOfTargets = 2;
820 ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
821
822 /* FIXME:
823 We must not store and use the last tested slot number. If there is a recall
824 to the some device and we will claim the primary channel again than the call
825 to ScsiPortGetDeviceBase in AtapiClaimHwResource will fail and we can try to
826 claim the secondary channel.
827 */
828 ChannelFound = FALSE;
829 if (LastSlotNumber.u.AsULONG != SlotNumber.u.AsULONG)
830 {
831 /* try to claim primary channel */
832 if ((PciConfig.u.type0.BaseAddresses[0] & PCI_ADDRESS_IO_SPACE) &&
833 (PciConfig.u.type0.BaseAddresses[1] & PCI_ADDRESS_IO_SPACE))
834 {
835 /* primary channel is enabled */
836 ChannelFound = AtapiClaimHwResources(DevExt,
837 ConfigInfo,
838 PCIBus,
839 PciConfig.u.type0.BaseAddresses[0] & PCI_ADDRESS_IO_ADDRESS_MASK,
840 PciConfig.u.type0.BaseAddresses[1] & PCI_ADDRESS_IO_ADDRESS_MASK,
841 BusMasterBasePort,
842 PciConfig.u.type0.InterruptLine);
843 if (ChannelFound)
844 {
845 AtapiFindDevices(DevExt, ConfigInfo);
846 *Again = TRUE;
847 ConfigInfo->SlotNumber = LastSlotNumber.u.AsULONG = SlotNumber.u.AsULONG;
848 return SP_RETURN_FOUND;
849 }
850 }
851 }
852 if (!ChannelFound)
853 {
854 /* try to claim secondary channel */
855 if ((PciConfig.u.type0.BaseAddresses[2] & PCI_ADDRESS_IO_SPACE) &&
856 (PciConfig.u.type0.BaseAddresses[3] & PCI_ADDRESS_IO_SPACE))
857 {
858 /* secondary channel is enabled */
859 ChannelFound = AtapiClaimHwResources(DevExt,
860 ConfigInfo,
861 PCIBus,
862 PciConfig.u.type0.BaseAddresses[2] & PCI_ADDRESS_IO_ADDRESS_MASK,
863 PciConfig.u.type0.BaseAddresses[3] & PCI_ADDRESS_IO_ADDRESS_MASK,
864 BusMasterBasePort ? BusMasterBasePort + 8 : 0,
865 PciConfig.u.type0.InterruptLine);
866 if (ChannelFound)
867 {
868 AtapiFindDevices(DevExt, ConfigInfo);
869 *Again = FALSE;
870 LastSlotNumber.u.AsULONG = 0xFFFFFFFF;
871 return SP_RETURN_FOUND;
872 }
873 }
874 }
875 }
876 }
877 StartFunctionNumber = 0;
878 }
879 *Again = FALSE;
880 LastSlotNumber.u.AsULONG = 0xFFFFFFFF;
881 DPRINT("AtapiFindNativePciController() done!\n");
882
883 return(SP_RETURN_NOT_FOUND);
884 }
885 #endif
886
887
888 static BOOLEAN STDCALL
889 AtapiInitialize(IN PVOID DeviceExtension)
890 {
891 return(TRUE);
892 }
893
894
895 static BOOLEAN STDCALL
896 AtapiResetBus(IN PVOID DeviceExtension,
897 IN ULONG PathId)
898 {
899 return(TRUE);
900 }
901
902
903 static BOOLEAN STDCALL
904 AtapiStartIo(IN PVOID DeviceExtension,
905 IN PSCSI_REQUEST_BLOCK Srb)
906 {
907 PATAPI_MINIPORT_EXTENSION DevExt;
908 ULONG Result;
909
910 DPRINT("AtapiStartIo() called\n");
911
912 DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
913
914 switch (Srb->Function)
915 {
916 case SRB_FUNCTION_EXECUTE_SCSI:
917 DevExt->CurrentSrb = Srb;
918 if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
919 {
920 Result = AtapiSendAtapiCommand(DevExt,
921 Srb);
922 }
923 else
924 {
925 Result = AtapiSendIdeCommand(DevExt,
926 Srb);
927 }
928 break;
929
930 case SRB_FUNCTION_ABORT_COMMAND:
931 if (DevExt->CurrentSrb != NULL)
932 {
933 Result = SRB_STATUS_ABORT_FAILED;
934 }
935 else
936 {
937 Result = SRB_STATUS_SUCCESS;
938 }
939 break;
940
941 case SRB_FUNCTION_IO_CONTROL:
942 {
943 PSRB_IO_CONTROL SrbIoControl = (PSRB_IO_CONTROL)Srb->DataBuffer;
944 if (!_strnicmp((char*)SrbIoControl->Signature, "ScsiDisk", 8))
945 {
946 switch (SrbIoControl->ControlCode)
947 {
948 default:
949 Result = SRB_STATUS_INVALID_REQUEST;
950 break;
951
952 case IOCTL_SCSI_MINIPORT_IDENTIFY:
953 {
954 PSENDCMDOUTPARAMS OutParams = (PSENDCMDOUTPARAMS)((ULONG_PTR)Srb->DataBuffer + sizeof(SRB_IO_CONTROL));
955 SENDCMDINPARAMS InParams = *(PSENDCMDINPARAMS)OutParams;
956
957
958 RtlZeroMemory(OutParams, Srb->DataTransferLength - sizeof(SRB_IO_CONTROL));
959
960 if (InParams.irDriveRegs.bCommandReg != IDE_CMD_IDENT_ATA_DRV)
961 {
962 DPRINT1("bCommandReg: %x\n", InParams.irDriveRegs.bCommandReg);
963 OutParams->DriverStatus.bIDEError = 1;
964 Result = SRB_STATUS_INVALID_REQUEST;
965 break;
966 }
967
968 if (InParams.bDriveNumber > 1 ||
969 (DevExt->DeviceFlags[InParams.bDriveNumber] & (DEVICE_PRESENT|DEVICE_ATAPI)) != DEVICE_PRESENT)
970 {
971 OutParams->DriverStatus.bIDEError = 1;
972 Result = SRB_STATUS_NO_DEVICE;
973 break;
974 }
975
976 if (Srb->DataTransferLength > sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDOUTPARAMS) - 1)
977 {
978 OutParams->cBufferSize = min(IDENTIFY_BUFFER_SIZE, Srb->DataTransferLength - (sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDOUTPARAMS) - 1));
979 RtlCopyMemory(OutParams->bBuffer, &DevExt->DeviceParams[InParams.bDriveNumber], OutParams->cBufferSize);
980 }
981
982 Result = SRB_STATUS_SUCCESS;
983 break;
984 }
985 }
986 }
987 else
988 {
989 Result = SRB_STATUS_INVALID_REQUEST;
990 }
991
992 break;
993 }
994
995 default:
996 Result = SRB_STATUS_INVALID_REQUEST;
997 break;
998 }
999
1000 Srb->SrbStatus = Result;
1001
1002
1003 if (Result != SRB_STATUS_PENDING)
1004 {
1005 DevExt->CurrentSrb = NULL;
1006
1007 ScsiPortNotification(RequestComplete,
1008 DeviceExtension,
1009 Srb);
1010 ScsiPortNotification(NextRequest,
1011 DeviceExtension,
1012 NULL);
1013 }
1014 else
1015 {
1016 DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
1017 }
1018
1019 DPRINT("AtapiStartIo() done\n");
1020
1021 return(TRUE);
1022 }
1023
1024 static BOOLEAN STDCALL
1025 AtapiInterrupt(IN PVOID DeviceExtension)
1026 {
1027 PATAPI_MINIPORT_EXTENSION DevExt;
1028 BYTE Status;
1029 DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
1030
1031 if (DevExt->Handler == NULL)
1032 {
1033 Status = IDEReadAltStatus(DevExt->ControlPortBase);
1034 if ((Status & (IDE_SR_DRDY|IDE_SR_BUSY|IDE_SR_ERR|IDE_SR_DRQ)) != IDE_SR_DRDY)
1035 {
1036 static ULONG Count = 0;
1037 Count++;
1038 DPRINT1("Unexpected Interrupt, CommandPort=%04x, Status=%02x, Count=%ld\n",
1039 DevExt->CommandPortBase, Status, Count);
1040 }
1041 return FALSE;
1042 }
1043 #ifdef ENABLE_DMA
1044 if (DevExt->UseDma)
1045 {
1046 Status = IDEReadDMAStatus(DevExt->BusMasterRegisterBase);
1047 if (!(Status & 0x04))
1048 {
1049 return FALSE;
1050 }
1051 }
1052 else
1053 #endif
1054 {
1055 Status = IDEReadAltStatus(DevExt->ControlPortBase);
1056 if (Status & IDE_SR_BUSY)
1057 {
1058 return FALSE;
1059 }
1060 }
1061 return DevExt->Handler(DevExt);
1062 }
1063
1064 // ---------------------------------------------------- Discardable statics
1065
1066 #ifdef ENABLE_DMA
1067 static BOOLEAN
1068 AtapiConfigDma(PATAPI_MINIPORT_EXTENSION DeviceExtension, ULONG UnitNumber)
1069 {
1070 BOOLEAN Result = FALSE;
1071 BYTE Status;
1072
1073 if (UnitNumber < 2)
1074 {
1075 if (DeviceExtension->PRDTable)
1076 {
1077 if (DeviceExtension->DeviceParams[UnitNumber].Capabilities & IDE_DRID_DMA_SUPPORTED)
1078 {
1079 if ((DeviceExtension->DeviceParams[UnitNumber].TMFieldsValid & 0x0004) &&
1080 (DeviceExtension->DeviceParams[UnitNumber].UltraDmaModes & 0x7F00))
1081 {
1082 Result = TRUE;
1083 }
1084 else if (DeviceExtension->DeviceParams[UnitNumber].TMFieldsValid & 0x0002)
1085 {
1086 if ((DeviceExtension->DeviceParams[UnitNumber].MultiDmaModes & 0x0404) == 0x0404)
1087 {
1088 Result = TRUE;
1089 }
1090 #if 0
1091 /* FIXME:
1092 * should we support single mode dma ?
1093 */
1094 else if ((DeviceExtension->DeviceParams[UnitNumber].DmaModes & 0x0404) == 0x0404)
1095 {
1096 Result = TRUE;
1097 }
1098 #endif
1099 }
1100 Status = IDEReadDMAStatus(DeviceExtension->BusMasterRegisterBase);
1101 if (Result)
1102 {
1103 IDEWriteDMAStatus(DeviceExtension->BusMasterRegisterBase, Status | (UnitNumber ? 0x40 : 0x20));
1104 }
1105 else
1106 {
1107 IDEWriteDMAStatus(DeviceExtension->BusMasterRegisterBase, Status & (UnitNumber ? ~0x40 : ~0x20));
1108 }
1109 }
1110 }
1111 }
1112 return Result;
1113 }
1114 #endif
1115
1116 /**********************************************************************
1117 * NAME INTERNAL
1118 * AtapiFindDevices
1119 *
1120 * DESCRIPTION
1121 * Searches for devices on the given port.
1122 *
1123 * RUN LEVEL
1124 * PASSIVE_LEVEL
1125 *
1126 * ARGUMENTS
1127 * DeviceExtension
1128 * Port device specific information.
1129 *
1130 * ConfigInfo
1131 * Port configuration information.
1132 *
1133 * RETURN VALUE
1134 * TRUE: At least one device is attached to the port.
1135 * FALSE: No device is attached to the port.
1136 */
1137
1138 static BOOLEAN
1139 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1140 PPORT_CONFIGURATION_INFORMATION ConfigInfo)
1141 {
1142 BOOLEAN DeviceFound = FALSE;
1143 ULONG CommandPortBase;
1144 ULONG ControlPortBase;
1145 ULONG UnitNumber;
1146 ULONG Retries;
1147 UCHAR High;
1148 UCHAR Low;
1149
1150 DPRINT("AtapiFindDevices() called\n");
1151
1152 CommandPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
1153 DPRINT(" CommandPortBase: %x\n", CommandPortBase);
1154
1155 ControlPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[1].RangeStart);
1156 DPRINT(" ControlPortBase: %x\n", ControlPortBase);
1157
1158 for (UnitNumber = 0; UnitNumber < 2; UnitNumber++)
1159 {
1160 /* Select drive */
1161 IDEWriteDriveHead(CommandPortBase,
1162 IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
1163 ScsiPortStallExecution(500);
1164
1165 /* Disable interrupts */
1166 IDEWriteDriveControl(ControlPortBase,
1167 IDE_DC_nIEN);
1168 ScsiPortStallExecution(500);
1169
1170 /* Check if a device is attached to the interface */
1171 IDEWriteCylinderHigh(CommandPortBase, 0xaa);
1172 IDEWriteCylinderLow(CommandPortBase, 0x55);
1173
1174 High = IDEReadCylinderHigh(CommandPortBase);
1175 Low = IDEReadCylinderLow(CommandPortBase);
1176
1177 IDEWriteCylinderHigh(CommandPortBase, 0);
1178 IDEWriteCylinderLow(CommandPortBase, 0);
1179
1180 if (Low != 0x55 || High != 0xaa)
1181 {
1182 DPRINT("No Drive found. UnitNumber %d CommandPortBase %x\n", UnitNumber, CommandPortBase);
1183 continue;
1184 }
1185
1186 AtapiExecuteCommand(DeviceExtension, IDE_CMD_RESET, NULL);
1187
1188 for (Retries = 0; Retries < 20000; Retries++)
1189 {
1190 if (!(IDEReadStatus(CommandPortBase) & IDE_SR_BUSY))
1191 {
1192 break;
1193 }
1194 ScsiPortStallExecution(150);
1195 }
1196 if (Retries >= 20000)
1197 {
1198 DPRINT("Timeout on drive %lu\n", UnitNumber);
1199 DeviceExtension->DeviceFlags[UnitNumber] &= ~DEVICE_PRESENT;
1200 continue;
1201 }
1202
1203 High = IDEReadCylinderHigh(CommandPortBase);
1204 Low = IDEReadCylinderLow(CommandPortBase);
1205
1206 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
1207 UnitNumber,
1208 High,
1209 Low);
1210
1211 if (High == 0xEB && Low == 0x14)
1212 {
1213 if (AtapiIdentifyDevice(CommandPortBase,
1214 ControlPortBase,
1215 UnitNumber,
1216 TRUE,
1217 &DeviceExtension->DeviceParams[UnitNumber]))
1218 {
1219 DPRINT(" ATAPI drive found!\n");
1220 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_PRESENT;
1221 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_ATAPI;
1222 DeviceExtension->TransferSize[UnitNumber] =
1223 DeviceExtension->DeviceParams[UnitNumber].BytesPerSector;
1224 #ifdef ENABLE_DMA
1225 if (AtapiConfigDma(DeviceExtension, UnitNumber))
1226 {
1227 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DMA_CMD;
1228 }
1229 #endif
1230 if (!(DeviceExtension->DeviceParams[UnitNumber].SupportedFeatures83 & 0x1000) ||
1231 !(DeviceExtension->DeviceParams[UnitNumber].EnabledFeatures86 & 0x1000))
1232 {
1233 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_NO_FLUSH;
1234 }
1235
1236 /* Don't flush CD/DVD drives */
1237 if (((DeviceExtension->DeviceParams[UnitNumber].ConfigBits >> 8) & 0x1F) == READ_ONLY_DIRECT_ACCESS_DEVICE)
1238 {
1239 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_NO_FLUSH;
1240 }
1241 DeviceFound = TRUE;
1242 }
1243 else
1244 {
1245 DPRINT(" No ATAPI drive found!\n");
1246 }
1247 }
1248 else
1249 {
1250 if (AtapiIdentifyDevice(CommandPortBase,
1251 ControlPortBase,
1252 UnitNumber,
1253 FALSE,
1254 &DeviceExtension->DeviceParams[UnitNumber]))
1255 {
1256 DPRINT(" IDE drive found!\n");
1257 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_PRESENT;
1258 DeviceExtension->TransferSize[UnitNumber] = DeviceExtension->DeviceParams[UnitNumber].BytesPerSector;
1259 if ((DeviceExtension->DeviceParams[UnitNumber].RWMultImplemented & 0x8000) &&
1260 (DeviceExtension->DeviceParams[UnitNumber].RWMultImplemented & 0xff) &&
1261 (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0x100) &&
1262 (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0xff))
1263 {
1264 DeviceExtension->TransferSize[UnitNumber] *= (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0xff);
1265 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_MULTI_SECTOR_CMD;
1266 }
1267 if (DeviceExtension->DeviceParams[UnitNumber].SupportedFeatures83 & 0x0400 &&
1268 DeviceExtension->DeviceParams[UnitNumber].EnabledFeatures86 & 0x0400)
1269 {
1270 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_48BIT_ADDRESS;
1271 }
1272 if (DeviceExtension->DeviceParams[UnitNumber].DWordIo)
1273 {
1274 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DWORD_IO;
1275 }
1276 #ifdef ENABLE_DMA
1277 if (AtapiConfigDma(DeviceExtension, UnitNumber))
1278 {
1279 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DMA_CMD;
1280 }
1281 #endif
1282 if (DeviceExtension->DeviceFlags[UnitNumber] & DEVICE_48BIT_ADDRESS)
1283 {
1284 if (!(DeviceExtension->DeviceParams[UnitNumber].SupportedFeatures83 & 0x2000) ||
1285 !(DeviceExtension->DeviceParams[UnitNumber].EnabledFeatures86 & 0x2000))
1286 {
1287 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_NO_FLUSH;
1288 }
1289 }
1290 else
1291 {
1292 if (!(DeviceExtension->DeviceParams[UnitNumber].SupportedFeatures83 & 0x1000) ||
1293 !(DeviceExtension->DeviceParams[UnitNumber].EnabledFeatures86 & 0x1000))
1294 {
1295 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_NO_FLUSH;
1296 }
1297 }
1298 DeviceFound = TRUE;
1299 }
1300 else
1301 {
1302 DPRINT(" No IDE drive found!\n");
1303 }
1304 }
1305 }
1306
1307 /* Reset pending interrupts */
1308 IDEReadStatus(CommandPortBase);
1309 /* Reenable interrupts */
1310 IDEWriteDriveControl(ControlPortBase, 0);
1311 ScsiPortStallExecution(500);
1312 /* Return with drive 0 selected */
1313 IDEWriteDriveHead(CommandPortBase, IDE_DH_FIXED);
1314 ScsiPortStallExecution(500);
1315
1316 DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound) ? "TRUE" : "FALSE");
1317
1318 return(DeviceFound);
1319 }
1320
1321
1322 /*
1323 * AtapiIdentifyDevice
1324 *
1325 * DESCRIPTION:
1326 * Get the identification block from the drive
1327 *
1328 * RUN LEVEL:
1329 * PASSIVE_LEVEL
1330 *
1331 * ARGUMENTS:
1332 * CommandPort
1333 * Address of the command port
1334 * ControlPort
1335 * Address of the control port
1336 * DriveNum
1337 * The drive index (0,1)
1338 * Atapi
1339 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1340 * DrvParms
1341 * Address to write drive ident block
1342 *
1343 * RETURNS:
1344 * TRUE: The drive identification block was retrieved successfully
1345 * FALSE: an error ocurred
1346 */
1347
1348 static BOOLEAN
1349 AtapiIdentifyDevice(IN ULONG CommandPort,
1350 IN ULONG ControlPort,
1351 IN ULONG DriveNum,
1352 IN BOOLEAN Atapi,
1353 OUT PIDE_DRIVE_IDENTIFY DrvParms)
1354 {
1355 LONG i;
1356 ULONG mode;
1357 char SerialNumber[20];
1358 char FirmwareRev[8];
1359 char ModelNumber[40];
1360
1361 /* Get the Drive Identify block from drive or die */
1362 if (AtapiPolledRead(CommandPort,
1363 ControlPort,
1364 0,
1365 1,
1366 0,
1367 0,
1368 0,
1369 (DriveNum ? IDE_DH_DRV1 : 0),
1370 (Atapi ? IDE_CMD_IDENT_ATAPI_DRV : IDE_CMD_IDENT_ATA_DRV),
1371 (PUCHAR)DrvParms) == FALSE)
1372 {
1373 DPRINT("AtapiPolledRead() failed\n");
1374 return FALSE;
1375 }
1376
1377 /* Report on drive parameters if debug mode */
1378 memcpy(SerialNumber, DrvParms->SerialNumber, 20);
1379 memcpy(FirmwareRev, DrvParms->FirmwareRev, 8);
1380 memcpy(ModelNumber, DrvParms->ModelNumber, 40);
1381 IDESwapBytePairs((PUCHAR)SerialNumber, 20);
1382 IDESwapBytePairs((PUCHAR)FirmwareRev, 8);
1383 IDESwapBytePairs((PUCHAR)ModelNumber, 40);
1384 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1385 DrvParms->ConfigBits,
1386 DrvParms->LogicalCyls,
1387 DrvParms->LogicalHeads,
1388 DrvParms->SectorsPerTrack,
1389 DrvParms->InterSectorGap,
1390 DrvParms->InterSectorGapSize);
1391 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1392 DrvParms->BytesInPLO,
1393 DrvParms->VendorUniqueCnt,
1394 SerialNumber);
1395 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1396 DrvParms->ControllerType,
1397 DrvParms->BufferSize * IDE_SECTOR_BUF_SZ,
1398 DrvParms->ECCByteCnt,
1399 FirmwareRev);
1400 DPRINT("Model:[%.40s]\n", ModelNumber);
1401 DPRINT("RWMultMax?:%04x RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1402 (DrvParms->RWMultImplemented),
1403 (DrvParms->RWMultCurrent) & 0xff,
1404 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0,
1405 (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
1406 DrvParms->MinPIOTransTime,
1407 DrvParms->MinDMATransTime);
1408 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1409 DrvParms->TMCylinders,
1410 DrvParms->TMHeads,
1411 DrvParms->TMSectorsPerTrk,
1412 (ULONG)(DrvParms->TMCapacityLo + (DrvParms->TMCapacityHi << 16)));
1413 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1414 DrvParms->TMSectorCountHi,
1415 DrvParms->TMSectorCountLo,
1416 (ULONG)((DrvParms->TMSectorCountHi << 16) + DrvParms->TMSectorCountLo));
1417 DPRINT("SupportedFeatures83: %x, EnabledFeatures86 %x\n", DrvParms->SupportedFeatures83, DrvParms->EnabledFeatures86);
1418 DPRINT("Max48BitAddress: %I64d\n", *(PULONGLONG)DrvParms->Max48BitAddress);
1419 if (DrvParms->TMFieldsValid & 0x0004)
1420 {
1421 if ((DrvParms->UltraDmaModes >> 8) && (DrvParms->UltraDmaModes & 0xff))
1422 {
1423 mode = 7;
1424 while (!(DrvParms->UltraDmaModes & (0x0100 << mode)))
1425 {
1426 mode--;
1427 }
1428 DPRINT("Ultra DMA mode %d is selected\n", mode);
1429 }
1430 else if ((DrvParms->MultiDmaModes >> 8) & (DrvParms->MultiDmaModes & 0x07))
1431 {
1432 mode = 2;
1433 while(!(DrvParms->MultiDmaModes & (0x01 << mode)))
1434 {
1435 mode--;
1436 }
1437 DPRINT("Multi DMA mode %d is selected\n", mode);
1438 }
1439 }
1440
1441 if (! Atapi && 0 != (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED))
1442 {
1443 /* LBA ATA drives always have a sector size of 512 */
1444 DrvParms->BytesPerSector = 512;
1445 }
1446 else
1447 {
1448 DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
1449 if (DrvParms->BytesPerSector == 0)
1450 {
1451 DrvParms->BytesPerSector = 512;
1452 }
1453 else
1454 {
1455 for (i = 15; i >= 0; i--)
1456 {
1457 if (DrvParms->BytesPerSector & (1 << i))
1458 {
1459 DrvParms->BytesPerSector = 1 << i;
1460 break;
1461 }
1462 }
1463 }
1464 }
1465 DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
1466
1467 return TRUE;
1468 }
1469
1470
1471 // AtapiPolledRead
1472 //
1473 // DESCRIPTION:
1474 // Read a sector of data from the drive in a polled fashion.
1475 //
1476 // RUN LEVEL:
1477 // PASSIVE_LEVEL
1478 //
1479 // ARGUMENTS:
1480 // IN ULONG CommandPort Address of command port for drive
1481 // IN ULONG ControlPort Address of control port for drive
1482 // IN UCHAR PreComp Value to write to precomp register
1483 // IN UCHAR SectorCnt Value to write to sectorCnt register
1484 // IN UCHAR SectorNum Value to write to sectorNum register
1485 // IN UCHAR CylinderLow Value to write to CylinderLow register
1486 // IN UCHAR CylinderHigh Value to write to CylinderHigh register
1487 // IN UCHAR DrvHead Value to write to Drive/Head register
1488 // IN UCHAR Command Value to write to Command register
1489 // OUT PUCHAR Buffer Buffer for output data
1490 //
1491 // RETURNS:
1492 // BOOLEAN: TRUE success, FALSE error
1493 //
1494
1495 static BOOLEAN
1496 AtapiPolledRead(IN ULONG CommandPort,
1497 IN ULONG ControlPort,
1498 IN UCHAR PreComp,
1499 IN UCHAR SectorCnt,
1500 IN UCHAR SectorNum,
1501 IN UCHAR CylinderLow,
1502 IN UCHAR CylinderHigh,
1503 IN UCHAR DrvHead,
1504 IN UCHAR Command,
1505 OUT PUCHAR Buffer)
1506 {
1507 ULONG SectorCount = 0;
1508 ULONG RetryCount;
1509 BOOLEAN Junk = FALSE;
1510 UCHAR Status;
1511
1512 /* Wait for BUSY to clear */
1513 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1514 {
1515 Status = IDEReadStatus(CommandPort);
1516 if (!(Status & IDE_SR_BUSY))
1517 {
1518 break;
1519 }
1520 ScsiPortStallExecution(10);
1521 }
1522 DPRINT("status=%02x\n", Status);
1523 DPRINT("waited %ld usecs for busy to clear\n", RetryCount * 10);
1524 if (RetryCount >= IDE_MAX_BUSY_RETRIES)
1525 {
1526 DPRINT("Drive is BUSY for too long\n");
1527 return FALSE;
1528 }
1529
1530 /* Write Drive/Head to select drive */
1531 IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
1532 ScsiPortStallExecution(500);
1533
1534 /* Disable interrupts */
1535 IDEWriteDriveControl(ControlPort, IDE_DC_nIEN);
1536 ScsiPortStallExecution(500);
1537
1538 #if 0
1539 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1540 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1541 {
1542 Status = IDEReadStatus(CommandPort);
1543 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1544 {
1545 break;
1546 }
1547 ScsiPortStallExecution(10);
1548 }
1549 if (RetryCount >= IDE_MAX_BUSY_RETRIES)
1550 {
1551 return FALSE;
1552 }
1553 #endif
1554
1555 /* Issue command to drive */
1556 if (DrvHead & IDE_DH_LBA)
1557 {
1558 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1559 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1560 ((DrvHead & 0x0f) << 24) + (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
1561 SectorCnt,
1562 Command);
1563 }
1564 else
1565 {
1566 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1567 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1568 CylinderHigh,
1569 CylinderLow,
1570 DrvHead & 0x0f,
1571 SectorNum,
1572 SectorCnt,
1573 Command);
1574 }
1575
1576 /* Setup command parameters */
1577 IDEWritePrecomp(CommandPort, PreComp);
1578 IDEWriteSectorCount(CommandPort, SectorCnt);
1579 IDEWriteSectorNum(CommandPort, SectorNum);
1580 IDEWriteCylinderHigh(CommandPort, CylinderHigh);
1581 IDEWriteCylinderLow(CommandPort, CylinderLow);
1582 IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
1583
1584 /* Issue the command */
1585 IDEWriteCommand(CommandPort, Command);
1586 ScsiPortStallExecution(50);
1587
1588 /* wait for DRQ or error */
1589 for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
1590 {
1591 Status = IDEReadStatus(CommandPort);
1592 if (!(Status & IDE_SR_BUSY))
1593 {
1594 if (Status & IDE_SR_ERR)
1595 {
1596 IDEWriteDriveControl(ControlPort, 0);
1597 ScsiPortStallExecution(50);
1598 IDEReadStatus(CommandPort);
1599
1600 return FALSE;
1601 }
1602
1603 if (Status & IDE_SR_DRQ)
1604 {
1605 break;
1606 }
1607 else
1608 {
1609 IDEWriteDriveControl(ControlPort, 0);
1610 ScsiPortStallExecution(50);
1611 IDEReadStatus(CommandPort);
1612
1613 return FALSE;
1614 }
1615 }
1616 ScsiPortStallExecution(10);
1617 }
1618
1619 /* timed out */
1620 if (RetryCount >= IDE_MAX_POLL_RETRIES)
1621 {
1622 IDEWriteDriveControl(ControlPort, 0);
1623 ScsiPortStallExecution(50);
1624 IDEReadStatus(CommandPort);
1625
1626 return FALSE;
1627 }
1628
1629 while (1)
1630 {
1631 /* Read data into buffer */
1632 if (Junk == FALSE)
1633 {
1634 IDEReadBlock(CommandPort, Buffer, IDE_SECTOR_BUF_SZ);
1635 Buffer += IDE_SECTOR_BUF_SZ;
1636 }
1637 else
1638 {
1639 UCHAR JunkBuffer[IDE_SECTOR_BUF_SZ];
1640 IDEReadBlock(CommandPort, JunkBuffer, IDE_SECTOR_BUF_SZ);
1641 }
1642 SectorCount++;
1643
1644 /* Check for error or more sectors to read */
1645 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1646 {
1647 Status = IDEReadStatus(CommandPort);
1648 if (!(Status & IDE_SR_BUSY))
1649 {
1650 if (Status & IDE_SR_ERR)
1651 {
1652 IDEWriteDriveControl(ControlPort, 0);
1653 ScsiPortStallExecution(50);
1654 IDEReadStatus(CommandPort);
1655
1656 return FALSE;
1657 }
1658 if (Status & IDE_SR_DRQ)
1659 {
1660 if (SectorCount >= SectorCnt)
1661 {
1662 DPRINT("Buffer size exceeded!\n");
1663 Junk = TRUE;
1664 }
1665 break;
1666 }
1667 else
1668 {
1669 if (SectorCount > SectorCnt)
1670 {
1671 DPRINT("Read %lu sectors of junk!\n",
1672 SectorCount - SectorCnt);
1673 }
1674 IDEWriteDriveControl(ControlPort, 0);
1675 ScsiPortStallExecution(50);
1676 IDEReadStatus(CommandPort);
1677
1678 return TRUE;
1679 }
1680 }
1681 }
1682 }
1683 }
1684
1685
1686 // ------------------------------------------- Nondiscardable statics
1687
1688 static ULONG
1689 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1690 IN PSCSI_REQUEST_BLOCK Srb)
1691 {
1692 UCHAR ByteCountHigh;
1693 UCHAR ByteCountLow;
1694 ULONG Retries;
1695 ULONG CdbSize;
1696 UCHAR Status;
1697
1698 DPRINT("AtapiSendAtapiCommand() called!\n");
1699
1700 if (Srb->PathId != 0)
1701 {
1702 Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
1703 return(SRB_STATUS_INVALID_PATH_ID);
1704 }
1705
1706 if (Srb->TargetId > 1)
1707 {
1708 Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
1709 return(SRB_STATUS_INVALID_TARGET_ID);
1710 }
1711
1712 if (Srb->Lun != 0)
1713 {
1714 Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
1715 return(SRB_STATUS_INVALID_LUN);
1716 }
1717
1718 if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_PRESENT))
1719 {
1720 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1721 return(SRB_STATUS_NO_DEVICE);
1722 }
1723
1724 if (Srb->Cdb[0] == SCSIOP_MODE_SENSE)
1725 {
1726 Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
1727 return (SRB_STATUS_INVALID_REQUEST);
1728 }
1729
1730 DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
1731 Srb->TargetId);
1732
1733 if (Srb->Cdb[0] == SCSIOP_INQUIRY)
1734 return(AtapiInquiry(DeviceExtension,
1735 Srb));
1736
1737 /* Set pointer to data buffer. */
1738 DeviceExtension->DataBuffer = (PUCHAR)Srb->DataBuffer;
1739 DeviceExtension->DataTransferLength = Srb->DataTransferLength;
1740 DeviceExtension->CurrentSrb = Srb;
1741
1742 DPRINT("BufferAddress %x, BufferLength %d\n", Srb->DataBuffer, Srb->DataTransferLength);
1743
1744 /* Wait for BUSY to clear */
1745 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1746 {
1747 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1748 if (!(Status & IDE_SR_BUSY))
1749 {
1750 break;
1751 }
1752 ScsiPortStallExecution(10);
1753 }
1754 DPRINT("status=%02x\n", Status);
1755 DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
1756 if (Retries >= IDE_MAX_BUSY_RETRIES)
1757 {
1758 DPRINT("Drive is BUSY for too long\n");
1759 return(SRB_STATUS_BUSY);
1760 }
1761
1762 /* Select the desired drive */
1763 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
1764 IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
1765
1766 /* Wait a little while */
1767 ScsiPortStallExecution(50);
1768
1769 #if 0
1770 /* Wait for BUSY to clear and DRDY to assert */
1771 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1772 {
1773 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1774 if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1775 {
1776 break;
1777 }
1778 ScsiPortStallExecution(10);
1779 }
1780 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
1781 if (Retries >= IDE_MAX_BUSY_RETRIES)
1782 {
1783 DPRINT("Drive is BUSY for too long after drive select\n");
1784 return(SRB_STATUS_BUSY);
1785 }
1786 #endif
1787
1788 #ifdef ENABLE_DMA
1789 if ((DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DMA_CMD) &&
1790 (Srb->Cdb[0] == SCSIOP_READ || Srb->Cdb[0] == SCSIOP_WRITE))
1791 {
1792 DeviceExtension->UseDma = AtapiInitDma(DeviceExtension, Srb, Srb->SrbFlags & SRB_FLAGS_DATA_IN ? 1 << 3 : 0);
1793 }
1794 else
1795 {
1796 DeviceExtension->UseDma = FALSE;
1797 }
1798 #endif
1799
1800 if (DeviceExtension->DataTransferLength < 0x10000)
1801 {
1802 ByteCountLow = (UCHAR)(DeviceExtension->DataTransferLength & 0xFF);
1803 ByteCountHigh = (UCHAR)(DeviceExtension->DataTransferLength >> 8);
1804 }
1805 else
1806 {
1807 ByteCountLow = 0xFF;
1808 ByteCountHigh = 0xFF;
1809 }
1810
1811 /* Set feature register */
1812 #ifdef ENABLE_DMA
1813 IDEWritePrecomp(DeviceExtension->CommandPortBase, DeviceExtension->UseDma ? 1 : 0);
1814 #else
1815 IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
1816 #endif
1817
1818 /* Set command packet length */
1819 IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, ByteCountHigh);
1820 IDEWriteCylinderLow(DeviceExtension->CommandPortBase, ByteCountLow);
1821
1822 /* Issue command to drive */
1823 #ifdef ENABLE_DMA
1824 if (DeviceExtension->UseDma)
1825 {
1826 AtapiExecuteCommand(DeviceExtension, IDE_CMD_PACKET, AtapiDmaPacketInterrupt);
1827 }
1828 else
1829 #endif
1830 {
1831 AtapiExecuteCommand(DeviceExtension, IDE_CMD_PACKET, AtapiPacketInterrupt);
1832 }
1833
1834 /* Wait for DRQ to assert */
1835 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1836 {
1837 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1838 if ((Status & IDE_SR_DRQ))
1839 {
1840 break;
1841 }
1842 ScsiPortStallExecution(10);
1843 }
1844
1845 /* Convert special SCSI SRBs to ATAPI format */
1846 switch (Srb->Cdb[0])
1847 {
1848 case SCSIOP_FORMAT_UNIT:
1849 case SCSIOP_MODE_SELECT:
1850 AtapiScsiSrbToAtapi (Srb);
1851 break;
1852 }
1853
1854 CdbSize = ((DeviceExtension->DeviceParams[Srb->TargetId].ConfigBits & 0x3) == 1) ? 16 : 12;
1855 DPRINT("CdbSize: %lu\n", CdbSize);
1856
1857 /* Write command packet */
1858 IDEWriteBlock(DeviceExtension->CommandPortBase,
1859 (PUSHORT)Srb->Cdb,
1860 CdbSize);
1861
1862 #ifdef ENABLE_DMA
1863 if (DeviceExtension->UseDma)
1864 {
1865 BYTE DmaCommand;
1866 /* start DMA */
1867 DmaCommand = IDEReadDMACommand(DeviceExtension->BusMasterRegisterBase);
1868 IDEWriteDMACommand(DeviceExtension->BusMasterRegisterBase, DmaCommand|0x01);
1869 }
1870 #endif
1871 DPRINT("AtapiSendAtapiCommand() done\n");
1872
1873 return(SRB_STATUS_PENDING);
1874 }
1875
1876
1877 static ULONG
1878 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1879 IN PSCSI_REQUEST_BLOCK Srb)
1880 {
1881 ULONG SrbStatus = SRB_STATUS_SUCCESS;
1882
1883 DPRINT("AtapiSendIdeCommand() called!\n");
1884
1885 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1886 Srb->PathId,
1887 Srb->TargetId,
1888 Srb->Lun);
1889
1890 if (Srb->PathId != 0)
1891 {
1892 Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
1893 return(SRB_STATUS_INVALID_PATH_ID);
1894 }
1895
1896 if (Srb->TargetId > 1)
1897 {
1898 Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
1899 return(SRB_STATUS_INVALID_TARGET_ID);
1900 }
1901
1902 if (Srb->Lun != 0)
1903 {
1904 Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
1905 return(SRB_STATUS_INVALID_LUN);
1906 }
1907
1908 if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_PRESENT))
1909 {
1910 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1911 return(SRB_STATUS_NO_DEVICE);
1912 }
1913
1914 switch (Srb->Cdb[0])
1915 {
1916 case SCSIOP_INQUIRY:
1917 SrbStatus = AtapiInquiry(DeviceExtension,
1918 Srb);
1919 break;
1920
1921 case SCSIOP_READ_CAPACITY:
1922 SrbStatus = AtapiReadCapacity(DeviceExtension,
1923 Srb);
1924 break;
1925
1926 case SCSIOP_READ:
1927 case SCSIOP_WRITE:
1928 SrbStatus = AtapiReadWrite(DeviceExtension,
1929 Srb);
1930 break;
1931
1932 case SCSIOP_SYNCHRONIZE_CACHE:
1933 SrbStatus = AtapiFlushCache(DeviceExtension,
1934 Srb);
1935 break;
1936
1937 case SCSIOP_TEST_UNIT_READY:
1938 SrbStatus = AtapiTestUnitReady(DeviceExtension,
1939 Srb);
1940 break;
1941
1942 case SCSIOP_MODE_SENSE:
1943
1944 case SCSIOP_VERIFY:
1945 case SCSIOP_START_STOP_UNIT:
1946 case SCSIOP_REQUEST_SENSE:
1947 break;
1948
1949 default:
1950 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1951 Srb->Cdb[0]);
1952 SrbStatus = SRB_STATUS_INVALID_REQUEST;
1953 break;
1954 }
1955
1956 DPRINT("AtapiSendIdeCommand() done!\n");
1957
1958 return(SrbStatus);
1959 }
1960
1961
1962 static ULONG
1963 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1964 PSCSI_REQUEST_BLOCK Srb)
1965 {
1966 PIDE_DRIVE_IDENTIFY DeviceParams;
1967 PINQUIRYDATA InquiryData;
1968
1969 DPRINT("SCSIOP_INQUIRY: DeviceExtension %p TargetId: %lu\n",
1970 DeviceExtension, Srb->TargetId);
1971
1972 InquiryData = Srb->DataBuffer;
1973 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1974
1975 /* clear buffer */
1976 memset(Srb->DataBuffer, 0, Srb->DataTransferLength);
1977
1978 /* set device class */
1979 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
1980 {
1981 /* get it from the ATAPI configuration word */
1982 InquiryData->DeviceType = (DeviceParams->ConfigBits >> 8) & 0x1F;
1983 DPRINT("Device class: %u\n", InquiryData->DeviceType);
1984 }
1985 else
1986 {
1987 /* hard-disk */
1988 InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
1989 }
1990
1991 DPRINT("ConfigBits: 0x%x\n", DeviceParams->ConfigBits);
1992 if (DeviceParams->ConfigBits & 0x80)
1993 {
1994 DPRINT("Removable media!\n");
1995 InquiryData->RemovableMedia = 1;
1996 }
1997
1998 memcpy(InquiryData->VendorId, DeviceParams->ModelNumber, 20);
1999 IDESwapBytePairs(InquiryData->VendorId, 20);
2000
2001 memcpy(&InquiryData->ProductId[12], " ", 4);
2002
2003 memcpy(InquiryData->ProductRevisionLevel, DeviceParams->FirmwareRev, 4);
2004 IDESwapBytePairs(InquiryData->ProductRevisionLevel, 4);
2005
2006 InquiryData->AdditionalLength = 31;
2007
2008 DPRINT("VendorId: '%.20s'\n", InquiryData->VendorId);
2009
2010 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2011 return(SRB_STATUS_SUCCESS);
2012 }
2013
2014
2015 static ULONG
2016 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension,
2017 PSCSI_REQUEST_BLOCK Srb)
2018 {
2019 PREAD_CAPACITY_DATA CapacityData;
2020 PIDE_DRIVE_IDENTIFY DeviceParams;
2021 LARGE_INTEGER LastSector;
2022
2023 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb->TargetId);
2024 CapacityData = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
2025 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
2026
2027 /* Set sector (block) size to 512 bytes (big-endian). */
2028 CapacityData->BytesPerBlock = 0x20000;
2029
2030 /* Calculate last sector (big-endian). */
2031 if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
2032 {
2033 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
2034 {
2035 ((PUSHORT)&LastSector)[0] = DeviceParams->Max48BitAddress[0];
2036 ((PUSHORT)&LastSector)[1] = DeviceParams->Max48BitAddress[1];
2037 ((PUSHORT)&LastSector)[2] = DeviceParams->Max48BitAddress[2];
2038 ((PUSHORT)&LastSector)[3] = DeviceParams->Max48BitAddress[3];
2039 LastSector.QuadPart -= 1;
2040
2041 }
2042 else
2043 {
2044 LastSector.u.HighPart = 0;
2045 LastSector.u.LowPart = (ULONG)((DeviceParams->TMSectorCountHi << 16) +
2046 DeviceParams->TMSectorCountLo)-1;
2047 }
2048 }
2049 else
2050 {
2051 LastSector.u.HighPart = 0;
2052 LastSector.u.LowPart = (ULONG)(DeviceParams->LogicalCyls *
2053 DeviceParams->LogicalHeads *
2054 DeviceParams->SectorsPerTrack)-1;
2055 }
2056 if (LastSector.u.HighPart)
2057 {
2058 DPRINT1("Disk is too large for our implementation (%I64d sectors\n", LastSector.QuadPart);
2059 KEBUGCHECK(0);
2060 }
2061
2062 CapacityData->LogicalBlockAddress = (((PUCHAR)&LastSector)[0] << 24) |
2063 (((PUCHAR)&LastSector)[1] << 16) |
2064 (((PUCHAR)&LastSector)[2] << 8) |
2065 ((PUCHAR)&LastSector)[3];
2066
2067 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
2068 LastSector,
2069 LastSector,
2070 CapacityData->LogicalBlockAddress);
2071
2072 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2073 return(SRB_STATUS_SUCCESS);
2074 }
2075
2076
2077 static ULONG
2078 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
2079 PSCSI_REQUEST_BLOCK Srb)
2080 {
2081 PIDE_DRIVE_IDENTIFY DeviceParams;
2082 ULONG StartingSector;
2083 ULONG SectorCount;
2084 UCHAR CylinderHigh[2];
2085 UCHAR CylinderLow[2];
2086 UCHAR DrvHead;
2087 UCHAR SectorNumber[2];
2088 UCHAR Command;
2089 ULONG Retries;
2090 UCHAR Status;
2091 BOOLEAN FASTCALL (*Handler)(PATAPI_MINIPORT_EXTENSION DevExt);
2092
2093 DPRINT("AtapiReadWrite() called!\n");
2094 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
2095 Srb->TargetId);
2096
2097 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
2098
2099 /* Get starting sector number from CDB. */
2100 StartingSector = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
2101 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
2102 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
2103 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
2104
2105 SectorCount = (Srb->DataTransferLength + DeviceParams->BytesPerSector - 1) /
2106 DeviceParams->BytesPerSector;
2107
2108 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
2109 StartingSector,
2110 Srb->DataTransferLength,
2111 SectorCount);
2112
2113 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
2114 {
2115 SectorNumber[0] = StartingSector & 0xff;
2116 CylinderLow[0] = (StartingSector >> 8) & 0xff;
2117 CylinderHigh[0] = (StartingSector >> 16) & 0xff;
2118 SectorNumber[1] = (StartingSector >> 24) & 0xff;
2119 CylinderLow[1] = 0;
2120 CylinderHigh[1] = 0;
2121 DrvHead = (Srb->TargetId ? IDE_DH_DRV1 : 0) | IDE_DH_LBA;
2122 #if 0
2123 DPRINT("%s:BUS=%04x:DRV=%d:LBA48=1:BLK=%08d:SC=%02x:CM=%02x\n",
2124 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
2125 DeviceExtension->CommandPortBase,
2126 DrvHead & IDE_DH_DRV1 ? 1 : 0,
2127 (SectorNumber[1] << 24) +
2128 (CylinderHigh[0] << 16) + (CylinderLow[0] << 8) + DectorNumberLow[0],
2129 SectorCount,
2130 Command);
2131 #endif
2132 }
2133 else if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
2134 {
2135 SectorNumber[0] = StartingSector & 0xff;
2136 CylinderLow[0] = (StartingSector >> 8) & 0xff;
2137 CylinderHigh[0] = (StartingSector >> 16) & 0xff;
2138 SectorNumber[1] = 0;
2139 CylinderLow[1] = 0;
2140 CylinderHigh[1] = 0;
2141 DrvHead = ((StartingSector >> 24) & 0x0f) |
2142 (Srb->TargetId ? IDE_DH_DRV1 : 0) |
2143 IDE_DH_LBA;
2144
2145 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
2146 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
2147 DeviceExtension->CommandPortBase,
2148 DrvHead & IDE_DH_DRV1 ? 1 : 0,
2149 ((DrvHead & 0x0f) << 24) +
2150 (CylinderHigh[0] << 16) + (CylinderLow[0] << 8) + SectorNumber[0],
2151 SectorCount,
2152 Command);
2153 }
2154 else
2155 {
2156 SectorNumber[0] = (StartingSector % DeviceParams->SectorsPerTrack) + 1;
2157 StartingSector /= DeviceParams->SectorsPerTrack;
2158 DrvHead = (StartingSector % DeviceParams->LogicalHeads) |
2159 (Srb->TargetId ? IDE_DH_DRV1 : 0);
2160 StartingSector /= DeviceParams->LogicalHeads;
2161 CylinderLow[0] = StartingSector & 0xff;
2162 CylinderHigh[0] = StartingSector >> 8;
2163 SectorNumber[1] = 0;
2164 CylinderLow[1] = 0;
2165 CylinderHigh[1] = 0;
2166
2167 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
2168 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
2169 DeviceExtension->CommandPortBase,
2170 DrvHead & IDE_DH_DRV1 ? 1 : 0,
2171 CylinderHigh[0],
2172 CylinderLow[0],
2173 DrvHead & 0x0f,
2174 SectorNumber[0],
2175 SectorCount,
2176 Command);
2177 }
2178
2179 /* Set pointer to data buffer. */
2180 DeviceExtension->DataBuffer = (PUCHAR)Srb->DataBuffer;
2181 DeviceExtension->DataTransferLength = Srb->DataTransferLength;
2182
2183 DeviceExtension->CurrentSrb = Srb;
2184
2185 /* wait for BUSY to clear */
2186 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
2187 {
2188 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2189 if (!(Status & IDE_SR_BUSY))
2190 {
2191 break;
2192 }
2193 ScsiPortStallExecution(10);
2194 }
2195 DPRINT("status=%02x\n", Status);
2196 DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
2197 if (Retries >= IDE_MAX_BUSY_RETRIES)
2198 {
2199 DPRINT ("Drive is BUSY for too long\n");
2200 return(SRB_STATUS_BUSY);
2201 }
2202
2203 /* Select the desired drive */
2204 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
2205 IDE_DH_FIXED | DrvHead);
2206
2207 ScsiPortStallExecution(10);
2208 #if 0
2209 /* wait for BUSY to clear and DRDY to assert */
2210 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
2211 {
2212 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2213 if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
2214 {
2215 break;
2216 }
2217 ScsiPortStallExecution(10);
2218 }
2219 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
2220 if (Retries >= IDE_MAX_BUSY_RETRIES)
2221 {
2222 DPRINT("Drive is BUSY for too long after drive select\n");
2223 return(SRB_STATUS_BUSY);
2224 }
2225 #endif
2226
2227 /* Setup command parameters */
2228 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
2229 {
2230 IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
2231 IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount >> 8);
2232 IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber[1]);
2233 IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow[1]);
2234 IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh[1]);
2235 }
2236
2237 IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
2238 IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount & 0xff);
2239 IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber[0]);
2240 IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow[0]);
2241 IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh[0]);
2242
2243 IDEWriteDriveHead(DeviceExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
2244
2245 #ifdef ENABLE_DMA
2246 if (DeviceExtension->PRDTable &&
2247 DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DMA_CMD)
2248 {
2249 DeviceExtension->UseDma = AtapiInitDma(DeviceExtension, Srb, Srb->SrbFlags & SRB_FLAGS_DATA_IN ? 1 << 3 : 0);
2250 }
2251 if (DeviceExtension->UseDma)
2252 {
2253 Handler = AtapiDmaInterrupt;
2254 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
2255 {
2256 Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_DMA_EXT : IDE_CMD_WRITE_DMA_EXT;
2257 }
2258 else
2259 {
2260 Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_DMA : IDE_CMD_WRITE_DMA;
2261 }
2262 }
2263 else
2264 #endif
2265 {
2266 Handler = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? AtapiReadInterrupt : AtapiWriteInterrupt;
2267 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_MULTI_SECTOR_CMD)
2268 {
2269 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
2270 {
2271 Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_MULTIPLE_EXT : IDE_CMD_WRITE_MULTIPLE_EXT;
2272 }
2273 else
2274 {
2275 Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_MULTIPLE : IDE_CMD_WRITE_MULTIPLE;
2276 }
2277 }
2278 else
2279 {
2280 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
2281 {
2282 Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_EXT : IDE_CMD_WRITE_EXT;
2283 }
2284 else
2285 {
2286 Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ : IDE_CMD_WRITE;
2287 }
2288 }
2289 }
2290
2291 AtapiExecuteCommand(DeviceExtension, Command, Handler);
2292
2293 #ifdef ENABLE_DMA
2294 if (DeviceExtension->UseDma)
2295 {
2296 BYTE DmaCommand;
2297 /* start DMA */
2298 DmaCommand = IDEReadDMACommand(DeviceExtension->BusMasterRegisterBase);
2299 IDEWriteDMACommand(DeviceExtension->BusMasterRegisterBase, DmaCommand|0x01);
2300 }
2301 else
2302 #endif
2303 {
2304 if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
2305 {
2306 /* Write data block */
2307 PUCHAR TargetAddress;
2308 ULONG TransferSize;
2309
2310 /* Wait for controller ready */
2311 for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
2312 {
2313 BYTE Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2314 if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
2315 {
2316 break;
2317 }
2318 ScsiPortStallExecution(10);
2319 }
2320 if (Retries >= IDE_MAX_WRITE_RETRIES)
2321 {
2322 DPRINT1("Drive is BUSY for too long after sending write command\n");
2323 return(SRB_STATUS_BUSY);
2324 }
2325
2326 /* Update DeviceExtension data */
2327 TransferSize = DeviceExtension->TransferSize[Srb->TargetId];
2328 if (DeviceExtension->DataTransferLength < TransferSize)
2329 {
2330 TransferSize = DeviceExtension->DataTransferLength;
2331 }
2332
2333 TargetAddress = DeviceExtension->DataBuffer;
2334 DeviceExtension->DataBuffer += TransferSize;
2335 DeviceExtension->DataTransferLength -= TransferSize;
2336
2337 /* Write data block */
2338 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
2339 {
2340 IDEWriteBlock32(DeviceExtension->CommandPortBase,
2341 TargetAddress,
2342 TransferSize);
2343 }
2344 else
2345 {
2346 IDEWriteBlock(DeviceExtension->CommandPortBase,
2347 TargetAddress,
2348 TransferSize);
2349 }
2350 }
2351 }
2352
2353 DPRINT("AtapiReadWrite() done!\n");
2354
2355 /* Wait for interrupt. */
2356 return(SRB_STATUS_PENDING);
2357 }
2358
2359
2360 static ULONG
2361 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension,
2362 PSCSI_REQUEST_BLOCK Srb)
2363 {
2364 ULONG Retries;
2365 UCHAR Status;
2366
2367 DPRINT("AtapiFlushCache() called!\n");
2368 DPRINT("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
2369 Srb->TargetId);
2370
2371 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_NO_FLUSH)
2372 {
2373 /*
2374 * NOTE: Don't flush the cache for CD/DVD drives. Although
2375 * the ATAPI-6 standard allows that, it has been experimentally
2376 * proved that it can damage some broken LG drives. Afterall
2377 * it doesn't make sense to flush cache on devices we don't
2378 * write to.
2379 */
2380
2381 /* The device states it doesn't support the command or it is disabled */
2382 DPRINT("The drive doesn't support FLUSH_CACHE\n");
2383 return SRB_STATUS_INVALID_REQUEST;
2384 }
2385
2386 /* Wait for BUSY to clear */
2387 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
2388 {
2389 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2390 if (!(Status & IDE_SR_BUSY))
2391 {
2392 break;
2393 }
2394 ScsiPortStallExecution(10);
2395 }
2396 DPRINT("Status=%02x\n", Status);
2397 DPRINT("Waited %ld usecs for busy to clear\n", Retries * 10);
2398 if (Retries >= IDE_MAX_BUSY_RETRIES)
2399 {
2400 DPRINT1("Drive is BUSY for too long\n");
2401 return(SRB_STATUS_BUSY);
2402 }
2403
2404 /* Select the desired drive */
2405 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
2406 IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
2407 ScsiPortStallExecution(10);
2408
2409 /* Issue command to drive */
2410 AtapiExecuteCommand(DeviceExtension,
2411 DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS ? IDE_CMD_FLUSH_CACHE_EXT : IDE_CMD_FLUSH_CACHE,
2412 AtapiNoDataInterrupt);
2413
2414
2415 DPRINT("AtapiFlushCache() done!\n");
2416
2417 /* Wait for interrupt. */
2418 return(SRB_STATUS_PENDING);
2419 }
2420
2421
2422 static ULONG
2423 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension,
2424 PSCSI_REQUEST_BLOCK Srb)
2425 {
2426 ULONG Retries;
2427 UCHAR Status;
2428 UCHAR Error;
2429
2430 DPRINT1("AtapiTestUnitReady() called!\n");
2431
2432 DPRINT1("SCSIOP_TEST_UNIT_READY: TargetId: %lu\n",
2433 Srb->TargetId);
2434
2435 /* Return success if media status is not supported */
2436 if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_MEDIA_STATUS))
2437 {
2438 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2439 return(SRB_STATUS_SUCCESS);
2440 }
2441
2442 /* Wait for BUSY to clear */
2443 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
2444 {
2445 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2446 if (!(Status & IDE_SR_BUSY))
2447 {
2448 break;
2449 }
2450 ScsiPortStallExecution(10);
2451 }
2452 DPRINT1("Status=%02x\n", Status);
2453 DPRINT1("Waited %ld usecs for busy to clear\n", Retries * 10);
2454 if (Retries >= IDE_MAX_BUSY_RETRIES)
2455 {
2456 DPRINT1("Drive is BUSY for too long\n");
2457 return(SRB_STATUS_BUSY);
2458 }
2459
2460 /* Select the desired drive */
2461 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
2462 IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
2463 ScsiPortStallExecution(10);
2464
2465 /* Issue command to drive */
2466 AtapiExecuteCommand(DeviceExtension, IDE_CMD_GET_MEDIA_STATUS, AtapiNoDataInterrupt);
2467
2468 /* Wait for controller ready */
2469 for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
2470 {
2471 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2472 if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
2473 {
2474 break;
2475 }
2476 ScsiPortStallExecution(10);
2477 }
2478 if (Retries >= IDE_MAX_WRITE_RETRIES)
2479 {
2480 DPRINT1("Drive is BUSY for too long after sending write command\n");
2481 DeviceExtension->Handler = NULL;
2482 return(SRB_STATUS_BUSY);
2483 }
2484
2485 if (Status & IDE_SR_ERR)
2486 {
2487 Error = IDEReadError(DeviceExtension->CommandPortBase);
2488 if (Error == IDE_ER_UNC)
2489 {
2490 CHECKPOINT1;
2491 /* Handle write protection 'error' */
2492 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2493 DeviceExtension->Handler = NULL;
2494 return(SRB_STATUS_SUCCESS);
2495 }
2496 else
2497 {
2498 CHECKPOINT1;
2499 /* Indicate expecting an interrupt. */
2500 return(SRB_STATUS_PENDING);
2501 }
2502 }
2503
2504 DeviceExtension->Handler = NULL;
2505
2506 DPRINT1("AtapiTestUnitReady() done!\n");
2507
2508 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2509 return(SRB_STATUS_SUCCESS);
2510 }
2511
2512
2513 static UCHAR
2514 AtapiErrorToScsi(PVOID DeviceExtension,
2515 PSCSI_REQUEST_BLOCK Srb)
2516 {
2517 PATAPI_MINIPORT_EXTENSION DevExt;
2518 ULONG CommandPortBase;
2519 ULONG ControlPortBase;
2520 UCHAR ErrorReg;
2521 UCHAR ScsiStatus;
2522 UCHAR SrbStatus;
2523
2524 DPRINT("AtapiErrorToScsi() called\n");
2525
2526 DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
2527
2528 CommandPortBase = DevExt->CommandPortBase;
2529 ControlPortBase = DevExt->ControlPortBase;
2530
2531 ErrorReg = IDEReadError(CommandPortBase);
2532
2533 if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
2534 {
2535 switch (ErrorReg >> 4)
2536 {
2537 case SCSI_SENSE_NO_SENSE:
2538 DPRINT("ATAPI error: SCSI_SENSE_NO_SENSE\n");
2539 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2540 SrbStatus = SRB_STATUS_ERROR;
2541 break;
2542
2543 case SCSI_SENSE_RECOVERED_ERROR:
2544 DPRINT("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
2545 ScsiStatus = 0;
2546 SrbStatus = SRB_STATUS_SUCCESS;
2547 break;
2548
2549 case SCSI_SENSE_NOT_READY:
2550 DPRINT("ATAPI error: SCSI_SENSE_NOT_READY\n");
2551 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2552 SrbStatus = SRB_STATUS_ERROR;
2553 break;
2554
2555 case SCSI_SENSE_MEDIUM_ERROR:
2556 DPRINT("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
2557 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2558 SrbStatus = SRB_STATUS_ERROR;
2559 break;
2560
2561 case SCSI_SENSE_HARDWARE_ERROR:
2562 DPRINT("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
2563 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2564 SrbStatus = SRB_STATUS_ERROR;
2565 break;
2566
2567 case SCSI_SENSE_ILLEGAL_REQUEST:
2568 DPRINT("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
2569 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2570 SrbStatus = SRB_STATUS_ERROR;
2571 break;
2572
2573 case SCSI_SENSE_UNIT_ATTENTION:
2574 DPRINT("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
2575 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2576 SrbStatus = SRB_STATUS_ERROR;
2577 break;
2578
2579 case SCSI_SENSE_DATA_PROTECT:
2580 DPRINT("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
2581 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2582 SrbStatus = SRB_STATUS_ERROR;
2583 break;
2584
2585 case SCSI_SENSE_BLANK_CHECK:
2586 DPRINT("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
2587 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2588 SrbStatus = SRB_STATUS_ERROR;
2589 break;
2590
2591 case SCSI_SENSE_ABORTED_COMMAND:
2592 DPRINT("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
2593 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2594 SrbStatus = SRB_STATUS_ERROR;
2595 break;
2596
2597 default:
2598 DPRINT("ATAPI error: Invalid sense key\n");
2599 ScsiStatus = 0;
2600 SrbStatus = SRB_STATUS_ERROR;
2601 break;
2602 }
2603 }
2604 else
2605 {
2606 DPRINT1("IDE error: %02x\n", ErrorReg);
2607
2608 ScsiStatus = 0;
2609 SrbStatus = SRB_STATUS_ERROR;
2610
2611 #if 0
2612 UCHAR SectorCount, SectorNum, CylinderLow, CylinderHigh;
2613 UCHAR DriveHead;
2614
2615 CylinderLow = IDEReadCylinderLow(CommandPortBase);
2616 CylinderHigh = IDEReadCylinderHigh(CommandPortBase);
2617 DriveHead = IDEReadDriveHead(CommandPortBase);
2618 SectorCount = IDEReadSectorCount(CommandPortBase);
2619 SectorNum = IDEReadSectorNum(CommandPortBase);
2620
2621 DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
2622 ErrorReg,
2623 CylinderLow,
2624 CylinderHigh,
2625 SectorCount,
2626 SectorNum);
2627 #endif
2628 }
2629
2630
2631
2632 Srb->ScsiStatus = ScsiStatus;
2633
2634 DPRINT("AtapiErrorToScsi() done\n");
2635
2636 return(SrbStatus);
2637 }
2638
2639
2640 static VOID
2641 AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb)
2642 {
2643 DPRINT("AtapiConvertScsiToAtapi() called\n");
2644
2645 Srb->CdbLength = 12;
2646
2647 switch (Srb->Cdb[0])
2648 {
2649 case SCSIOP_FORMAT_UNIT:
2650 Srb->Cdb[0] = ATAPI_FORMAT_UNIT;
2651 break;
2652
2653 case SCSIOP_MODE_SELECT:
2654 {
2655 PATAPI_MODE_SELECT12 AtapiModeSelect;
2656 UCHAR Length;
2657
2658 AtapiModeSelect = (PATAPI_MODE_SELECT12)Srb->Cdb;
2659 Length = ((PCDB)Srb->Cdb)->MODE_SELECT.ParameterListLength;
2660
2661 RtlZeroMemory (Srb->Cdb,
2662 MAXIMUM_CDB_SIZE);
2663 AtapiModeSelect->OperationCode = ATAPI_MODE_SELECT;
2664 AtapiModeSelect->PFBit = 1;
2665 AtapiModeSelect->ParameterListLengthMsb = 0;
2666 AtapiModeSelect->ParameterListLengthLsb = Length;
2667 }
2668 break;
2669 }
2670 }
2671
2672 static VOID FASTCALL
2673 AtapiCompleteRequest(PATAPI_MINIPORT_EXTENSION DevExt,
2674 UCHAR SrbStatus)
2675 {
2676 PSCSI_REQUEST_BLOCK Srb;
2677 Srb = DevExt->CurrentSrb;
2678
2679 DPRINT("AtapiCompleteRequest(DevExt %x, SrbStatus %x)\n", DevExt, SrbStatus);
2680
2681 Srb->SrbStatus = SrbStatus;
2682 if (SrbStatus == SRB_STATUS_ERROR)
2683 {
2684 Srb->SrbStatus = AtapiErrorToScsi((PVOID)DevExt, Srb);
2685 }
2686 else if (SrbStatus == SRB_STATUS_DATA_OVERRUN)
2687 {
2688 Srb->DataTransferLength -= DevExt->DataTransferLength;
2689 }
2690
2691 DevExt->Handler = NULL;
2692 ScsiPortNotification(RequestComplete, (PVOID)DevExt, Srb);
2693 ScsiPortNotification(NextRequest, (PVOID)DevExt, NULL);
2694 }
2695
2696 #ifdef ENABLE_DMA
2697 static BOOLEAN FASTCALL
2698 AtapiDmaPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
2699 {
2700 BYTE SrbStatus;
2701 BYTE DmaCommand;
2702 BYTE DmaStatus;
2703 BYTE Status;
2704 BYTE Error;
2705 BYTE SensKey;
2706
2707 DPRINT("AtapiPacketDmaInterrupt\n");
2708
2709 DevExt->UseDma = FALSE;
2710
2711 /* stop DMA */
2712 DmaCommand = IDEReadDMACommand(DevExt->BusMasterRegisterBase);
2713 IDEWriteDMACommand(DevExt->BusMasterRegisterBase, DmaCommand & 0xfe);
2714 /* get DMA status */
2715 DmaStatus = IDEReadDMAStatus(DevExt->BusMasterRegisterBase);
2716 /* clear the INTR & ERROR bits */
2717 IDEWriteDMAStatus(DevExt->BusMasterRegisterBase, DmaStatus | 0x06);
2718
2719 Status = IDEReadStatus(DevExt->CommandPortBase);
2720 DPRINT("DriveStatus: %x\n", Status);
2721
2722 if (Status & (IDE_SR_BUSY|IDE_SR_ERR))
2723 {
2724 if (Status & IDE_SR_ERR)
2725 {
2726 Error = IDEReadError(DevExt->CommandPortBase);
2727 SensKey = Error >> 4;
2728 DPRINT("DriveError: %x, SenseKey: %x\n", Error, SensKey);
2729 }
2730 SrbStatus = SRB_STATUS_ERROR;
2731 }
2732 else
2733 {
2734 if ((DmaStatus & 0x07) != 0x04)
2735 {
2736 DPRINT("DmaStatus: %02x\n", DmaStatus);
2737 SrbStatus = SRB_STATUS_ERROR;
2738 }
2739 else
2740 {
2741 SrbStatus = STATUS_SUCCESS;
2742 }
2743 }
2744 AtapiCompleteRequest(DevExt, SrbStatus);
2745 DPRINT("AtapiDmaPacketInterrupt() done\n");
2746 return TRUE;
2747 }
2748 #endif
2749
2750 static BOOLEAN FASTCALL
2751 AtapiPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
2752 {
2753 PSCSI_REQUEST_BLOCK Srb;
2754 BYTE Status;
2755 BYTE IntReason;
2756 ULONG TransferSize;
2757 ULONG JunkSize = 0;
2758 BOOL IsLastBlock;
2759 PBYTE TargetAddress;
2760 ULONG Retries;
2761 BYTE SrbStatus;
2762 BYTE Error;
2763 BYTE SensKey;
2764
2765 DPRINT("AtapiPacketInterrupt()\n");
2766
2767 Srb = DevExt->CurrentSrb;
2768
2769 Status = IDEReadStatus(DevExt->CommandPortBase);
2770 DPRINT("DriveStatus: %x\n", Status);
2771
2772 if (Status & (IDE_SR_BUSY|IDE_SR_ERR))
2773 {
2774 if (Status & IDE_SR_ERR)
2775 {
2776 Error = IDEReadError(DevExt->CommandPortBase);
2777 SensKey = Error >> 4;
2778 DPRINT("DriveError: %x, SenseKey: %x\n", Error, SensKey);
2779 }
2780
2781 AtapiCompleteRequest(DevExt, SRB_STATUS_ERROR);
2782 DPRINT("AtapiPacketInterrupt() done\n");
2783 return TRUE;
2784 }
2785
2786 IntReason = IDEReadSectorCount(DevExt->CommandPortBase);
2787 TransferSize = IDEReadCylinderLow(DevExt->CommandPortBase);
2788 TransferSize += IDEReadCylinderHigh(DevExt->CommandPortBase) << 8;
2789
2790 if (!(Status & IDE_SR_DRQ))
2791 {
2792 if (DevExt->DataTransferLength > 0)
2793 {
2794 DPRINT1("AtapiPacketInterrupt: data underrun (%d bytes), command was %02x\n",
2795 DevExt->DataTransferLength, Srb->Cdb[0]);
2796 SrbStatus = SRB_STATUS_DATA_OVERRUN;
2797 }
2798 else
2799 {
2800 SrbStatus = SRB_STATUS_SUCCESS;
2801 }
2802 AtapiCompleteRequest(DevExt, SrbStatus);
2803 DPRINT("AtapiPacketInterrupt() done\n");
2804 return TRUE;
2805 }
2806
2807 TargetAddress = DevExt->DataBuffer;
2808
2809 if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
2810 {
2811 DPRINT("read data\n");
2812 if (DevExt->DataTransferLength <= TransferSize)
2813 {
2814 JunkSize = TransferSize - DevExt->DataTransferLength;
2815 TransferSize = DevExt->DataTransferLength;
2816
2817 DevExt->DataTransferLength = 0;
2818 IsLastBlock = TRUE;
2819 }
2820 else
2821 {
2822 DevExt->DataTransferLength -= TransferSize;
2823 IsLastBlock = FALSE;
2824 }
2825
2826 DPRINT("TargetAddress %x, TransferSize %d\n", TargetAddress, TransferSize);
2827
2828 DevExt->DataBuffer += TransferSize;
2829
2830 IDEReadBlock(DevExt->CommandPortBase, TargetAddress, TransferSize);
2831
2832 /* check DRQ */
2833 if (IsLastBlock)
2834 {
2835 /* Read remaining junk from device */
2836 while (JunkSize > 0)
2837 {
2838 IDEReadWord(DevExt->CommandPortBase);
2839 JunkSize -= 2;
2840 }
2841
2842 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES && (IDEReadStatus(DevExt->CommandPortBase) & IDE_SR_BUSY); Retries++)
2843 {
2844 ScsiPortStallExecution(10);
2845 }
2846
2847 /* Check for data overrun */
2848 while (IDEReadStatus(DevExt->CommandPortBase) & IDE_SR_DRQ)
2849 {
2850 DPRINT1("AtapiInterrupt(): reading overrun data!\n");
2851 IDEReadWord(DevExt->CommandPortBase);
2852 }
2853 }
2854
2855 SrbStatus = SRB_STATUS_SUCCESS;
2856 }
2857 else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
2858 {
2859 DPRINT("write data\n");
2860 if (DevExt->DataTransferLength < TransferSize)
2861 {
2862 TransferSize = DevExt->DataTransferLength;
2863 }
2864
2865 TargetAddress = DevExt->DataBuffer;
2866
2867 DPRINT("TargetAddress %x, TransferSize %x\n", TargetAddress, TransferSize);
2868
2869 DevExt->DataBuffer += TransferSize;
2870 DevExt->DataTransferLength -= TransferSize;
2871
2872 /* Write the sector */
2873 IDEWriteBlock(DevExt->CommandPortBase, TargetAddress, TransferSize);
2874 SrbStatus = SRB_STATUS_SUCCESS;
2875 IsLastBlock = FALSE;
2876 }
2877 else
2878 {
2879 DPRINT("Unspecified transfer direction!\n");
2880 SrbStatus = SRB_STATUS_SUCCESS;
2881 IsLastBlock = TRUE;
2882 }
2883 if (IsLastBlock)
2884 {
2885 AtapiCompleteRequest(DevExt, SrbStatus);
2886 }
2887 DPRINT("AtapiPacketInterrupt() done\n");
2888 return TRUE;
2889 }
2890
2891 static BOOLEAN FASTCALL
2892 AtapiNoDataInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
2893 {
2894 BYTE Status;
2895
2896 DPRINT("AtapiNoDataInterrupt()\n");
2897
2898 Status = IDEReadStatus(DevExt->CommandPortBase);
2899 AtapiCompleteRequest(DevExt,
2900 (Status & (IDE_SR_DRDY|IDE_SR_BUSY|IDE_SR_ERR|IDE_SR_DRQ)) == IDE_SR_DRDY ? SRB_STATUS_SUCCESS : SRB_STATUS_ERROR);
2901
2902 DPRINT("AtapiNoDatanterrupt() done!\n");
2903 return TRUE;
2904 }
2905
2906 #ifdef ENABLE_DMA
2907 static BOOLEAN FASTCALL
2908 AtapiDmaInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
2909 {
2910 BYTE DmaCommand;
2911 BYTE DmaStatus;
2912 BYTE Status;
2913
2914 DPRINT("AtapiDmaInterrupt()\n");
2915
2916 DevExt->UseDma = FALSE;
2917 /* stop DMA */
2918 DmaCommand = IDEReadDMACommand(DevExt->BusMasterRegisterBase);
2919 IDEWriteDMACommand(DevExt->BusMasterRegisterBase, DmaCommand & 0xfe);
2920 /* get DMA status */
2921 DmaStatus = IDEReadDMAStatus(DevExt->BusMasterRegisterBase);
2922 /* clear the INTR & ERROR bits */
2923 IDEWriteDMAStatus(DevExt->BusMasterRegisterBase, DmaStatus | 0x06);
2924
2925 /* read the drive status */
2926 Status = IDEReadStatus(DevExt->CommandPortBase);
2927 if ((Status & (IDE_SR_DRDY|IDE_SR_BUSY|IDE_SR_ERR|IDE_SR_WERR|IDE_SR_DRQ)) == IDE_SR_DRDY &&
2928 (DmaStatus & 0x07) == 4)
2929 {
2930 AtapiCompleteRequest(DevExt, SRB_STATUS_SUCCESS);
2931 DPRINT("AtapiDmaInterrupt() done\n");
2932 return TRUE;
2933 }
2934 DPRINT1("Status %x\n", Status);
2935 DPRINT1("%x\n", DmaStatus);
2936 AtapiCompleteRequest(DevExt, SRB_STATUS_ERROR);
2937 DPRINT1("AtapiDmaReadInterrupt() done\n");
2938 return TRUE;
2939 }
2940 #endif
2941
2942 static BOOLEAN FASTCALL
2943 AtapiReadInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
2944 {
2945 PSCSI_REQUEST_BLOCK Srb;
2946 UCHAR DeviceStatus;
2947 BOOLEAN IsLastBlock;
2948 PUCHAR TargetAddress;
2949 ULONG TransferSize;
2950
2951 DPRINT("AtapiReadInterrupt() called!\n");
2952
2953 Srb = DevExt->CurrentSrb;
2954
2955 DeviceStatus = IDEReadStatus(DevExt->CommandPortBase);
2956 if ((DeviceStatus & (IDE_SR_DRQ|IDE_SR_BUSY|IDE_SR_ERR)) != IDE_SR_DRQ)
2957 {
2958 if (DeviceStatus & (IDE_SR_ERR|IDE_SR_DRQ))
2959 {
2960 AtapiCompleteRequest(DevExt, SRB_STATUS_ERROR);
2961 DPRINT("AtapiReadInterrupt() done!\n");
2962 return TRUE;
2963 }
2964 DPRINT("AtapiReadInterrupt() done!\n");
2965 return FALSE;
2966 }
2967
2968 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", DevExt->CommandPortBase, DevExt->ControlPortBase);
2969
2970 /* Update controller/device state variables */
2971 TargetAddress = DevExt->DataBuffer;
2972 TransferSize = DevExt->TransferSize[Srb->TargetId];
2973
2974 DPRINT("TransferLength: %lu\n", Srb->DataTransferLength);
2975 DPRINT("TransferSize: %lu\n", TransferSize);
2976
2977 if (DevExt->DataTransferLength <= TransferSize)
2978 {
2979 TransferSize = DevExt->DataTransferLength;
2980 DevExt->DataTransferLength = 0;
2981 IsLastBlock = TRUE;
2982 }
2983 else
2984 {
2985 DevExt->DataTransferLength -= TransferSize;
2986 IsLastBlock = FALSE;
2987 }
2988 DevExt->DataBuffer += TransferSize;
2989 DPRINT("IsLastBlock == %s\n", (IsLastBlock) ? "TRUE" : "FALSE");
2990
2991 /* Copy the block of data */
2992 if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
2993 {
2994 IDEReadBlock32(DevExt->CommandPortBase, TargetAddress, TransferSize);
2995 }
2996 else
2997 {
2998 IDEReadBlock(DevExt->CommandPortBase, TargetAddress, TransferSize);
2999 }
3000
3001 if (IsLastBlock)
3002 {
3003 AtapiCompleteRequest(DevExt, SRB_STATUS_SUCCESS);
3004 }
3005
3006 DPRINT("AtapiReadInterrupt() done!\n");
3007
3008 return(TRUE);
3009 }
3010
3011 static BOOLEAN FASTCALL
3012 AtapiWriteInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt)
3013 {
3014 PSCSI_REQUEST_BLOCK Srb;
3015 UCHAR DeviceStatus;
3016 BOOLEAN IsLastBlock;
3017 PUCHAR TargetAddress;
3018 ULONG TransferSize;
3019
3020 DPRINT("AtapiWriteInterrupt() called!\n");
3021
3022 DeviceStatus = IDEReadStatus(DevExt->CommandPortBase);
3023 if ((DeviceStatus & (IDE_SR_DRDY|IDE_SR_BUSY|IDE_SR_ERR|IDE_SR_WERR)) != IDE_SR_DRDY)
3024 {
3025 if (DeviceStatus & (IDE_SR_DRDY|IDE_SR_ERR|IDE_SR_WERR))
3026 {
3027 AtapiCompleteRequest(DevExt, SRB_STATUS_ERROR);
3028 DPRINT("AtapiWriteInterrupt() done!\n");
3029 return TRUE;
3030 }
3031 DPRINT("AtapiWriteInterrupt() done!\n");
3032 return FALSE;
3033 }
3034 else
3035 {
3036 Srb = DevExt->CurrentSrb;
3037 TransferSize = DevExt->TransferSize[Srb->TargetId];
3038 if (DevExt->DataTransferLength < TransferSize)
3039 {
3040 TransferSize = DevExt->DataTransferLength;
3041 }
3042 if (TransferSize > 0 && (DeviceStatus & IDE_SR_DRQ))
3043 {
3044 IsLastBlock = FALSE;
3045 TargetAddress = DevExt->DataBuffer;
3046 DevExt->DataBuffer += TransferSize;
3047 DevExt->DataTransferLength -= TransferSize;
3048
3049 DPRINT("TransferLength: %lu\n", Srb->DataTransferLength);
3050 DPRINT("TransferSize: %lu\n", TransferSize);
3051 /* Write the sector */
3052 if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
3053 {
3054 IDEWriteBlock32(DevExt->CommandPortBase, TargetAddress, TransferSize);
3055 }
3056 else
3057 {
3058 IDEWriteBlock(DevExt->CommandPortBase, TargetAddress, TransferSize);
3059 }
3060 }
3061 else if (DeviceStatus & IDE_SR_DRQ)
3062 {
3063 DPRINT("AtapiWriteInterrupt(): data overrun error!\n");
3064 IsLastBlock = TRUE;
3065 }
3066 else if (TransferSize > 0 && !(DeviceStatus & IDE_SR_DRQ))
3067 {
3068 DPRINT1("%d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", TransferSize);
3069 IsLastBlock = TRUE;
3070 }
3071 else
3072 {
3073 IsLastBlock = TRUE;
3074 }
3075 if (IsLastBlock)
3076 {
3077 AtapiCompleteRequest(DevExt, SRB_STATUS_SUCCESS);
3078 }
3079 DPRINT("AtapiWriteInterrupt() done!\n");
3080 return TRUE;
3081 }
3082 }
3083
3084 static VOID
3085 AtapiExecuteCommand(PATAPI_MINIPORT_EXTENSION DevExt,
3086 BYTE command,
3087 BOOLEAN FASTCALL (*Handler)(PATAPI_MINIPORT_EXTENSION))
3088 {
3089 if (DevExt->Handler != NULL)
3090 {
3091 DPRINT1("DevExt->Handler is already set!!\n");
3092 }
3093 DevExt->Handler = Handler;
3094 IDEWriteCommand(DevExt->CommandPortBase, command);
3095 ScsiPortStallExecution(1);
3096 }
3097
3098 #ifdef ENABLE_DMA
3099 static BOOLEAN
3100 AtapiInitDma(PATAPI_MINIPORT_EXTENSION DevExt,
3101 PSCSI_REQUEST_BLOCK Srb,
3102 BYTE cmd)
3103 {
3104 PVOID StartAddress;
3105 PVOID EndAddress;
3106 PPRD PRDEntry = DevExt->PRDTable;
3107 SCSI_PHYSICAL_ADDRESS PhysicalAddress;
3108 ULONG Length;
3109 ULONG tmpLength;
3110 BYTE Status;
3111
3112 DPRINT("AtapiInitDma()\n");
3113
3114 StartAddress = Srb->DataBuffer;
3115 EndAddress = (PVOID)((ULONG_PTR)StartAddress + Srb->DataTransferLength);
3116 DevExt->PRDCount = 0;
3117
3118 while (StartAddress < EndAddress)
3119 {
3120 PhysicalAddress = ScsiPortGetPhysicalAddress(DevExt, Srb, StartAddress, &Length);
3121 if (PhysicalAddress.QuadPart == 0LL || Length == 0)
3122 {
3123 return FALSE;
3124 }
3125
3126 while (Length)
3127 {
3128 /* calculate the length up to the next 64k boundary */
3129 tmpLength = 0x10000 - (PhysicalAddress.u.LowPart & 0xffff);
3130 if (tmpLength > Length)
3131 {
3132 tmpLength = Length;
3133 }
3134 DevExt->PRDCount++;
3135 if (DevExt->PRDCount > DevExt->PRDMaxCount)
3136 {
3137 return FALSE;
3138 }
3139 if (tmpLength == 0x10000)
3140 {
3141 /* Some dirty controllers cannot handle 64k transfers. We split a 64k transfer in two 32k. */
3142 tmpLength = 0x8000;
3143 DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
3144 DevExt->PRDCount - 1, StartAddress, PhysicalAddress.u.LowPart, tmpLength);
3145 PRDEntry->PhysAddress = PhysicalAddress.u.LowPart;
3146 PRDEntry->Length = tmpLength;
3147 PRDEntry++;
3148 DevExt->PRDCount++;
3149 if (DevExt->PRDCount > DevExt->PRDMaxCount)
3150 {
3151 return FALSE;
3152 }
3153 PhysicalAddress.u.LowPart += tmpLength;
3154 StartAddress = (PVOID)((ULONG_PTR)StartAddress + tmpLength);
3155 Length -= tmpLength;
3156 PRDEntry->PhysAddress = PhysicalAddress.u.LowPart;
3157 }
3158 DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
3159 DevExt->PRDCount - 1, StartAddress, PhysicalAddress.u.LowPart, tmpLength);
3160 PRDEntry->PhysAddress = PhysicalAddress.u.LowPart;
3161 PRDEntry->Length = tmpLength;
3162 PRDEntry++;
3163 StartAddress = (PVOID)((ULONG_PTR)StartAddress + tmpLength);
3164 PhysicalAddress.u.LowPart += tmpLength;
3165 Length -= tmpLength;
3166 }
3167 }
3168 /* set the end marker in the last PRD */
3169 PRDEntry--;
3170 PRDEntry->Length |= 0x80000000;
3171 /* set the PDR table */
3172 IDEWritePRDTable(DevExt->BusMasterRegisterBase, DevExt->PRDTablePhysicalAddress.u.LowPart);
3173 /* write the DMA command */
3174 IDEWriteDMACommand(DevExt->BusMasterRegisterBase, cmd);
3175 /* reset the status and interrupt bit */
3176 Status = IDEReadDMAStatus(DevExt->BusMasterRegisterBase);
3177 IDEWriteDMAStatus(DevExt->BusMasterRegisterBase, Status | 0x06);
3178 return TRUE;
3179 }
3180 #endif
3181
3182 /* EOF */