Don't wait after the flush command for a non busy hd.
[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 DeviceFound = TRUE;
1175 }
1176 else
1177 {
1178 DPRINT(" No ATAPI drive found!\n");
1179 }
1180 }
1181 else
1182 {
1183 if (AtapiIdentifyDevice(CommandPortBase,
1184 ControlPortBase,
1185 UnitNumber,
1186 FALSE,
1187 &DeviceExtension->DeviceParams[UnitNumber]))
1188 {
1189 DPRINT(" IDE drive found!\n");
1190 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_PRESENT;
1191 DeviceExtension->TransferSize[UnitNumber] = DeviceExtension->DeviceParams[UnitNumber].BytesPerSector;
1192 if ((DeviceExtension->DeviceParams[UnitNumber].RWMultImplemented & 0x8000) &&
1193 (DeviceExtension->DeviceParams[UnitNumber].RWMultImplemented & 0xff) &&
1194 (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0x100) &&
1195 (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0xff))
1196 {
1197 DeviceExtension->TransferSize[UnitNumber] *= (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0xff);
1198 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_MULTI_SECTOR_CMD;
1199 }
1200 if (DeviceExtension->DeviceParams[UnitNumber].SupportedFeatures83 & 0x0400 &&
1201 DeviceExtension->DeviceParams[UnitNumber].EnabledFeatures86 & 0x0400)
1202 {
1203 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_48BIT_ADDRESS;
1204 }
1205 if (DeviceExtension->DeviceParams[UnitNumber].DWordIo)
1206 {
1207 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DWORD_IO;
1208 }
1209 #ifdef ENABLE_DMA
1210 if (AtapiConfigDma(DeviceExtension, UnitNumber))
1211 {
1212 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DMA_CMD;
1213 }
1214 #endif
1215 DeviceFound = TRUE;
1216 }
1217 else
1218 {
1219 DPRINT(" No IDE drive found!\n");
1220 }
1221 }
1222 }
1223
1224 /* Reset pending interrupts */
1225 IDEReadStatus(CommandPortBase);
1226 /* Reenable interrupts */
1227 IDEWriteDriveControl(ControlPortBase, 0);
1228 ScsiPortStallExecution(500);
1229 /* Return with drive 0 selected */
1230 IDEWriteDriveHead(CommandPortBase, IDE_DH_FIXED);
1231 ScsiPortStallExecution(500);
1232
1233 DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound) ? "TRUE" : "FALSE");
1234
1235 return(DeviceFound);
1236 }
1237
1238
1239 /*
1240 * AtapiIdentifyDevice
1241 *
1242 * DESCRIPTION:
1243 * Get the identification block from the drive
1244 *
1245 * RUN LEVEL:
1246 * PASSIVE_LEVEL
1247 *
1248 * ARGUMENTS:
1249 * CommandPort
1250 * Address of the command port
1251 * ControlPort
1252 * Address of the control port
1253 * DriveNum
1254 * The drive index (0,1)
1255 * Atapi
1256 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1257 * DrvParms
1258 * Address to write drive ident block
1259 *
1260 * RETURNS:
1261 * TRUE: The drive identification block was retrieved successfully
1262 * FALSE: an error ocurred
1263 */
1264
1265 static BOOLEAN
1266 AtapiIdentifyDevice(IN ULONG CommandPort,
1267 IN ULONG ControlPort,
1268 IN ULONG DriveNum,
1269 IN BOOLEAN Atapi,
1270 OUT PIDE_DRIVE_IDENTIFY DrvParms)
1271 {
1272 LONG i;
1273 ULONG mode;
1274
1275 /* Get the Drive Identify block from drive or die */
1276 if (AtapiPolledRead(CommandPort,
1277 ControlPort,
1278 0,
1279 1,
1280 0,
1281 0,
1282 0,
1283 (DriveNum ? IDE_DH_DRV1 : 0),
1284 (Atapi ? IDE_CMD_IDENT_ATAPI_DRV : IDE_CMD_IDENT_ATA_DRV),
1285 (PUCHAR)DrvParms) == FALSE)
1286 {
1287 DPRINT("AtapiPolledRead() failed\n");
1288 return FALSE;
1289 }
1290
1291 /* Report on drive parameters if debug mode */
1292 IDESwapBytePairs(DrvParms->SerialNumber, 20);
1293 IDESwapBytePairs(DrvParms->FirmwareRev, 8);
1294 IDESwapBytePairs(DrvParms->ModelNumber, 40);
1295 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1296 DrvParms->ConfigBits,
1297 DrvParms->LogicalCyls,
1298 DrvParms->LogicalHeads,
1299 DrvParms->SectorsPerTrack,
1300 DrvParms->InterSectorGap,
1301 DrvParms->InterSectorGapSize);
1302 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1303 DrvParms->BytesInPLO,
1304 DrvParms->VendorUniqueCnt,
1305 DrvParms->SerialNumber);
1306 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1307 DrvParms->ControllerType,
1308 DrvParms->BufferSize * IDE_SECTOR_BUF_SZ,
1309 DrvParms->ECCByteCnt,
1310 DrvParms->FirmwareRev);
1311 DPRINT("Model:[%.40s]\n", DrvParms->ModelNumber);
1312 DPRINT("RWMultMax?:%04x RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1313 (DrvParms->RWMultImplemented),
1314 (DrvParms->RWMultCurrent) & 0xff,
1315 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0,
1316 (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
1317 DrvParms->MinPIOTransTime,
1318 DrvParms->MinDMATransTime);
1319 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1320 DrvParms->TMCylinders,
1321 DrvParms->TMHeads,
1322 DrvParms->TMSectorsPerTrk,
1323 (ULONG)(DrvParms->TMCapacityLo + (DrvParms->TMCapacityHi << 16)));
1324 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1325 DrvParms->TMSectorCountHi,
1326 DrvParms->TMSectorCountLo,
1327 (ULONG)((DrvParms->TMSectorCountHi << 16) + DrvParms->TMSectorCountLo));
1328 DPRINT("SupportedFeatures83: %x, EnabledFeatures86 %x\n", DrvParms->SupportedFeatures83, DrvParms->EnabledFeatures86);
1329 DPRINT("Max48BitAddress: %I64d\n", *(PULONGLONG)DrvParms->Max48BitAddress);
1330 if (DrvParms->TMFieldsValid & 0x0004)
1331 {
1332 if ((DrvParms->UltraDmaModes >> 8) && (DrvParms->UltraDmaModes & 0xff))
1333 {
1334 mode = 7;
1335 while (!(DrvParms->UltraDmaModes & (0x0100 << mode)))
1336 {
1337 mode--;
1338 }
1339 DPRINT("Ultra DMA mode %d is selected\n", mode);
1340 }
1341 else if ((DrvParms->MultiDmaModes >> 8) & (DrvParms->MultiDmaModes & 0x07))
1342 {
1343 mode = 2;
1344 while(!(DrvParms->MultiDmaModes & (0x01 << mode)))
1345 {
1346 mode--;
1347 }
1348 DPRINT("Multi DMA mode %d is selected\n", mode);
1349 }
1350 }
1351
1352 if (! Atapi && 0 != (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED))
1353 {
1354 /* LBA ATA drives always have a sector size of 512 */
1355 DrvParms->BytesPerSector = 512;
1356 }
1357 else
1358 {
1359 DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
1360 if (DrvParms->BytesPerSector == 0)
1361 {
1362 DrvParms->BytesPerSector = 512;
1363 }
1364 else
1365 {
1366 for (i = 15; i >= 0; i--)
1367 {
1368 if (DrvParms->BytesPerSector & (1 << i))
1369 {
1370 DrvParms->BytesPerSector = 1 << i;
1371 break;
1372 }
1373 }
1374 }
1375 }
1376 DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
1377
1378 return TRUE;
1379 }
1380
1381
1382 // AtapiPolledRead
1383 //
1384 // DESCRIPTION:
1385 // Read a sector of data from the drive in a polled fashion.
1386 //
1387 // RUN LEVEL:
1388 // PASSIVE_LEVEL
1389 //
1390 // ARGUMENTS:
1391 // IN ULONG CommandPort Address of command port for drive
1392 // IN ULONG ControlPort Address of control port for drive
1393 // IN UCHAR PreComp Value to write to precomp register
1394 // IN UCHAR SectorCnt Value to write to sectorCnt register
1395 // IN UCHAR SectorNum Value to write to sectorNum register
1396 // IN UCHAR CylinderLow Value to write to CylinderLow register
1397 // IN UCHAR CylinderHigh Value to write to CylinderHigh register
1398 // IN UCHAR DrvHead Value to write to Drive/Head register
1399 // IN UCHAR Command Value to write to Command register
1400 // OUT PUCHAR Buffer Buffer for output data
1401 //
1402 // RETURNS:
1403 // BOOLEAN: TRUE success, FALSE error
1404 //
1405
1406 static BOOLEAN
1407 AtapiPolledRead(IN ULONG CommandPort,
1408 IN ULONG ControlPort,
1409 IN UCHAR PreComp,
1410 IN UCHAR SectorCnt,
1411 IN UCHAR SectorNum,
1412 IN UCHAR CylinderLow,
1413 IN UCHAR CylinderHigh,
1414 IN UCHAR DrvHead,
1415 IN UCHAR Command,
1416 OUT PUCHAR Buffer)
1417 {
1418 ULONG SectorCount = 0;
1419 ULONG RetryCount;
1420 BOOLEAN Junk = FALSE;
1421 UCHAR Status;
1422
1423 /* Wait for BUSY to clear */
1424 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1425 {
1426 Status = IDEReadStatus(CommandPort);
1427 if (!(Status & IDE_SR_BUSY))
1428 {
1429 break;
1430 }
1431 ScsiPortStallExecution(10);
1432 }
1433 DPRINT("status=%02x\n", Status);
1434 DPRINT("waited %ld usecs for busy to clear\n", RetryCount * 10);
1435 if (RetryCount >= IDE_MAX_BUSY_RETRIES)
1436 {
1437 DPRINT("Drive is BUSY for too long\n");
1438 return FALSE;
1439 }
1440
1441 /* Write Drive/Head to select drive */
1442 IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
1443 ScsiPortStallExecution(500);
1444
1445 /* Disable interrupts */
1446 IDEWriteDriveControl(ControlPort, IDE_DC_nIEN);
1447 ScsiPortStallExecution(500);
1448
1449 #if 0
1450 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1451 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1452 {
1453 Status = IDEReadStatus(CommandPort);
1454 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1455 {
1456 break;
1457 }
1458 ScsiPortStallExecution(10);
1459 }
1460 if (RetryCount >= IDE_MAX_BUSY_RETRIES)
1461 {
1462 return FALSE;
1463 }
1464 #endif
1465
1466 /* Issue command to drive */
1467 if (DrvHead & IDE_DH_LBA)
1468 {
1469 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1470 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1471 ((DrvHead & 0x0f) << 24) + (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
1472 SectorCnt,
1473 Command);
1474 }
1475 else
1476 {
1477 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1478 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1479 CylinderHigh,
1480 CylinderLow,
1481 DrvHead & 0x0f,
1482 SectorNum,
1483 SectorCnt,
1484 Command);
1485 }
1486
1487 /* Setup command parameters */
1488 IDEWritePrecomp(CommandPort, PreComp);
1489 IDEWriteSectorCount(CommandPort, SectorCnt);
1490 IDEWriteSectorNum(CommandPort, SectorNum);
1491 IDEWriteCylinderHigh(CommandPort, CylinderHigh);
1492 IDEWriteCylinderLow(CommandPort, CylinderLow);
1493 IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
1494
1495 /* Issue the command */
1496 IDEWriteCommand(CommandPort, Command);
1497 ScsiPortStallExecution(50);
1498
1499 /* wait for DRQ or error */
1500 for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
1501 {
1502 Status = IDEReadStatus(CommandPort);
1503 if (!(Status & IDE_SR_BUSY))
1504 {
1505 if (Status & IDE_SR_ERR)
1506 {
1507 IDEWriteDriveControl(ControlPort, 0);
1508 ScsiPortStallExecution(50);
1509 IDEReadStatus(CommandPort);
1510
1511 return FALSE;
1512 }
1513
1514 if (Status & IDE_SR_DRQ)
1515 {
1516 break;
1517 }
1518 else
1519 {
1520 IDEWriteDriveControl(ControlPort, 0);
1521 ScsiPortStallExecution(50);
1522 IDEReadStatus(CommandPort);
1523
1524 return FALSE;
1525 }
1526 }
1527 ScsiPortStallExecution(10);
1528 }
1529
1530 /* timed out */
1531 if (RetryCount >= IDE_MAX_POLL_RETRIES)
1532 {
1533 IDEWriteDriveControl(ControlPort, 0);
1534 ScsiPortStallExecution(50);
1535 IDEReadStatus(CommandPort);
1536
1537 return FALSE;
1538 }
1539
1540 while (1)
1541 {
1542 /* Read data into buffer */
1543 if (Junk == FALSE)
1544 {
1545 IDEReadBlock(CommandPort, Buffer, IDE_SECTOR_BUF_SZ);
1546 Buffer += IDE_SECTOR_BUF_SZ;
1547 }
1548 else
1549 {
1550 UCHAR JunkBuffer[IDE_SECTOR_BUF_SZ];
1551 IDEReadBlock(CommandPort, JunkBuffer, IDE_SECTOR_BUF_SZ);
1552 }
1553 SectorCount++;
1554
1555 /* Check for error or more sectors to read */
1556 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1557 {
1558 Status = IDEReadStatus(CommandPort);
1559 if (!(Status & IDE_SR_BUSY))
1560 {
1561 if (Status & IDE_SR_ERR)
1562 {
1563 IDEWriteDriveControl(ControlPort, 0);
1564 ScsiPortStallExecution(50);
1565 IDEReadStatus(CommandPort);
1566
1567 return FALSE;
1568 }
1569 if (Status & IDE_SR_DRQ)
1570 {
1571 if (SectorCount >= SectorCnt)
1572 {
1573 DPRINT("Buffer size exceeded!\n");
1574 Junk = TRUE;
1575 }
1576 break;
1577 }
1578 else
1579 {
1580 if (SectorCount > SectorCnt)
1581 {
1582 DPRINT("Read %lu sectors of junk!\n",
1583 SectorCount - SectorCnt);
1584 }
1585 IDEWriteDriveControl(ControlPort, 0);
1586 ScsiPortStallExecution(50);
1587 IDEReadStatus(CommandPort);
1588
1589 return TRUE;
1590 }
1591 }
1592 }
1593 }
1594 }
1595
1596
1597 // ------------------------------------------- Nondiscardable statics
1598
1599 static ULONG
1600 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1601 IN PSCSI_REQUEST_BLOCK Srb)
1602 {
1603 UCHAR ByteCountHigh;
1604 UCHAR ByteCountLow;
1605 ULONG Retries;
1606 ULONG CdbSize;
1607 UCHAR Status;
1608
1609 DPRINT("AtapiSendAtapiCommand() called!\n");
1610
1611 if (Srb->PathId != 0)
1612 {
1613 Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
1614 return(SRB_STATUS_INVALID_PATH_ID);
1615 }
1616
1617 if (Srb->TargetId > 1)
1618 {
1619 Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
1620 return(SRB_STATUS_INVALID_TARGET_ID);
1621 }
1622
1623 if (Srb->Lun != 0)
1624 {
1625 Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
1626 return(SRB_STATUS_INVALID_LUN);
1627 }
1628
1629 if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_PRESENT))
1630 {
1631 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1632 return(SRB_STATUS_NO_DEVICE);
1633 }
1634
1635 if (Srb->Cdb[0] == SCSIOP_MODE_SENSE)
1636 {
1637 Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
1638 return (SRB_STATUS_INVALID_REQUEST);
1639 }
1640
1641 DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
1642 Srb->TargetId);
1643
1644 if (Srb->Cdb[0] == SCSIOP_INQUIRY)
1645 return(AtapiInquiry(DeviceExtension,
1646 Srb));
1647
1648 /* Set pointer to data buffer. */
1649 DeviceExtension->DataBuffer = (PUCHAR)Srb->DataBuffer;
1650 DeviceExtension->DataTransferLength = Srb->DataTransferLength;
1651 DeviceExtension->CurrentSrb = Srb;
1652
1653 DPRINT("BufferAddress %x, BufferLength %d\n", Srb->DataBuffer, Srb->DataTransferLength);
1654
1655 /* Wait for BUSY to clear */
1656 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1657 {
1658 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1659 if (!(Status & IDE_SR_BUSY))
1660 {
1661 break;
1662 }
1663 ScsiPortStallExecution(10);
1664 }
1665 DPRINT("status=%02x\n", Status);
1666 DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
1667 if (Retries >= IDE_MAX_BUSY_RETRIES)
1668 {
1669 DPRINT("Drive is BUSY for too long\n");
1670 return(SRB_STATUS_BUSY);
1671 }
1672
1673 /* Select the desired drive */
1674 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
1675 IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
1676
1677 /* Wait a little while */
1678 ScsiPortStallExecution(50);
1679
1680 #if 0
1681 /* Wait for BUSY to clear and DRDY to assert */
1682 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1683 {
1684 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1685 if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1686 {
1687 break;
1688 }
1689 ScsiPortStallExecution(10);
1690 }
1691 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
1692 if (Retries >= IDE_MAX_BUSY_RETRIES)
1693 {
1694 DPRINT("Drive is BUSY for too long after drive select\n");
1695 return(SRB_STATUS_BUSY);
1696 }
1697 #endif
1698
1699 #ifdef ENABLE_DMA
1700 if ((DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DMA_CMD) &&
1701 (Srb->Cdb[0] == SCSIOP_READ || Srb->Cdb[0] == SCSIOP_WRITE))
1702 {
1703 DeviceExtension->UseDma = AtapiInitDma(DeviceExtension, Srb, Srb->SrbFlags & SRB_FLAGS_DATA_IN ? 1 << 3 : 0);
1704 }
1705 else
1706 {
1707 DeviceExtension->UseDma = FALSE;
1708 }
1709 #endif
1710
1711 if (DeviceExtension->DataTransferLength < 0x10000)
1712 {
1713 ByteCountLow = (UCHAR)(DeviceExtension->DataTransferLength & 0xFF);
1714 ByteCountHigh = (UCHAR)(DeviceExtension->DataTransferLength >> 8);
1715 }
1716 else
1717 {
1718 ByteCountLow = 0xFF;
1719 ByteCountHigh = 0xFF;
1720 }
1721
1722 /* Set feature register */
1723 #ifdef ENABLE_DMA
1724 IDEWritePrecomp(DeviceExtension->CommandPortBase, DeviceExtension->UseDma ? 1 : 0);
1725 #else
1726 IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
1727 #endif
1728
1729 /* Set command packet length */
1730 IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, ByteCountHigh);
1731 IDEWriteCylinderLow(DeviceExtension->CommandPortBase, ByteCountLow);
1732
1733 /* Issue command to drive */
1734 #ifdef ENABLE_DMA
1735 if (DeviceExtension->UseDma)
1736 {
1737 AtapiExecuteCommand(DeviceExtension, IDE_CMD_PACKET, AtapiDmaPacketInterrupt);
1738 }
1739 else
1740 #endif
1741 {
1742 AtapiExecuteCommand(DeviceExtension, IDE_CMD_PACKET, AtapiPacketInterrupt);
1743 }
1744
1745 /* Wait for DRQ to assert */
1746 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1747 {
1748 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1749 if ((Status & IDE_SR_DRQ))
1750 {
1751 break;
1752 }
1753 ScsiPortStallExecution(10);
1754 }
1755
1756 /* Convert special SCSI SRBs to ATAPI format */
1757 switch (Srb->Cdb[0])
1758 {
1759 case SCSIOP_FORMAT_UNIT:
1760 case SCSIOP_MODE_SELECT:
1761 AtapiScsiSrbToAtapi (Srb);
1762 break;
1763 }
1764
1765 CdbSize = ((DeviceExtension->DeviceParams[Srb->TargetId].ConfigBits & 0x3) == 1) ? 16 : 12;
1766 DPRINT("CdbSize: %lu\n", CdbSize);
1767
1768 /* Write command packet */
1769 IDEWriteBlock(DeviceExtension->CommandPortBase,
1770 (PUSHORT)Srb->Cdb,
1771 CdbSize);
1772
1773 #ifdef ENABLE_DMA
1774 if (DeviceExtension->UseDma)
1775 {
1776 BYTE DmaCommand;
1777 /* start DMA */
1778 DmaCommand = IDEReadDMACommand(DeviceExtension->BusMasterRegisterBase);
1779 IDEWriteDMACommand(DeviceExtension->BusMasterRegisterBase, DmaCommand|0x01);
1780 }
1781 #endif
1782 DPRINT("AtapiSendAtapiCommand() done\n");
1783
1784 return(SRB_STATUS_PENDING);
1785 }
1786
1787
1788 static ULONG
1789 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1790 IN PSCSI_REQUEST_BLOCK Srb)
1791 {
1792 ULONG SrbStatus = SRB_STATUS_SUCCESS;
1793
1794 DPRINT("AtapiSendIdeCommand() called!\n");
1795
1796 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1797 Srb->PathId,
1798 Srb->TargetId,
1799 Srb->Lun);
1800
1801 if (Srb->PathId != 0)
1802 {
1803 Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
1804 return(SRB_STATUS_INVALID_PATH_ID);
1805 }
1806
1807 if (Srb->TargetId > 1)
1808 {
1809 Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
1810 return(SRB_STATUS_INVALID_TARGET_ID);
1811 }
1812
1813 if (Srb->Lun != 0)
1814 {
1815 Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
1816 return(SRB_STATUS_INVALID_LUN);
1817 }
1818
1819 if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_PRESENT))
1820 {
1821 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1822 return(SRB_STATUS_NO_DEVICE);
1823 }
1824
1825 switch (Srb->Cdb[0])
1826 {
1827 case SCSIOP_INQUIRY:
1828 SrbStatus = AtapiInquiry(DeviceExtension,
1829 Srb);
1830 break;
1831
1832 case SCSIOP_READ_CAPACITY:
1833 SrbStatus = AtapiReadCapacity(DeviceExtension,
1834 Srb);
1835 break;
1836
1837 case SCSIOP_READ:
1838 case SCSIOP_WRITE:
1839 SrbStatus = AtapiReadWrite(DeviceExtension,
1840 Srb);
1841 break;
1842
1843 case SCSIOP_SYNCHRONIZE_CACHE:
1844 SrbStatus = AtapiFlushCache(DeviceExtension,
1845 Srb);
1846 break;
1847
1848 case SCSIOP_TEST_UNIT_READY:
1849 SrbStatus = AtapiTestUnitReady(DeviceExtension,
1850 Srb);
1851 break;
1852
1853 case SCSIOP_MODE_SENSE:
1854
1855 case SCSIOP_VERIFY:
1856 case SCSIOP_START_STOP_UNIT:
1857 case SCSIOP_REQUEST_SENSE:
1858 break;
1859
1860 default:
1861 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1862 Srb->Cdb[0]);
1863 SrbStatus = SRB_STATUS_INVALID_REQUEST;
1864 break;
1865 }
1866
1867 DPRINT("AtapiSendIdeCommand() done!\n");
1868
1869 return(SrbStatus);
1870 }
1871
1872
1873 static ULONG
1874 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1875 PSCSI_REQUEST_BLOCK Srb)
1876 {
1877 PIDE_DRIVE_IDENTIFY DeviceParams;
1878 PINQUIRYDATA InquiryData;
1879 ULONG i;
1880
1881 DPRINT("SCSIOP_INQUIRY: DeviceExtension %p TargetId: %lu\n",
1882 DeviceExtension, Srb->TargetId);
1883
1884 InquiryData = Srb->DataBuffer;
1885 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1886
1887 /* clear buffer */
1888 for (i = 0; i < Srb->DataTransferLength; i++)
1889 {
1890 ((PUCHAR)Srb->DataBuffer)[i] = 0;
1891 }
1892
1893 /* set device class */
1894 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
1895 {
1896 /* get it from the ATAPI configuration word */
1897 InquiryData->DeviceType = (DeviceParams->ConfigBits >> 8) & 0x1F;
1898 DPRINT("Device class: %u\n", InquiryData->DeviceType);
1899
1900 /* Don't flush CD/DVD drives */
1901 if (InquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE)
1902 {
1903 DeviceExtension->DeviceFlags[Srb->TargetId] |= DEVICE_NO_FLUSH;
1904 }
1905 }
1906 else
1907 {
1908 /* hard-disk */
1909 InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
1910 }
1911
1912 DPRINT("ConfigBits: 0x%x\n", DeviceParams->ConfigBits);
1913 if (DeviceParams->ConfigBits & 0x80)
1914 {
1915 DPRINT("Removable media!\n");
1916 InquiryData->RemovableMedia = 1;
1917 }
1918
1919 for (i = 0; i < 20; i += 2)
1920 {
1921 InquiryData->VendorId[i] =
1922 ((PUCHAR)DeviceParams->ModelNumber)[i];
1923 InquiryData->VendorId[i+1] =
1924 ((PUCHAR)DeviceParams->ModelNumber)[i+1];
1925 }
1926
1927 for (i = 0; i < 4; i++)
1928 {
1929 InquiryData->ProductId[12+i] = ' ';
1930 }
1931
1932 for (i = 0; i < 4; i += 2)
1933 {
1934 InquiryData->ProductRevisionLevel[i] =
1935 ((PUCHAR)DeviceParams->FirmwareRev)[i];
1936 InquiryData->ProductRevisionLevel[i+1] =
1937 ((PUCHAR)DeviceParams->FirmwareRev)[i+1];
1938 }
1939
1940 InquiryData->AdditionalLength = 31;
1941
1942 DPRINT("VendorId: '%.20s'\n", InquiryData->VendorId);
1943
1944 Srb->SrbStatus = SRB_STATUS_SUCCESS;
1945 return(SRB_STATUS_SUCCESS);
1946 }
1947
1948
1949 static ULONG
1950 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1951 PSCSI_REQUEST_BLOCK Srb)
1952 {
1953 PREAD_CAPACITY_DATA CapacityData;
1954 PIDE_DRIVE_IDENTIFY DeviceParams;
1955 LARGE_INTEGER LastSector;
1956
1957 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb->TargetId);
1958 CapacityData = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
1959 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1960
1961 /* Set sector (block) size to 512 bytes (big-endian). */
1962 CapacityData->BytesPerBlock = 0x20000;
1963
1964 /* Calculate last sector (big-endian). */
1965 if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
1966 {
1967 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
1968 {
1969 ((PUSHORT)&LastSector)[0] = DeviceParams->Max48BitAddress[0];
1970 ((PUSHORT)&LastSector)[1] = DeviceParams->Max48BitAddress[1];
1971 ((PUSHORT)&LastSector)[2] = DeviceParams->Max48BitAddress[2];
1972 ((PUSHORT)&LastSector)[3] = DeviceParams->Max48BitAddress[3];
1973 LastSector.QuadPart -= 1;
1974
1975 }
1976 else
1977 {
1978 LastSector.u.HighPart = 0;
1979 LastSector.u.LowPart = (ULONG)((DeviceParams->TMSectorCountHi << 16) +
1980 DeviceParams->TMSectorCountLo)-1;
1981 }
1982 }
1983 else
1984 {
1985 LastSector.u.HighPart = 0;
1986 LastSector.u.LowPart = (ULONG)(DeviceParams->LogicalCyls *
1987 DeviceParams->LogicalHeads *
1988 DeviceParams->SectorsPerTrack)-1;
1989 }
1990 if (LastSector.u.HighPart)
1991 {
1992 DPRINT1("Disk is too large for our implementation (%I64d sectors\n", LastSector.QuadPart);
1993 KEBUGCHECK(0);
1994 }
1995
1996 CapacityData->LogicalBlockAddress = (((PUCHAR)&LastSector)[0] << 24) |
1997 (((PUCHAR)&LastSector)[1] << 16) |
1998 (((PUCHAR)&LastSector)[2] << 8) |
1999 ((PUCHAR)&LastSector)[3];
2000
2001 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
2002 LastSector,
2003 LastSector,
2004 CapacityData->LogicalBlockAddress);
2005
2006 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2007 return(SRB_STATUS_SUCCESS);
2008 }
2009
2010
2011 static ULONG
2012 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
2013 PSCSI_REQUEST_BLOCK Srb)
2014 {
2015 PIDE_DRIVE_IDENTIFY DeviceParams;
2016 ULONG StartingSector;
2017 ULONG SectorCount;
2018 UCHAR CylinderHigh[2];
2019 UCHAR CylinderLow[2];
2020 UCHAR DrvHead;
2021 UCHAR SectorNumber[2];
2022 UCHAR Command;
2023 ULONG Retries;
2024 UCHAR Status;
2025 BOOLEAN FASTCALL (*Handler)(PATAPI_MINIPORT_EXTENSION DevExt);
2026
2027 DPRINT("AtapiReadWrite() called!\n");
2028 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
2029 Srb->TargetId);
2030
2031 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
2032
2033 /* Get starting sector number from CDB. */
2034 StartingSector = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
2035 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
2036 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
2037 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
2038
2039 SectorCount = (Srb->DataTransferLength + DeviceParams->BytesPerSector - 1) /
2040 DeviceParams->BytesPerSector;
2041
2042 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
2043 StartingSector,
2044 Srb->DataTransferLength,
2045 SectorCount);
2046
2047 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
2048 {
2049 SectorNumber[0] = StartingSector & 0xff;
2050 CylinderLow[0] = (StartingSector >> 8) & 0xff;
2051 CylinderHigh[0] = (StartingSector >> 16) & 0xff;
2052 SectorNumber[1] = (StartingSector >> 24) & 0xff;
2053 CylinderLow[1] = 0;
2054 CylinderHigh[1] = 0;
2055 DrvHead = (Srb->TargetId ? IDE_DH_DRV1 : 0) | IDE_DH_LBA;
2056 #if 0
2057 DPRINT("%s:BUS=%04x:DRV=%d:LBA48=1:BLK=%08d:SC=%02x:CM=%02x\n",
2058 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
2059 DeviceExtension->CommandPortBase,
2060 DrvHead & IDE_DH_DRV1 ? 1 : 0,
2061 (SectorNumber[1] << 24) +
2062 (CylinderHigh[0] << 16) + (CylinderLow[0] << 8) + DectorNumberLow[0],
2063 SectorCount,
2064 Command);
2065 #endif
2066 }
2067 else if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
2068 {
2069 SectorNumber[0] = StartingSector & 0xff;
2070 CylinderLow[0] = (StartingSector >> 8) & 0xff;
2071 CylinderHigh[0] = (StartingSector >> 16) & 0xff;
2072 SectorNumber[1] = 0;
2073 CylinderLow[1] = 0;
2074 CylinderHigh[1] = 0;
2075 DrvHead = ((StartingSector >> 24) & 0x0f) |
2076 (Srb->TargetId ? IDE_DH_DRV1 : 0) |
2077 IDE_DH_LBA;
2078
2079 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
2080 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
2081 DeviceExtension->CommandPortBase,
2082 DrvHead & IDE_DH_DRV1 ? 1 : 0,
2083 ((DrvHead & 0x0f) << 24) +
2084 (CylinderHigh[0] << 16) + (CylinderLow[0] << 8) + SectorNumber[0],
2085 SectorCount,
2086 Command);
2087 }
2088 else
2089 {
2090 SectorNumber[0] = (StartingSector % DeviceParams->SectorsPerTrack) + 1;
2091 StartingSector /= DeviceParams->SectorsPerTrack;
2092 DrvHead = (StartingSector % DeviceParams->LogicalHeads) |
2093 (Srb->TargetId ? IDE_DH_DRV1 : 0);
2094 StartingSector /= DeviceParams->LogicalHeads;
2095 CylinderLow[0] = StartingSector & 0xff;
2096 CylinderHigh[0] = StartingSector >> 8;
2097 SectorNumber[1] = 0;
2098 CylinderLow[1] = 0;
2099 CylinderHigh[1] = 0;
2100
2101 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
2102 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
2103 DeviceExtension->CommandPortBase,
2104 DrvHead & IDE_DH_DRV1 ? 1 : 0,
2105 CylinderHigh[0],
2106 CylinderLow[0],
2107 DrvHead & 0x0f,
2108 SectorNumber[0],
2109 SectorCount,
2110 Command);
2111 }
2112
2113 /* Set pointer to data buffer. */
2114 DeviceExtension->DataBuffer = (PUCHAR)Srb->DataBuffer;
2115 DeviceExtension->DataTransferLength = Srb->DataTransferLength;
2116
2117 DeviceExtension->CurrentSrb = Srb;
2118
2119 /* wait for BUSY to clear */
2120 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
2121 {
2122 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2123 if (!(Status & IDE_SR_BUSY))
2124 {
2125 break;
2126 }
2127 ScsiPortStallExecution(10);
2128 }
2129 DPRINT("status=%02x\n", Status);
2130 DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
2131 if (Retries >= IDE_MAX_BUSY_RETRIES)
2132 {
2133 DPRINT ("Drive is BUSY for too long\n");
2134 return(SRB_STATUS_BUSY);
2135 }
2136
2137 /* Select the desired drive */
2138 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
2139 IDE_DH_FIXED | DrvHead);
2140
2141 ScsiPortStallExecution(10);
2142 #if 0
2143 /* wait for BUSY to clear and DRDY to assert */
2144 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
2145 {
2146 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2147 if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
2148 {
2149 break;
2150 }
2151 ScsiPortStallExecution(10);
2152 }
2153 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
2154 if (Retries >= IDE_MAX_BUSY_RETRIES)
2155 {
2156 DPRINT("Drive is BUSY for too long after drive select\n");
2157 return(SRB_STATUS_BUSY);
2158 }
2159 #endif
2160
2161 /* Setup command parameters */
2162 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
2163 {
2164 IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
2165 IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount >> 8);
2166 IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber[1]);
2167 IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow[1]);
2168 IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh[1]);
2169 }
2170
2171 IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
2172 IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount & 0xff);
2173 IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber[0]);
2174 IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow[0]);
2175 IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh[0]);
2176
2177 IDEWriteDriveHead(DeviceExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
2178
2179 #ifdef ENABLE_DMA
2180 if (DeviceExtension->PRDTable &&
2181 DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DMA_CMD)
2182 {
2183 DeviceExtension->UseDma = AtapiInitDma(DeviceExtension, Srb, Srb->SrbFlags & SRB_FLAGS_DATA_IN ? 1 << 3 : 0);
2184 }
2185 if (DeviceExtension->UseDma)
2186 {
2187 Handler = AtapiDmaInterrupt;
2188 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
2189 {
2190 Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_DMA_EXT : IDE_CMD_WRITE_DMA_EXT;
2191 }
2192 else
2193 {
2194 Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_DMA : IDE_CMD_WRITE_DMA;
2195 }
2196 }
2197 else
2198 #endif
2199 {
2200 Handler = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? AtapiReadInterrupt : AtapiWriteInterrupt;
2201 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_MULTI_SECTOR_CMD)
2202 {
2203 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
2204 {
2205 Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_MULTIPLE_EXT : IDE_CMD_WRITE_MULTIPLE_EXT;
2206 }
2207 else
2208 {
2209 Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_MULTIPLE : IDE_CMD_WRITE_MULTIPLE;
2210 }
2211 }
2212 else
2213 {
2214 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
2215 {
2216 Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_EXT : IDE_CMD_WRITE_EXT;
2217 }
2218 else
2219 {
2220 Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ : IDE_CMD_WRITE;
2221 }
2222 }
2223 }
2224
2225 AtapiExecuteCommand(DeviceExtension, Command, Handler);
2226
2227 #ifdef ENABLE_DMA
2228 if (DeviceExtension->UseDma)
2229 {
2230 BYTE DmaCommand;
2231 /* start DMA */
2232 DmaCommand = IDEReadDMACommand(DeviceExtension->BusMasterRegisterBase);
2233 IDEWriteDMACommand(DeviceExtension->BusMasterRegisterBase, DmaCommand|0x01);
2234 }
2235 else
2236 #endif
2237 {
2238 if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
2239 {
2240 /* Write data block */
2241 PUCHAR TargetAddress;
2242 ULONG TransferSize;
2243
2244 /* Wait for controller ready */
2245 for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
2246 {
2247 BYTE Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2248 if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
2249 {
2250 break;
2251 }
2252 ScsiPortStallExecution(10);
2253 }
2254 if (Retries >= IDE_MAX_WRITE_RETRIES)
2255 {
2256 DPRINT1("Drive is BUSY for too long after sending write command\n");
2257 return(SRB_STATUS_BUSY);
2258 }
2259
2260 /* Update DeviceExtension data */
2261 TransferSize = DeviceExtension->TransferSize[Srb->TargetId];
2262 if (DeviceExtension->DataTransferLength < TransferSize)
2263 {
2264 TransferSize = DeviceExtension->DataTransferLength;
2265 }
2266
2267 TargetAddress = DeviceExtension->DataBuffer;
2268 DeviceExtension->DataBuffer += TransferSize;
2269 DeviceExtension->DataTransferLength -= TransferSize;
2270
2271 /* Write data block */
2272 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
2273 {
2274 IDEWriteBlock32(DeviceExtension->CommandPortBase,
2275 TargetAddress,
2276 TransferSize);
2277 }
2278 else
2279 {
2280 IDEWriteBlock(DeviceExtension->CommandPortBase,
2281 TargetAddress,
2282 TransferSize);
2283 }
2284 }
2285 }
2286
2287 DPRINT("AtapiReadWrite() done!\n");
2288
2289 /* Wait for interrupt. */
2290 return(SRB_STATUS_PENDING);
2291 }
2292
2293
2294 static ULONG
2295 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension,
2296 PSCSI_REQUEST_BLOCK Srb)
2297 {
2298 ULONG Retries;
2299 UCHAR Status;
2300
2301 DPRINT("AtapiFlushCache() called!\n");
2302 DPRINT("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
2303 Srb->TargetId);
2304
2305 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_NO_FLUSH)
2306 {
2307 /*
2308 * NOTE: Don't flush the cache for CD/DVD drives. Although
2309 * the ATAPI-6 standard allows that, it has been experimentally
2310 * proved that it can damage some broken LG drives. Afterall
2311 * it doesn't make sense to flush cache on devices we don't
2312 * write to.
2313 */
2314 return SRB_STATUS_INVALID_REQUEST;
2315 }
2316
2317 if (!(DeviceExtension->DeviceParams[Srb->TargetId].SupportedFeatures83 & 0x1000))
2318 {
2319 /* The device states it doesn't support the command */
2320 DPRINT("The drive doesn't support FLUSH_CACHE\n");
2321 return SRB_STATUS_INVALID_REQUEST;
2322 }
2323
2324 /* Wait for BUSY to clear */
2325 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
2326 {
2327 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2328 if (!(Status & IDE_SR_BUSY))
2329 {
2330 break;
2331 }
2332 ScsiPortStallExecution(10);
2333 }
2334 DPRINT("Status=%02x\n", Status);
2335 DPRINT("Waited %ld usecs for busy to clear\n", Retries * 10);
2336 if (Retries >= IDE_MAX_BUSY_RETRIES)
2337 {
2338 DPRINT1("Drive is BUSY for too long\n");
2339 return(SRB_STATUS_BUSY);
2340 }
2341
2342 /* Select the desired drive */
2343 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
2344 IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
2345 ScsiPortStallExecution(10);
2346
2347 /* Issue command to drive */
2348 AtapiExecuteCommand(DeviceExtension,
2349 DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS ? IDE_CMD_FLUSH_CACHE_EXT : IDE_CMD_FLUSH_CACHE,
2350 AtapiNoDataInterrupt);
2351
2352
2353 DPRINT("AtapiFlushCache() done!\n");
2354
2355 /* Wait for interrupt. */
2356 return(SRB_STATUS_PENDING);
2357 }
2358
2359
2360 static ULONG
2361 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension,
2362 PSCSI_REQUEST_BLOCK Srb)
2363 {
2364 ULONG Retries;
2365 UCHAR Status;
2366 UCHAR Error;
2367
2368 DPRINT1("AtapiTestUnitReady() called!\n");
2369
2370 DPRINT1("SCSIOP_TEST_UNIT_READY: TargetId: %lu\n",
2371 Srb->TargetId);
2372
2373 /* Return success if media status is not supported */
2374 if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_MEDIA_STATUS))
2375 {
2376 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2377 return(SRB_STATUS_SUCCESS);
2378 }
2379
2380 /* Wait for BUSY to clear */
2381 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
2382 {
2383 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2384 if (!(Status & IDE_SR_BUSY))
2385 {
2386 break;
2387 }
2388 ScsiPortStallExecution(10);
2389 }
2390 DPRINT1("Status=%02x\n", Status);
2391 DPRINT1("Waited %ld usecs for busy to clear\n", Retries * 10);
2392 if (Retries >= IDE_MAX_BUSY_RETRIES)
2393 {
2394 DPRINT1("Drive is BUSY for too long\n");
2395 return(SRB_STATUS_BUSY);
2396 }
2397
2398 /* Select the desired drive */
2399 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
2400 IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
2401 ScsiPortStallExecution(10);
2402
2403 /* Issue command to drive */
2404 AtapiExecuteCommand(DeviceExtension, IDE_CMD_GET_MEDIA_STATUS, AtapiNoDataInterrupt);
2405
2406 /* Wait for controller ready */
2407 for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
2408 {
2409 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2410 if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
2411 {
2412 break;
2413 }
2414 ScsiPortStallExecution(10);
2415 }
2416 if (Retries >= IDE_MAX_WRITE_RETRIES)
2417 {
2418 DPRINT1("Drive is BUSY for too long after sending write command\n");
2419 DeviceExtension->Handler = NULL;
2420 return(SRB_STATUS_BUSY);
2421 }
2422
2423 if (Status & IDE_SR_ERR)
2424 {
2425 Error = IDEReadError(DeviceExtension->CommandPortBase);
2426 if (Error == IDE_ER_UNC)
2427 {
2428 CHECKPOINT1;
2429 /* Handle write protection 'error' */
2430 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2431 DeviceExtension->Handler = NULL;
2432 return(SRB_STATUS_SUCCESS);
2433 }
2434 else
2435 {
2436 CHECKPOINT1;
2437 /* Indicate expecting an interrupt. */
2438 return(SRB_STATUS_PENDING);
2439 }
2440 }
2441
2442 DeviceExtension->Handler = NULL;
2443
2444 DPRINT1("AtapiTestUnitReady() done!\n");
2445
2446 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2447 return(SRB_STATUS_SUCCESS);
2448 }
2449
2450
2451 static UCHAR
2452 AtapiErrorToScsi(PVOID DeviceExtension,
2453 PSCSI_REQUEST_BLOCK Srb)
2454 {
2455 PATAPI_MINIPORT_EXTENSION DevExt;
2456 ULONG CommandPortBase;
2457 ULONG ControlPortBase;
2458 UCHAR ErrorReg;
2459 UCHAR ScsiStatus;
2460 UCHAR SrbStatus;
2461
2462 DPRINT("AtapiErrorToScsi() called\n");
2463
2464 DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
2465
2466 CommandPortBase = DevExt->CommandPortBase;
2467 ControlPortBase = DevExt->ControlPortBase;
2468
2469 ErrorReg = IDEReadError(CommandPortBase);
2470
2471 if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
2472 {
2473 switch (ErrorReg >> 4)
2474 {
2475 case SCSI_SENSE_NO_SENSE:
2476 DPRINT("ATAPI error: SCSI_SENSE_NO_SENSE\n");
2477 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2478 SrbStatus = SRB_STATUS_ERROR;
2479 break;
2480
2481 case SCSI_SENSE_RECOVERED_ERROR:
2482 DPRINT("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
2483 ScsiStatus = 0;
2484 SrbStatus = SRB_STATUS_SUCCESS;
2485 break;
2486
2487 case SCSI_SENSE_NOT_READY:
2488 DPRINT("ATAPI error: SCSI_SENSE_NOT_READY\n");
2489 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2490 SrbStatus = SRB_STATUS_ERROR;
2491 break;
2492
2493 case SCSI_SENSE_MEDIUM_ERROR:
2494 DPRINT("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
2495 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2496 SrbStatus = SRB_STATUS_ERROR;
2497 break;
2498
2499 case SCSI_SENSE_HARDWARE_ERROR:
2500 DPRINT("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
2501 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2502 SrbStatus = SRB_STATUS_ERROR;
2503 break;
2504
2505 case SCSI_SENSE_ILLEGAL_REQUEST:
2506 DPRINT("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
2507 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2508 SrbStatus = SRB_STATUS_ERROR;
2509 break;
2510
2511 case SCSI_SENSE_UNIT_ATTENTION:
2512 DPRINT("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
2513 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2514 SrbStatus = SRB_STATUS_ERROR;
2515 break;
2516
2517 case SCSI_SENSE_DATA_PROTECT:
2518 DPRINT("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
2519 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2520 SrbStatus = SRB_STATUS_ERROR;
2521 break;
2522
2523 case SCSI_SENSE_BLANK_CHECK:
2524 DPRINT("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
2525 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2526 SrbStatus = SRB_STATUS_ERROR;
2527 break;
2528
2529 case SCSI_SENSE_ABORTED_COMMAND:
2530 DPRINT("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
2531 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2532 SrbStatus = SRB_STATUS_ERROR;
2533 break;
2534
2535 default:
2536 DPRINT("ATAPI error: Invalid sense key\n");
2537 ScsiStatus = 0;
2538 SrbStatus = SRB_STATUS_ERROR;
2539 break;
2540 }
2541 }
2542 else
2543 {
2544 DPRINT1("IDE error: %02x\n", ErrorReg);
2545
2546 ScsiStatus = 0;
2547 SrbStatus = SRB_STATUS_ERROR;
2548
2549 #if 0
2550 UCHAR SectorCount, SectorNum, CylinderLow, CylinderHigh;
2551 UCHAR DriveHead;
2552
2553 CylinderLow = IDEReadCylinderLow(CommandPortBase);
2554 CylinderHigh = IDEReadCylinderHigh(CommandPortBase);
2555 DriveHead = IDEReadDriveHead(CommandPortBase);
2556 SectorCount = IDEReadSectorCount(CommandPortBase);
2557 SectorNum = IDEReadSectorNum(CommandPortBase);
2558
2559 DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
2560 ErrorReg,
2561 CylinderLow,
2562 CylinderHigh,
2563 SectorCount,
2564 SectorNum);
2565 #endif
2566 }
2567
2568
2569
2570 Srb->ScsiStatus = ScsiStatus;
2571
2572 DPRINT("AtapiErrorToScsi() done\n");
2573
2574 return(SrbStatus);
2575 }
2576
2577
2578 static VOID
2579 AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb)
2580 {
2581 DPRINT("AtapiConvertScsiToAtapi() called\n");
2582
2583 Srb->CdbLength = 12;
2584
2585 switch (Srb->Cdb[0])
2586 {
2587 case SCSIOP_FORMAT_UNIT:
2588 Srb->Cdb[0] = ATAPI_FORMAT_UNIT;
2589 break;
2590
2591 case SCSIOP_MODE_SELECT:
2592 {
2593 PATAPI_MODE_SELECT12 AtapiModeSelect;
2594 UCHAR Length;
2595
2596 AtapiModeSelect = (PATAPI_MODE_SELECT12)Srb->Cdb;
2597 Length = ((PCDB)Srb->Cdb)->MODE_SELECT.ParameterListLength;
2598
2599 RtlZeroMemory (Srb->Cdb,
2600 MAXIMUM_CDB_SIZE);
2601 AtapiModeSelect->OperationCode = ATAPI_MODE_SELECT;
2602 AtapiModeSelect->PFBit = 1;
2603 AtapiModeSelect->ParameterListLengthMsb = 0;
2604 AtapiModeSelect->ParameterListLengthLsb = Length;
2605 }
2606 break;
2607 }
2608 }
2609
2610 static VOID FASTCALL
2611 AtapiCompleteRequest(PATAPI_MINIPORT_EXTENSION DevExt,
2612 UCHAR SrbStatus)
2613 {
2614 PSCSI_REQUEST_BLOCK Srb;
2615 Srb = DevExt->CurrentSrb;
2616
2617 DPRINT("AtapiCompleteRequest(DevExt %x, SrbStatus %x)\n", DevExt, SrbStatus);
2618
2619 Srb->SrbStatus = SrbStatus;
2620 if (SrbStatus == SRB_STATUS_ERROR)
2621 {
2622 Srb->SrbStatus = AtapiErrorToScsi((PVOID)DevExt, Srb);
2623 }
2624 else if (SrbStatus == SRB_STATUS_DATA_OVERRUN)
2625 {
2626 Srb->DataTransferLength -= DevExt->DataTransferLength;
2627 }
2628
2629 DevExt->Handler = NULL;
2630 ScsiPortNotification(RequestComplete, (PVOID)DevExt, Srb);
2631 ScsiPortNotification(NextRequest, (PVOID)DevExt, NULL);
2632 }
2633
2634 #ifdef ENABLE_DMA
2635 static BOOLEAN FASTCALL
2636 AtapiDmaPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
2637 {
2638 BYTE SrbStatus;
2639 BYTE DmaCommand;
2640 BYTE DmaStatus;
2641 BYTE Status;
2642 BYTE Error;
2643 BYTE SensKey;
2644
2645 DPRINT("AtapiPacketDmaInterrupt\n");
2646
2647 DevExt->UseDma = FALSE;
2648
2649 /* stop DMA */
2650 DmaCommand = IDEReadDMACommand(DevExt->BusMasterRegisterBase);
2651 IDEWriteDMACommand(DevExt->BusMasterRegisterBase, DmaCommand & 0xfe);
2652 /* get DMA status */
2653 DmaStatus = IDEReadDMAStatus(DevExt->BusMasterRegisterBase);
2654 /* clear the INTR & ERROR bits */
2655 IDEWriteDMAStatus(DevExt->BusMasterRegisterBase, DmaStatus | 0x06);
2656
2657 Status = IDEReadStatus(DevExt->CommandPortBase);
2658 DPRINT("DriveStatus: %x\n", Status);
2659
2660 if (Status & (IDE_SR_BUSY|IDE_SR_ERR))
2661 {
2662 if (Status & IDE_SR_ERR)
2663 {
2664 Error = IDEReadError(DevExt->CommandPortBase);
2665 SensKey = Error >> 4;
2666 DPRINT("DriveError: %x, SenseKey: %x\n", Error, SensKey);
2667 }
2668 SrbStatus = SRB_STATUS_ERROR;
2669 }
2670 else
2671 {
2672 if ((DmaStatus & 0x07) != 0x04)
2673 {
2674 DPRINT("DmaStatus: %02x\n", DmaStatus);
2675 SrbStatus = SRB_STATUS_ERROR;
2676 }
2677 else
2678 {
2679 SrbStatus = STATUS_SUCCESS;
2680 }
2681 }
2682 AtapiCompleteRequest(DevExt, SrbStatus);
2683 DPRINT("AtapiDmaPacketInterrupt() done\n");
2684 return TRUE;
2685 }
2686 #endif
2687
2688 static BOOLEAN FASTCALL
2689 AtapiPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
2690 {
2691 PSCSI_REQUEST_BLOCK Srb;
2692 BYTE Status;
2693 BYTE IntReason;
2694 ULONG TransferSize;
2695 ULONG JunkSize = 0;
2696 BOOL IsLastBlock;
2697 PBYTE TargetAddress;
2698 ULONG Retries;
2699 BYTE SrbStatus;
2700 BYTE Error;
2701 BYTE SensKey;
2702
2703 DPRINT("AtapiPacketInterrupt()\n");
2704
2705 Srb = DevExt->CurrentSrb;
2706
2707 Status = IDEReadStatus(DevExt->CommandPortBase);
2708 DPRINT("DriveStatus: %x\n", Status);
2709
2710 if (Status & (IDE_SR_BUSY|IDE_SR_ERR))
2711 {
2712 if (Status & IDE_SR_ERR)
2713 {
2714 Error = IDEReadError(DevExt->CommandPortBase);
2715 SensKey = Error >> 4;
2716 DPRINT("DriveError: %x, SenseKey: %x\n", Error, SensKey);
2717 }
2718
2719 AtapiCompleteRequest(DevExt, SRB_STATUS_ERROR);
2720 DPRINT("AtapiPacketInterrupt() done\n");
2721 return TRUE;
2722 }
2723
2724 IntReason = IDEReadSectorCount(DevExt->CommandPortBase);
2725 TransferSize = IDEReadCylinderLow(DevExt->CommandPortBase);
2726 TransferSize += IDEReadCylinderHigh(DevExt->CommandPortBase) << 8;
2727
2728 if (!(Status & IDE_SR_DRQ))
2729 {
2730 if (DevExt->DataTransferLength > 0)
2731 {
2732 DPRINT1("AtapiPacketInterrupt: data underrun (%d bytes), command was %02x\n",
2733 DevExt->DataTransferLength, Srb->Cdb[0]);
2734 SrbStatus = SRB_STATUS_DATA_OVERRUN;
2735 }
2736 else
2737 {
2738 SrbStatus = SRB_STATUS_SUCCESS;
2739 }
2740 AtapiCompleteRequest(DevExt, SrbStatus);
2741 DPRINT("AtapiPacketInterrupt() done\n");
2742 return TRUE;
2743 }
2744
2745 TargetAddress = DevExt->DataBuffer;
2746
2747 if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
2748 {
2749 DPRINT("read data\n");
2750 if (DevExt->DataTransferLength <= TransferSize)
2751 {
2752 JunkSize = TransferSize - DevExt->DataTransferLength;
2753 TransferSize = DevExt->DataTransferLength;
2754
2755 DevExt->DataTransferLength = 0;
2756 IsLastBlock = TRUE;
2757 }
2758 else
2759 {
2760 DevExt->DataTransferLength -= TransferSize;
2761 IsLastBlock = FALSE;
2762 }
2763
2764 DPRINT("TargetAddress %x, TransferSize %d\n", TargetAddress, TransferSize);
2765
2766 DevExt->DataBuffer += TransferSize;
2767
2768 IDEReadBlock(DevExt->CommandPortBase, TargetAddress, TransferSize);
2769
2770 /* check DRQ */
2771 if (IsLastBlock)
2772 {
2773 /* Read remaining junk from device */
2774 while (JunkSize > 0)
2775 {
2776 IDEReadWord(DevExt->CommandPortBase);
2777 JunkSize -= 2;
2778 }
2779
2780 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES && (IDEReadStatus(DevExt->CommandPortBase) & IDE_SR_BUSY); Retries++)
2781 {
2782 ScsiPortStallExecution(10);
2783 }
2784
2785 /* Check for data overrun */
2786 while (IDEReadStatus(DevExt->CommandPortBase) & IDE_SR_DRQ)
2787 {
2788 DPRINT1("AtapiInterrupt(): reading overrun data!\n");
2789 IDEReadWord(DevExt->CommandPortBase);
2790 }
2791 }
2792
2793 SrbStatus = SRB_STATUS_SUCCESS;
2794 }
2795 else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
2796 {
2797 DPRINT("write data\n");
2798 if (DevExt->DataTransferLength < TransferSize)
2799 {
2800 TransferSize = DevExt->DataTransferLength;
2801 }
2802
2803 TargetAddress = DevExt->DataBuffer;
2804
2805 DPRINT("TargetAddress %x, TransferSize %x\n", TargetAddress, TransferSize);
2806
2807 DevExt->DataBuffer += TransferSize;
2808 DevExt->DataTransferLength -= TransferSize;
2809
2810 /* Write the sector */
2811 IDEWriteBlock(DevExt->CommandPortBase, TargetAddress, TransferSize);
2812 SrbStatus = SRB_STATUS_SUCCESS;
2813 IsLastBlock = FALSE;
2814 }
2815 else
2816 {
2817 DPRINT("Unspecified transfer direction!\n");
2818 SrbStatus = SRB_STATUS_SUCCESS;
2819 IsLastBlock = TRUE;
2820 }
2821 if (IsLastBlock)
2822 {
2823 AtapiCompleteRequest(DevExt, SrbStatus);
2824 }
2825 DPRINT("AtapiPacketInterrupt() done\n");
2826 return TRUE;
2827 }
2828
2829 static BOOLEAN FASTCALL
2830 AtapiNoDataInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
2831 {
2832 BYTE Status;
2833
2834 DPRINT("AtapiNoDataInterrupt()\n");
2835
2836 Status = IDEReadStatus(DevExt->CommandPortBase);
2837 AtapiCompleteRequest(DevExt,
2838 (Status & (IDE_SR_DRDY|IDE_SR_BUSY|IDE_SR_ERR|IDE_SR_DRQ)) == IDE_SR_DRDY ? SRB_STATUS_SUCCESS : SRB_STATUS_ERROR);
2839
2840 DPRINT("AtapiNoDatanterrupt() done!\n");
2841 return TRUE;
2842 }
2843
2844 #ifdef ENABLE_DMA
2845 static BOOLEAN FASTCALL
2846 AtapiDmaInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
2847 {
2848 BYTE DmaCommand;
2849 BYTE DmaStatus;
2850 BYTE Status;
2851
2852 DPRINT("AtapiDmaInterrupt()\n");
2853
2854 DevExt->UseDma = FALSE;
2855 /* stop DMA */
2856 DmaCommand = IDEReadDMACommand(DevExt->BusMasterRegisterBase);
2857 IDEWriteDMACommand(DevExt->BusMasterRegisterBase, DmaCommand & 0xfe);
2858 /* get DMA status */
2859 DmaStatus = IDEReadDMAStatus(DevExt->BusMasterRegisterBase);
2860 /* clear the INTR & ERROR bits */
2861 IDEWriteDMAStatus(DevExt->BusMasterRegisterBase, DmaStatus | 0x06);
2862
2863 /* read the drive status */
2864 Status = IDEReadStatus(DevExt->CommandPortBase);
2865 if ((Status & (IDE_SR_DRDY|IDE_SR_BUSY|IDE_SR_ERR|IDE_SR_WERR|IDE_SR_DRQ)) == IDE_SR_DRDY &&
2866 (DmaStatus & 0x07) == 4)
2867 {
2868 AtapiCompleteRequest(DevExt, SRB_STATUS_SUCCESS);
2869 DPRINT("AtapiDmaInterrupt() done\n");
2870 return TRUE;
2871 }
2872 DPRINT1("Status %x\n", Status);
2873 DPRINT1("%x\n", DmaStatus);
2874 AtapiCompleteRequest(DevExt, SRB_STATUS_ERROR);
2875 DPRINT1("AtapiDmaReadInterrupt() done\n");
2876 return TRUE;
2877 }
2878 #endif
2879
2880 static BOOLEAN FASTCALL
2881 AtapiReadInterrupt(PATAPI_MINIPORT_EXTENSION DevExt)
2882 {
2883 PSCSI_REQUEST_BLOCK Srb;
2884 UCHAR DeviceStatus;
2885 BOOLEAN IsLastBlock;
2886 PUCHAR TargetAddress;
2887 ULONG TransferSize;
2888
2889 DPRINT("AtapiReadInterrupt() called!\n");
2890
2891 Srb = DevExt->CurrentSrb;
2892
2893 DeviceStatus = IDEReadStatus(DevExt->CommandPortBase);
2894 if ((DeviceStatus & (IDE_SR_DRQ|IDE_SR_BUSY|IDE_SR_ERR)) != IDE_SR_DRQ)
2895 {
2896 if (DeviceStatus & (IDE_SR_ERR|IDE_SR_DRQ))
2897 {
2898 AtapiCompleteRequest(DevExt, SRB_STATUS_ERROR);
2899 DPRINT("AtapiReadInterrupt() done!\n");
2900 return TRUE;
2901 }
2902 DPRINT("AtapiReadInterrupt() done!\n");
2903 return FALSE;
2904 }
2905
2906 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", DevExt->CommandPortBase, DevExt->ControlPortBase);
2907
2908 /* Update controller/device state variables */
2909 TargetAddress = DevExt->DataBuffer;
2910 TransferSize = DevExt->TransferSize[Srb->TargetId];
2911
2912 DPRINT("TransferLength: %lu\n", Srb->DataTransferLength);
2913 DPRINT("TransferSize: %lu\n", TransferSize);
2914
2915 if (DevExt->DataTransferLength <= TransferSize)
2916 {
2917 TransferSize = DevExt->DataTransferLength;
2918 DevExt->DataTransferLength = 0;
2919 IsLastBlock = TRUE;
2920 }
2921 else
2922 {
2923 DevExt->DataTransferLength -= TransferSize;
2924 IsLastBlock = FALSE;
2925 }
2926 DevExt->DataBuffer += TransferSize;
2927 DPRINT("IsLastBlock == %s\n", (IsLastBlock) ? "TRUE" : "FALSE");
2928
2929 /* Copy the block of data */
2930 if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
2931 {
2932 IDEReadBlock32(DevExt->CommandPortBase, TargetAddress, TransferSize);
2933 }
2934 else
2935 {
2936 IDEReadBlock(DevExt->CommandPortBase, TargetAddress, TransferSize);
2937 }
2938
2939 if (IsLastBlock)
2940 {
2941 AtapiCompleteRequest(DevExt, SRB_STATUS_SUCCESS);
2942 }
2943
2944 DPRINT("AtapiReadInterrupt() done!\n");
2945
2946 return(TRUE);
2947 }
2948
2949 static BOOLEAN FASTCALL
2950 AtapiWriteInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt)
2951 {
2952 PSCSI_REQUEST_BLOCK Srb;
2953 UCHAR DeviceStatus;
2954 BOOLEAN IsLastBlock;
2955 PUCHAR TargetAddress;
2956 ULONG TransferSize;
2957
2958 DPRINT("AtapiWriteInterrupt() called!\n");
2959
2960 DeviceStatus = IDEReadStatus(DevExt->CommandPortBase);
2961 if ((DeviceStatus & (IDE_SR_DRDY|IDE_SR_BUSY|IDE_SR_ERR|IDE_SR_WERR)) != IDE_SR_DRDY)
2962 {
2963 if (DeviceStatus & (IDE_SR_DRDY|IDE_SR_ERR|IDE_SR_WERR))
2964 {
2965 AtapiCompleteRequest(DevExt, SRB_STATUS_ERROR);
2966 DPRINT("AtapiWriteInterrupt() done!\n");
2967 return TRUE;
2968 }
2969 DPRINT("AtapiWriteInterrupt() done!\n");
2970 return FALSE;
2971 }
2972 else
2973 {
2974 Srb = DevExt->CurrentSrb;
2975 TransferSize = DevExt->TransferSize[Srb->TargetId];
2976 if (DevExt->DataTransferLength < TransferSize)
2977 {
2978 TransferSize = DevExt->DataTransferLength;
2979 }
2980 if (TransferSize > 0 && (DeviceStatus & IDE_SR_DRQ))
2981 {
2982 IsLastBlock = FALSE;
2983 TargetAddress = DevExt->DataBuffer;
2984 DevExt->DataBuffer += TransferSize;
2985 DevExt->DataTransferLength -= TransferSize;
2986
2987 DPRINT("TransferLength: %lu\n", Srb->DataTransferLength);
2988 DPRINT("TransferSize: %lu\n", TransferSize);
2989 /* Write the sector */
2990 if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
2991 {
2992 IDEWriteBlock32(DevExt->CommandPortBase, TargetAddress, TransferSize);
2993 }
2994 else
2995 {
2996 IDEWriteBlock(DevExt->CommandPortBase, TargetAddress, TransferSize);
2997 }
2998 }
2999 else if (DeviceStatus & IDE_SR_DRQ)
3000 {
3001 DPRINT("AtapiWriteInterrupt(): data overrun error!\n");
3002 IsLastBlock = TRUE;
3003 }
3004 else if (TransferSize > 0 && !(DeviceStatus & IDE_SR_DRQ))
3005 {
3006 DPRINT1("%d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", TransferSize);
3007 IsLastBlock = TRUE;
3008 }
3009 else
3010 {
3011 IsLastBlock = TRUE;
3012 }
3013 if (IsLastBlock)
3014 {
3015 AtapiCompleteRequest(DevExt, SRB_STATUS_SUCCESS);
3016 }
3017 DPRINT("AtapiWriteInterrupt() done!\n");
3018 return TRUE;
3019 }
3020 }
3021
3022 static VOID
3023 AtapiExecuteCommand(PATAPI_MINIPORT_EXTENSION DevExt,
3024 BYTE command,
3025 BOOLEAN FASTCALL (*Handler)(PATAPI_MINIPORT_EXTENSION))
3026 {
3027 if (DevExt->Handler != NULL)
3028 {
3029 DPRINT1("DevExt->Handler is already set!!\n");
3030 }
3031 DevExt->Handler = Handler;
3032 IDEWriteCommand(DevExt->CommandPortBase, command);
3033 ScsiPortStallExecution(1);
3034 }
3035
3036 #ifdef ENABLE_DMA
3037 static BOOLEAN
3038 AtapiInitDma(PATAPI_MINIPORT_EXTENSION DevExt,
3039 PSCSI_REQUEST_BLOCK Srb,
3040 BYTE cmd)
3041 {
3042 PVOID StartAddress;
3043 PVOID EndAddress;
3044 PPRD PRDEntry = DevExt->PRDTable;
3045 SCSI_PHYSICAL_ADDRESS PhysicalAddress;
3046 ULONG Length;
3047 ULONG tmpLength;
3048 BYTE Status;
3049
3050 DPRINT("AtapiInitDma()\n");
3051
3052 StartAddress = Srb->DataBuffer;
3053 EndAddress = (PVOID)((ULONG_PTR)StartAddress + Srb->DataTransferLength);
3054 DevExt->PRDCount = 0;
3055
3056 while (StartAddress < EndAddress)
3057 {
3058 PhysicalAddress = ScsiPortGetPhysicalAddress(DevExt, Srb, StartAddress, &Length);
3059 if (PhysicalAddress.QuadPart == 0LL || Length == 0)
3060 {
3061 return FALSE;
3062 }
3063
3064 while (Length)
3065 {
3066 /* calculate the length up to the next 64k boundary */
3067 tmpLength = 0x10000 - (PhysicalAddress.u.LowPart & 0xffff);
3068 if (tmpLength > Length)
3069 {
3070 tmpLength = Length;
3071 }
3072 DevExt->PRDCount++;
3073 if (DevExt->PRDCount > DevExt->PRDMaxCount)
3074 {
3075 return FALSE;
3076 }
3077 if (tmpLength == 0x10000)
3078 {
3079 /* Some dirty controllers cannot handle 64k transfers. We split a 64k transfer in two 32k. */
3080 tmpLength = 0x8000;
3081 DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
3082 DevExt->PRDCount - 1, StartAddress, PhysicalAddress.u.LowPart, tmpLength);
3083 PRDEntry->PhysAddress = PhysicalAddress.u.LowPart;
3084 PRDEntry->Length = tmpLength;
3085 PRDEntry++;
3086 DevExt->PRDCount++;
3087 if (DevExt->PRDCount > DevExt->PRDMaxCount)
3088 {
3089 return FALSE;
3090 }
3091 PhysicalAddress.u.LowPart += tmpLength;
3092 StartAddress = (PVOID)((ULONG_PTR)StartAddress + tmpLength);
3093 Length -= tmpLength;
3094 PRDEntry->PhysAddress = PhysicalAddress.u.LowPart;
3095 }
3096 DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
3097 DevExt->PRDCount - 1, StartAddress, PhysicalAddress.u.LowPart, tmpLength);
3098 PRDEntry->PhysAddress = PhysicalAddress.u.LowPart;
3099 PRDEntry->Length = tmpLength;
3100 PRDEntry++;
3101 StartAddress = (PVOID)((ULONG_PTR)StartAddress + tmpLength);
3102 PhysicalAddress.u.LowPart += tmpLength;
3103 Length -= tmpLength;
3104 }
3105 }
3106 /* set the end marker in the last PRD */
3107 PRDEntry--;
3108 PRDEntry->Length |= 0x80000000;
3109 /* set the PDR table */
3110 IDEWritePRDTable(DevExt->BusMasterRegisterBase, DevExt->PRDTablePhysicalAddress.u.LowPart);
3111 /* write the DMA command */
3112 IDEWriteDMACommand(DevExt->BusMasterRegisterBase, cmd);
3113 /* reset the status and interrupt bit */
3114 Status = IDEReadDMAStatus(DevExt->BusMasterRegisterBase);
3115 IDEWriteDMAStatus(DevExt->BusMasterRegisterBase, Status | 0x06);
3116 return TRUE;
3117 }
3118 #endif
3119
3120 /* EOF */