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