[FREELDR] Addendum / actual fix for ef76709b
[reactos.git] / boot / freeldr / freeldr / disk / scsiport.c
1 /*
2 * PROJECT: ReactOS Boot Loader (FreeLDR)
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: boot/freeldr/freeldr/disk/scsiport.c
5 * PURPOSE: Interface for SCSI Emulation
6 * PROGRAMMERS: Hervé Poussineau <hpoussin@reactos.org>
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <freeldr.h>
12
13 #include <debug.h>
14 DBG_DEFAULT_CHANNEL(SCSIPORT);
15
16 #define _SCSIPORT_
17
18 #include <ntddk.h>
19 #include <srb.h>
20 #include <scsi.h>
21 #include <ntddscsi.h>
22 #include <ntddstor.h>
23 #include <ntdddisk.h>
24 #include <stdio.h>
25 #include <stdarg.h>
26
27 #undef ScsiPortLogError
28 #undef ScsiPortMoveMemory
29 #undef ScsiPortWritePortBufferUchar
30 #undef ScsiPortWritePortBufferUlong
31 #undef ScsiPortWritePortBufferUshort
32 #undef ScsiPortWritePortUchar
33 #undef ScsiPortWritePortUlong
34 #undef ScsiPortWritePortUshort
35 #undef ScsiPortWriteRegisterBufferUchar
36 #undef ScsiPortWriteRegisterBufferUlong
37 #undef ScsiPortWriteRegisterBufferUshort
38 #undef ScsiPortWriteRegisterUchar
39 #undef ScsiPortWriteRegisterUlong
40 #undef ScsiPortWriteRegisterUshort
41 #undef ScsiPortReadPortBufferUchar
42 #undef ScsiPortReadPortBufferUlong
43 #undef ScsiPortReadPortBufferUshort
44 #undef ScsiPortReadPortUchar
45 #undef ScsiPortReadPortUlong
46 #undef ScsiPortReadPortUshort
47 #undef ScsiPortReadRegisterBufferUchar
48 #undef ScsiPortReadRegisterBufferUlong
49 #undef ScsiPortReadRegisterBufferUshort
50 #undef ScsiPortReadRegisterUchar
51 #undef ScsiPortReadRegisterUlong
52 #undef ScsiPortReadRegisterUshort
53
54 #define SCSI_PORT_NEXT_REQUEST_READY 0x0008
55
56 #define TAG_SCSI_DEVEXT 'DscS'
57 #define TAG_SCSI_ACCESS_RANGES 'AscS'
58
59 /* GLOBALS ********************************************************************/
60
61 #ifdef _M_IX86
62 VOID NTAPI HalpInitializePciStubs(VOID);
63 VOID NTAPI HalpInitBusHandler(VOID);
64 #endif
65
66 typedef struct
67 {
68 PVOID NonCachedExtension;
69
70 ULONG BusNum;
71 ULONG MaxTargedIds;
72
73 ULONG InterruptFlags;
74
75 /* SRB extension stuff */
76 ULONG SrbExtensionSize;
77 PVOID SrbExtensionBuffer;
78
79 IO_SCSI_CAPABILITIES PortCapabilities;
80
81 PHW_INITIALIZE HwInitialize;
82 PHW_STARTIO HwStartIo;
83 PHW_INTERRUPT HwInterrupt;
84 PHW_RESET_BUS HwResetBus;
85
86 /* DMA related stuff */
87 PADAPTER_OBJECT AdapterObject;
88
89 ULONG CommonBufferLength;
90
91 PVOID MiniPortDeviceExtension;
92 } SCSI_PORT_DEVICE_EXTENSION, *PSCSI_PORT_DEVICE_EXTENSION;
93
94 typedef struct tagDISKCONTEXT
95 {
96 /* Device ID */
97 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
98 UCHAR PathId;
99 UCHAR TargetId;
100 UCHAR Lun;
101
102 /* Device characteristics */
103 ULONG SectorSize;
104 ULONGLONG SectorOffset;
105 ULONGLONG SectorCount;
106 ULONGLONG SectorNumber;
107 } DISKCONTEXT;
108
109 PSCSI_PORT_DEVICE_EXTENSION ScsiDeviceExtensions[SCSI_MAXIMUM_BUSES];
110
111 /* FUNCTIONS ******************************************************************/
112
113 ULONG
114 ntohl(
115 IN ULONG Value)
116 {
117 FOUR_BYTE Dest;
118 PFOUR_BYTE Source = (PFOUR_BYTE)&Value;
119
120 Dest.Byte0 = Source->Byte3;
121 Dest.Byte1 = Source->Byte2;
122 Dest.Byte2 = Source->Byte1;
123 Dest.Byte3 = Source->Byte0;
124
125 return Dest.AsULong;
126 }
127
128 static
129 BOOLEAN
130 SpiSendSynchronousSrb(
131 IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
132 IN PSCSI_REQUEST_BLOCK Srb)
133 {
134 BOOLEAN ret;
135
136 ASSERT(!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE));
137
138 /* HACK: handle lack of interrupts */
139 while (!(DeviceExtension->InterruptFlags & SCSI_PORT_NEXT_REQUEST_READY))
140 {
141 KeStallExecutionProcessor(100 * 1000);
142 DeviceExtension->HwInterrupt(DeviceExtension->MiniPortDeviceExtension);
143 }
144
145 DeviceExtension->InterruptFlags &= ~SCSI_PORT_NEXT_REQUEST_READY;
146 Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
147
148 if (!DeviceExtension->HwStartIo(
149 DeviceExtension->MiniPortDeviceExtension,
150 Srb))
151 {
152 ExFreePool(Srb);
153 return FALSE;
154 }
155
156 /* HACK: handle lack of interrupts */
157 while (Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)
158 {
159 KeStallExecutionProcessor(100 * 1000);
160 DeviceExtension->HwInterrupt(DeviceExtension->MiniPortDeviceExtension);
161 }
162
163 ret = SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS;
164 ExFreePool(Srb);
165
166 return ret;
167 }
168
169 static ARC_STATUS DiskClose(ULONG FileId)
170 {
171 DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
172 ExFreePool(Context);
173 return ESUCCESS;
174 }
175
176 static ARC_STATUS DiskGetFileInformation(ULONG FileId, FILEINFORMATION* Information)
177 {
178 DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
179
180 RtlZeroMemory(Information, sizeof(*Information));
181
182 /*
183 * The ARC specification mentions that for partitions, StartingAddress and
184 * EndingAddress are the start and end positions of the partition in terms
185 * of byte offsets from the start of the disk.
186 * CurrentAddress is the current offset into (i.e. relative to) the partition.
187 */
188 Information->StartingAddress.QuadPart = Context->SectorOffset * Context->SectorSize;
189 Information->EndingAddress.QuadPart = (Context->SectorOffset + Context->SectorCount) * Context->SectorSize;
190 Information->CurrentAddress.QuadPart = Context->SectorNumber * Context->SectorSize;
191
192 return ESUCCESS;
193 }
194
195 static ARC_STATUS DiskOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
196 {
197 PSCSI_REQUEST_BLOCK Srb;
198 PCDB Cdb;
199 READ_CAPACITY_DATA ReadCapacityBuffer;
200
201 DISKCONTEXT* Context;
202 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
203 ULONG ScsiBus, PathId, TargetId, Lun, Partition, PathSyntax;
204 ULONG SectorSize;
205 ULONGLONG SectorOffset = 0;
206 ULONGLONG SectorCount;
207
208 /* Parse ARC path */
209 if (!DissectArcPath2(Path, &ScsiBus, &TargetId, &Lun, &Partition, &PathSyntax))
210 return EINVAL;
211 if (PathSyntax != 0) /* scsi() format */
212 return EINVAL;
213 DeviceExtension = ScsiDeviceExtensions[ScsiBus];
214 PathId = ScsiBus - DeviceExtension->BusNum;
215
216 /* Get disk capacity and sector size */
217 Srb = ExAllocatePool(PagedPool, sizeof(SCSI_REQUEST_BLOCK));
218 if (!Srb)
219 return ENOMEM;
220 RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
221 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
222 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
223 Srb->PathId = (UCHAR)PathId;
224 Srb->TargetId = (UCHAR)TargetId;
225 Srb->Lun = (UCHAR)Lun;
226 Srb->CdbLength = 10;
227 Srb->SrbFlags = SRB_FLAGS_DATA_IN;
228 Srb->DataTransferLength = sizeof(READ_CAPACITY_DATA);
229 Srb->TimeOutValue = 5; /* in seconds */
230 Srb->DataBuffer = &ReadCapacityBuffer;
231 Cdb = (PCDB)Srb->Cdb;
232 Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
233 if (!SpiSendSynchronousSrb(DeviceExtension, Srb))
234 {
235 return EIO;
236 }
237
238 /* Transform result to host endianness */
239 SectorCount = ntohl(ReadCapacityBuffer.LogicalBlockAddress);
240 SectorSize = ntohl(ReadCapacityBuffer.BytesPerBlock);
241
242 if (Partition != 0)
243 {
244 /* Need to offset start of disk and length */
245 UNIMPLEMENTED;
246 return EIO;
247 }
248
249 Context = ExAllocatePool(PagedPool, sizeof(DISKCONTEXT));
250 if (!Context)
251 return ENOMEM;
252 Context->DeviceExtension = DeviceExtension;
253 Context->PathId = (UCHAR)PathId;
254 Context->TargetId = (UCHAR)TargetId;
255 Context->Lun = (UCHAR)Lun;
256 Context->SectorSize = SectorSize;
257 Context->SectorOffset = SectorOffset;
258 Context->SectorCount = SectorCount;
259 Context->SectorNumber = 0;
260 FsSetDeviceSpecific(*FileId, Context);
261
262 return ESUCCESS;
263 }
264
265 static ARC_STATUS DiskRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count)
266 {
267 DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
268 PSCSI_REQUEST_BLOCK Srb;
269 PCDB Cdb;
270 ULONG FullSectors, NbSectors;
271 ULONG Lba;
272
273 *Count = 0;
274
275 if (N == 0)
276 return ESUCCESS;
277
278 FullSectors = N / Context->SectorSize;
279 NbSectors = (N + Context->SectorSize - 1) / Context->SectorSize;
280 if (Context->SectorNumber + NbSectors >= Context->SectorCount)
281 return EINVAL;
282 if (FullSectors > 0xffff)
283 return EINVAL;
284
285 /* Read full sectors */
286 ASSERT(Context->SectorNumber < 0xFFFFFFFF);
287 Lba = (ULONG)(Context->SectorOffset + Context->SectorNumber);
288 if (FullSectors > 0)
289 {
290 Srb = ExAllocatePool(PagedPool, sizeof(SCSI_REQUEST_BLOCK));
291 if (!Srb)
292 return ENOMEM;
293
294 RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
295 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
296 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
297 Srb->PathId = Context->PathId;
298 Srb->TargetId = Context->TargetId;
299 Srb->Lun = Context->Lun;
300 Srb->CdbLength = 10;
301 Srb->SrbFlags = SRB_FLAGS_DATA_IN;
302 Srb->DataTransferLength = FullSectors * Context->SectorSize;
303 Srb->TimeOutValue = 5; /* in seconds */
304 Srb->DataBuffer = Buffer;
305 Cdb = (PCDB)Srb->Cdb;
306 Cdb->CDB10.OperationCode = SCSIOP_READ;
307 Cdb->CDB10.LogicalUnitNumber = Srb->Lun;
308 Cdb->CDB10.LogicalBlockByte0 = (Lba >> 24) & 0xff;
309 Cdb->CDB10.LogicalBlockByte1 = (Lba >> 16) & 0xff;
310 Cdb->CDB10.LogicalBlockByte2 = (Lba >> 8) & 0xff;
311 Cdb->CDB10.LogicalBlockByte3 = Lba & 0xff;
312 Cdb->CDB10.TransferBlocksMsb = (FullSectors >> 8) & 0xff;
313 Cdb->CDB10.TransferBlocksLsb = FullSectors & 0xff;
314 if (!SpiSendSynchronousSrb(Context->DeviceExtension, Srb))
315 {
316 return EIO;
317 }
318 Buffer = (PUCHAR)Buffer + FullSectors * Context->SectorSize;
319 N -= FullSectors * Context->SectorSize;
320 *Count += FullSectors * Context->SectorSize;
321 Lba += FullSectors;
322 }
323
324 /* Read incomplete last sector */
325 if (N > 0)
326 {
327 PUCHAR Sector;
328
329 Sector = ExAllocatePool(PagedPool, Context->SectorSize);
330 if (!Sector)
331 return ENOMEM;
332
333 Srb = ExAllocatePool(PagedPool, sizeof(SCSI_REQUEST_BLOCK));
334 if (!Srb)
335 {
336 ExFreePool(Sector);
337 return ENOMEM;
338 }
339
340 RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
341 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
342 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
343 Srb->PathId = Context->PathId;
344 Srb->TargetId = Context->TargetId;
345 Srb->Lun = Context->Lun;
346 Srb->CdbLength = 10;
347 Srb->SrbFlags = SRB_FLAGS_DATA_IN;
348 Srb->DataTransferLength = Context->SectorSize;
349 Srb->TimeOutValue = 5; /* in seconds */
350 Srb->DataBuffer = Sector;
351 Cdb = (PCDB)Srb->Cdb;
352 Cdb->CDB10.OperationCode = SCSIOP_READ;
353 Cdb->CDB10.LogicalUnitNumber = Srb->Lun;
354 Cdb->CDB10.LogicalBlockByte0 = (Lba >> 24) & 0xff;
355 Cdb->CDB10.LogicalBlockByte1 = (Lba >> 16) & 0xff;
356 Cdb->CDB10.LogicalBlockByte2 = (Lba >> 8) & 0xff;
357 Cdb->CDB10.LogicalBlockByte3 = Lba & 0xff;
358 Cdb->CDB10.TransferBlocksMsb = 0;
359 Cdb->CDB10.TransferBlocksLsb = 1;
360 if (!SpiSendSynchronousSrb(Context->DeviceExtension, Srb))
361 {
362 ExFreePool(Sector);
363 return EIO;
364 }
365 RtlCopyMemory(Buffer, Sector, N);
366 *Count += N;
367 ExFreePool(Sector);
368 }
369
370 return ESUCCESS;
371 }
372
373 static ARC_STATUS DiskSeek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode)
374 {
375 DISKCONTEXT* Context = FsGetDeviceSpecific(FileId);
376 ULONGLONG SectorNumber;
377
378 if (SeekMode != SeekAbsolute)
379 return EINVAL;
380 if (Position->QuadPart & (Context->SectorSize - 1))
381 return EINVAL;
382
383 SectorNumber = Position->QuadPart / Context->SectorSize;
384 if (SectorNumber >= Context->SectorCount)
385 return EINVAL;
386
387 Context->SectorNumber = SectorNumber;
388 return ESUCCESS;
389 }
390
391 static const DEVVTBL DiskVtbl = {
392 DiskClose,
393 DiskGetFileInformation,
394 DiskOpen,
395 DiskRead,
396 DiskSeek,
397 };
398
399 static
400 NTSTATUS
401 SpiCreatePortConfig(
402 IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
403 IN PHW_INITIALIZATION_DATA HwInitData,
404 OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
405 IN BOOLEAN ZeroStruct)
406 {
407 ULONG Bus;
408
409 /* Zero out the struct if told so */
410 if (ZeroStruct)
411 {
412 /* First zero the portconfig */
413 RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION));
414
415 /* Initialize the struct */
416 ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
417 ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType;
418 ConfigInfo->InterruptMode = Latched;
419 ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
420 ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
421 ConfigInfo->MaximumTransferLength = SP_UNINITIALIZED_VALUE;
422 ConfigInfo->MaximumNumberOfTargets = SCSI_MAXIMUM_TARGETS_PER_BUS;
423
424 /* Store parameters */
425 ConfigInfo->NeedPhysicalAddresses = HwInitData->NeedPhysicalAddresses;
426 ConfigInfo->MapBuffers = HwInitData->MapBuffers;
427 ConfigInfo->AutoRequestSense = HwInitData->AutoRequestSense;
428 ConfigInfo->ReceiveEvent = HwInitData->ReceiveEvent;
429 ConfigInfo->TaggedQueuing = HwInitData->TaggedQueuing;
430 ConfigInfo->MultipleRequestPerLu = HwInitData->MultipleRequestPerLu;
431
432 /* Get the disk usage */
433 ConfigInfo->AtdiskPrimaryClaimed = FALSE; // FIXME
434 ConfigInfo->AtdiskSecondaryClaimed = FALSE; // FIXME
435
436 /* Initiator bus id is not set */
437 for (Bus = 0; Bus < 8; Bus++)
438 ConfigInfo->InitiatorBusId[Bus] = (CCHAR)SP_UNINITIALIZED_VALUE;
439 }
440
441 ConfigInfo->NumberOfPhysicalBreaks = 17;
442
443 return STATUS_SUCCESS;
444 }
445
446 VOID
447 __cdecl
448 ScsiDebugPrint(
449 IN ULONG DebugPrintLevel,
450 IN PCCHAR DebugMessage,
451 IN ...)
452 {
453 va_list ap;
454 CHAR Buffer[512];
455 ULONG Length;
456
457 if (DebugPrintLevel > 10)
458 return;
459
460 va_start(ap, DebugMessage);
461
462 /* Construct a string */
463 Length = _vsnprintf(Buffer, 512, DebugMessage, ap);
464
465 /* Check if we went past the buffer */
466 if (Length == MAXULONG)
467 {
468 /* Terminate it if we went over-board */
469 Buffer[sizeof(Buffer) - 1] = '\0';
470
471 /* Put maximum */
472 Length = sizeof(Buffer);
473 }
474
475 /* Print the message */
476 TRACE("%s", Buffer);
477
478 /* Cleanup */
479 va_end(ap);
480 }
481
482 VOID
483 NTAPI
484 ScsiPortCompleteRequest(
485 IN PVOID HwDeviceExtension,
486 IN UCHAR PathId,
487 IN UCHAR TargetId,
488 IN UCHAR Lun,
489 IN UCHAR SrbStatus)
490 {
491 // FIXME
492 UNIMPLEMENTED;
493 }
494
495 #undef ScsiPortConvertPhysicalAddressToUlong
496 ULONG
497 NTAPI
498 ScsiPortConvertPhysicalAddressToUlong(
499 IN SCSI_PHYSICAL_ADDRESS Address)
500 {
501 return Address.LowPart;
502 }
503
504 SCSI_PHYSICAL_ADDRESS
505 NTAPI
506 ScsiPortConvertUlongToPhysicalAddress(
507 IN ULONG_PTR UlongAddress)
508 {
509 SCSI_PHYSICAL_ADDRESS Address;
510
511 Address.QuadPart = UlongAddress;
512 return Address;
513 }
514
515 VOID
516 NTAPI
517 ScsiPortFlushDma(
518 IN PVOID DeviceExtension)
519 {
520 // FIXME
521 UNIMPLEMENTED;
522 }
523
524 VOID
525 NTAPI
526 ScsiPortFreeDeviceBase(
527 IN PVOID HwDeviceExtension,
528 IN PVOID MappedAddress)
529 {
530 // Nothing to do
531 }
532
533 ULONG
534 NTAPI
535 ScsiPortGetBusData(
536 IN PVOID DeviceExtension,
537 IN ULONG BusDataType,
538 IN ULONG SystemIoBusNumber,
539 IN ULONG SlotNumber,
540 IN PVOID Buffer,
541 IN ULONG Length)
542 {
543 return HalGetBusDataByOffset(BusDataType, SystemIoBusNumber, SlotNumber, Buffer, 0, Length);
544 }
545
546 PVOID
547 NTAPI
548 ScsiPortGetDeviceBase(
549 IN PVOID HwDeviceExtension,
550 IN INTERFACE_TYPE BusType,
551 IN ULONG SystemIoBusNumber,
552 IN SCSI_PHYSICAL_ADDRESS IoAddress,
553 IN ULONG NumberOfBytes,
554 IN BOOLEAN InIoSpace)
555 {
556 PHYSICAL_ADDRESS TranslatedAddress;
557 ULONG AddressSpace;
558
559 AddressSpace = (ULONG)InIoSpace;
560 if (HalTranslateBusAddress(BusType,
561 SystemIoBusNumber,
562 IoAddress,
563 &AddressSpace,
564 &TranslatedAddress) == FALSE)
565 {
566 return NULL;
567 }
568
569 /* I/O space */
570 if (AddressSpace != 0)
571 return (PVOID)TranslatedAddress.u.LowPart;
572
573 // FIXME
574 UNIMPLEMENTED;
575 return (PVOID)IoAddress.LowPart;
576 }
577
578 PVOID
579 NTAPI
580 ScsiPortGetLogicalUnit(
581 IN PVOID HwDeviceExtension,
582 IN UCHAR PathId,
583 IN UCHAR TargetId,
584 IN UCHAR Lun)
585 {
586 // FIXME
587 UNIMPLEMENTED;
588 return NULL;
589 }
590
591 SCSI_PHYSICAL_ADDRESS
592 NTAPI
593 ScsiPortGetPhysicalAddress(
594 IN PVOID HwDeviceExtension,
595 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
596 IN PVOID VirtualAddress,
597 OUT ULONG *Length)
598 {
599 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
600 SCSI_PHYSICAL_ADDRESS PhysicalAddress;
601 ULONG BufferLength = 0;
602 ULONG Offset;
603
604 TRACE("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
605 HwDeviceExtension, Srb, VirtualAddress, Length);
606
607 DeviceExtension = ((PSCSI_PORT_DEVICE_EXTENSION)HwDeviceExtension) - 1;
608
609 if (Srb == NULL || Srb->SenseInfoBuffer == VirtualAddress)
610 {
611 /* Simply look it up in the allocated common buffer */
612 Offset = (PUCHAR)VirtualAddress - (PUCHAR)DeviceExtension->SrbExtensionBuffer;
613
614 BufferLength = DeviceExtension->CommonBufferLength - Offset;
615 PhysicalAddress.QuadPart = Offset;
616 }
617 else
618 {
619 /* Nothing */
620 PhysicalAddress.QuadPart = (LONGLONG)(SP_UNINITIALIZED_VALUE);
621 }
622
623 *Length = BufferLength;
624 return PhysicalAddress;
625 }
626
627 PSCSI_REQUEST_BLOCK
628 NTAPI
629 ScsiPortGetSrb(
630 IN PVOID DeviceExtension,
631 IN UCHAR PathId,
632 IN UCHAR TargetId,
633 IN UCHAR Lun,
634 IN LONG QueueTag)
635 {
636 // FIXME
637 UNIMPLEMENTED;
638 return NULL;
639 }
640
641 static
642 NTSTATUS
643 SpiAllocateCommonBuffer(
644 IN OUT PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
645 IN ULONG NonCachedSize)
646 {
647 PVOID CommonBuffer;
648 ULONG CommonBufferLength, BufSize;
649
650 /* If size is 0, set it to 16 */
651 if (!DeviceExtension->SrbExtensionSize)
652 DeviceExtension->SrbExtensionSize = 16;
653
654 /* Calculate size */
655 BufSize = DeviceExtension->SrbExtensionSize;
656
657 /* Round it */
658 BufSize = (BufSize + sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
659
660 /* Sum up into the total common buffer length, and round it to page size */
661 CommonBufferLength =
662 ROUND_TO_PAGES(NonCachedSize);
663
664 /* Allocate it */
665 if (!DeviceExtension->AdapterObject)
666 {
667 /* From nonpaged pool if there is no DMA */
668 CommonBuffer = ExAllocatePool(NonPagedPool, CommonBufferLength);
669 }
670 else
671 {
672 /* Perform a full request since we have a DMA adapter*/
673 UNIMPLEMENTED;
674 CommonBuffer = NULL;
675 }
676
677 /* Fail in case of error */
678 if (!CommonBuffer)
679 return STATUS_INSUFFICIENT_RESOURCES;
680
681 /* Zero it */
682 RtlZeroMemory(CommonBuffer, CommonBufferLength);
683
684 /* Store its size in Device Extension */
685 DeviceExtension->CommonBufferLength = CommonBufferLength;
686
687 /* SrbExtension buffer is located at the beginning of the buffer */
688 DeviceExtension->SrbExtensionBuffer = CommonBuffer;
689
690 /* Non-cached extension buffer is located at the end of
691 the common buffer */
692 if (NonCachedSize)
693 {
694 CommonBufferLength -= NonCachedSize;
695 DeviceExtension->NonCachedExtension = (PUCHAR)CommonBuffer + CommonBufferLength;
696 }
697 else
698 {
699 DeviceExtension->NonCachedExtension = NULL;
700 }
701
702 return STATUS_SUCCESS;
703 }
704
705 PVOID
706 NTAPI
707 ScsiPortGetUncachedExtension(
708 IN PVOID HwDeviceExtension,
709 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
710 IN ULONG NumberOfBytes)
711 {
712 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
713 DEVICE_DESCRIPTION DeviceDescription;
714 ULONG MapRegistersCount;
715 NTSTATUS Status;
716
717 TRACE("ScsiPortGetUncachedExtension(%p %p %lu)\n",
718 HwDeviceExtension, ConfigInfo, NumberOfBytes);
719
720 DeviceExtension = ((PSCSI_PORT_DEVICE_EXTENSION)HwDeviceExtension) - 1;
721
722 /* Check for allocated common DMA buffer */
723 if (DeviceExtension->SrbExtensionBuffer != NULL)
724 {
725 return NULL;
726 }
727
728 /* Check for DMA adapter object */
729 if (DeviceExtension->AdapterObject == NULL)
730 {
731 /* Initialize DMA adapter description */
732 RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
733
734 DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
735 DeviceDescription.Master = ConfigInfo->Master;
736 DeviceDescription.ScatterGather = ConfigInfo->ScatterGather;
737 DeviceDescription.DemandMode = ConfigInfo->DemandMode;
738 DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
739 DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
740 DeviceDescription.DmaChannel = ConfigInfo->DmaChannel;
741 DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
742 DeviceDescription.DmaWidth = ConfigInfo->DmaWidth;
743 DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
744 DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
745 DeviceDescription.DmaPort = ConfigInfo->DmaPort;
746
747 /* Get a DMA adapter object */
748 #if 0
749 DeviceExtension->AdapterObject =
750 HalGetAdapter(&DeviceDescription, &MapRegistersCount);
751
752 /* Fail in case of error */
753 if (DeviceExtension->AdapterObject == NULL)
754 {
755 return NULL;
756 }
757 #else
758 MapRegistersCount = 0;
759 #endif
760
761 /* Set number of physical breaks */
762 if (ConfigInfo->NumberOfPhysicalBreaks != 0 &&
763 MapRegistersCount > ConfigInfo->NumberOfPhysicalBreaks)
764 {
765 DeviceExtension->PortCapabilities.MaximumPhysicalPages =
766 ConfigInfo->NumberOfPhysicalBreaks;
767 }
768 else
769 {
770 DeviceExtension->PortCapabilities.MaximumPhysicalPages = MapRegistersCount;
771 }
772 }
773
774 /* Update Srb extension size */
775 if (DeviceExtension->SrbExtensionSize != ConfigInfo->SrbExtensionSize)
776 DeviceExtension->SrbExtensionSize = ConfigInfo->SrbExtensionSize;
777
778 /* Allocate a common DMA buffer */
779 Status = SpiAllocateCommonBuffer(DeviceExtension, NumberOfBytes);
780
781 if (!NT_SUCCESS(Status))
782 {
783 TRACE("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status);
784 return NULL;
785 }
786
787 return DeviceExtension->NonCachedExtension;
788 }
789
790 PVOID
791 NTAPI
792 ScsiPortGetVirtualAddress(
793 IN PVOID HwDeviceExtension,
794 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
795 {
796 // FIXME
797 UNIMPLEMENTED;
798 return NULL;
799 }
800
801 static
802 VOID
803 SpiScanDevice(
804 IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
805 IN PCHAR ArcName,
806 IN ULONG ScsiBus,
807 IN ULONG TargetId,
808 IN ULONG Lun)
809 {
810 ULONG FileId, i;
811 ARC_STATUS Status;
812 NTSTATUS ret;
813 struct _DRIVE_LAYOUT_INFORMATION *PartitionBuffer;
814 CHAR PartitionName[64];
815
816 /* Register device with partition(0) suffix */
817 RtlStringCbPrintfA(PartitionName, sizeof(PartitionName), "%spartition(0)", ArcName);
818 FsRegisterDevice(PartitionName, &DiskVtbl);
819
820 /* Read device partition table */
821 Status = ArcOpen(PartitionName, OpenReadOnly, &FileId);
822 if (Status == ESUCCESS)
823 {
824 ret = HALDISPATCH->HalIoReadPartitionTable((PDEVICE_OBJECT)FileId, 512, FALSE, &PartitionBuffer);
825 if (NT_SUCCESS(ret))
826 {
827 for (i = 0; i < PartitionBuffer->PartitionCount; i++)
828 {
829 if (PartitionBuffer->PartitionEntry[i].PartitionType != PARTITION_ENTRY_UNUSED)
830 {
831 RtlStringCbPrintfA(PartitionName,
832 sizeof(PartitionName),
833 "%spartition(%lu)",
834 ArcName,
835 PartitionBuffer->PartitionEntry[i].PartitionNumber);
836 FsRegisterDevice(PartitionName, &DiskVtbl);
837 }
838 }
839 ExFreePool(PartitionBuffer);
840 }
841 ArcClose(FileId);
842 }
843 }
844
845 static
846 VOID
847 SpiScanAdapter(
848 IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
849 IN ULONG ScsiBus,
850 IN UCHAR PathId)
851 {
852 CHAR ArcName[64];
853 PSCSI_REQUEST_BLOCK Srb;
854 PCDB Cdb;
855 INQUIRYDATA InquiryBuffer;
856 UCHAR TargetId;
857 UCHAR Lun;
858
859 if (!DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, PathId))
860 {
861 return;
862 }
863
864 /* Remember the extension */
865 ScsiDeviceExtensions[ScsiBus] = DeviceExtension;
866
867 for (TargetId = 0; TargetId < DeviceExtension->MaxTargedIds; TargetId++)
868 {
869 Lun = 0;
870 do
871 {
872 TRACE("Scanning SCSI device %d.%d.%d\n",
873 ScsiBus, TargetId, Lun);
874
875 Srb = ExAllocatePool(PagedPool, sizeof(SCSI_REQUEST_BLOCK));
876 if (!Srb)
877 break;
878 RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
879 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
880 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
881 Srb->PathId = PathId;
882 Srb->TargetId = TargetId;
883 Srb->Lun = Lun;
884 Srb->CdbLength = 6;
885 Srb->SrbFlags = SRB_FLAGS_DATA_IN;
886 Srb->DataTransferLength = INQUIRYDATABUFFERSIZE;
887 Srb->TimeOutValue = 5; /* in seconds */
888 Srb->DataBuffer = &InquiryBuffer;
889 Cdb = (PCDB)Srb->Cdb;
890 Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
891 Cdb->CDB6INQUIRY.LogicalUnitNumber = Srb->Lun;
892 Cdb->CDB6INQUIRY.AllocationLength = (UCHAR)Srb->DataTransferLength;
893 if (!SpiSendSynchronousSrb(DeviceExtension, Srb))
894 {
895 /* Don't check next LUNs */
896 break;
897 }
898
899 /* Device exists, create its ARC name */
900 if (InquiryBuffer.RemovableMedia)
901 {
902 sprintf(ArcName, "scsi(%ld)cdrom(%d)fdisk(%d)",
903 ScsiBus, TargetId, Lun);
904 FsRegisterDevice(ArcName, &DiskVtbl);
905 }
906 else
907 {
908 sprintf(ArcName, "scsi(%ld)disk(%d)rdisk(%d)",
909 ScsiBus, TargetId, Lun);
910 /* Now, check if it has partitions */
911 SpiScanDevice(DeviceExtension, ArcName, PathId, TargetId, Lun);
912 }
913
914 /* Check next LUN */
915 Lun++;
916 } while (Lun < SCSI_MAXIMUM_LOGICAL_UNITS);
917 }
918 }
919
920 static
921 VOID
922 SpiResourceToConfig(
923 IN PHW_INITIALIZATION_DATA HwInitializationData,
924 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
925 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig)
926 {
927 PACCESS_RANGE AccessRange;
928 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData;
929 ULONG RangeNumber;
930 ULONG Index;
931
932 RangeNumber = 0;
933
934 /* Loop through all entries */
935 for (Index = 0; Index < ResourceDescriptor->PartialResourceList.Count; Index++)
936 {
937 PartialData = &ResourceDescriptor->PartialResourceList.PartialDescriptors[Index];
938
939 switch (PartialData->Type)
940 {
941 case CmResourceTypePort:
942 /* Copy access ranges */
943 if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
944 {
945 TRACE("Got port at 0x%I64x, len 0x%x\n",
946 PartialData->u.Port.Start.QuadPart, PartialData->u.Port.Length);
947 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
948
949 AccessRange->RangeStart = PartialData->u.Port.Start;
950 AccessRange->RangeLength = PartialData->u.Port.Length;
951
952 AccessRange->RangeInMemory = FALSE;
953 RangeNumber++;
954 }
955 break;
956
957 case CmResourceTypeMemory:
958 /* Copy access ranges */
959 if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
960 {
961 TRACE("Got memory at 0x%I64x, len 0x%x\n",
962 PartialData->u.Memory.Start.QuadPart, PartialData->u.Memory.Length);
963 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
964
965 AccessRange->RangeStart = PartialData->u.Memory.Start;
966 AccessRange->RangeLength = PartialData->u.Memory.Length;
967
968 AccessRange->RangeInMemory = TRUE;
969 RangeNumber++;
970 }
971 break;
972
973 case CmResourceTypeInterrupt:
974 /* Copy interrupt data */
975 TRACE("Got interrupt level %d, vector %d\n",
976 PartialData->u.Interrupt.Level, PartialData->u.Interrupt.Vector);
977 PortConfig->BusInterruptLevel = PartialData->u.Interrupt.Level;
978 PortConfig->BusInterruptVector = PartialData->u.Interrupt.Vector;
979
980 /* Set interrupt mode accordingly to the resource */
981 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
982 {
983 PortConfig->InterruptMode = Latched;
984 }
985 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
986 {
987 PortConfig->InterruptMode = LevelSensitive;
988 }
989 break;
990
991 case CmResourceTypeDma:
992 TRACE("Got DMA channel %d, port %d\n",
993 PartialData->u.Dma.Channel, PartialData->u.Dma.Port);
994 PortConfig->DmaChannel = PartialData->u.Dma.Channel;
995 PortConfig->DmaPort = PartialData->u.Dma.Port;
996 break;
997 }
998 }
999 }
1000
1001 static
1002 BOOLEAN
1003 SpiGetPciConfigData(
1004 IN PHW_INITIALIZATION_DATA HwInitializationData,
1005 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
1006 IN ULONG BusNumber,
1007 IN OUT PPCI_SLOT_NUMBER NextSlotNumber)
1008 {
1009 PCI_COMMON_CONFIG PciConfig;
1010 PCI_SLOT_NUMBER SlotNumber;
1011 ULONG DataSize;
1012 ULONG DeviceNumber;
1013 ULONG FunctionNumber;
1014 CHAR VendorIdString[8];
1015 CHAR DeviceIdString[8];
1016 PCM_RESOURCE_LIST ResourceList = NULL;
1017 NTSTATUS Status;
1018
1019 SlotNumber.u.AsULONG = 0;
1020
1021 /* Loop through all devices */
1022 for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
1023 {
1024 SlotNumber.u.bits.DeviceNumber = DeviceNumber;
1025
1026 /* Loop through all functions */
1027 for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
1028 {
1029 SlotNumber.u.bits.FunctionNumber = FunctionNumber;
1030
1031 /* Get PCI config bytes */
1032 DataSize = HalGetBusDataByOffset(
1033 PCIConfiguration,
1034 BusNumber,
1035 SlotNumber.u.AsULONG,
1036 &PciConfig,
1037 0,
1038 sizeof(ULONG));
1039
1040 /* If result of HalGetBusData is 0, then the bus is wrong */
1041 if (DataSize == 0)
1042 return FALSE;
1043
1044 /* If result is PCI_INVALID_VENDORID, then this device has no more
1045 "Functions" */
1046 if (PciConfig.VendorID == PCI_INVALID_VENDORID)
1047 break;
1048
1049 sprintf(VendorIdString, "%04hx", PciConfig.VendorID);
1050 sprintf(DeviceIdString, "%04hx", PciConfig.DeviceID);
1051
1052 if (_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) ||
1053 _strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength))
1054 {
1055 /* It is not our device */
1056 continue;
1057 }
1058
1059 TRACE( "Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
1060 PciConfig.VendorID, PciConfig.DeviceID,
1061 BusNumber,
1062 SlotNumber.u.bits.DeviceNumber, SlotNumber.u.bits.FunctionNumber);
1063
1064 Status = HalAssignSlotResources(NULL,
1065 NULL,
1066 NULL,
1067 NULL,
1068 PCIBus,
1069 BusNumber,
1070 SlotNumber.u.AsULONG,
1071 &ResourceList);
1072
1073 if (!NT_SUCCESS(Status))
1074 break;
1075
1076 /* Create configuration information */
1077 SpiResourceToConfig(HwInitializationData,
1078 ResourceList->List,
1079 PortConfig);
1080
1081 /* Free the resource list */
1082 ExFreePool(ResourceList);
1083
1084 /* Set dev & fn numbers */
1085 NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
1086 NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1;
1087
1088 /* Save the slot number */
1089 PortConfig->SlotNumber = SlotNumber.u.AsULONG;
1090
1091 return TRUE;
1092 }
1093 NextSlotNumber->u.bits.FunctionNumber = 0;
1094 }
1095
1096 NextSlotNumber->u.bits.DeviceNumber = 0;
1097
1098 return FALSE;
1099 }
1100
1101 ULONG
1102 NTAPI
1103 ScsiPortInitialize(
1104 IN PVOID Argument1,
1105 IN PVOID Argument2,
1106 IN PHW_INITIALIZATION_DATA HwInitializationData,
1107 IN PVOID HwContext OPTIONAL)
1108 {
1109 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1110 ULONG DeviceExtensionSize;
1111 PORT_CONFIGURATION_INFORMATION PortConfig;
1112 BOOLEAN Again;
1113 BOOLEAN FirstConfigCall = TRUE;
1114 PCI_SLOT_NUMBER SlotNumber;
1115 UCHAR ScsiBus;
1116 NTSTATUS Status;
1117
1118 if (HwInitializationData->HwInitializationDataSize != sizeof(HW_INITIALIZATION_DATA))
1119 {
1120 return STATUS_INVALID_PARAMETER;
1121 }
1122
1123 /* Check params for validity */
1124 if ((HwInitializationData->HwInitialize == NULL) ||
1125 (HwInitializationData->HwStartIo == NULL) ||
1126 (HwInitializationData->HwInterrupt == NULL) ||
1127 (HwInitializationData->HwFindAdapter == NULL) ||
1128 (HwInitializationData->HwResetBus == NULL))
1129 {
1130 return STATUS_INVALID_PARAMETER;
1131 }
1132
1133 /* Zero starting slot number */
1134 SlotNumber.u.AsULONG = 0;
1135
1136 while (TRUE)
1137 {
1138 Again = FALSE;
1139
1140 DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) + HwInitializationData->DeviceExtensionSize;
1141 DeviceExtension = FrLdrTempAlloc(DeviceExtensionSize, TAG_SCSI_DEVEXT);
1142 if (!DeviceExtension)
1143 {
1144 return STATUS_NO_MEMORY;
1145 }
1146 RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
1147 DeviceExtension->InterruptFlags = SCSI_PORT_NEXT_REQUEST_READY;
1148 DeviceExtension->HwInitialize = HwInitializationData->HwInitialize;
1149 DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
1150 DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
1151 DeviceExtension->HwResetBus = HwInitializationData->HwResetBus;
1152 DeviceExtension->MiniPortDeviceExtension = (PVOID)(DeviceExtension + 1);
1153
1154 Status = SpiCreatePortConfig(DeviceExtension,
1155 HwInitializationData,
1156 &PortConfig,
1157 FirstConfigCall);
1158 if (Status != STATUS_SUCCESS)
1159 {
1160 FrLdrTempFree(DeviceExtension, TAG_SCSI_DEVEXT);
1161 return Status;
1162 }
1163
1164 PortConfig.NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
1165 PortConfig.AccessRanges = FrLdrTempAlloc(sizeof(ACCESS_RANGE) * HwInitializationData->NumberOfAccessRanges,
1166 TAG_SCSI_ACCESS_RANGES);
1167 if (!PortConfig.AccessRanges)
1168 {
1169 FrLdrTempFree(DeviceExtension, TAG_SCSI_DEVEXT);
1170 return STATUS_NO_MEMORY;
1171 }
1172 RtlZeroMemory(PortConfig.AccessRanges, sizeof(ACCESS_RANGE) * HwInitializationData->NumberOfAccessRanges);
1173
1174 /* Search for matching PCI device */
1175 if ((HwInitializationData->AdapterInterfaceType == PCIBus) &&
1176 (HwInitializationData->VendorIdLength > 0) &&
1177 (HwInitializationData->VendorId != NULL) &&
1178 (HwInitializationData->DeviceIdLength > 0) &&
1179 (HwInitializationData->DeviceId != NULL))
1180 {
1181 PortConfig.BusInterruptLevel = 0;
1182
1183 /* Get PCI device data */
1184 TRACE("VendorId '%.*s' DeviceId '%.*s'\n",
1185 HwInitializationData->VendorIdLength,
1186 HwInitializationData->VendorId,
1187 HwInitializationData->DeviceIdLength,
1188 HwInitializationData->DeviceId);
1189
1190 if (!SpiGetPciConfigData(HwInitializationData,
1191 &PortConfig,
1192 0, /* FIXME */
1193 &SlotNumber))
1194 {
1195 /* Continue to the next bus, nothing here */
1196 FrLdrTempFree(DeviceExtension, TAG_SCSI_DEVEXT);
1197 return STATUS_INTERNAL_ERROR;
1198 }
1199
1200 if (!PortConfig.BusInterruptLevel)
1201 {
1202 /* Bypass this slot, because no interrupt was assigned */
1203 FrLdrTempFree(DeviceExtension, TAG_SCSI_DEVEXT);
1204 return STATUS_INTERNAL_ERROR;
1205 }
1206 }
1207
1208 if (HwInitializationData->HwFindAdapter(
1209 DeviceExtension->MiniPortDeviceExtension,
1210 HwContext,
1211 NULL,
1212 NULL,
1213 &PortConfig,
1214 &Again) != SP_RETURN_FOUND)
1215 {
1216 FrLdrTempFree(DeviceExtension, TAG_SCSI_DEVEXT);
1217 return STATUS_INTERNAL_ERROR;
1218 }
1219
1220 /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1221 if (PortConfig.MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS)
1222 DeviceExtension->MaxTargedIds = SCSI_MAXIMUM_TARGETS_PER_BUS;
1223 else
1224 DeviceExtension->MaxTargedIds = PortConfig.MaximumNumberOfTargets;
1225
1226 DeviceExtension->BusNum = PortConfig.SystemIoBusNumber;
1227
1228 TRACE("Adapter found: buses = %d, targets = %d\n",
1229 PortConfig.NumberOfBuses, DeviceExtension->MaxTargedIds);
1230
1231 /* Initialize adapter */
1232 if (!DeviceExtension->HwInitialize(DeviceExtension->MiniPortDeviceExtension))
1233 {
1234 FrLdrTempFree(DeviceExtension, TAG_SCSI_DEVEXT);
1235 return STATUS_INTERNAL_ERROR;
1236 }
1237
1238 /* Scan bus */
1239 for (ScsiBus = 0; ScsiBus < PortConfig.NumberOfBuses; ScsiBus++)
1240 {
1241 SpiScanAdapter(DeviceExtension, PortConfig.SystemIoBusNumber, ScsiBus);
1242 PortConfig.SystemIoBusNumber++;
1243 }
1244
1245 FirstConfigCall = FALSE;
1246 if (!Again)
1247 {
1248 break;
1249 }
1250 }
1251
1252 return STATUS_SUCCESS;
1253 }
1254
1255 VOID
1256 NTAPI
1257 ScsiPortIoMapTransfer(
1258 IN PVOID HwDeviceExtension,
1259 IN PSCSI_REQUEST_BLOCK Srb,
1260 IN PVOID LogicalAddress,
1261 IN ULONG Length)
1262 {
1263 // FIXME
1264 UNIMPLEMENTED;
1265 }
1266
1267 VOID
1268 NTAPI
1269 ScsiPortLogError(
1270 IN PVOID HwDeviceExtension,
1271 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
1272 IN UCHAR PathId,
1273 IN UCHAR TargetId,
1274 IN UCHAR Lun,
1275 IN ULONG ErrorCode,
1276 IN ULONG UniqueId)
1277 {
1278 // FIXME
1279 UNIMPLEMENTED;
1280 }
1281
1282 VOID
1283 NTAPI
1284 ScsiPortMoveMemory(
1285 IN PVOID WriteBuffer,
1286 IN PVOID ReadBuffer,
1287 IN ULONG Length)
1288 {
1289 RtlMoveMemory(WriteBuffer, ReadBuffer, Length);
1290 }
1291
1292 VOID
1293 __cdecl
1294 ScsiPortNotification(
1295 IN SCSI_NOTIFICATION_TYPE NotificationType,
1296 IN PVOID HwDeviceExtension,
1297 IN ...)
1298 {
1299 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1300 PSCSI_REQUEST_BLOCK Srb;
1301 va_list ap;
1302
1303 DeviceExtension = ((PSCSI_PORT_DEVICE_EXTENSION)HwDeviceExtension) - 1;
1304
1305 va_start(ap, HwDeviceExtension);
1306
1307 switch (NotificationType)
1308 {
1309 case RequestComplete:
1310 /* Mask the SRB as completed */
1311 Srb = va_arg(ap, PSCSI_REQUEST_BLOCK);
1312 Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
1313 break;
1314
1315 case NextRequest:
1316 /* Say that device is ready */
1317 DeviceExtension->InterruptFlags |= SCSI_PORT_NEXT_REQUEST_READY;
1318 break;
1319
1320 default:
1321 // FIXME
1322 UNIMPLEMENTED;
1323 }
1324
1325 va_end(ap);
1326 }
1327
1328 VOID
1329 NTAPI
1330 ScsiPortReadPortBufferUchar(
1331 IN PUCHAR Port,
1332 OUT PUCHAR Buffer,
1333 IN ULONG Count)
1334 {
1335 __inbytestring(H2I(Port), Buffer, Count);
1336 }
1337
1338 VOID
1339 NTAPI
1340 ScsiPortReadPortBufferUlong(
1341 IN PULONG Port,
1342 OUT PULONG Buffer,
1343 IN ULONG Count)
1344 {
1345 __indwordstring(H2I(Port), Buffer, Count);
1346 }
1347
1348 VOID
1349 NTAPI
1350 ScsiPortReadPortBufferUshort(
1351 IN PUSHORT Port,
1352 OUT PUSHORT Buffer,
1353 IN ULONG Count)
1354 {
1355 __inwordstring(H2I(Port), Buffer, Count);
1356 }
1357
1358 UCHAR
1359 NTAPI
1360 ScsiPortReadPortUchar(
1361 IN PUCHAR Port)
1362 {
1363 TRACE("ScsiPortReadPortUchar(%p)\n", Port);
1364
1365 return READ_PORT_UCHAR(Port);
1366 }
1367
1368 ULONG
1369 NTAPI
1370 ScsiPortReadPortUlong(
1371 IN PULONG Port)
1372 {
1373 return READ_PORT_ULONG(Port);
1374 }
1375
1376 USHORT
1377 NTAPI
1378 ScsiPortReadPortUshort(
1379 IN PUSHORT Port)
1380 {
1381 return READ_PORT_USHORT(Port);
1382 }
1383
1384 VOID
1385 NTAPI
1386 ScsiPortReadRegisterBufferUchar(
1387 IN PUCHAR Register,
1388 IN PUCHAR Buffer,
1389 IN ULONG Count)
1390 {
1391 // FIXME
1392 UNIMPLEMENTED;
1393 }
1394
1395 VOID
1396 NTAPI
1397 ScsiPortReadRegisterBufferUlong(
1398 IN PULONG Register,
1399 IN PULONG Buffer,
1400 IN ULONG Count)
1401 {
1402 // FIXME
1403 UNIMPLEMENTED;
1404 }
1405
1406 VOID
1407 NTAPI
1408 ScsiPortReadRegisterBufferUshort(
1409 IN PUSHORT Register,
1410 IN PUSHORT Buffer,
1411 IN ULONG Count)
1412 {
1413 // FIXME
1414 UNIMPLEMENTED;
1415 }
1416
1417 UCHAR
1418 NTAPI
1419 ScsiPortReadRegisterUchar(
1420 IN PUCHAR Register)
1421 {
1422 return READ_REGISTER_UCHAR(Register);
1423 }
1424
1425 ULONG
1426 NTAPI
1427 ScsiPortReadRegisterUlong(
1428 IN PULONG Register)
1429 {
1430 return READ_REGISTER_ULONG(Register);
1431 }
1432
1433 USHORT
1434 NTAPI
1435 ScsiPortReadRegisterUshort(
1436 IN PUSHORT Register)
1437 {
1438 return READ_REGISTER_USHORT(Register);
1439 }
1440
1441 ULONG
1442 NTAPI
1443 ScsiPortSetBusDataByOffset(
1444 IN PVOID DeviceExtension,
1445 IN ULONG BusDataType,
1446 IN ULONG SystemIoBusNumber,
1447 IN ULONG SlotNumber,
1448 IN PVOID Buffer,
1449 IN ULONG Offset,
1450 IN ULONG Length)
1451 {
1452 // FIXME
1453 UNIMPLEMENTED;
1454 return 0;
1455 }
1456
1457 VOID
1458 NTAPI
1459 ScsiPortStallExecution(
1460 IN ULONG Delay)
1461 {
1462 KeStallExecutionProcessor(Delay);
1463 }
1464
1465 BOOLEAN
1466 NTAPI
1467 ScsiPortValidateRange(
1468 IN PVOID HwDeviceExtension,
1469 IN INTERFACE_TYPE BusType,
1470 IN ULONG SystemIoBusNumber,
1471 IN SCSI_PHYSICAL_ADDRESS IoAddress,
1472 IN ULONG NumberOfBytes,
1473 IN BOOLEAN InIoSpace)
1474 {
1475 // FIXME
1476 UNIMPLEMENTED;
1477 return TRUE;
1478 }
1479
1480 #if 0
1481 // ScsiPortWmi*
1482 #endif
1483
1484
1485 VOID
1486 NTAPI
1487 ScsiPortWritePortBufferUchar(
1488 IN PUCHAR Port,
1489 IN PUCHAR Buffer,
1490 IN ULONG Count)
1491 {
1492 __outbytestring(H2I(Port), Buffer, Count);
1493 }
1494
1495 VOID
1496 NTAPI
1497 ScsiPortWritePortBufferUlong(
1498 IN PULONG Port,
1499 IN PULONG Buffer,
1500 IN ULONG Count)
1501 {
1502 __outdwordstring(H2I(Port), Buffer, Count);
1503 }
1504
1505 VOID
1506 NTAPI
1507 ScsiPortWritePortBufferUshort(
1508 IN PUSHORT Port,
1509 IN PUSHORT Buffer,
1510 IN ULONG Count)
1511 {
1512 __outwordstring(H2I(Port), Buffer, Count);
1513 }
1514
1515 VOID
1516 NTAPI
1517 ScsiPortWritePortUchar(
1518 IN PUCHAR Port,
1519 IN UCHAR Value)
1520 {
1521 WRITE_PORT_UCHAR(Port, Value);
1522 }
1523
1524 VOID
1525 NTAPI
1526 ScsiPortWritePortUlong(
1527 IN PULONG Port,
1528 IN ULONG Value)
1529 {
1530 WRITE_PORT_ULONG(Port, Value);
1531 }
1532
1533 VOID
1534 NTAPI
1535 ScsiPortWritePortUshort(
1536 IN PUSHORT Port,
1537 IN USHORT Value)
1538 {
1539 WRITE_PORT_USHORT(Port, Value);
1540 }
1541
1542 VOID
1543 NTAPI
1544 ScsiPortWriteRegisterBufferUchar(
1545 IN PUCHAR Register,
1546 IN PUCHAR Buffer,
1547 IN ULONG Count)
1548 {
1549 // FIXME
1550 UNIMPLEMENTED;
1551 }
1552
1553 VOID
1554 NTAPI
1555 ScsiPortWriteRegisterBufferUlong(
1556 IN PULONG Register,
1557 IN PULONG Buffer,
1558 IN ULONG Count)
1559 {
1560 // FIXME
1561 UNIMPLEMENTED;
1562 }
1563
1564 VOID
1565 NTAPI
1566 ScsiPortWriteRegisterBufferUshort(
1567 IN PUSHORT Register,
1568 IN PUSHORT Buffer,
1569 IN ULONG Count)
1570 {
1571 // FIXME
1572 UNIMPLEMENTED;
1573 }
1574
1575 VOID
1576 NTAPI
1577 ScsiPortWriteRegisterUchar(
1578 IN PUCHAR Register,
1579 IN UCHAR Value)
1580 {
1581 WRITE_REGISTER_UCHAR(Register, Value);
1582 }
1583
1584 VOID
1585 NTAPI
1586 ScsiPortWriteRegisterUlong(
1587 IN PULONG Register,
1588 IN ULONG Value)
1589 {
1590 WRITE_REGISTER_ULONG(Register, Value);
1591 }
1592
1593 VOID
1594 NTAPI
1595 ScsiPortWriteRegisterUshort(
1596 IN PUSHORT Register,
1597 IN USHORT Value)
1598 {
1599 WRITE_REGISTER_USHORT(Register, Value);
1600 }
1601
1602 extern char __ImageBase;
1603
1604 ULONG
1605 LoadBootDeviceDriver(VOID)
1606 {
1607 PIMAGE_NT_HEADERS NtHeaders;
1608 LIST_ENTRY ModuleListHead;
1609 PIMAGE_IMPORT_DESCRIPTOR ImportTable;
1610 ULONG ImportTableSize;
1611 PLDR_DATA_TABLE_ENTRY BootDdDTE, FreeldrDTE;
1612 CHAR NtBootDdPath[MAX_PATH];
1613 PVOID ImageBase = NULL;
1614 ULONG (NTAPI *EntryPoint)(IN PVOID DriverObject, IN PVOID RegistryPath);
1615 BOOLEAN Success;
1616
1617 // FIXME: Must be done *INSIDE* the HAL!
1618 #ifdef _M_IX86
1619 HalpInitializePciStubs();
1620 HalpInitBusHandler();
1621 #endif
1622
1623 /* Initialize the loaded module list */
1624 InitializeListHead(&ModuleListHead);
1625
1626 /* Create full ntbootdd.sys path */
1627 strcpy(NtBootDdPath, FrLdrBootPath);
1628 strcat(NtBootDdPath, "\\NTBOOTDD.SYS");
1629
1630 /* Load file */
1631 Success = WinLdrLoadImage(NtBootDdPath, LoaderBootDriver, &ImageBase);
1632 if (!Success)
1633 {
1634 /* That's OK. File simply doesn't exist */
1635 return ESUCCESS;
1636 }
1637
1638 /* Allocate a DTE for ntbootdd */
1639 Success = WinLdrAllocateDataTableEntry(&ModuleListHead, "ntbootdd.sys",
1640 "NTBOOTDD.SYS", ImageBase, &BootDdDTE);
1641 if (!Success)
1642 return EIO;
1643
1644 /* Add the PE part of freeldr.sys to the list of loaded executables, it
1645 contains ScsiPort* exports, imported by ntbootdd.sys */
1646 Success = WinLdrAllocateDataTableEntry(&ModuleListHead, "scsiport.sys",
1647 "FREELDR.SYS", &__ImageBase, &FreeldrDTE);
1648 if (!Success)
1649 {
1650 RemoveEntryList(&BootDdDTE->InLoadOrderLinks);
1651 return EIO;
1652 }
1653
1654 /* Fix imports */
1655 Success = WinLdrScanImportDescriptorTable(&ModuleListHead, "", BootDdDTE);
1656
1657 /* Now unlinkt the DTEs, they won't be valid later */
1658 RemoveEntryList(&BootDdDTE->InLoadOrderLinks);
1659 RemoveEntryList(&FreeldrDTE->InLoadOrderLinks);
1660
1661 if (!Success)
1662 return EIO;
1663
1664 /* Change imports to PA */
1665 ImportTable = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(VaToPa(BootDdDTE->DllBase),
1666 TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ImportTableSize);
1667 for (;(ImportTable->Name != 0) && (ImportTable->FirstThunk != 0);ImportTable++)
1668 {
1669 PIMAGE_THUNK_DATA ThunkData = (PIMAGE_THUNK_DATA)VaToPa(RVA(BootDdDTE->DllBase, ImportTable->FirstThunk));
1670
1671 while (((PIMAGE_THUNK_DATA)ThunkData)->u1.AddressOfData != 0)
1672 {
1673 ThunkData->u1.Function = (ULONG)VaToPa((PVOID)ThunkData->u1.Function);
1674 ThunkData++;
1675 }
1676 }
1677
1678 /* Relocate image to PA */
1679 NtHeaders = RtlImageNtHeader(VaToPa(BootDdDTE->DllBase));
1680 if (!NtHeaders)
1681 return EIO;
1682 Success = (BOOLEAN)LdrRelocateImageWithBias(VaToPa(BootDdDTE->DllBase),
1683 NtHeaders->OptionalHeader.ImageBase - (ULONG_PTR)BootDdDTE->DllBase,
1684 "FreeLdr",
1685 TRUE,
1686 TRUE, /* in case of conflict still return success */
1687 FALSE);
1688 if (!Success)
1689 return EIO;
1690
1691 /* Call the entrypoint */
1692 EntryPoint = VaToPa(BootDdDTE->EntryPoint);
1693 (*EntryPoint)(NULL, NULL);
1694
1695 return ESUCCESS;
1696 }
1697
1698 /* EOF */