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