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