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