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