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