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