7105f9a5d95b8eaa95f621284f9851c8bedcfc06
[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 Srb->SrbStatus = (UCHAR)Result;
951
952 ScsiPortNotification(RequestComplete,
953 DeviceExtension,
954 Srb);
955 ScsiPortNotification(NextRequest,
956 DeviceExtension,
957 NULL);
958 }
959 else
960 {
961 DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
962 }
963
964 DPRINT("AtapiStartIo() done\n");
965
966 return(TRUE);
967 }
968
969 static BOOLEAN STDCALL
970 AtapiInterrupt(IN PVOID DeviceExtension)
971 {
972 PATAPI_MINIPORT_EXTENSION DevExt;
973 BYTE Status;
974 DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
975
976 if (DevExt->Handler == NULL)
977 {
978 Status = IDEReadAltStatus(DevExt->ControlPortBase);
979 if ((Status & (IDE_SR_DRDY|IDE_SR_BUSY|IDE_SR_ERR|IDE_SR_DRQ)) != IDE_SR_DRDY)
980 {
981 static ULONG Count = 0;
982 Count++;
983 DPRINT1("Unexpected Interrupt, CommandPort=%04x, Status=%02x, Count=%ld\n",
984 DevExt->CommandPortBase, Status, Count);
985 }
986 return FALSE;
987 }
988 #ifdef ENABLE_DMA
989 if (DevExt->UseDma)
990 {
991 Status = IDEReadDMAStatus(DevExt->BusMasterRegisterBase);
992 if (!(Status & 0x04))
993 {
994 return FALSE;
995 }
996 }
997 else
998 #endif
999 {
1000 Status = IDEReadAltStatus(DevExt->ControlPortBase);
1001 if (Status & IDE_SR_BUSY)
1002 {
1003 return FALSE;
1004 }
1005 }
1006 return DevExt->Handler(DevExt);
1007 }
1008
1009 // ---------------------------------------------------- Discardable statics
1010
1011 #ifdef ENABLE_DMA
1012 static BOOLEAN
1013 AtapiConfigDma(PATAPI_MINIPORT_EXTENSION DeviceExtension, ULONG UnitNumber)
1014 {
1015 BOOLEAN Result = FALSE;
1016 BYTE Status;
1017
1018 if (UnitNumber < 2)
1019 {
1020 if (DeviceExtension->PRDTable)
1021 {
1022 if (DeviceExtension->DeviceParams[UnitNumber].Capabilities & IDE_DRID_DMA_SUPPORTED)
1023 {
1024 if ((DeviceExtension->DeviceParams[UnitNumber].TMFieldsValid & 0x0004) &&
1025 (DeviceExtension->DeviceParams[UnitNumber].UltraDmaModes & 0x7F00))
1026 {
1027 Result = TRUE;
1028 }
1029 else if (DeviceExtension->DeviceParams[UnitNumber].TMFieldsValid & 0x0002)
1030 {
1031 if ((DeviceExtension->DeviceParams[UnitNumber].MultiDmaModes & 0x0404) == 0x0404)
1032 {
1033 Result = TRUE;
1034 }
1035 #if 0
1036 /* FIXME:
1037 * should we support single mode dma ?
1038 */
1039 else if ((DeviceExtension->DeviceParams[UnitNumber].DmaModes & 0x0404) == 0x0404)
1040 {
1041 Result = TRUE;
1042 }
1043 #endif
1044 }
1045 Status = IDEReadDMAStatus(DeviceExtension->BusMasterRegisterBase);
1046 if (Result)
1047 {
1048 IDEWriteDMAStatus(DeviceExtension->BusMasterRegisterBase, Status | (UnitNumber ? 0x40 : 0x20));
1049 }
1050 else
1051 {
1052 IDEWriteDMAStatus(DeviceExtension->BusMasterRegisterBase, Status & (UnitNumber ? ~0x40 : ~0x20));
1053 }
1054 }
1055 }
1056 }
1057 return Result;
1058 }
1059 #endif
1060
1061 /**********************************************************************
1062 * NAME INTERNAL
1063 * AtapiFindDevices
1064 *
1065 * DESCRIPTION
1066 * Searches for devices on the given port.
1067 *
1068 * RUN LEVEL
1069 * PASSIVE_LEVEL
1070 *
1071 * ARGUMENTS
1072 * DeviceExtension
1073 * Port device specific information.
1074 *
1075 * ConfigInfo
1076 * Port configuration information.
1077 *
1078 * RETURN VALUE
1079 * TRUE: At least one device is attached to the port.
1080 * FALSE: No device is attached to the port.
1081 */
1082
1083 static BOOLEAN
1084 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1085 PPORT_CONFIGURATION_INFORMATION ConfigInfo)
1086 {
1087 BOOLEAN DeviceFound = FALSE;
1088 ULONG CommandPortBase;
1089 ULONG ControlPortBase;
1090 ULONG UnitNumber;
1091 ULONG Retries;
1092 UCHAR High;
1093 UCHAR Low;
1094
1095 DPRINT("AtapiFindDevices() called\n");
1096
1097 CommandPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
1098 DPRINT(" CommandPortBase: %x\n", CommandPortBase);
1099
1100 ControlPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[1].RangeStart);
1101 DPRINT(" ControlPortBase: %x\n", ControlPortBase);
1102
1103 for (UnitNumber = 0; UnitNumber < 2; UnitNumber++)
1104 {
1105 /* Select drive */
1106 IDEWriteDriveHead(CommandPortBase,
1107 IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
1108 ScsiPortStallExecution(500);
1109
1110 /* Disable interrupts */
1111 IDEWriteDriveControl(ControlPortBase,
1112 IDE_DC_nIEN);
1113 ScsiPortStallExecution(500);
1114
1115 /* Check if a device is attached to the interface */
1116 IDEWriteCylinderHigh(CommandPortBase, 0xaa);
1117 IDEWriteCylinderLow(CommandPortBase, 0x55);
1118
1119 High = IDEReadCylinderHigh(CommandPortBase);
1120 Low = IDEReadCylinderLow(CommandPortBase);
1121
1122 IDEWriteCylinderHigh(CommandPortBase, 0);
1123 IDEWriteCylinderLow(CommandPortBase, 0);
1124
1125 if (Low != 0x55 || High != 0xaa)
1126 {
1127 DPRINT("No Drive found. UnitNumber %d CommandPortBase %x\n", UnitNumber, CommandPortBase);
1128 continue;
1129 }
1130
1131 AtapiExecuteCommand(DeviceExtension, IDE_CMD_RESET, NULL);
1132
1133 for (Retries = 0; Retries < 20000; Retries++)
1134 {
1135 if (!(IDEReadStatus(CommandPortBase) & IDE_SR_BUSY))
1136 {
1137 break;
1138 }
1139 ScsiPortStallExecution(150);
1140 }
1141 if (Retries >= 20000)
1142 {
1143 DPRINT("Timeout on drive %lu\n", UnitNumber);
1144 DeviceExtension->DeviceFlags[UnitNumber] &= ~DEVICE_PRESENT;
1145 continue;
1146 }
1147
1148 High = IDEReadCylinderHigh(CommandPortBase);
1149 Low = IDEReadCylinderLow(CommandPortBase);
1150
1151 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
1152 UnitNumber,
1153 High,
1154 Low);
1155
1156 if (High == 0xEB && Low == 0x14)
1157 {
1158 if (AtapiIdentifyDevice(CommandPortBase,
1159 ControlPortBase,
1160 UnitNumber,
1161 TRUE,
1162 &DeviceExtension->DeviceParams[UnitNumber]))
1163 {
1164 DPRINT(" ATAPI drive found!\n");
1165 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_PRESENT;
1166 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_ATAPI;
1167 DeviceExtension->TransferSize[UnitNumber] =
1168 DeviceExtension->DeviceParams[UnitNumber].BytesPerSector;
1169 #ifdef ENABLE_DMA
1170 if (AtapiConfigDma(DeviceExtension, UnitNumber))
1171 {
1172 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DMA_CMD;
1173 }
1174 #endif
1175 DeviceFound = TRUE;
1176 }
1177 else
1178 {
1179 DPRINT(" No ATAPI drive found!\n");
1180 }
1181 }
1182 else
1183 {
1184 if (AtapiIdentifyDevice(CommandPortBase,
1185 ControlPortBase,
1186 UnitNumber,
1187 FALSE,
1188 &DeviceExtension->DeviceParams[UnitNumber]))
1189 {
1190 DPRINT(" IDE drive found!\n");
1191 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_PRESENT;
1192 DeviceExtension->TransferSize[UnitNumber] = DeviceExtension->DeviceParams[UnitNumber].BytesPerSector;
1193 if ((DeviceExtension->DeviceParams[UnitNumber].RWMultImplemented & 0x8000) &&
1194 (DeviceExtension->DeviceParams[UnitNumber].RWMultImplemented & 0xff) &&
1195 (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0x100) &&
1196 (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0xff))
1197 {
1198 DeviceExtension->TransferSize[UnitNumber] *= (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0xff);
1199 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_MULTI_SECTOR_CMD;
1200 }
1201 if (DeviceExtension->DeviceParams[UnitNumber].SupportedFeatures83 & 0x0400 &&
1202 DeviceExtension->DeviceParams[UnitNumber].EnabledFeatures86 & 0x0400)
1203 {
1204 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_48BIT_ADDRESS;
1205 }
1206 if (DeviceExtension->DeviceParams[UnitNumber].DWordIo)
1207 {
1208 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DWORD_IO;
1209 }
1210 #ifdef ENABLE_DMA
1211 if (AtapiConfigDma(DeviceExtension, UnitNumber))
1212 {
1213 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DMA_CMD;
1214 }
1215 #endif
1216 DeviceFound = TRUE;
1217 }
1218 else
1219 {
1220 DPRINT(" No IDE drive found!\n");
1221 }
1222 }
1223 }
1224
1225 /* Reset pending interrupts */
1226 IDEReadStatus(CommandPortBase);
1227 /* Reenable interrupts */
1228 IDEWriteDriveControl(ControlPortBase, 0);
1229 ScsiPortStallExecution(500);
1230 /* Return with drive 0 selected */
1231 IDEWriteDriveHead(CommandPortBase, IDE_DH_FIXED);
1232 ScsiPortStallExecution(500);
1233
1234 DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound) ? "TRUE" : "FALSE");
1235
1236 return(DeviceFound);
1237 }
1238
1239
1240 /*
1241 * AtapiIdentifyDevice
1242 *
1243 * DESCRIPTION:
1244 * Get the identification block from the drive
1245 *
1246 * RUN LEVEL:
1247 * PASSIVE_LEVEL
1248 *
1249 * ARGUMENTS:
1250 * CommandPort
1251 * Address of the command port
1252 * ControlPort
1253 * Address of the control port
1254 * DriveNum
1255 * The drive index (0,1)
1256 * Atapi
1257 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1258 * DrvParms
1259 * Address to write drive ident block
1260 *
1261 * RETURNS:
1262 * TRUE: The drive identification block was retrieved successfully
1263 * FALSE: an error ocurred
1264 */
1265
1266 static BOOLEAN
1267 AtapiIdentifyDevice(IN ULONG CommandPort,
1268 IN ULONG ControlPort,
1269 IN ULONG DriveNum,
1270 IN BOOLEAN Atapi,
1271 OUT PIDE_DRIVE_IDENTIFY DrvParms)
1272 {
1273 LONG i;
1274 ULONG mode;
1275
1276 /* Get the Drive Identify block from drive or die */
1277 if (AtapiPolledRead(CommandPort,
1278 ControlPort,
1279 0,
1280 1,
1281 0,
1282 0,
1283 0,
1284 (DriveNum ? IDE_DH_DRV1 : 0),
1285 (Atapi ? IDE_CMD_IDENT_ATAPI_DRV : IDE_CMD_IDENT_ATA_DRV),
1286 (PUCHAR)DrvParms) == FALSE)
1287 {
1288 DPRINT("AtapiPolledRead() failed\n");
1289 return FALSE;
1290 }
1291
1292 /* Report on drive parameters if debug mode */
1293 IDESwapBytePairs(DrvParms->SerialNumber, 20);
1294 IDESwapBytePairs(DrvParms->FirmwareRev, 8);
1295 IDESwapBytePairs(DrvParms->ModelNumber, 40);
1296 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1297 DrvParms->ConfigBits,
1298 DrvParms->LogicalCyls,
1299 DrvParms->LogicalHeads,
1300 DrvParms->SectorsPerTrack,
1301 DrvParms->InterSectorGap,
1302 DrvParms->InterSectorGapSize);
1303 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1304 DrvParms->BytesInPLO,
1305 DrvParms->VendorUniqueCnt,
1306 DrvParms->SerialNumber);
1307 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1308 DrvParms->ControllerType,
1309 DrvParms->BufferSize * IDE_SECTOR_BUF_SZ,
1310 DrvParms->ECCByteCnt,
1311 DrvParms->FirmwareRev);
1312 DPRINT("Model:[%.40s]\n", DrvParms->ModelNumber);
1313 DPRINT("RWMultMax?:%04x RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1314 (DrvParms->RWMultImplemented),
1315 (DrvParms->RWMultCurrent) & 0xff,
1316 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0,
1317 (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
1318 DrvParms->MinPIOTransTime,
1319 DrvParms->MinDMATransTime);
1320 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1321 DrvParms->TMCylinders,
1322 DrvParms->TMHeads,
1323 DrvParms->TMSectorsPerTrk,
1324 (ULONG)(DrvParms->TMCapacityLo + (DrvParms->TMCapacityHi << 16)));
1325 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1326 DrvParms->TMSectorCountHi,
1327 DrvParms->TMSectorCountLo,
1328 (ULONG)((DrvParms->TMSectorCountHi << 16) + DrvParms->TMSectorCountLo));
1329 DPRINT("SupportedFeatures83: %x, EnabledFeatures86 %x\n", DrvParms->SupportedFeatures83, DrvParms->EnabledFeatures86);
1330 DPRINT("Max48BitAddress: %I64d\n", *(PULONGLONG)DrvParms->Max48BitAddress);
1331 if (DrvParms->TMFieldsValid & 0x0004)
1332 {
1333 if ((DrvParms->UltraDmaModes >> 8) && (DrvParms->UltraDmaModes & 0xff))
1334 {
1335 mode = 7;
1336 while (!(DrvParms->UltraDmaModes & (0x0100 << mode)))
1337 {
1338 mode--;
1339 }
1340 DPRINT("Ultra DMA mode %d is selected\n", mode);
1341 }
1342 else if ((DrvParms->MultiDmaModes >> 8) & (DrvParms->MultiDmaModes & 0x07))
1343 {
1344 mode = 2;
1345 while(!(DrvParms->MultiDmaModes & (0x01 << mode)))
1346 {
1347 mode--;
1348 }
1349 DPRINT("Multi DMA mode %d is selected\n", mode);
1350 }
1351 }
1352
1353 if (! Atapi && 0 != (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED))
1354 {
1355 /* LBA ATA drives always have a sector size of 512 */
1356 DrvParms->BytesPerSector = 512;
1357 }
1358 else
1359 {
1360 DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
1361 if (DrvParms->BytesPerSector == 0)
1362 {
1363 DrvParms->BytesPerSector = 512;
1364 }
1365 else
1366 {
1367 for (i = 15; i >= 0; i--)
1368 {
1369 if (DrvParms->BytesPerSector & (1 << i))
1370 {
1371 DrvParms->BytesPerSector = 1 << i;
1372 break;
1373 }
1374 }
1375 }
1376 }
1377 DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
1378
1379 return TRUE;
1380 }
1381
1382
1383 // AtapiPolledRead
1384 //
1385 // DESCRIPTION:
1386 // Read a sector of data from the drive in a polled fashion.
1387 //
1388 // RUN LEVEL:
1389 // PASSIVE_LEVEL
1390 //
1391 // ARGUMENTS:
1392 // IN ULONG CommandPort Address of command port for drive
1393 // IN ULONG ControlPort Address of control port for drive
1394 // IN UCHAR PreComp Value to write to precomp register
1395 // IN UCHAR SectorCnt Value to write to sectorCnt register
1396 // IN UCHAR SectorNum Value to write to sectorNum register
1397 // IN UCHAR CylinderLow Value to write to CylinderLow register
1398 // IN UCHAR CylinderHigh Value to write to CylinderHigh register
1399 // IN UCHAR DrvHead Value to write to Drive/Head register
1400 // IN UCHAR Command Value to write to Command register
1401 // OUT PUCHAR Buffer Buffer for output data
1402 //
1403 // RETURNS:
1404 // BOOLEAN: TRUE success, FALSE error
1405 //
1406
1407 static BOOLEAN
1408 AtapiPolledRead(IN ULONG CommandPort,
1409 IN ULONG ControlPort,
1410 IN UCHAR PreComp,
1411 IN UCHAR SectorCnt,
1412 IN UCHAR SectorNum,
1413 IN UCHAR CylinderLow,
1414 IN UCHAR CylinderHigh,
1415 IN UCHAR DrvHead,
1416 IN UCHAR Command,
1417 OUT PUCHAR Buffer)
1418 {
1419 ULONG SectorCount = 0;
1420 ULONG RetryCount;
1421 BOOLEAN Junk = FALSE;
1422 UCHAR Status;
1423
1424 /* Wait for BUSY to clear */
1425 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1426 {
1427 Status = IDEReadStatus(CommandPort);
1428 if (!(Status & IDE_SR_BUSY))
1429 {
1430 break;
1431 }
1432 ScsiPortStallExecution(10);
1433 }
1434 DPRINT("status=%02x\n", Status);
1435 DPRINT("waited %ld usecs for busy to clear\n", RetryCount * 10);
1436 if (RetryCount >= IDE_MAX_BUSY_RETRIES)
1437 {
1438 DPRINT("Drive is BUSY for too long\n");
1439 return FALSE;
1440 }
1441
1442 /* Write Drive/Head to select drive */
1443 IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
1444 ScsiPortStallExecution(500);
1445
1446 /* Disable interrupts */
1447 IDEWriteDriveControl(ControlPort, IDE_DC_nIEN);
1448 ScsiPortStallExecution(500);
1449
1450 #if 0
1451 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1452 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1453 {
1454 Status = IDEReadStatus(CommandPort);
1455 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1456 {
1457 break;
1458 }
1459 ScsiPortStallExecution(10);
1460 }
1461 if (RetryCount >= IDE_MAX_BUSY_RETRIES)
1462 {
1463 return FALSE;
1464 }
1465 #endif
1466
1467 /* Issue command to drive */
1468 if (DrvHead & IDE_DH_LBA)
1469 {
1470 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1471 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1472 ((DrvHead & 0x0f) << 24) + (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
1473 SectorCnt,
1474 Command);
1475 }
1476 else
1477 {
1478 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1479 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1480 CylinderHigh,
1481 CylinderLow,
1482 DrvHead & 0x0f,
1483 SectorNum,
1484 SectorCnt,
1485 Command);
1486 }
1487
1488 /* Setup command parameters */
1489 IDEWritePrecomp(CommandPort, PreComp);
1490 IDEWriteSectorCount(CommandPort, SectorCnt);
1491 IDEWriteSectorNum(CommandPort, SectorNum);
1492 IDEWriteCylinderHigh(CommandPort, CylinderHigh);
1493 IDEWriteCylinderLow(CommandPort, CylinderLow);
1494 IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
1495
1496 /* Issue the command */
1497 IDEWriteCommand(CommandPort, Command);
1498 ScsiPortStallExecution(50);
1499
1500 /* wait for DRQ or error */
1501 for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
1502 {
1503 Status = IDEReadStatus(CommandPort);
1504 if (!(Status & IDE_SR_BUSY))
1505 {
1506 if (Status & IDE_SR_ERR)
1507 {
1508 IDEWriteDriveControl(ControlPort, 0);
1509 ScsiPortStallExecution(50);
1510 IDEReadStatus(CommandPort);
1511
1512 return FALSE;
1513 }
1514
1515 if (Status & IDE_SR_DRQ)
1516 {
1517 break;
1518 }
1519 else
1520 {
1521 IDEWriteDriveControl(ControlPort, 0);
1522 ScsiPortStallExecution(50);
1523 IDEReadStatus(CommandPort);
1524
1525 return FALSE;
1526 }
1527 }
1528 ScsiPortStallExecution(10);
1529 }
1530
1531 /* timed out */
1532 if (RetryCount >= IDE_MAX_POLL_RETRIES)
1533 {
1534 IDEWriteDriveControl(ControlPort, 0);
1535 ScsiPortStallExecution(50);
1536 IDEReadStatus(CommandPort);
1537
1538 return FALSE;
1539 }
1540
1541 while (1)
1542 {
1543 /* Read data into buffer */
1544 if (Junk == FALSE)
1545 {
1546 IDEReadBlock(CommandPort, Buffer, IDE_SECTOR_BUF_SZ);
1547 Buffer += IDE_SECTOR_BUF_SZ;
1548 }
1549 else
1550 {
1551 UCHAR JunkBuffer[IDE_SECTOR_BUF_SZ];
1552 IDEReadBlock(CommandPort, JunkBuffer, IDE_SECTOR_BUF_SZ);
1553 }
1554 SectorCount++;
1555
1556 /* Check for error or more sectors to read */
1557 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1558 {
1559 Status = IDEReadStatus(CommandPort);
1560 if (!(Status & IDE_SR_BUSY))
1561 {
1562 if (Status & IDE_SR_ERR)
1563 {
1564 IDEWriteDriveControl(ControlPort, 0);
1565 ScsiPortStallExecution(50);
1566 IDEReadStatus(CommandPort);
1567
1568 return FALSE;
1569 }
1570 if (Status & IDE_SR_DRQ)
1571 {
1572 if (SectorCount >= SectorCnt)
1573 {
1574 DPRINT("Buffer size exceeded!\n");
1575 Junk = TRUE;
1576 }
1577 break;
1578 }
1579 else
1580 {
1581 if (SectorCount > SectorCnt)
1582 {
1583 DPRINT("Read %lu sectors of junk!\n",
1584 SectorCount - SectorCnt);
1585 }
1586 IDEWriteDriveControl(ControlPort, 0);
1587 ScsiPortStallExecution(50);
1588 IDEReadStatus(CommandPort);
1589
1590 return TRUE;
1591 }
1592 }
1593 }
1594 }
1595 }
1596
1597
1598 // ------------------------------------------- Nondiscardable statics
1599
1600 static ULONG
1601 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1602 IN PSCSI_REQUEST_BLOCK Srb)
1603 {
1604 UCHAR ByteCountHigh;
1605 UCHAR ByteCountLow;
1606 ULONG Retries;
1607 ULONG CdbSize;
1608 UCHAR Status;
1609
1610 DPRINT("AtapiSendAtapiCommand() called!\n");
1611
1612 if (Srb->PathId != 0)
1613 {
1614 Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
1615 return(SRB_STATUS_INVALID_PATH_ID);
1616 }
1617
1618 if (Srb->TargetId > 1)
1619 {
1620 Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
1621 return(SRB_STATUS_INVALID_TARGET_ID);
1622 }
1623
1624 if (Srb->Lun != 0)
1625 {
1626 Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
1627 return(SRB_STATUS_INVALID_LUN);
1628 }
1629
1630 if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_PRESENT))
1631 {
1632 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1633 return(SRB_STATUS_NO_DEVICE);
1634 }
1635
1636 if (Srb->Cdb[0] == SCSIOP_MODE_SENSE)
1637 {
1638 Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
1639 return (SRB_STATUS_INVALID_REQUEST);
1640 }
1641
1642 DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
1643 Srb->TargetId);
1644
1645 if (Srb->Cdb[0] == SCSIOP_INQUIRY)
1646 return(AtapiInquiry(DeviceExtension,
1647 Srb));
1648
1649 /* Set pointer to data buffer. */
1650 DeviceExtension->DataBuffer = (PUCHAR)Srb->DataBuffer;
1651 DeviceExtension->DataTransferLength = Srb->DataTransferLength;
1652 DeviceExtension->CurrentSrb = Srb;
1653
1654 DPRINT("BufferAddress %x, BufferLength %d\n", Srb->DataBuffer, Srb->DataTransferLength);
1655
1656 /* Wait for BUSY to clear */
1657 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1658 {
1659 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1660 if (!(Status & IDE_SR_BUSY))
1661 {
1662 break;
1663 }
1664 ScsiPortStallExecution(10);
1665 }
1666 DPRINT("status=%02x\n", Status);
1667 DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
1668 if (Retries >= IDE_MAX_BUSY_RETRIES)
1669 {
1670 DPRINT("Drive is BUSY for too long\n");
1671 return(SRB_STATUS_BUSY);
1672 }
1673
1674 /* Select the desired drive */
1675 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
1676 IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
1677
1678 /* Wait a little while */
1679 ScsiPortStallExecution(50);
1680
1681 #if 0
1682 /* Wait for BUSY to clear and DRDY to assert */
1683 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1684 {
1685 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1686 if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1687 {
1688 break;
1689 }
1690 ScsiPortStallExecution(10);
1691 }
1692 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
1693 if (Retries >= IDE_MAX_BUSY_RETRIES)
1694 {
1695 DPRINT("Drive is BUSY for too long after drive select\n");
1696 return(SRB_STATUS_BUSY);
1697 }
1698 #endif
1699
1700 #ifdef ENABLE_DMA
1701 if ((DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DMA_CMD) &&
1702 (Srb->Cdb[0] == SCSIOP_READ || Srb->Cdb[0] == SCSIOP_WRITE))
1703 {
1704 DeviceExtension->UseDma = AtapiInitDma(DeviceExtension, Srb, Srb->SrbFlags & SRB_FLAGS_DATA_IN ? 1 << 3 : 0);
1705 }
1706 else
1707 {
1708 DeviceExtension->UseDma = FALSE;
1709 }
1710 #endif
1711
1712 if (DeviceExtension->DataTransferLength < 0x10000)
1713 {
1714 ByteCountLow = (UCHAR)(DeviceExtension->DataTransferLength & 0xFF);
1715 ByteCountHigh = (UCHAR)(DeviceExtension->DataTransferLength >> 8);
1716 }
1717 else
1718 {
1719 ByteCountLow = 0xFF;
1720 ByteCountHigh = 0xFF;
1721 }
1722
1723 /* Set feature register */
1724 #ifdef ENABLE_DMA
1725 IDEWritePrecomp(DeviceExtension->CommandPortBase, DeviceExtension->UseDma ? 1 : 0);
1726 #else
1727 IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
1728 #endif
1729
1730 /* Set command packet length */
1731 IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, ByteCountHigh);
1732 IDEWriteCylinderLow(DeviceExtension->CommandPortBase, ByteCountLow);
1733
1734 /* Issue command to drive */
1735 #ifdef ENABLE_DMA
1736 if (DeviceExtension->UseDma)
1737 {
1738 AtapiExecuteCommand(DeviceExtension, IDE_CMD_PACKET, AtapiDmaPacketInterrupt);
1739 }
1740 else
1741 #endif
1742 {
1743 AtapiExecuteCommand(DeviceExtension, IDE_CMD_PACKET, AtapiPacketInterrupt);
1744 }
1745
1746 /* Wait for DRQ to assert */
1747 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1748 {
1749 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1750 if ((Status & IDE_SR_DRQ))
1751 {
1752 break;
1753 }
1754 ScsiPortStallExecution(10);
1755 }
1756
1757 /* Convert special SCSI SRBs to ATAPI format */
1758 switch (Srb->Cdb[0])
1759 {
1760 case SCSIOP_FORMAT_UNIT:
1761 case SCSIOP_MODE_SELECT:
1762 AtapiScsiSrbToAtapi (Srb);
1763 break;
1764 }
1765
1766 CdbSize = ((DeviceExtension->DeviceParams[Srb->TargetId].ConfigBits & 0x3) == 1) ? 16 : 12;
1767 DPRINT("CdbSize: %lu\n", CdbSize);
1768
1769 /* Write command packet */
1770 IDEWriteBlock(DeviceExtension->CommandPortBase,
1771 (PUSHORT)Srb->Cdb,
1772 CdbSize);
1773
1774 #ifdef ENABLE_DMA
1775 if (DeviceExtension->UseDma)
1776 {
1777 BYTE DmaCommand;
1778 /* start DMA */
1779 DmaCommand = IDEReadDMACommand(DeviceExtension->BusMasterRegisterBase);
1780 IDEWriteDMACommand(DeviceExtension->BusMasterRegisterBase, DmaCommand|0x01);
1781 }
1782 #endif
1783 DPRINT("AtapiSendAtapiCommand() done\n");
1784
1785 return(SRB_STATUS_PENDING);
1786 }
1787
1788
1789 static ULONG
1790 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1791 IN PSCSI_REQUEST_BLOCK Srb)
1792 {
1793 ULONG SrbStatus = SRB_STATUS_SUCCESS;
1794
1795 DPRINT("AtapiSendIdeCommand() called!\n");
1796
1797 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1798 Srb->PathId,
1799 Srb->TargetId,
1800 Srb->Lun);
1801
1802 if (Srb->PathId != 0)
1803 {
1804 Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
1805 return(SRB_STATUS_INVALID_PATH_ID);
1806 }
1807
1808 if (Srb->TargetId > 1)
1809 {
1810 Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
1811 return(SRB_STATUS_INVALID_TARGET_ID);
1812 }
1813
1814 if (Srb->Lun != 0)
1815 {
1816 Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
1817 return(SRB_STATUS_INVALID_LUN);
1818 }
1819
1820 if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_PRESENT))
1821 {
1822 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1823 return(SRB_STATUS_NO_DEVICE);
1824 }
1825
1826 switch (Srb->Cdb[0])
1827 {
1828 case SCSIOP_INQUIRY:
1829 SrbStatus = AtapiInquiry(DeviceExtension,
1830 Srb);
1831 break;
1832
1833 case SCSIOP_READ_CAPACITY:
1834 SrbStatus = AtapiReadCapacity(DeviceExtension,
1835 Srb);
1836 break;
1837
1838 case SCSIOP_READ:
1839 case SCSIOP_WRITE:
1840 SrbStatus = AtapiReadWrite(DeviceExtension,
1841 Srb);
1842 break;
1843
1844 case SCSIOP_SYNCHRONIZE_CACHE:
1845 SrbStatus = AtapiFlushCache(DeviceExtension,
1846 Srb);
1847 break;
1848
1849 case SCSIOP_TEST_UNIT_READY:
1850 SrbStatus = AtapiTestUnitReady(DeviceExtension,
1851 Srb);
1852 break;
1853
1854 case SCSIOP_MODE_SENSE:
1855
1856 case SCSIOP_VERIFY:
1857 case SCSIOP_START_STOP_UNIT:
1858 case SCSIOP_REQUEST_SENSE:
1859 break;
1860
1861 default:
1862 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1863 Srb->Cdb[0]);
1864 SrbStatus = SRB_STATUS_INVALID_REQUEST;
1865 break;
1866 }
1867
1868 DPRINT("AtapiSendIdeCommand() done!\n");
1869
1870 return(SrbStatus);
1871 }
1872
1873
1874 static ULONG
1875 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1876 PSCSI_REQUEST_BLOCK Srb)
1877 {
1878 PIDE_DRIVE_IDENTIFY DeviceParams;
1879 PINQUIRYDATA InquiryData;
1880 ULONG i;
1881
1882 DPRINT("SCSIOP_INQUIRY: DeviceExtension %p TargetId: %lu\n",
1883 DeviceExtension, Srb->TargetId);
1884
1885 InquiryData = Srb->DataBuffer;
1886 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1887
1888 /* clear buffer */
1889 for (i = 0; i < Srb->DataTransferLength; i++)
1890 {
1891 ((PUCHAR)Srb->DataBuffer)[i] = 0;
1892 }
1893
1894 /* set device class */
1895 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
1896 {
1897 /* get it from the ATAPI configuration word */
1898 InquiryData->DeviceType = (DeviceParams->ConfigBits >> 8) & 0x1F;
1899 DPRINT("Device class: %u\n", InquiryData->DeviceType);
1900
1901 /* Don't flush CD/DVD drives */
1902 if (InquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE)
1903 {
1904 DeviceExtension->DeviceFlags[Srb->TargetId] |= DEVICE_NO_FLUSH;
1905 }
1906 }
1907 else
1908 {
1909 /* hard-disk */
1910 InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
1911 }
1912
1913 DPRINT("ConfigBits: 0x%x\n", DeviceParams->ConfigBits);
1914 if (DeviceParams->ConfigBits & 0x80)
1915 {
1916 DPRINT("Removable media!\n");
1917 InquiryData->RemovableMedia = 1;
1918 }
1919
1920 for (i = 0; i < 20; i += 2)
1921 {
1922 InquiryData->VendorId[i] =
1923 ((PUCHAR)DeviceParams->ModelNumber)[i];
1924 InquiryData->VendorId[i+1] =
1925 ((PUCHAR)DeviceParams->ModelNumber)[i+1];
1926 }
1927
1928 for (i = 0; i < 4; i++)
1929 {
1930 InquiryData->ProductId[12+i] = ' ';
1931 }
1932
1933 for (i = 0; i < 4; i += 2)
1934 {
1935 InquiryData->ProductRevisionLevel[i] =
1936 ((PUCHAR)DeviceParams->FirmwareRev)[i];
1937 InquiryData->ProductRevisionLevel[i+1] =
1938 ((PUCHAR)DeviceParams->FirmwareRev)[i+1];
1939 }
1940
1941 InquiryData->AdditionalLength = 31;
1942
1943 DPRINT("VendorId: '%.20s'\n", InquiryData->VendorId);
1944
1945 Srb->SrbStatus = SRB_STATUS_SUCCESS;
1946 return(SRB_STATUS_SUCCESS);
1947 }
1948
1949
1950 static ULONG
1951 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1952 PSCSI_REQUEST_BLOCK Srb)
1953 {
1954 PREAD_CAPACITY_DATA CapacityData;
1955 PIDE_DRIVE_IDENTIFY DeviceParams;
1956 LARGE_INTEGER LastSector;
1957
1958 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb->TargetId);
1959 CapacityData = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
1960 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1961
1962 /* Set sector (block) size to 512 bytes (big-endian). */
1963 CapacityData->BytesPerBlock = 0x20000;
1964
1965 /* Calculate last sector (big-endian). */
1966 if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
1967 {
1968 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
1969 {
1970 ((PUSHORT)&LastSector)[0] = DeviceParams->Max48BitAddress[0];
1971 ((PUSHORT)&LastSector)[1] = DeviceParams->Max48BitAddress[1];
1972 ((PUSHORT)&LastSector)[2] = DeviceParams->Max48BitAddress[2];
1973 ((PUSHORT)&LastSector)[3] = DeviceParams->Max48BitAddress[3];
1974 LastSector.QuadPart -= 1;
1975
1976 }
1977 else
1978 {
1979 LastSector.u.HighPart = 0;
1980 LastSector.u.LowPart = (ULONG)((DeviceParams->TMSectorCountHi << 16) +
1981 DeviceParams->TMSectorCountLo)-1;
1982 }
1983 }
1984 else
1985 {
1986 LastSector.u.HighPart = 0;
1987 LastSector.u.LowPart = (ULONG)(DeviceParams->LogicalCyls *
1988 DeviceParams->LogicalHeads *
1989 DeviceParams->SectorsPerTrack)-1;
1990 }
1991 if (LastSector.u.HighPart)
1992 {
1993 DPRINT1("Disk is too large for our implementation (%I64d sectors\n", LastSector.QuadPart);
1994 KEBUGCHECK(0);
1995 }
1996
1997 CapacityData->LogicalBlockAddress = (((PUCHAR)&LastSector)[0] << 24) |
1998 (((PUCHAR)&LastSector)[1] << 16) |
1999 (((PUCHAR)&LastSector)[2] << 8) |
2000 ((PUCHAR)&LastSector)[3];
2001
2002 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
2003 LastSector,
2004 LastSector,
2005 CapacityData->LogicalBlockAddress);
2006
2007 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2008 return(SRB_STATUS_SUCCESS);
2009 }
2010
2011
2012 static ULONG
2013 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
2014 PSCSI_REQUEST_BLOCK Srb)
2015 {
2016 PIDE_DRIVE_IDENTIFY DeviceParams;
2017 ULONG StartingSector;
2018 ULONG SectorCount;
2019 UCHAR CylinderHigh[2];
2020 UCHAR CylinderLow[2];
2021 UCHAR DrvHead;
2022 UCHAR SectorNumber[2];
2023 UCHAR Command;
2024 ULONG Retries;
2025 UCHAR Status;
2026 BOOLEAN FASTCALL (*Handler)(PATAPI_MINIPORT_EXTENSION DevExt);
2027
2028 DPRINT("AtapiReadWrite() called!\n");
2029 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
2030 Srb->TargetId);
2031
2032 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
2033
2034 /* Get starting sector number from CDB. */
2035 StartingSector = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
2036 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
2037 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
2038 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
2039
2040 SectorCount = (Srb->DataTransferLength + DeviceParams->BytesPerSector - 1) /
2041 DeviceParams->BytesPerSector;
2042
2043 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
2044 StartingSector,
2045 Srb->DataTransferLength,
2046 SectorCount);
2047
2048 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
2049 {
2050 SectorNumber[0] = StartingSector & 0xff;
2051 CylinderLow[0] = (StartingSector >> 8) & 0xff;
2052 CylinderHigh[0] = (StartingSector >> 16) & 0xff;
2053 SectorNumber[1] = (StartingSector >> 24) & 0xff;
2054 CylinderLow[1] = 0;
2055 CylinderHigh[1] = 0;
2056 DrvHead = (Srb->TargetId ? IDE_DH_DRV1 : 0) | IDE_DH_LBA;
2057 #if 0
2058 DPRINT("%s:BUS=%04x:DRV=%d:LBA48=1:BLK=%08d:SC=%02x:CM=%02x\n",
2059 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
2060 DeviceExtension->CommandPortBase,
2061 DrvHead & IDE_DH_DRV1 ? 1 : 0,
2062 (SectorNumber[1] << 24) +
2063 (CylinderHigh[0] << 16) + (CylinderLow[0] << 8) + DectorNumberLow[0],
2064 SectorCount,
2065 Command);
2066 #endif
2067 }
2068 else if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
2069 {
2070 SectorNumber[0] = StartingSector & 0xff;
2071 CylinderLow[0] = (StartingSector >> 8) & 0xff;
2072 CylinderHigh[0] = (StartingSector >> 16) & 0xff;
2073 SectorNumber[1] = 0;
2074 CylinderLow[1] = 0;
2075 CylinderHigh[1] = 0;
2076 DrvHead = ((StartingSector >> 24) & 0x0f) |
2077 (Srb->TargetId ? IDE_DH_DRV1 : 0) |
2078 IDE_DH_LBA;
2079
2080 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
2081 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
2082 DeviceExtension->CommandPortBase,
2083 DrvHead & IDE_DH_DRV1 ? 1 : 0,
2084 ((DrvHead & 0x0f) << 24) +
2085 (CylinderHigh[0] << 16) + (CylinderLow[0] << 8) + SectorNumber[0],
2086 SectorCount,
2087 Command);
2088 }
2089 else
2090 {
2091 SectorNumber[0] = (StartingSector % DeviceParams->SectorsPerTrack) + 1;
2092 StartingSector /= DeviceParams->SectorsPerTrack;
2093 DrvHead = (StartingSector % DeviceParams->LogicalHeads) |
2094 (Srb->TargetId ? IDE_DH_DRV1 : 0);
2095 StartingSector /= DeviceParams->LogicalHeads;
2096 CylinderLow[0] = StartingSector & 0xff;
2097 CylinderHigh[0] = StartingSector >> 8;
2098 SectorNumber[1] = 0;
2099 CylinderLow[1] = 0;
2100 CylinderHigh[1] = 0;
2101
2102 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
2103 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
2104 DeviceExtension->CommandPortBase,
2105 DrvHead & IDE_DH_DRV1 ? 1 : 0,
2106 CylinderHigh[0],
2107 CylinderLow[0],
2108 DrvHead & 0x0f,
2109 SectorNumber[0],
2110 SectorCount,
2111 Command);
2112 }
2113
2114 /* Set pointer to data buffer. */
2115 DeviceExtension->DataBuffer = (PUCHAR)Srb->DataBuffer;
2116 DeviceExtension->DataTransferLength = Srb->DataTransferLength;
2117
2118 DeviceExtension->CurrentSrb = Srb;
2119
2120 /* wait for BUSY to clear */
2121 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
2122 {
2123 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2124 if (!(Status & IDE_SR_BUSY))
2125 {
2126 break;
2127 }
2128 ScsiPortStallExecution(10);
2129 }
2130 DPRINT("status=%02x\n", Status);
2131 DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
2132 if (Retries >= IDE_MAX_BUSY_RETRIES)
2133 {
2134 DPRINT ("Drive is BUSY for too long\n");
2135 return(SRB_STATUS_BUSY);
2136 }
2137
2138 /* Select the desired drive */
2139 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
2140 IDE_DH_FIXED | DrvHead);
2141
2142 ScsiPortStallExecution(10);
2143 #if 0
2144 /* wait for BUSY to clear and DRDY to assert */
2145 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
2146 {
2147 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2148 if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
2149 {
2150 break;
2151 }
2152 ScsiPortStallExecution(10);
2153 }
2154 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
2155 if (Retries >= IDE_MAX_BUSY_RETRIES)
2156 {
2157 DPRINT("Drive is BUSY for too long after drive select\n");
2158 return(SRB_STATUS_BUSY);
2159 }
2160 #endif
2161
2162 /* Setup command parameters */
2163 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
2164 {
2165 IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
2166 IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount >> 8);
2167 IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber[1]);
2168 IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow[1]);
2169 IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh[1]);
2170 }
2171
2172 IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
2173 IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount & 0xff);
2174 IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber[0]);
2175 IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow[0]);
2176 IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh[0]);
2177
2178 IDEWriteDriveHead(DeviceExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
2179
2180 #ifdef ENABLE_DMA
2181 if (DeviceExtension->PRDTable &&
2182 DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DMA_CMD)
2183 {
2184 DeviceExtension->UseDma = AtapiInitDma(DeviceExtension, Srb, Srb->SrbFlags & SRB_FLAGS_DATA_IN ? 1 << 3 : 0);
2185 }
2186 if (DeviceExtension->UseDma)
2187 {
2188 Handler = AtapiDmaInterrupt;
2189 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
2190 {
2191 Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_DMA_EXT : IDE_CMD_WRITE_DMA_EXT;
2192 }
2193 else
2194 {
2195 Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_DMA : IDE_CMD_WRITE_DMA;
2196 }
2197 }
2198 else
2199 #endif
2200 {
2201 Handler = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? AtapiReadInterrupt : AtapiWriteInterrupt;
2202 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_MULTI_SECTOR_CMD)
2203 {
2204 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
2205 {
2206 Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_MULTIPLE_EXT : IDE_CMD_WRITE_MULTIPLE_EXT;
2207 }
2208 else
2209 {
2210 Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_MULTIPLE : IDE_CMD_WRITE_MULTIPLE;
2211 }
2212 }
2213 else
2214 {
2215 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS)
2216 {
2217 Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ_EXT : IDE_CMD_WRITE_EXT;
2218 }
2219 else
2220 {
2221 Command = Srb->SrbFlags & SRB_FLAGS_DATA_IN ? IDE_CMD_READ : IDE_CMD_WRITE;
2222 }
2223 }
2224 }
2225
2226 AtapiExecuteCommand(DeviceExtension, Command, Handler);
2227
2228 #ifdef ENABLE_DMA
2229 if (DeviceExtension->UseDma)
2230 {
2231 BYTE DmaCommand;
2232 /* start DMA */
2233 DmaCommand = IDEReadDMACommand(DeviceExtension->BusMasterRegisterBase);
2234 IDEWriteDMACommand(DeviceExtension->BusMasterRegisterBase, DmaCommand|0x01);
2235 }
2236 else
2237 #endif
2238 {
2239 if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
2240 {
2241 /* Write data block */
2242 PUCHAR TargetAddress;
2243 ULONG TransferSize;
2244
2245 /* Wait for controller ready */
2246 for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
2247 {
2248 BYTE Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2249 if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
2250 {
2251 break;
2252 }
2253 ScsiPortStallExecution(10);
2254 }
2255 if (Retries >= IDE_MAX_WRITE_RETRIES)
2256 {
2257 DPRINT1("Drive is BUSY for too long after sending write command\n");
2258 return(SRB_STATUS_BUSY);
2259 }
2260
2261 /* Update DeviceExtension data */
2262 TransferSize = DeviceExtension->TransferSize[Srb->TargetId];
2263 if (DeviceExtension->DataTransferLength < TransferSize)
2264 {
2265 TransferSize = DeviceExtension->DataTransferLength;
2266 }
2267
2268 TargetAddress = DeviceExtension->DataBuffer;
2269 DeviceExtension->DataBuffer += TransferSize;
2270 DeviceExtension->DataTransferLength -= TransferSize;
2271
2272 /* Write data block */
2273 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
2274 {
2275 IDEWriteBlock32(DeviceExtension->CommandPortBase,
2276 TargetAddress,
2277 TransferSize);
2278 }
2279 else
2280 {
2281 IDEWriteBlock(DeviceExtension->CommandPortBase,
2282 TargetAddress,
2283 TransferSize);
2284 }
2285 }
2286 }
2287
2288 DPRINT("AtapiReadWrite() done!\n");
2289
2290 /* Wait for interrupt. */
2291 return(SRB_STATUS_PENDING);
2292 }
2293
2294
2295 static ULONG
2296 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension,
2297 PSCSI_REQUEST_BLOCK Srb)
2298 {
2299 ULONG Retries;
2300 UCHAR Status;
2301
2302 DPRINT("AtapiFlushCache() called!\n");
2303 DPRINT("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
2304 Srb->TargetId);
2305
2306 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_NO_FLUSH)
2307 {
2308 /*
2309 * NOTE: Don't flush the cache for CD/DVD drives. Although
2310 * the ATAPI-6 standard allows that, it has been experimentally
2311 * proved that it can damage some broken LG drives. Afterall
2312 * it doesn't make sense to flush cache on devices we don't
2313 * write to.
2314 */
2315 return SRB_STATUS_INVALID_REQUEST;
2316 }
2317
2318 if (!(DeviceExtension->DeviceParams[Srb->TargetId].SupportedFeatures83 & 0x1000))
2319 {
2320 /* The device states it doesn't support the command */
2321 DPRINT("The drive doesn't support FLUSH_CACHE\n");
2322 return SRB_STATUS_INVALID_REQUEST;
2323 }
2324
2325 /* Wait for BUSY to clear */
2326 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
2327 {
2328 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2329 if (!(Status & IDE_SR_BUSY))
2330 {
2331 break;
2332 }
2333 ScsiPortStallExecution(10);
2334 }
2335 DPRINT("Status=%02x\n", Status);
2336 DPRINT("Waited %ld usecs for busy to clear\n", Retries * 10);
2337 if (Retries >= IDE_MAX_BUSY_RETRIES)
2338 {
2339 DPRINT1("Drive is BUSY for too long\n");
2340 return(SRB_STATUS_BUSY);
2341 }
2342
2343 /* Select the desired drive */
2344 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
2345 IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
2346 ScsiPortStallExecution(10);
2347
2348 /* Issue command to drive */
2349 AtapiExecuteCommand(DeviceExtension,
2350 DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_48BIT_ADDRESS ? IDE_CMD_FLUSH_CACHE_EXT : IDE_CMD_FLUSH_CACHE,
2351 AtapiNoDataInterrupt);
2352
2353 /* Wait for controller ready */
2354 for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
2355 {
2356 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2357 if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
2358 {
2359 break;
2360 }
2361 ScsiPortStallExecution(10);
2362 }
2363 if (Retries >= IDE_MAX_WRITE_RETRIES)
2364 {
2365 DPRINT1("Drive is BUSY for too long after sending write command\n");
2366 DeviceExtension->Handler = NULL;
2367 return(SRB_STATUS_BUSY);
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 */