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