Merged duplicate code.
[reactos.git] / reactos / drivers / storage / atapi / atapi.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2001, 2002 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: atapi.c,v 1.40 2003/06/24 21:30:08 ekohl Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS ATAPI miniport driver
23 * FILE: services/storage/atapi/atapi.c
24 * PURPOSE: ATAPI miniport driver
25 * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de)
26 * REVISIONS:
27 * 09-09-2001 Created
28 */
29
30 /*
31 * Note:
32 * This driver is derived from Rex Jolliff's ide driver. Lots of his
33 * routines are still in here although they belong into the higher level
34 * drivers. They will be moved away as soon as possible.
35 */
36
37 /*
38 * TODO:
39 * - implement sending of atapi commands
40 * - handle removable atapi non-cdrom drives
41 */
42
43 #define ENABLE_PCI
44 #define ENABLE_NATIVE_PCI
45 #define ENABLE_ISA
46
47 // -------------------------------------------------------------------------
48
49 #include <ddk/ntddk.h>
50 #include <ddk/srb.h>
51 #include <ddk/scsi.h>
52 #include <ddk/ntddscsi.h>
53
54 #include "atapi.h"
55
56 #define NDEBUG
57 #include <debug.h>
58
59 #define VERSION "0.0.1"
60
61
62 // ------------------------------------------------------- File Static Data
63
64 // ATAPI_MINIPORT_EXTENSION
65 //
66 // DESCRIPTION:
67 // Extension to be placed in each port device object
68 //
69 // ACCESS:
70 // Allocated from NON-PAGED POOL
71 // Available at any IRQL
72 //
73
74 typedef struct _ATAPI_MINIPORT_EXTENSION
75 {
76 IDE_DRIVE_IDENTIFY DeviceParams[2];
77 ULONG DeviceFlags[2];
78 ULONG TransferSize[2];
79
80 ULONG CommandPortBase;
81 ULONG ControlPortBase;
82 ULONG BusMasterRegisterBase;
83
84 BOOLEAN ExpectingInterrupt;
85 PSCSI_REQUEST_BLOCK CurrentSrb;
86
87
88 PUCHAR DataBuffer;
89 ULONG DataTransferLength;
90 } ATAPI_MINIPORT_EXTENSION, *PATAPI_MINIPORT_EXTENSION;
91
92 /* DeviceFlags */
93 #define DEVICE_PRESENT 0x00000001
94 #define DEVICE_ATAPI 0x00000002
95 #define DEVICE_MULTI_SECTOR_CMD 0x00000004
96 #define DEVICE_DWORD_IO 0x00000008
97 #define DEVICE_48BIT_ADDRESS 0x00000010
98 #define DEVICE_MEDIA_STATUS 0x00000020
99
100
101 typedef struct _UNIT_EXTENSION
102 {
103 ULONG Dummy;
104 } UNIT_EXTENSION, *PUNIT_EXTENSION;
105
106 PCI_SLOT_NUMBER LastSlotNumber;
107
108 #ifdef ENABLE_NATIVE_PCI
109 typedef struct _PCI_NATIVE_CONTROLLER
110 {
111 USHORT VendorID;
112 USHORT DeviceID;
113 }
114 PCI_NATIVE_CONTROLLER, *PPCI_NATIVE_CONTROLLER;
115
116 PCI_NATIVE_CONTROLLER const PciNativeController[] =
117 {
118 {
119 0x105A, // Promise
120 0x4D68, // PDC20268, Ultra100TX2
121 },
122 {
123 0x105A, // Promise
124 0x4D30, // PDC20267, Ultra100
125 }
126 };
127 #endif
128
129
130 // ----------------------------------------------- Discardable Declarations
131
132 #ifdef ALLOC_PRAGMA
133
134 // make the initialization routines discardable, so that they
135 // don't waste space
136
137 #pragma alloc_text(init, DriverEntry)
138 #pragma alloc_text(init, IDECreateController)
139 #pragma alloc_text(init, IDEPolledRead)
140
141 // make the PASSIVE_LEVEL routines pageable, so that they don't
142 // waste nonpaged memory
143
144 #pragma alloc_text(page, IDEShutdown)
145 #pragma alloc_text(page, IDEDispatchOpenClose)
146 #pragma alloc_text(page, IDEDispatchRead)
147 #pragma alloc_text(page, IDEDispatchWrite)
148
149 #endif /* ALLOC_PRAGMA */
150
151 // ---------------------------------------------------- Forward Declarations
152
153 static ULONG STDCALL
154 AtapiFindCompatiblePciController(PVOID DeviceExtension,
155 PVOID HwContext,
156 PVOID BusInformation,
157 PCHAR ArgumentString,
158 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
159 PBOOLEAN Again);
160
161 static ULONG STDCALL
162 AtapiFindIsaBusController(PVOID DeviceExtension,
163 PVOID HwContext,
164 PVOID BusInformation,
165 PCHAR ArgumentString,
166 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
167 PBOOLEAN Again);
168
169 static ULONG STDCALL
170 AtapiFindNativePciController(PVOID DeviceExtension,
171 PVOID HwContext,
172 PVOID BusInformation,
173 PCHAR ArgumentString,
174 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
175 PBOOLEAN Again);
176
177 static BOOLEAN STDCALL
178 AtapiInitialize(IN PVOID DeviceExtension);
179
180 static BOOLEAN STDCALL
181 AtapiResetBus(IN PVOID DeviceExtension,
182 IN ULONG PathId);
183
184 static BOOLEAN STDCALL
185 AtapiStartIo(IN PVOID DeviceExtension,
186 IN PSCSI_REQUEST_BLOCK Srb);
187
188 static BOOLEAN STDCALL
189 AtapiInterrupt(IN PVOID DeviceExtension);
190
191 static BOOLEAN
192 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
193 PPORT_CONFIGURATION_INFORMATION ConfigInfo);
194
195 static BOOLEAN
196 AtapiIdentifyDevice(IN ULONG CommandPort,
197 IN ULONG ControlPort,
198 IN ULONG DriveNum,
199 IN BOOLEAN Atapi,
200 OUT PIDE_DRIVE_IDENTIFY DrvParms);
201
202 static BOOLEAN
203 IDEResetController(IN ULONG CommandPort,
204 IN ULONG ControlPort);
205
206 static int
207 AtapiPolledRead(IN ULONG CommandPort,
208 IN ULONG ControlPort,
209 IN BYTE PreComp,
210 IN BYTE SectorCnt,
211 IN BYTE SectorNum,
212 IN BYTE CylinderLow,
213 IN BYTE CylinderHigh,
214 IN BYTE DrvHead,
215 IN BYTE Command,
216 OUT BYTE *Buffer);
217
218
219
220 static ULONG
221 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
222 IN PSCSI_REQUEST_BLOCK Srb);
223
224 static ULONG
225 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
226 IN PSCSI_REQUEST_BLOCK Srb);
227
228 static ULONG
229 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
230 IN PSCSI_REQUEST_BLOCK Srb);
231
232 static ULONG
233 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
234 IN PSCSI_REQUEST_BLOCK Srb);
235
236 static ULONG
237 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
238 IN PSCSI_REQUEST_BLOCK Srb);
239
240 static ULONG
241 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension,
242 PSCSI_REQUEST_BLOCK Srb);
243
244 static ULONG
245 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension,
246 PSCSI_REQUEST_BLOCK Srb);
247
248 static UCHAR
249 AtapiErrorToScsi(PVOID DeviceExtension,
250 PSCSI_REQUEST_BLOCK Srb);
251
252 // ---------------------------------------------------------------- Inlines
253
254 void
255 IDESwapBytePairs(char *Buf,
256 int Cnt)
257 {
258 char t;
259 int i;
260
261 for (i = 0; i < Cnt; i += 2)
262 {
263 t = Buf[i];
264 Buf[i] = Buf[i+1];
265 Buf[i+1] = t;
266 }
267 }
268
269
270 // ------------------------------------------------------- Public Interface
271
272 // DriverEntry
273 //
274 // DESCRIPTION:
275 // This function initializes the driver, locates and claims
276 // hardware resources, and creates various NT objects needed
277 // to process I/O requests.
278 //
279 // RUN LEVEL:
280 // PASSIVE_LEVEL
281 //
282 // ARGUMENTS:
283 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
284 // for this driver
285 // IN PUNICODE_STRING RegistryPath Name of registry driver service
286 // key
287 //
288 // RETURNS:
289 // NTSTATUS
290
291 STDCALL NTSTATUS
292 DriverEntry(IN PDRIVER_OBJECT DriverObject,
293 IN PUNICODE_STRING RegistryPath)
294 {
295 HW_INITIALIZATION_DATA InitData;
296 NTSTATUS Status;
297
298 DPRINT("ATAPI Driver %s\n", VERSION);
299 DPRINT("RegistryPath: '%wZ'\n", RegistryPath);
300
301 /* Initialize data structure */
302 RtlZeroMemory(&InitData,
303 sizeof(HW_INITIALIZATION_DATA));
304 InitData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
305 InitData.HwInitialize = AtapiInitialize;
306 InitData.HwResetBus = AtapiResetBus;
307 InitData.HwStartIo = AtapiStartIo;
308 InitData.HwInterrupt = AtapiInterrupt;
309
310 InitData.DeviceExtensionSize = sizeof(ATAPI_MINIPORT_EXTENSION);
311 InitData.SpecificLuExtensionSize = sizeof(UNIT_EXTENSION);
312
313 InitData.MapBuffers = TRUE;
314
315
316 /* Search the PCI bus for compatibility mode ide controllers */
317 #ifdef ENABLE_PCI
318 InitData.HwFindAdapter = AtapiFindCompatiblePciController;
319 InitData.NumberOfAccessRanges = 3;
320 InitData.AdapterInterfaceType = PCIBus;
321
322 InitData.VendorId = NULL;
323 InitData.VendorIdLength = 0;
324 InitData.DeviceId = NULL;
325 InitData.DeviceIdLength = 0;
326
327 Status = ScsiPortInitialize(DriverObject,
328 RegistryPath,
329 &InitData,
330 NULL);
331 // if (newStatus < statusToReturn)
332 // statusToReturn = newStatus;
333 #endif
334
335 /* Search the PCI bus for all ide controllers */
336 #ifdef ENABLE_NATIVE_PCI
337
338 InitData.HwFindAdapter = AtapiFindNativePciController;
339 InitData.NumberOfAccessRanges = 3;
340 InitData.AdapterInterfaceType = PCIBus;
341
342 InitData.VendorId = 0;
343 InitData.VendorIdLength = 0;
344 InitData.DeviceId = 0;
345 InitData.DeviceIdLength = 0;
346
347 LastSlotNumber.u.AsULONG = 0xFFFFFFFF;
348
349 Status = ScsiPortInitialize(DriverObject,
350 RegistryPath,
351 &InitData,
352 NULL);
353 // if (newStatus < statusToReturn)
354 // statusToReturn = newStatus;
355 #endif
356
357 /* Search the ISA bus for ide controllers */
358 #ifdef ENABLE_ISA
359 InitData.HwFindAdapter = AtapiFindIsaBusController;
360 InitData.NumberOfAccessRanges = 2;
361 InitData.AdapterInterfaceType = Isa;
362
363 InitData.VendorId = NULL;
364 InitData.VendorIdLength = 0;
365 InitData.DeviceId = NULL;
366 InitData.DeviceIdLength = 0;
367
368 Status = ScsiPortInitialize(DriverObject,
369 RegistryPath,
370 &InitData,
371 NULL);
372 // if (newStatus < statusToReturn)
373 // statusToReturn = newStatus;
374 #endif
375
376 DPRINT("Returning from DriverEntry\n");
377
378 return(Status);
379 }
380
381
382 BOOLEAN
383 AtapiClaimHwResources(PATAPI_MINIPORT_EXTENSION DevExt,
384 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
385 INTERFACE_TYPE InterfaceType,
386 ULONG CommandPortBase,
387 ULONG ControlPortBase,
388 ULONG BusMasterPortBase,
389 ULONG InterruptVector)
390 {
391 SCSI_PHYSICAL_ADDRESS IoAddress;
392 PVOID IoBase;
393
394 IoAddress = ScsiPortConvertUlongToPhysicalAddress(CommandPortBase);
395 IoBase = ScsiPortGetDeviceBase((PVOID)DevExt,
396 InterfaceType,
397 ConfigInfo->SystemIoBusNumber,
398 IoAddress,
399 8,
400 TRUE);
401 if (IoBase == NULL)
402 {
403 return FALSE;
404 }
405 DevExt->CommandPortBase = (ULONG)IoBase;
406 ConfigInfo->AccessRanges[0].RangeStart = IoAddress;
407 ConfigInfo->AccessRanges[0].RangeLength = 8;
408 ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
409
410 if (ControlPortBase)
411 {
412 IoAddress = ScsiPortConvertUlongToPhysicalAddress(ControlPortBase + 2);
413 IoBase = ScsiPortGetDeviceBase((PVOID)DevExt,
414 InterfaceType,
415 ConfigInfo->SystemIoBusNumber,
416 IoAddress,
417 1,
418 TRUE);
419 if (IoBase == NULL)
420 {
421 ScsiPortFreeDeviceBase((PVOID)DevExt,
422 (PVOID)DevExt->CommandPortBase);
423 return FALSE;
424 }
425 DevExt->ControlPortBase = (ULONG)IoBase;
426 ConfigInfo->AccessRanges[1].RangeStart = IoAddress;
427 ConfigInfo->AccessRanges[1].RangeLength = 1;
428 ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
429 }
430 if (BusMasterPortBase)
431 {
432 IoAddress = ScsiPortConvertUlongToPhysicalAddress(BusMasterPortBase);
433 IoBase = ScsiPortGetDeviceBase((PVOID)DevExt,
434 InterfaceType,
435 ConfigInfo->SystemIoBusNumber,
436 IoAddress,
437 8,
438 TRUE);
439 if (IoBase == NULL)
440 {
441 ScsiPortFreeDeviceBase((PVOID)DevExt, (PVOID)DevExt->CommandPortBase);
442 ScsiPortFreeDeviceBase((PVOID)DevExt, (PVOID)DevExt->ControlPortBase);
443 return FALSE;
444 }
445 ConfigInfo->AccessRanges[2].RangeStart = IoAddress;
446 ConfigInfo->AccessRanges[2].RangeLength = 8;
447 ConfigInfo->AccessRanges[2].RangeInMemory = FALSE;
448 }
449 ConfigInfo->BusInterruptLevel = InterruptVector;
450 ConfigInfo->BusInterruptVector = InterruptVector;
451 ConfigInfo->InterruptMode = (InterfaceType == Isa) ? Latched : LevelSensitive;
452
453 if ((CommandPortBase == 0x1F0 || ControlPortBase == 0x3F4) && !ConfigInfo->AtdiskPrimaryClaimed)
454 {
455 ConfigInfo->AtdiskPrimaryClaimed = TRUE;
456 }
457 if ((CommandPortBase == 0x170 || ControlPortBase == 0x374) && !ConfigInfo->AtdiskSecondaryClaimed)
458 {
459 ConfigInfo->AtdiskSecondaryClaimed = TRUE;
460 }
461 return TRUE;
462 }
463
464
465 #ifdef ENABLE_PCI
466 static ULONG STDCALL
467 AtapiFindCompatiblePciController(PVOID DeviceExtension,
468 PVOID HwContext,
469 PVOID BusInformation,
470 PCHAR ArgumentString,
471 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
472 PBOOLEAN Again)
473 {
474 PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
475 PCI_SLOT_NUMBER SlotNumber;
476 PCI_COMMON_CONFIG PciConfig;
477 ULONG DataSize;
478 ULONG StartDeviceNumber;
479 ULONG DeviceNumber;
480 ULONG StartFunctionNumber;
481 ULONG FunctionNumber;
482 BOOLEAN ChannelFound;
483 BOOLEAN DeviceFound;
484 ULONG BusMasterBasePort = 0;
485
486 DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
487 ConfigInfo->SystemIoBusNumber,
488 ConfigInfo->SlotNumber);
489
490 *Again = FALSE;
491
492 /* both channels were claimed: exit */
493 if (ConfigInfo->AtdiskPrimaryClaimed == TRUE &&
494 ConfigInfo->AtdiskSecondaryClaimed == TRUE)
495 return(SP_RETURN_NOT_FOUND);
496
497 SlotNumber.u.AsULONG = ConfigInfo->SlotNumber;
498 StartDeviceNumber = SlotNumber.u.bits.DeviceNumber;
499 StartFunctionNumber = SlotNumber.u.bits.FunctionNumber;
500 for (DeviceNumber = StartDeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
501 {
502 SlotNumber.u.bits.DeviceNumber = DeviceNumber;
503 for (FunctionNumber = StartFunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
504 {
505 SlotNumber.u.bits.FunctionNumber = FunctionNumber;
506 ChannelFound = FALSE;
507 DeviceFound = FALSE;
508
509 DataSize = ScsiPortGetBusData(DeviceExtension,
510 PCIConfiguration,
511 ConfigInfo->SystemIoBusNumber,
512 SlotNumber.u.AsULONG,
513 &PciConfig,
514 PCI_COMMON_HDR_LENGTH);
515 if (DataSize != PCI_COMMON_HDR_LENGTH)
516 {
517 if (FunctionNumber == 0)
518 {
519 break;
520 }
521 else
522 {
523 continue;
524 }
525 }
526
527 DPRINT("%x %x\n", PciConfig.BaseClass, PciConfig.SubClass);
528 if (PciConfig.BaseClass == 0x01 &&
529 PciConfig.SubClass == 0x01) // &&
530 // (PciConfig.ProgIf & 0x05) == 0)
531 {
532 /* both channels are in compatibility mode */
533 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
534 ConfigInfo->SystemIoBusNumber,
535 SlotNumber.u.bits.DeviceNumber,
536 SlotNumber.u.bits.FunctionNumber,
537 PciConfig.VendorID,
538 PciConfig.DeviceID);
539 DPRINT("ProgIF 0x%02hx\n", PciConfig.ProgIf);
540
541 DPRINT("Found IDE controller in compatibility mode!\n");
542
543 ConfigInfo->NumberOfBuses = 1;
544 ConfigInfo->MaximumNumberOfTargets = 2;
545 ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
546
547 if (PciConfig.ProgIf & 0x80)
548 {
549 DPRINT("Found IDE Bus Master controller!\n");
550 if (PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_SPACE)
551 {
552 BusMasterBasePort = PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_ADDRESS_MASK;
553 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort);
554 }
555 }
556 if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
557 {
558 /* Both channels unclaimed: Claim primary channel */
559 DPRINT("Primary channel!\n");
560 ChannelFound = AtapiClaimHwResources(DevExt,
561 ConfigInfo,
562 PCIBus,
563 0x1F0,
564 0x3F4,
565 BusMasterBasePort,
566 14);
567 *Again = TRUE;
568 }
569 else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
570 {
571 /* Primary channel already claimed: claim secondary channel */
572 DPRINT("Secondary channel!\n");
573
574 ChannelFound = AtapiClaimHwResources(DevExt,
575 ConfigInfo,
576 PCIBus,
577 0x170,
578 0x374,
579 BusMasterBasePort ? BusMasterBasePort + 8 : 0,
580 15);
581 *Again = FALSE;
582 }
583 /* Find attached devices */
584 if (ChannelFound)
585 {
586 DeviceFound = AtapiFindDevices(DevExt, ConfigInfo);
587 ConfigInfo->SlotNumber = SlotNumber.u.AsULONG;
588 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
589 return(SP_RETURN_FOUND);
590 }
591 }
592 if (FunctionNumber == 0 && !(PciConfig.HeaderType & PCI_MULTIFUNCTION))
593 {
594 break;
595 }
596 }
597 StartFunctionNumber = 0;
598 }
599 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
600
601 return(SP_RETURN_NOT_FOUND);
602 }
603 #endif
604
605
606 #ifdef ENABLE_ISA
607 static ULONG STDCALL
608 AtapiFindIsaBusController(PVOID DeviceExtension,
609 PVOID HwContext,
610 PVOID BusInformation,
611 PCHAR ArgumentString,
612 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
613 PBOOLEAN Again)
614 {
615 PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
616 BOOLEAN ChannelFound = FALSE;
617 BOOLEAN DeviceFound = FALSE;
618
619 DPRINT("AtapiFindIsaBusController() called!\n");
620
621 *Again = FALSE;
622
623 ConfigInfo->NumberOfBuses = 1;
624 ConfigInfo->MaximumNumberOfTargets = 2;
625 ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
626
627 if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
628 {
629 /* Both channels unclaimed: Claim primary channel */
630 DPRINT("Primary channel!\n");
631
632 ChannelFound = AtapiClaimHwResources(DevExt,
633 ConfigInfo,
634 Isa,
635 0x1F0,
636 0x3F4,
637 0,
638 14);
639 *Again = TRUE;
640 }
641 else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
642 {
643 /* Primary channel already claimed: claim secondary channel */
644 DPRINT("Secondary channel!\n");
645
646 ChannelFound = AtapiClaimHwResources(DevExt,
647 ConfigInfo,
648 Isa,
649 0x170,
650 0x374,
651 0,
652 15);
653 *Again = FALSE;
654 }
655 else
656 {
657 DPRINT("AtapiFindIsaBusController() both channels claimed. Returns: SP_RETURN_NOT_FOUND\n");
658 *Again = FALSE;
659 return(SP_RETURN_NOT_FOUND);
660 }
661
662 /* Find attached devices */
663 if (ChannelFound)
664 {
665 DeviceFound = AtapiFindDevices(DevExt,
666 ConfigInfo);
667 DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
668 return(SP_RETURN_FOUND);
669 }
670 *Again = FALSE;
671 return SP_RETURN_NOT_FOUND;
672 }
673 #endif
674
675
676 #ifdef ENABLE_NATIVE_PCI
677 static ULONG STDCALL
678 AtapiFindNativePciController(PVOID DeviceExtension,
679 PVOID HwContext,
680 PVOID BusInformation,
681 PCHAR ArgumentString,
682 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
683 PBOOLEAN Again)
684 {
685 PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
686 PCI_COMMON_CONFIG PciConfig;
687 PCI_SLOT_NUMBER SlotNumber;
688 ULONG DataSize;
689 ULONG DeviceNumber;
690 ULONG StartDeviceNumber;
691 ULONG FunctionNumber;
692 ULONG StartFunctionNumber;
693 ULONG BusMasterBasePort;
694 ULONG Count;
695 BOOLEAN ChannelFound;
696
697 DPRINT("AtapiFindNativePciController() called!\n");
698
699 SlotNumber.u.AsULONG = ConfigInfo->SlotNumber;
700 StartDeviceNumber = SlotNumber.u.bits.DeviceNumber;
701 StartFunctionNumber = SlotNumber.u.bits.FunctionNumber;
702 for (DeviceNumber = StartDeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
703 {
704 SlotNumber.u.bits.DeviceNumber = DeviceNumber;
705 for (FunctionNumber = StartFunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
706 {
707 SlotNumber.u.bits.FunctionNumber = FunctionNumber;
708 DataSize = ScsiPortGetBusData(DeviceExtension,
709 PCIConfiguration,
710 ConfigInfo->SystemIoBusNumber,
711 SlotNumber.u.AsULONG,
712 &PciConfig,
713 PCI_COMMON_HDR_LENGTH);
714 if (DataSize != PCI_COMMON_HDR_LENGTH)
715 {
716 break;
717 }
718 for (Count = 0; Count < sizeof(PciNativeController)/sizeof(PCI_NATIVE_CONTROLLER); Count++)
719 {
720 if (PciConfig.VendorID == PciNativeController[Count].VendorID &&
721 PciConfig.DeviceID == PciNativeController[Count].DeviceID)
722 {
723 break;
724 }
725 }
726 if (Count < sizeof(PciNativeController)/sizeof(PCI_NATIVE_CONTROLLER))
727 {
728 /* We have found a known native pci ide controller */
729 if ((PciConfig.ProgIf & 0x80) && (PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_SPACE))
730 {
731 DPRINT("Found IDE Bus Master controller!\n");
732 BusMasterBasePort = PciConfig.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_ADDRESS_MASK;
733 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort);
734 }
735 else
736 {
737 BusMasterBasePort = 0;
738 }
739
740 DPRINT("VendorID: %04x, DeviceID: %04x\n", PciConfig.VendorID, PciConfig.DeviceID);
741 ConfigInfo->NumberOfBuses = 1;
742 ConfigInfo->MaximumNumberOfTargets = 2;
743 ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
744
745 /* FIXME:
746 We must not store and use the last tested slot number. If there is a recall
747 to the some device and we will claim the primary channel again than the call
748 to ScsiPortGetDeviceBase in AtapiClaimHwResource will fail and we can try to
749 claim the secondary channel.
750 */
751 ChannelFound = FALSE;
752 if (LastSlotNumber.u.AsULONG != SlotNumber.u.AsULONG)
753 {
754 /* try to claim primary channel */
755 if ((PciConfig.u.type0.BaseAddresses[0] & PCI_ADDRESS_IO_SPACE) &&
756 (PciConfig.u.type0.BaseAddresses[1] & PCI_ADDRESS_IO_SPACE))
757 {
758 /* primary channel is enabled */
759 ChannelFound = AtapiClaimHwResources(DevExt,
760 ConfigInfo,
761 PCIBus,
762 PciConfig.u.type0.BaseAddresses[0] & PCI_ADDRESS_IO_ADDRESS_MASK,
763 PciConfig.u.type0.BaseAddresses[1] & PCI_ADDRESS_IO_ADDRESS_MASK,
764 BusMasterBasePort,
765 PciConfig.u.type0.InterruptLine);
766 if (ChannelFound)
767 {
768 AtapiFindDevices(DevExt, ConfigInfo);
769 *Again = TRUE;
770 ConfigInfo->SlotNumber = LastSlotNumber.u.AsULONG = SlotNumber.u.AsULONG;
771 return SP_RETURN_FOUND;
772 }
773 }
774 }
775 if (!ChannelFound)
776 {
777 /* try to claim secondary channel */
778 if ((PciConfig.u.type0.BaseAddresses[2] & PCI_ADDRESS_IO_SPACE) &&
779 (PciConfig.u.type0.BaseAddresses[3] & PCI_ADDRESS_IO_SPACE))
780 {
781 /* secondary channel is enabled */
782 ChannelFound = AtapiClaimHwResources(DevExt,
783 ConfigInfo,
784 PCIBus,
785 PciConfig.u.type0.BaseAddresses[2] & PCI_ADDRESS_IO_ADDRESS_MASK,
786 PciConfig.u.type0.BaseAddresses[3] & PCI_ADDRESS_IO_ADDRESS_MASK,
787 BusMasterBasePort ? BusMasterBasePort + 8 : 0,
788 PciConfig.u.type0.InterruptLine);
789 if (ChannelFound)
790 {
791 AtapiFindDevices(DevExt, ConfigInfo);
792 *Again = FALSE;
793 LastSlotNumber.u.AsULONG = 0xFFFFFFFF;
794 return SP_RETURN_FOUND;
795 }
796 }
797 }
798 }
799 }
800 StartFunctionNumber = 0;
801 }
802 *Again = FALSE;
803 LastSlotNumber.u.AsULONG = 0xFFFFFFFF;
804 DPRINT("AtapiFindNativePciController() done!\n");
805
806 return(SP_RETURN_NOT_FOUND);
807 }
808 #endif
809
810
811 static BOOLEAN STDCALL
812 AtapiInitialize(IN PVOID DeviceExtension)
813 {
814 return(TRUE);
815 }
816
817
818 static BOOLEAN STDCALL
819 AtapiResetBus(IN PVOID DeviceExtension,
820 IN ULONG PathId)
821 {
822 return(TRUE);
823 }
824
825
826 static BOOLEAN STDCALL
827 AtapiStartIo(IN PVOID DeviceExtension,
828 IN PSCSI_REQUEST_BLOCK Srb)
829 {
830 PATAPI_MINIPORT_EXTENSION DevExt;
831 ULONG Result;
832
833 DPRINT("AtapiStartIo() called\n");
834
835 DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
836
837 switch (Srb->Function)
838 {
839 case SRB_FUNCTION_EXECUTE_SCSI:
840 DevExt->CurrentSrb = Srb;
841 if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
842 {
843 Result = AtapiSendAtapiCommand(DevExt,
844 Srb);
845 }
846 else
847 {
848 Result = AtapiSendIdeCommand(DevExt,
849 Srb);
850 }
851 break;
852
853 }
854
855 Srb->SrbStatus = Result;
856
857
858 if (Result != SRB_STATUS_PENDING)
859 {
860 DevExt->CurrentSrb = NULL;
861 Srb->SrbStatus = (UCHAR)Result;
862
863 ScsiPortNotification(RequestComplete,
864 DeviceExtension,
865 Srb);
866 ScsiPortNotification(NextRequest,
867 DeviceExtension,
868 NULL);
869 }
870 else
871 {
872 DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
873 }
874
875 DPRINT("AtapiStartIo() done\n");
876
877 return(TRUE);
878 }
879
880
881 static BOOLEAN STDCALL
882 AtapiInterrupt(IN PVOID DeviceExtension)
883 {
884 PATAPI_MINIPORT_EXTENSION DevExt;
885 PSCSI_REQUEST_BLOCK Srb;
886 ULONG CommandPortBase;
887 ULONG ControlPortBase;
888
889 UCHAR DeviceStatus;
890 BOOLEAN IsLastBlock;
891 BOOLEAN IsAtapi;
892 ULONG Retries;
893 PUCHAR TargetAddress;
894 ULONG TransferSize;
895
896 DPRINT("AtapiInterrupt() called!\n");
897
898 DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
899
900 CommandPortBase = DevExt->CommandPortBase;
901 ControlPortBase = DevExt->ControlPortBase;
902
903 if (DevExt->ExpectingInterrupt == FALSE)
904 {
905 DeviceStatus = IDEReadStatus(CommandPortBase);
906 DPRINT("AtapiInterrupt(): Unexpected interrupt (port=%x)\n", CommandPortBase);
907 return(FALSE);
908 }
909
910 /* check if it was our irq */
911 if ((DeviceStatus = IDEReadAltStatus(ControlPortBase)) & IDE_SR_BUSY)
912 {
913 ScsiPortStallExecution(1);
914 if ((DeviceStatus = IDEReadAltStatus(ControlPortBase) & IDE_SR_BUSY))
915 {
916 DPRINT("AtapiInterrupt(): Unexpected interrupt (port=%x)\n", CommandPortBase);
917 return(FALSE);
918 }
919 }
920
921 Srb = DevExt->CurrentSrb;
922 DPRINT("Srb: %p\n", Srb);
923
924 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", CommandPortBase, ControlPortBase);
925
926 IsAtapi = (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI);
927 DPRINT("IsAtapi == %s\n", (IsAtapi) ? "TRUE" : "FALSE");
928
929 IsLastBlock = FALSE;
930
931 DeviceStatus = IDEReadStatus(CommandPortBase);
932 DPRINT("DeviceStatus: %x\n", DeviceStatus);
933
934 if ((DeviceStatus & IDE_SR_ERR) &&
935 (Srb->Cdb[0] != SCSIOP_REQUEST_SENSE))
936 {
937 /* Report error condition */
938 Srb->SrbStatus = SRB_STATUS_ERROR;
939 IsLastBlock = TRUE;
940 }
941 else
942 {
943 if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
944 {
945 DPRINT("Read data\n");
946
947 /* Update controller/device state variables */
948 TargetAddress = DevExt->DataBuffer;
949
950 if (IsAtapi)
951 {
952 TransferSize = IDEReadCylinderLow(CommandPortBase);
953 TransferSize += IDEReadCylinderHigh(CommandPortBase) << 8;
954 }
955 else
956 {
957 TransferSize = DevExt->TransferSize[Srb->TargetId];
958 }
959
960 DPRINT("TransferLength: %lu\n", Srb->DataTransferLength);
961 DPRINT("TransferSize: %lu\n", TransferSize);
962
963 if (DevExt->DataTransferLength <= TransferSize)
964 {
965 if (!IsAtapi)
966 {
967 TransferSize = DevExt->DataTransferLength;
968 }
969 DevExt->DataTransferLength = 0;
970 IsLastBlock = TRUE;
971 }
972 else
973 {
974 DevExt->DataTransferLength -= TransferSize;
975 IsLastBlock = FALSE;
976 }
977 DevExt->DataBuffer += TransferSize;
978 DPRINT("IsLastBlock == %s\n", (IsLastBlock) ? "TRUE" : "FALSE");
979
980 /* Wait for DRQ assertion */
981 for (Retries = 0; Retries < IDE_MAX_DRQ_RETRIES &&
982 !(IDEReadStatus(CommandPortBase) & IDE_SR_DRQ);
983 Retries++)
984 {
985 KeStallExecutionProcessor(10);
986 }
987
988 /* Copy the block of data */
989 if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
990 {
991 IDEReadBlock32(CommandPortBase,
992 TargetAddress,
993 TransferSize);
994 }
995 else
996 {
997 IDEReadBlock(CommandPortBase,
998 TargetAddress,
999 TransferSize);
1000 }
1001
1002 /* check DRQ */
1003 if (IsLastBlock)
1004 {
1005 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
1006 (IDEReadStatus(CommandPortBase) & IDE_SR_BUSY);
1007 Retries++)
1008 {
1009 KeStallExecutionProcessor(10);
1010 }
1011
1012 /* Check for data overrun */
1013 while (IDEReadStatus(CommandPortBase) & IDE_SR_DRQ)
1014 {
1015 DPRINT1("AtapiInterrupt(): reading overrun data!\n");
1016 IDEReadWord(CommandPortBase);
1017 }
1018 }
1019
1020 Srb->SrbStatus = SRB_STATUS_SUCCESS;
1021 }
1022 else if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
1023 {
1024 DPRINT("Write data\n");
1025
1026 if (DevExt->DataTransferLength == 0)
1027 {
1028 /* Check for data overrun */
1029 if (DeviceStatus & IDE_SR_DRQ)
1030 {
1031 /* FIXME: Handle error! */
1032 /* This can occure if the irq is shared with an other and if the
1033 ide controller has a write buffer. We have write the last sectors
1034 and the other device has a irq before ours. The isr is called but
1035 we haven't a interrupt. The controller writes the sector buffer
1036 and the status register shows DRQ because the write is not ended. */
1037 DPRINT("AtapiInterrupt(): data overrun error!\n");
1038 }
1039 IsLastBlock = TRUE;
1040 }
1041 else
1042 {
1043 /* Update DevExt data */
1044 TransferSize = DevExt->TransferSize[Srb->TargetId];
1045 if (DevExt->DataTransferLength < TransferSize)
1046 {
1047 TransferSize = DevExt->DataTransferLength;
1048 }
1049
1050 TargetAddress = DevExt->DataBuffer;
1051 DevExt->DataBuffer += TransferSize;
1052 DevExt->DataTransferLength -= TransferSize;
1053
1054 /* Write the sector */
1055 if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
1056 {
1057 IDEWriteBlock32(CommandPortBase,
1058 TargetAddress,
1059 TransferSize);
1060 }
1061 else
1062 {
1063 IDEWriteBlock(CommandPortBase,
1064 TargetAddress,
1065 TransferSize);
1066 }
1067 }
1068
1069 Srb->SrbStatus = SRB_STATUS_SUCCESS;
1070 }
1071 else
1072 {
1073 DPRINT1("Unspecified transfer direction!\n");
1074 Srb->SrbStatus = SRB_STATUS_SUCCESS; // SRB_STATUS_ERROR;
1075 IsLastBlock = TRUE;
1076 }
1077 }
1078
1079
1080 if (Srb->SrbStatus == SRB_STATUS_ERROR)
1081 {
1082 Srb->SrbStatus = AtapiErrorToScsi(DeviceExtension,
1083 Srb);
1084 }
1085
1086
1087 /* complete this packet */
1088 if (IsLastBlock)
1089 {
1090 DevExt->ExpectingInterrupt = FALSE;
1091
1092 ScsiPortNotification(RequestComplete,
1093 DeviceExtension,
1094 Srb);
1095
1096 ScsiPortNotification(NextRequest,
1097 DeviceExtension,
1098 NULL);
1099 }
1100
1101 DPRINT("AtapiInterrupt() done!\n");
1102
1103 return(TRUE);
1104 }
1105
1106 // ---------------------------------------------------- Discardable statics
1107
1108
1109 /**********************************************************************
1110 * NAME INTERNAL
1111 * AtapiFindDevices
1112 *
1113 * DESCRIPTION
1114 * Searches for devices on the given port.
1115 *
1116 * RUN LEVEL
1117 * PASSIVE_LEVEL
1118 *
1119 * ARGUMENTS
1120 * DeviceExtension
1121 * Port device specific information.
1122 *
1123 * ConfigInfo
1124 * Port configuration information.
1125 *
1126 * RETURN VALUE
1127 * TRUE: At least one device is attached to the port.
1128 * FALSE: No device is attached to the port.
1129 */
1130
1131 static BOOLEAN
1132 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1133 PPORT_CONFIGURATION_INFORMATION ConfigInfo)
1134 {
1135 BOOLEAN DeviceFound = FALSE;
1136 ULONG CommandPortBase;
1137 ULONG ControlPortBase;
1138 ULONG UnitNumber;
1139 ULONG Retries;
1140 BYTE High, Low;
1141
1142 DPRINT("AtapiFindDevices() called\n");
1143
1144 CommandPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[0].RangeStart);
1145 DPRINT(" CommandPortBase: %x\n", CommandPortBase);
1146
1147 ControlPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[1].RangeStart);
1148 DPRINT(" ControlPortBase: %x\n", ControlPortBase);
1149
1150 for (UnitNumber = 0; UnitNumber < 2; UnitNumber++)
1151 {
1152 /* Select drive */
1153 IDEWriteDriveHead(CommandPortBase,
1154 IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
1155 ScsiPortStallExecution(500);
1156
1157 /* Disable interrupts */
1158 IDEWriteDriveControl(ControlPortBase,
1159 IDE_DC_nIEN);
1160 ScsiPortStallExecution(500);
1161
1162 /* Check if a device is attached to the interface */
1163 IDEWriteCylinderHigh(CommandPortBase, 0xaa);
1164 IDEWriteCylinderLow(CommandPortBase, 0x55);
1165
1166 High = IDEReadCylinderHigh(CommandPortBase);
1167 Low = IDEReadCylinderLow(CommandPortBase);
1168
1169 IDEWriteCylinderHigh(CommandPortBase, 0);
1170 IDEWriteCylinderLow(CommandPortBase, 0);
1171
1172 if (Low != 0x55 || High != 0xaa)
1173 {
1174 DPRINT("No Drive found. UnitNumber %d CommandPortBase %x\n", UnitNumber, CommandPortBase);
1175 continue;
1176 }
1177
1178 IDEWriteCommand(CommandPortBase, IDE_CMD_RESET);
1179
1180 for (Retries = 0; Retries < 20000; Retries++)
1181 {
1182 if (!(IDEReadStatus(CommandPortBase) & IDE_SR_BUSY))
1183 {
1184 break;
1185 }
1186 ScsiPortStallExecution(150);
1187 }
1188 if (Retries >= 20000)
1189 {
1190 DPRINT("Timeout on drive %lu\n", UnitNumber);
1191 DeviceExtension->DeviceFlags[UnitNumber] &= ~DEVICE_PRESENT;
1192 continue;
1193 }
1194
1195 High = IDEReadCylinderHigh(CommandPortBase);
1196 Low = IDEReadCylinderLow(CommandPortBase);
1197
1198 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
1199 UnitNumber,
1200 High,
1201 Low);
1202
1203 if (High == 0xEB && Low == 0x14)
1204 {
1205 if (AtapiIdentifyDevice(CommandPortBase,
1206 ControlPortBase,
1207 UnitNumber,
1208 TRUE,
1209 &DeviceExtension->DeviceParams[UnitNumber]))
1210 {
1211 DPRINT(" ATAPI drive found!\n");
1212 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_PRESENT;
1213 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_ATAPI;
1214 DeviceExtension->TransferSize[UnitNumber] =
1215 DeviceExtension->DeviceParams[UnitNumber].BytesPerSector;
1216 DeviceFound = TRUE;
1217 }
1218 else
1219 {
1220 DPRINT(" No ATAPI drive found!\n");
1221 }
1222 }
1223 else
1224 {
1225 if (AtapiIdentifyDevice(CommandPortBase,
1226 ControlPortBase,
1227 UnitNumber,
1228 FALSE,
1229 &DeviceExtension->DeviceParams[UnitNumber]))
1230 {
1231 DPRINT(" IDE drive found!\n");
1232 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_PRESENT;
1233 DeviceExtension->TransferSize[UnitNumber] = DeviceExtension->DeviceParams[UnitNumber].BytesPerSector;
1234 if ((DeviceExtension->DeviceParams[UnitNumber].RWMultImplemented & 0x8000) &&
1235 (DeviceExtension->DeviceParams[UnitNumber].RWMultImplemented & 0xff) &&
1236 (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0x100) &&
1237 (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0xff))
1238 {
1239 DeviceExtension->TransferSize[UnitNumber] *= (DeviceExtension->DeviceParams[UnitNumber].RWMultCurrent & 0xff);
1240 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_MULTI_SECTOR_CMD;
1241 }
1242
1243 if (DeviceExtension->DeviceParams[UnitNumber].DWordIo)
1244 {
1245 DeviceExtension->DeviceFlags[UnitNumber] |= DEVICE_DWORD_IO;
1246 }
1247
1248 DeviceFound = TRUE;
1249 }
1250 else
1251 {
1252 DPRINT(" No IDE drive found!\n");
1253 }
1254 }
1255 }
1256
1257 /* Reset pending interrupts */
1258 IDEReadStatus(CommandPortBase);
1259 /* Reenable interrupts */
1260 IDEWriteDriveControl(ControlPortBase, 0);
1261 ScsiPortStallExecution(500);
1262 /* Return with drive 0 selected */
1263 IDEWriteDriveHead(CommandPortBase, IDE_DH_FIXED);
1264 ScsiPortStallExecution(500);
1265
1266 DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound) ? "TRUE" : "FALSE");
1267
1268 return(DeviceFound);
1269 }
1270
1271
1272 // AtapiResetController
1273 //
1274 // DESCRIPTION:
1275 // Reset the controller and report completion status
1276 //
1277 // RUN LEVEL:
1278 // PASSIVE_LEVEL
1279 //
1280 // ARGUMENTS:
1281 // IN WORD CommandPort The address of the command port
1282 // IN WORD ControlPort The address of the control port
1283 //
1284 // RETURNS:
1285 //
1286
1287 static BOOLEAN
1288 AtapiResetController(IN ULONG CommandPort,
1289 IN ULONG ControlPort)
1290 {
1291 int Retries;
1292
1293 /* Assert drive reset line */
1294 IDEWriteDriveControl(ControlPort, IDE_DC_SRST);
1295
1296 /* Wait for min. 25 microseconds */
1297 ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH);
1298
1299 /* Negate drive reset line */
1300 IDEWriteDriveControl(ControlPort, 0);
1301
1302 /* Wait for BUSY negation */
1303 for (Retries = 0; Retries < IDE_RESET_BUSY_TIMEOUT * 1000; Retries++)
1304 {
1305 if (!(IDEReadStatus(CommandPort) & IDE_SR_BUSY))
1306 {
1307 break;
1308 }
1309 ScsiPortStallExecution(10);
1310 }
1311
1312 if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
1313 {
1314 return(FALSE);
1315 }
1316
1317 // return TRUE if controller came back to life. and
1318 // the registers are initialized correctly
1319 return(IDEReadError(CommandPort) == 1);
1320 }
1321
1322 /*
1323 * AtapiIdentifyDevice
1324 *
1325 * DESCRIPTION:
1326 * Get the identification block from the drive
1327 *
1328 * RUN LEVEL:
1329 * PASSIVE_LEVEL
1330 *
1331 * ARGUMENTS:
1332 * CommandPort
1333 * Address of the command port
1334 * ControlPort
1335 * Address of the control port
1336 * DriveNum
1337 * The drive index (0,1)
1338 * Atapi
1339 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1340 * DrvParms
1341 * Address to write drive ident block
1342 *
1343 * RETURNS:
1344 * TRUE: The drive identification block was retrieved successfully
1345 * FALSE: an error ocurred
1346 */
1347
1348 static BOOLEAN
1349 AtapiIdentifyDevice(IN ULONG CommandPort,
1350 IN ULONG ControlPort,
1351 IN ULONG DriveNum,
1352 IN BOOLEAN Atapi,
1353 OUT PIDE_DRIVE_IDENTIFY DrvParms)
1354 {
1355 LONG i;
1356
1357 /* Get the Drive Identify block from drive or die */
1358 if (AtapiPolledRead(CommandPort,
1359 ControlPort,
1360 0,
1361 1,
1362 0,
1363 0,
1364 0,
1365 (DriveNum ? IDE_DH_DRV1 : 0),
1366 (Atapi ? IDE_CMD_IDENT_ATAPI_DRV : IDE_CMD_IDENT_ATA_DRV),
1367 (BYTE *)DrvParms) != 0)
1368 {
1369 DPRINT("IDEPolledRead() failed\n");
1370 return(FALSE);
1371 }
1372
1373 /* Report on drive parameters if debug mode */
1374 IDESwapBytePairs(DrvParms->SerialNumber, 20);
1375 IDESwapBytePairs(DrvParms->FirmwareRev, 8);
1376 IDESwapBytePairs(DrvParms->ModelNumber, 40);
1377 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1378 DrvParms->ConfigBits,
1379 DrvParms->LogicalCyls,
1380 DrvParms->LogicalHeads,
1381 DrvParms->SectorsPerTrack,
1382 DrvParms->InterSectorGap,
1383 DrvParms->InterSectorGapSize);
1384 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1385 DrvParms->BytesInPLO,
1386 DrvParms->VendorUniqueCnt,
1387 DrvParms->SerialNumber);
1388 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1389 DrvParms->ControllerType,
1390 DrvParms->BufferSize * IDE_SECTOR_BUF_SZ,
1391 DrvParms->ECCByteCnt,
1392 DrvParms->FirmwareRev);
1393 DPRINT("Model:[%.40s]\n", DrvParms->ModelNumber);
1394 DPRINT("RWMultMax?:%04x RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1395 (DrvParms->RWMultImplemented),
1396 (DrvParms->RWMultCurrent) & 0xff,
1397 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0,
1398 (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
1399 DrvParms->MinPIOTransTime,
1400 DrvParms->MinDMATransTime);
1401 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1402 DrvParms->TMCylinders,
1403 DrvParms->TMHeads,
1404 DrvParms->TMSectorsPerTrk,
1405 (ULONG)(DrvParms->TMCapacityLo + (DrvParms->TMCapacityHi << 16)));
1406 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1407 DrvParms->TMSectorCountHi,
1408 DrvParms->TMSectorCountLo,
1409 (ULONG)((DrvParms->TMSectorCountHi << 16) + DrvParms->TMSectorCountLo));
1410
1411 if (! Atapi && 0 != (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED))
1412 {
1413 /* LBA ATA drives always have a sector size of 512 */
1414 DrvParms->BytesPerSector = 512;
1415 }
1416 else
1417 {
1418 DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
1419 if (DrvParms->BytesPerSector == 0)
1420 {
1421 DrvParms->BytesPerSector = 512;
1422 }
1423 else
1424 {
1425 for (i = 15; i >= 0; i--)
1426 {
1427 if (DrvParms->BytesPerSector & (1 << i))
1428 {
1429 DrvParms->BytesPerSector = 1 << i;
1430 break;
1431 }
1432 }
1433 }
1434 }
1435 DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
1436
1437 return(TRUE);
1438 }
1439
1440
1441 // AtapiPolledRead
1442 //
1443 // DESCRIPTION:
1444 // Read a sector of data from the drive in a polled fashion.
1445 //
1446 // RUN LEVEL:
1447 // PASSIVE_LEVEL
1448 //
1449 // ARGUMENTS:
1450 // IN WORD Address Address of command port for drive
1451 // IN BYTE PreComp Value to write to precomp register
1452 // IN BYTE SectorCnt Value to write to sectorCnt register
1453 // IN BYTE SectorNum Value to write to sectorNum register
1454 // IN BYTE CylinderLow Value to write to CylinderLow register
1455 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1456 // IN BYTE DrvHead Value to write to Drive/Head register
1457 // IN BYTE Command Value to write to Command register
1458 // OUT BYTE *Buffer Buffer for output data
1459 //
1460 // RETURNS:
1461 // int 0 is success, non 0 is an error code
1462 //
1463
1464 static int
1465 AtapiPolledRead(IN ULONG CommandPort,
1466 IN ULONG ControlPort,
1467 IN BYTE PreComp,
1468 IN BYTE SectorCnt,
1469 IN BYTE SectorNum,
1470 IN BYTE CylinderLow,
1471 IN BYTE CylinderHigh,
1472 IN BYTE DrvHead,
1473 IN BYTE Command,
1474 OUT BYTE *Buffer)
1475 {
1476 ULONG SectorCount = 0;
1477 ULONG RetryCount;
1478 BOOLEAN Junk = FALSE;
1479 UCHAR Status;
1480
1481 //#if 0
1482 /* Wait for BUSY to clear */
1483 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1484 {
1485 Status = IDEReadStatus(CommandPort);
1486 if (!(Status & IDE_SR_BUSY))
1487 {
1488 break;
1489 }
1490 ScsiPortStallExecution(10);
1491 }
1492 DPRINT("status=%02x\n", Status);
1493 DPRINT("waited %ld usecs for busy to clear\n", RetryCount * 10);
1494 if (RetryCount >= IDE_MAX_BUSY_RETRIES)
1495 {
1496 DPRINT("Drive is BUSY for too long\n");
1497 return(IDE_ER_ABRT);
1498 }
1499 //#endif
1500
1501 /* Write Drive/Head to select drive */
1502 IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
1503 ScsiPortStallExecution(500);
1504
1505 /* Disable interrupts */
1506 IDEWriteDriveControl(ControlPort, IDE_DC_nIEN);
1507 ScsiPortStallExecution(500);
1508
1509 #if 0
1510 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1511 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1512 {
1513 Status = IDEReadStatus(CommandPort);
1514 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1515 {
1516 break;
1517 }
1518 ScsiPortStallExecution(10);
1519 }
1520 if (RetryCount >= IDE_MAX_BUSY_RETRIES)
1521 {
1522 return IDE_ER_ABRT;
1523 }
1524 #endif
1525
1526 /* Issue command to drive */
1527 if (DrvHead & IDE_DH_LBA)
1528 {
1529 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1530 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1531 ((DrvHead & 0x0f) << 24) + (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
1532 SectorCnt,
1533 Command);
1534 }
1535 else
1536 {
1537 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1538 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1539 CylinderHigh,
1540 CylinderLow,
1541 DrvHead & 0x0f,
1542 SectorNum,
1543 SectorCnt,
1544 Command);
1545 }
1546
1547 /* Setup command parameters */
1548 IDEWritePrecomp(CommandPort, PreComp);
1549 IDEWriteSectorCount(CommandPort, SectorCnt);
1550 IDEWriteSectorNum(CommandPort, SectorNum);
1551 IDEWriteCylinderHigh(CommandPort, CylinderHigh);
1552 IDEWriteCylinderLow(CommandPort, CylinderLow);
1553 IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
1554
1555 /* Issue the command */
1556 IDEWriteCommand(CommandPort, Command);
1557 ScsiPortStallExecution(50);
1558
1559 /* wait for DRQ or error */
1560 for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
1561 {
1562 Status = IDEReadStatus(CommandPort);
1563 if (!(Status & IDE_SR_BUSY))
1564 {
1565 if (Status & IDE_SR_ERR)
1566 {
1567 IDEWriteDriveControl(ControlPort, 0);
1568 ScsiPortStallExecution(50);
1569 IDEReadStatus(CommandPort);
1570
1571 return(IDE_ER_ABRT);
1572 }
1573 if (Status & IDE_SR_DRQ)
1574 {
1575 break;
1576 }
1577 else
1578 {
1579 IDEWriteDriveControl(ControlPort, 0);
1580 ScsiPortStallExecution(50);
1581 IDEReadStatus(CommandPort);
1582
1583 return(IDE_ER_ABRT);
1584 }
1585 }
1586 ScsiPortStallExecution(10);
1587 }
1588
1589 /* timed out */
1590 if (RetryCount >= IDE_MAX_POLL_RETRIES)
1591 {
1592 IDEWriteDriveControl(ControlPort, 0);
1593 ScsiPortStallExecution(50);
1594 IDEReadStatus(CommandPort);
1595
1596 return(IDE_ER_ABRT);
1597 }
1598
1599 while (1)
1600 {
1601 /* Read data into buffer */
1602 if (Junk == FALSE)
1603 {
1604 IDEReadBlock(CommandPort, Buffer, IDE_SECTOR_BUF_SZ);
1605 Buffer += IDE_SECTOR_BUF_SZ;
1606 }
1607 else
1608 {
1609 UCHAR JunkBuffer[IDE_SECTOR_BUF_SZ];
1610 IDEReadBlock(CommandPort, JunkBuffer, IDE_SECTOR_BUF_SZ);
1611 }
1612 SectorCount++;
1613
1614 /* Check for error or more sectors to read */
1615 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1616 {
1617 Status = IDEReadStatus(CommandPort);
1618 if (!(Status & IDE_SR_BUSY))
1619 {
1620 if (Status & IDE_SR_ERR)
1621 {
1622 IDEWriteDriveControl(ControlPort, 0);
1623 ScsiPortStallExecution(50);
1624 IDEReadStatus(CommandPort);
1625
1626 return(IDE_ER_ABRT);
1627 }
1628 if (Status & IDE_SR_DRQ)
1629 {
1630 if (SectorCount >= SectorCnt)
1631 {
1632 DPRINT("Buffer size exceeded!\n");
1633 Junk = TRUE;
1634 }
1635 break;
1636 }
1637 else
1638 {
1639 if (SectorCount > SectorCnt)
1640 {
1641 DPRINT("Read %lu sectors of junk!\n",
1642 SectorCount - SectorCnt);
1643 }
1644 IDEWriteDriveControl(ControlPort, 0);
1645 ScsiPortStallExecution(50);
1646 IDEReadStatus(CommandPort);
1647
1648 return(0);
1649 }
1650 }
1651 }
1652 }
1653 }
1654
1655
1656 // ------------------------------------------- Nondiscardable statics
1657
1658 static ULONG
1659 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1660 IN PSCSI_REQUEST_BLOCK Srb)
1661 {
1662 UCHAR ByteCountHigh;
1663 UCHAR ByteCountLow;
1664 ULONG Retries;
1665 ULONG CdbSize;
1666 UCHAR Status;
1667
1668 DPRINT("AtapiSendAtapiCommand() called!\n");
1669
1670 if (Srb->PathId != 0)
1671 {
1672 Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
1673 return(SRB_STATUS_INVALID_PATH_ID);
1674 }
1675
1676 if (Srb->TargetId > 1)
1677 {
1678 Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
1679 return(SRB_STATUS_INVALID_TARGET_ID);
1680 }
1681
1682 if (Srb->Lun != 0)
1683 {
1684 Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
1685 return(SRB_STATUS_INVALID_LUN);
1686 }
1687
1688 if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_PRESENT))
1689 {
1690 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1691 return(SRB_STATUS_NO_DEVICE);
1692 }
1693
1694 DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
1695 Srb->TargetId);
1696
1697 if (Srb->Cdb[0] == SCSIOP_INQUIRY)
1698 return(AtapiInquiry(DeviceExtension,
1699 Srb));
1700
1701 /* Set pointer to data buffer. */
1702 DeviceExtension->DataBuffer = (PUCHAR)Srb->DataBuffer;
1703 DeviceExtension->DataTransferLength = Srb->DataTransferLength;
1704 DeviceExtension->CurrentSrb = Srb;
1705
1706 /* Wait for BUSY to clear */
1707 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1708 {
1709 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1710 if (!(Status & IDE_SR_BUSY))
1711 {
1712 break;
1713 }
1714 ScsiPortStallExecution(10);
1715 }
1716 DPRINT("status=%02x\n", Status);
1717 DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
1718 if (Retries >= IDE_MAX_BUSY_RETRIES)
1719 {
1720 DPRINT("Drive is BUSY for too long\n");
1721 return(SRB_STATUS_BUSY);
1722 }
1723
1724 /* Select the desired drive */
1725 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
1726 IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
1727
1728 /* Wait a little while */
1729 ScsiPortStallExecution(50);
1730
1731 #if 0
1732 /* Wait for BUSY to clear and DRDY to assert */
1733 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1734 {
1735 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1736 if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1737 {
1738 break;
1739 }
1740 ScsiPortStallExecution(10);
1741 }
1742 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
1743 if (Retries >= IDE_MAX_BUSY_RETRIES)
1744 {
1745 DPRINT("Drive is BUSY for too long after drive select\n");
1746 return(SRB_STATUS_BUSY);
1747 }
1748 #endif
1749
1750 if (DeviceExtension->DataTransferLength < 0x10000)
1751 {
1752 ByteCountLow = (UCHAR)(DeviceExtension->DataTransferLength & 0xFF);
1753 ByteCountHigh = (UCHAR)(DeviceExtension->DataTransferLength >> 8);
1754 }
1755 else
1756 {
1757 ByteCountLow = 0xFF;
1758 ByteCountHigh = 0xFF;
1759 }
1760
1761 /* Set feature register */
1762 IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
1763
1764 /* Set command packet length */
1765 IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, ByteCountHigh);
1766 IDEWriteCylinderLow(DeviceExtension->CommandPortBase, ByteCountLow);
1767
1768 /* Issue command to drive */
1769 IDEWriteCommand(DeviceExtension->CommandPortBase, IDE_CMD_PACKET);
1770
1771 /* Wait for DRQ to assert */
1772 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1773 {
1774 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1775 if ((Status & IDE_SR_DRQ))
1776 {
1777 break;
1778 }
1779 ScsiPortStallExecution(10);
1780 }
1781
1782 CdbSize = (DeviceExtension->DeviceParams[Srb->TargetId].ConfigBits & 0x3 == 1) ? 16 : 12;
1783 DPRINT("CdbSize: %lu\n", CdbSize);
1784
1785 /* Write command packet */
1786 IDEWriteBlock(DeviceExtension->CommandPortBase,
1787 (PUSHORT)Srb->Cdb,
1788 CdbSize);
1789
1790 DeviceExtension->ExpectingInterrupt = TRUE;
1791
1792 DPRINT("AtapiSendAtapiCommand() done\n");
1793
1794 return(SRB_STATUS_PENDING);
1795 }
1796
1797
1798 static ULONG
1799 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1800 IN PSCSI_REQUEST_BLOCK Srb)
1801 {
1802 ULONG SrbStatus = SRB_STATUS_SUCCESS;
1803
1804 DPRINT("AtapiSendIdeCommand() called!\n");
1805
1806 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1807 Srb->PathId,
1808 Srb->TargetId,
1809 Srb->Lun);
1810
1811 if (Srb->PathId != 0)
1812 {
1813 Srb->SrbStatus = SRB_STATUS_INVALID_PATH_ID;
1814 return(SRB_STATUS_INVALID_PATH_ID);
1815 }
1816
1817 if (Srb->TargetId > 1)
1818 {
1819 Srb->SrbStatus = SRB_STATUS_INVALID_TARGET_ID;
1820 return(SRB_STATUS_INVALID_TARGET_ID);
1821 }
1822
1823 if (Srb->Lun != 0)
1824 {
1825 Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
1826 return(SRB_STATUS_INVALID_LUN);
1827 }
1828
1829 if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_PRESENT))
1830 {
1831 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1832 return(SRB_STATUS_NO_DEVICE);
1833 }
1834
1835 switch (Srb->Cdb[0])
1836 {
1837 case SCSIOP_INQUIRY:
1838 SrbStatus = AtapiInquiry(DeviceExtension,
1839 Srb);
1840 break;
1841
1842 case SCSIOP_READ_CAPACITY:
1843 SrbStatus = AtapiReadCapacity(DeviceExtension,
1844 Srb);
1845 break;
1846
1847 case SCSIOP_READ:
1848 case SCSIOP_WRITE:
1849 SrbStatus = AtapiReadWrite(DeviceExtension,
1850 Srb);
1851 break;
1852
1853 case SCSIOP_SYNCHRONIZE_CACHE:
1854 SrbStatus = AtapiFlushCache(DeviceExtension,
1855 Srb);
1856 break;
1857
1858 case SCSIOP_TEST_UNIT_READY:
1859 SrbStatus = AtapiTestUnitReady(DeviceExtension,
1860 Srb);
1861 break;
1862
1863 case SCSIOP_MODE_SENSE:
1864 case SCSIOP_VERIFY:
1865 case SCSIOP_START_STOP_UNIT:
1866 case SCSIOP_REQUEST_SENSE:
1867 break;
1868
1869 default:
1870 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1871 Srb->Cdb[0]);
1872 SrbStatus = SRB_STATUS_INVALID_REQUEST;
1873 break;
1874 }
1875
1876 DPRINT("AtapiSendIdeCommand() done!\n");
1877
1878 return(SrbStatus);
1879 }
1880
1881
1882 static ULONG
1883 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1884 PSCSI_REQUEST_BLOCK Srb)
1885 {
1886 PIDE_DRIVE_IDENTIFY DeviceParams;
1887 PINQUIRYDATA InquiryData;
1888 ULONG i;
1889
1890 DPRINT("SCSIOP_INQUIRY: DeviceExtension %p TargetId: %lu\n",
1891 DeviceExtension, Srb->TargetId);
1892
1893 InquiryData = Srb->DataBuffer;
1894 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1895
1896 /* clear buffer */
1897 for (i = 0; i < Srb->DataTransferLength; i++)
1898 {
1899 ((PUCHAR)Srb->DataBuffer)[i] = 0;
1900 }
1901
1902 /* set device class */
1903 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
1904 {
1905 /* get it from the ATAPI configuration word */
1906 InquiryData->DeviceType = (DeviceParams->ConfigBits >> 8) & 0x1F;
1907 DPRINT("Device class: %u\n", InquiryData->DeviceType);
1908 }
1909 else
1910 {
1911 /* hard-disk */
1912 InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
1913 }
1914
1915 DPRINT("ConfigBits: 0x%x\n", DeviceParams->ConfigBits);
1916 if (DeviceParams->ConfigBits & 0x80)
1917 {
1918 DPRINT("Removable media!\n");
1919 InquiryData->RemovableMedia = 1;
1920 }
1921
1922 for (i = 0; i < 20; i += 2)
1923 {
1924 InquiryData->VendorId[i] =
1925 ((PUCHAR)DeviceParams->ModelNumber)[i];
1926 InquiryData->VendorId[i+1] =
1927 ((PUCHAR)DeviceParams->ModelNumber)[i+1];
1928 }
1929
1930 for (i = 0; i < 4; i++)
1931 {
1932 InquiryData->ProductId[12+i] = ' ';
1933 }
1934
1935 for (i = 0; i < 4; i += 2)
1936 {
1937 InquiryData->ProductRevisionLevel[i] =
1938 ((PUCHAR)DeviceParams->FirmwareRev)[i];
1939 InquiryData->ProductRevisionLevel[i+1] =
1940 ((PUCHAR)DeviceParams->FirmwareRev)[i+1];
1941 }
1942
1943 DPRINT("VendorId: '%.20s'\n", InquiryData->VendorId);
1944
1945 Srb->SrbStatus = SRB_STATUS_SUCCESS;
1946 return(SRB_STATUS_SUCCESS);
1947 }
1948
1949
1950 static ULONG
1951 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1952 PSCSI_REQUEST_BLOCK Srb)
1953 {
1954 PREAD_CAPACITY_DATA CapacityData;
1955 PIDE_DRIVE_IDENTIFY DeviceParams;
1956 ULONG LastSector;
1957
1958 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb->TargetId);
1959 CapacityData = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
1960 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1961
1962 /* Set sector (block) size to 512 bytes (big-endian). */
1963 CapacityData->BytesPerBlock = 0x20000;
1964
1965 /* Calculate last sector (big-endian). */
1966 if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
1967 {
1968 LastSector = (ULONG)((DeviceParams->TMSectorCountHi << 16) +
1969 DeviceParams->TMSectorCountLo) - 1;
1970 }
1971 else
1972 {
1973 LastSector = (ULONG)(DeviceParams->LogicalCyls *
1974 DeviceParams->LogicalHeads *
1975 DeviceParams->SectorsPerTrack)-1;
1976 }
1977
1978 CapacityData->LogicalBlockAddress = (((PUCHAR)&LastSector)[0] << 24) |
1979 (((PUCHAR)&LastSector)[1] << 16) |
1980 (((PUCHAR)&LastSector)[2] << 8) |
1981 ((PUCHAR)&LastSector)[3];
1982
1983 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
1984 LastSector,
1985 LastSector,
1986 CapacityData->LogicalBlockAddress);
1987
1988 Srb->SrbStatus = SRB_STATUS_SUCCESS;
1989 return(SRB_STATUS_SUCCESS);
1990 }
1991
1992
1993 static ULONG
1994 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1995 PSCSI_REQUEST_BLOCK Srb)
1996 {
1997 PIDE_DRIVE_IDENTIFY DeviceParams;
1998 ULONG StartingSector;
1999 ULONG SectorCount;
2000 UCHAR CylinderHigh;
2001 UCHAR CylinderLow;
2002 UCHAR DrvHead;
2003 UCHAR SectorNumber;
2004 UCHAR Command;
2005 ULONG Retries;
2006 UCHAR Status;
2007
2008 DPRINT("AtapiReadWrite() called!\n");
2009 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
2010 Srb->TargetId);
2011
2012 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
2013
2014 /* Get starting sector number from CDB. */
2015 StartingSector = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
2016 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
2017 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
2018 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
2019
2020 SectorCount = (Srb->DataTransferLength + DeviceParams->BytesPerSector - 1) /
2021 DeviceParams->BytesPerSector;
2022
2023 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
2024 StartingSector,
2025 Srb->DataTransferLength,
2026 SectorCount);
2027
2028 if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
2029 {
2030 SectorNumber = StartingSector & 0xff;
2031 CylinderLow = (StartingSector >> 8) & 0xff;
2032 CylinderHigh = (StartingSector >> 16) & 0xff;
2033 DrvHead = ((StartingSector >> 24) & 0x0f) |
2034 (Srb->TargetId ? IDE_DH_DRV1 : 0) |
2035 IDE_DH_LBA;
2036 }
2037 else
2038 {
2039 SectorNumber = (StartingSector % DeviceParams->SectorsPerTrack) + 1;
2040 StartingSector /= DeviceParams->SectorsPerTrack;
2041 DrvHead = (StartingSector % DeviceParams->LogicalHeads) |
2042 (Srb->TargetId ? IDE_DH_DRV1 : 0);
2043 StartingSector /= DeviceParams->LogicalHeads;
2044 CylinderLow = StartingSector & 0xff;
2045 CylinderHigh = StartingSector >> 8;
2046 }
2047
2048
2049 if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
2050 {
2051 Command = (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_MULTI_SECTOR_CMD) ? IDE_CMD_READ_MULTIPLE : IDE_CMD_READ;
2052 }
2053 else
2054 {
2055 Command = (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_MULTI_SECTOR_CMD) ? IDE_CMD_WRITE_MULTIPLE : IDE_CMD_WRITE;
2056 }
2057
2058 if (DrvHead & IDE_DH_LBA)
2059 {
2060 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
2061 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
2062 DeviceExtension->CommandPortBase,
2063 DrvHead & IDE_DH_DRV1 ? 1 : 0,
2064 ((DrvHead & 0x0f) << 24) +
2065 (CylinderHigh << 16) + (CylinderLow << 8) + SectorNumber,
2066 SectorCount,
2067 Command);
2068 }
2069 else
2070 {
2071 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
2072 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
2073 DeviceExtension->CommandPortBase,
2074 DrvHead & IDE_DH_DRV1 ? 1 : 0,
2075 CylinderHigh,
2076 CylinderLow,
2077 DrvHead & 0x0f,
2078 SectorNumber,
2079 SectorCount,
2080 Command);
2081 }
2082
2083 /* Set pointer to data buffer. */
2084 DeviceExtension->DataBuffer = (PUCHAR)Srb->DataBuffer;
2085 DeviceExtension->DataTransferLength = Srb->DataTransferLength;
2086
2087 DeviceExtension->CurrentSrb = Srb;
2088
2089 /* wait for BUSY to clear */
2090 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
2091 {
2092 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2093 if (!(Status & IDE_SR_BUSY))
2094 {
2095 break;
2096 }
2097 ScsiPortStallExecution(10);
2098 }
2099 DPRINT("status=%02x\n", Status);
2100 DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
2101 if (Retries >= IDE_MAX_BUSY_RETRIES)
2102 {
2103 DPRINT ("Drive is BUSY for too long\n");
2104 return(SRB_STATUS_BUSY);
2105 }
2106
2107 /* Select the desired drive */
2108 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
2109 IDE_DH_FIXED | DrvHead);
2110
2111 ScsiPortStallExecution(10);
2112 #if 0
2113 /* wait for BUSY to clear and DRDY to assert */
2114 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
2115 {
2116 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2117 if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
2118 {
2119 break;
2120 }
2121 ScsiPortStallExecution(10);
2122 }
2123 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
2124 if (Retries >= IDE_MAX_BUSY_RETRIES)
2125 {
2126 DPRINT("Drive is BUSY for too long after drive select\n");
2127 return(SRB_STATUS_BUSY);
2128 }
2129 #endif
2130
2131 /* Setup command parameters */
2132 IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
2133 IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount);
2134 IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber);
2135 IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh);
2136 IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow);
2137 IDEWriteDriveHead(DeviceExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
2138
2139 /* Indicate expecting an interrupt. */
2140 DeviceExtension->ExpectingInterrupt = TRUE;
2141
2142 /* Issue command to drive */
2143 IDEWriteCommand(DeviceExtension->CommandPortBase, Command);
2144
2145 /* Write data block */
2146 if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT)
2147 {
2148 PUCHAR TargetAddress;
2149 ULONG TransferSize;
2150
2151 /* Wait for controller ready */
2152 for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
2153 {
2154 BYTE Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2155 if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
2156 {
2157 break;
2158 }
2159 KeStallExecutionProcessor(10);
2160 }
2161 if (Retries >= IDE_MAX_WRITE_RETRIES)
2162 {
2163 DPRINT1("Drive is BUSY for too long after sending write command\n");
2164 return(SRB_STATUS_BUSY);
2165 }
2166
2167 /* Update DeviceExtension data */
2168 TransferSize = DeviceExtension->TransferSize[Srb->TargetId];
2169 if (DeviceExtension->DataTransferLength < TransferSize)
2170 {
2171 TransferSize = DeviceExtension->DataTransferLength;
2172 }
2173
2174 TargetAddress = DeviceExtension->DataBuffer;
2175 DeviceExtension->DataBuffer += TransferSize;
2176 DeviceExtension->DataTransferLength -= TransferSize;
2177
2178 /* Write data block */
2179 if (DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_DWORD_IO)
2180 {
2181 IDEWriteBlock32(DeviceExtension->CommandPortBase,
2182 TargetAddress,
2183 TransferSize);
2184 }
2185 else
2186 {
2187 IDEWriteBlock(DeviceExtension->CommandPortBase,
2188 TargetAddress,
2189 TransferSize);
2190 }
2191 }
2192
2193 DPRINT("AtapiReadWrite() done!\n");
2194
2195 /* Wait for interrupt. */
2196 return(SRB_STATUS_PENDING);
2197 }
2198
2199
2200 static ULONG
2201 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension,
2202 PSCSI_REQUEST_BLOCK Srb)
2203 {
2204 ULONG Retries;
2205 UCHAR Status;
2206
2207 DPRINT("AtapiFlushCache() called!\n");
2208 DPRINT("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
2209 Srb->TargetId);
2210
2211 /* Wait for BUSY to clear */
2212 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
2213 {
2214 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2215 if (!(Status & IDE_SR_BUSY))
2216 {
2217 break;
2218 }
2219 ScsiPortStallExecution(10);
2220 }
2221 DPRINT("Status=%02x\n", Status);
2222 DPRINT("Waited %ld usecs for busy to clear\n", Retries * 10);
2223 if (Retries >= IDE_MAX_BUSY_RETRIES)
2224 {
2225 DPRINT1("Drive is BUSY for too long\n");
2226 return(SRB_STATUS_BUSY);
2227 }
2228
2229 /* Select the desired drive */
2230 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
2231 IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
2232 ScsiPortStallExecution(10);
2233
2234 /* Issue command to drive */
2235 IDEWriteCommand(DeviceExtension->CommandPortBase, IDE_CMD_FLUSH_CACHE);
2236
2237 /* Wait for controller ready */
2238 for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
2239 {
2240 BYTE Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2241 if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
2242 {
2243 break;
2244 }
2245 KeStallExecutionProcessor(10);
2246 }
2247 if (Retries >= IDE_MAX_WRITE_RETRIES)
2248 {
2249 DPRINT1("Drive is BUSY for too long after sending write command\n");
2250 return(SRB_STATUS_BUSY);
2251 }
2252
2253 /* Indicate expecting an interrupt. */
2254 DeviceExtension->ExpectingInterrupt = TRUE;
2255
2256 DPRINT("AtapiFlushCache() done!\n");
2257
2258 /* Wait for interrupt. */
2259 return(SRB_STATUS_PENDING);
2260 }
2261
2262
2263 static ULONG
2264 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension,
2265 PSCSI_REQUEST_BLOCK Srb)
2266 {
2267 ULONG Retries;
2268 UCHAR Status;
2269 UCHAR Error;
2270
2271 DPRINT1("AtapiTestUnitReady() called!\n");
2272
2273 DPRINT1("SCSIOP_TEST_UNIT_READY: TargetId: %lu\n",
2274 Srb->TargetId);
2275
2276 /* Return success if media status is not supported */
2277 if (!(DeviceExtension->DeviceFlags[Srb->TargetId] & DEVICE_MEDIA_STATUS))
2278 {
2279 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2280 return(SRB_STATUS_SUCCESS);
2281 }
2282
2283 /* Wait for BUSY to clear */
2284 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
2285 {
2286 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2287 if (!(Status & IDE_SR_BUSY))
2288 {
2289 break;
2290 }
2291 ScsiPortStallExecution(10);
2292 }
2293 DPRINT1("Status=%02x\n", Status);
2294 DPRINT1("Waited %ld usecs for busy to clear\n", Retries * 10);
2295 if (Retries >= IDE_MAX_BUSY_RETRIES)
2296 {
2297 DPRINT1("Drive is BUSY for too long\n");
2298 return(SRB_STATUS_BUSY);
2299 }
2300
2301 /* Select the desired drive */
2302 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
2303 IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
2304 ScsiPortStallExecution(10);
2305
2306 /* Issue command to drive */
2307 IDEWriteCommand(DeviceExtension->CommandPortBase, IDE_CMD_GET_MEDIA_STATUS);
2308
2309 /* Wait for controller ready */
2310 for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
2311 {
2312 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
2313 if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
2314 {
2315 break;
2316 }
2317 KeStallExecutionProcessor(10);
2318 }
2319 if (Retries >= IDE_MAX_WRITE_RETRIES)
2320 {
2321 DPRINT1("Drive is BUSY for too long after sending write command\n");
2322 return(SRB_STATUS_BUSY);
2323 }
2324
2325 if (Status & IDE_SR_ERR)
2326 {
2327 Error = IDEReadError(DeviceExtension->CommandPortBase);
2328 if (Error == IDE_ER_UNC)
2329 {
2330 CHECKPOINT1;
2331 /* Handle write protection 'error' */
2332 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2333 return(SRB_STATUS_SUCCESS);
2334 }
2335 else
2336 {
2337 CHECKPOINT1;
2338 /* Indicate expecting an interrupt. */
2339 DeviceExtension->ExpectingInterrupt = TRUE;
2340 return(SRB_STATUS_PENDING);
2341 }
2342 }
2343
2344 DPRINT1("AtapiTestUnitReady() done!\n");
2345
2346 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2347 return(SRB_STATUS_SUCCESS);
2348 }
2349
2350
2351 static UCHAR
2352 AtapiErrorToScsi(PVOID DeviceExtension,
2353 PSCSI_REQUEST_BLOCK Srb)
2354 {
2355 PATAPI_MINIPORT_EXTENSION DevExt;
2356 ULONG CommandPortBase;
2357 ULONG ControlPortBase;
2358 UCHAR ErrorReg;
2359 UCHAR ScsiStatus;
2360 UCHAR SrbStatus;
2361
2362 DPRINT("AtapiErrorToScsi() called\n");
2363
2364 DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
2365
2366 CommandPortBase = DevExt->CommandPortBase;
2367 ControlPortBase = DevExt->ControlPortBase;
2368
2369 ErrorReg = IDEReadError(CommandPortBase);
2370
2371 if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
2372 {
2373 switch (ErrorReg >> 4)
2374 {
2375 case SCSI_SENSE_NO_SENSE:
2376 DPRINT("ATAPI error: SCSI_SENSE_NO_SENSE\n");
2377 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2378 SrbStatus = SRB_STATUS_ERROR;
2379 break;
2380
2381 case SCSI_SENSE_RECOVERED_ERROR:
2382 DPRINT("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
2383 ScsiStatus = 0;
2384 SrbStatus = SRB_STATUS_SUCCESS;
2385 break;
2386
2387 case SCSI_SENSE_NOT_READY:
2388 DPRINT("ATAPI error: SCSI_SENSE_NOT_READY\n");
2389 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2390 SrbStatus = SRB_STATUS_ERROR;
2391 break;
2392
2393 case SCSI_SENSE_MEDIUM_ERROR:
2394 DPRINT("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
2395 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2396 SrbStatus = SRB_STATUS_ERROR;
2397 break;
2398
2399 case SCSI_SENSE_HARDWARE_ERROR:
2400 DPRINT("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
2401 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2402 SrbStatus = SRB_STATUS_ERROR;
2403 break;
2404
2405 case SCSI_SENSE_ILLEGAL_REQUEST:
2406 DPRINT("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
2407 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2408 SrbStatus = SRB_STATUS_ERROR;
2409 break;
2410
2411 case SCSI_SENSE_UNIT_ATTENTION:
2412 DPRINT("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
2413 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2414 SrbStatus = SRB_STATUS_ERROR;
2415 break;
2416
2417 case SCSI_SENSE_DATA_PROTECT:
2418 DPRINT("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
2419 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2420 SrbStatus = SRB_STATUS_ERROR;
2421 break;
2422
2423 case SCSI_SENSE_BLANK_CHECK:
2424 DPRINT("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
2425 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2426 SrbStatus = SRB_STATUS_ERROR;
2427 break;
2428
2429 case SCSI_SENSE_ABORTED_COMMAND:
2430 DPRINT("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
2431 ScsiStatus = SCSISTAT_CHECK_CONDITION;
2432 SrbStatus = SRB_STATUS_ERROR;
2433 break;
2434
2435 default:
2436 DPRINT("ATAPI error: Invalid sense key\n");
2437 ScsiStatus = 0;
2438 SrbStatus = SRB_STATUS_ERROR;
2439 break;
2440 }
2441 }
2442 else
2443 {
2444 DPRINT1("IDE error: %02x\n", ErrorReg);
2445
2446 ScsiStatus = 0;
2447 SrbStatus = SRB_STATUS_ERROR;
2448
2449 #if 0
2450 UCHAR SectorCount, SectorNum, CylinderLow, CylinderHigh;
2451 UCHAR DriveHead;
2452
2453 CylinderLow = IDEReadCylinderLow(CommandPortBase);
2454 CylinderHigh = IDEReadCylinderHigh(CommandPortBase);
2455 DriveHead = IDEReadDriveHead(CommandPortBase);
2456 SectorCount = IDEReadSectorCount(CommandPortBase);
2457 SectorNum = IDEReadSectorNum(CommandPortBase);
2458
2459 DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
2460 ErrorReg,
2461 CylinderLow,
2462 CylinderHigh,
2463 SectorCount,
2464 SectorNum);
2465 #endif
2466 }
2467
2468
2469
2470 Srb->ScsiStatus = ScsiStatus;
2471
2472 DPRINT("AtapiErrorToScsi() done\n");
2473
2474 return(SrbStatus);
2475 }
2476
2477 /* EOF */