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