[FREELDR] Implement 'SeekRelative' mode for the *Seek() methods for disks & filesystems.
[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 LARGE_INTEGER NewPosition = *Position;
377
378 switch (SeekMode)
379 {
380 case SeekAbsolute:
381 break;
382 case SeekRelative:
383 NewPosition.QuadPart += (Context->SectorNumber * Context->SectorSize);
384 break;
385 default:
386 ASSERT(FALSE);
387 return EINVAL;
388 }
389
390 if (NewPosition.QuadPart & (Context->SectorSize - 1))
391 return EINVAL;
392
393 /* Convert in number of sectors */
394 NewPosition.QuadPart /= Context->SectorSize;
395 if (NewPosition.QuadPart >= Context->SectorCount)
396 return EINVAL;
397
398 Context->SectorNumber = NewPosition.QuadPart;
399 return ESUCCESS;
400 }
401
402 static const DEVVTBL DiskVtbl = {
403 DiskClose,
404 DiskGetFileInformation,
405 DiskOpen,
406 DiskRead,
407 DiskSeek,
408 };
409
410 static
411 NTSTATUS
412 SpiCreatePortConfig(
413 IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
414 IN PHW_INITIALIZATION_DATA HwInitData,
415 OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
416 IN BOOLEAN ZeroStruct)
417 {
418 ULONG Bus;
419
420 /* Zero out the struct if told so */
421 if (ZeroStruct)
422 {
423 /* First zero the portconfig */
424 RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION));
425
426 /* Initialize the struct */
427 ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
428 ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType;
429 ConfigInfo->InterruptMode = Latched;
430 ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
431 ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
432 ConfigInfo->MaximumTransferLength = SP_UNINITIALIZED_VALUE;
433 ConfigInfo->MaximumNumberOfTargets = SCSI_MAXIMUM_TARGETS_PER_BUS;
434
435 /* Store parameters */
436 ConfigInfo->NeedPhysicalAddresses = HwInitData->NeedPhysicalAddresses;
437 ConfigInfo->MapBuffers = HwInitData->MapBuffers;
438 ConfigInfo->AutoRequestSense = HwInitData->AutoRequestSense;
439 ConfigInfo->ReceiveEvent = HwInitData->ReceiveEvent;
440 ConfigInfo->TaggedQueuing = HwInitData->TaggedQueuing;
441 ConfigInfo->MultipleRequestPerLu = HwInitData->MultipleRequestPerLu;
442
443 /* Get the disk usage */
444 ConfigInfo->AtdiskPrimaryClaimed = FALSE; // FIXME
445 ConfigInfo->AtdiskSecondaryClaimed = FALSE; // FIXME
446
447 /* Initiator bus id is not set */
448 for (Bus = 0; Bus < 8; Bus++)
449 ConfigInfo->InitiatorBusId[Bus] = (CCHAR)SP_UNINITIALIZED_VALUE;
450 }
451
452 ConfigInfo->NumberOfPhysicalBreaks = 17;
453
454 return STATUS_SUCCESS;
455 }
456
457 VOID
458 __cdecl
459 ScsiDebugPrint(
460 IN ULONG DebugPrintLevel,
461 IN PCCHAR DebugMessage,
462 IN ...)
463 {
464 va_list ap;
465 CHAR Buffer[512];
466 ULONG Length;
467
468 if (DebugPrintLevel > 10)
469 return;
470
471 va_start(ap, DebugMessage);
472
473 /* Construct a string */
474 Length = _vsnprintf(Buffer, 512, DebugMessage, ap);
475
476 /* Check if we went past the buffer */
477 if (Length == MAXULONG)
478 {
479 /* Terminate it if we went over-board */
480 Buffer[sizeof(Buffer) - 1] = '\0';
481
482 /* Put maximum */
483 Length = sizeof(Buffer);
484 }
485
486 /* Print the message */
487 TRACE("%s", Buffer);
488
489 /* Cleanup */
490 va_end(ap);
491 }
492
493 VOID
494 NTAPI
495 ScsiPortCompleteRequest(
496 IN PVOID HwDeviceExtension,
497 IN UCHAR PathId,
498 IN UCHAR TargetId,
499 IN UCHAR Lun,
500 IN UCHAR SrbStatus)
501 {
502 // FIXME
503 UNIMPLEMENTED;
504 }
505
506 #undef ScsiPortConvertPhysicalAddressToUlong
507 ULONG
508 NTAPI
509 ScsiPortConvertPhysicalAddressToUlong(
510 IN SCSI_PHYSICAL_ADDRESS Address)
511 {
512 return Address.LowPart;
513 }
514
515 SCSI_PHYSICAL_ADDRESS
516 NTAPI
517 ScsiPortConvertUlongToPhysicalAddress(
518 IN ULONG_PTR UlongAddress)
519 {
520 SCSI_PHYSICAL_ADDRESS Address;
521
522 Address.QuadPart = UlongAddress;
523 return Address;
524 }
525
526 VOID
527 NTAPI
528 ScsiPortFlushDma(
529 IN PVOID DeviceExtension)
530 {
531 // FIXME
532 UNIMPLEMENTED;
533 }
534
535 VOID
536 NTAPI
537 ScsiPortFreeDeviceBase(
538 IN PVOID HwDeviceExtension,
539 IN PVOID MappedAddress)
540 {
541 // Nothing to do
542 }
543
544 ULONG
545 NTAPI
546 ScsiPortGetBusData(
547 IN PVOID DeviceExtension,
548 IN ULONG BusDataType,
549 IN ULONG SystemIoBusNumber,
550 IN ULONG SlotNumber,
551 IN PVOID Buffer,
552 IN ULONG Length)
553 {
554 return HalGetBusDataByOffset(BusDataType, SystemIoBusNumber, SlotNumber, Buffer, 0, Length);
555 }
556
557 PVOID
558 NTAPI
559 ScsiPortGetDeviceBase(
560 IN PVOID HwDeviceExtension,
561 IN INTERFACE_TYPE BusType,
562 IN ULONG SystemIoBusNumber,
563 IN SCSI_PHYSICAL_ADDRESS IoAddress,
564 IN ULONG NumberOfBytes,
565 IN BOOLEAN InIoSpace)
566 {
567 PHYSICAL_ADDRESS TranslatedAddress;
568 ULONG AddressSpace;
569
570 AddressSpace = (ULONG)InIoSpace;
571 if (HalTranslateBusAddress(BusType,
572 SystemIoBusNumber,
573 IoAddress,
574 &AddressSpace,
575 &TranslatedAddress) == FALSE)
576 {
577 return NULL;
578 }
579
580 /* I/O space */
581 if (AddressSpace != 0)
582 return (PVOID)TranslatedAddress.u.LowPart;
583
584 // FIXME
585 UNIMPLEMENTED;
586 return (PVOID)IoAddress.LowPart;
587 }
588
589 PVOID
590 NTAPI
591 ScsiPortGetLogicalUnit(
592 IN PVOID HwDeviceExtension,
593 IN UCHAR PathId,
594 IN UCHAR TargetId,
595 IN UCHAR Lun)
596 {
597 // FIXME
598 UNIMPLEMENTED;
599 return NULL;
600 }
601
602 SCSI_PHYSICAL_ADDRESS
603 NTAPI
604 ScsiPortGetPhysicalAddress(
605 IN PVOID HwDeviceExtension,
606 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
607 IN PVOID VirtualAddress,
608 OUT ULONG *Length)
609 {
610 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
611 SCSI_PHYSICAL_ADDRESS PhysicalAddress;
612 ULONG BufferLength = 0;
613 ULONG Offset;
614
615 TRACE("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
616 HwDeviceExtension, Srb, VirtualAddress, Length);
617
618 DeviceExtension = ((PSCSI_PORT_DEVICE_EXTENSION)HwDeviceExtension) - 1;
619
620 if (Srb == NULL || Srb->SenseInfoBuffer == VirtualAddress)
621 {
622 /* Simply look it up in the allocated common buffer */
623 Offset = (PUCHAR)VirtualAddress - (PUCHAR)DeviceExtension->SrbExtensionBuffer;
624
625 BufferLength = DeviceExtension->CommonBufferLength - Offset;
626 PhysicalAddress.QuadPart = Offset;
627 }
628 else
629 {
630 /* Nothing */
631 PhysicalAddress.QuadPart = (LONGLONG)(SP_UNINITIALIZED_VALUE);
632 }
633
634 *Length = BufferLength;
635 return PhysicalAddress;
636 }
637
638 PSCSI_REQUEST_BLOCK
639 NTAPI
640 ScsiPortGetSrb(
641 IN PVOID DeviceExtension,
642 IN UCHAR PathId,
643 IN UCHAR TargetId,
644 IN UCHAR Lun,
645 IN LONG QueueTag)
646 {
647 // FIXME
648 UNIMPLEMENTED;
649 return NULL;
650 }
651
652 static
653 NTSTATUS
654 SpiAllocateCommonBuffer(
655 IN OUT PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
656 IN ULONG NonCachedSize)
657 {
658 PVOID CommonBuffer;
659 ULONG CommonBufferLength, BufSize;
660
661 /* If size is 0, set it to 16 */
662 if (!DeviceExtension->SrbExtensionSize)
663 DeviceExtension->SrbExtensionSize = 16;
664
665 /* Calculate size */
666 BufSize = DeviceExtension->SrbExtensionSize;
667
668 /* Round it */
669 BufSize = (BufSize + sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
670
671 /* Sum up into the total common buffer length, and round it to page size */
672 CommonBufferLength =
673 ROUND_TO_PAGES(NonCachedSize);
674
675 /* Allocate it */
676 if (!DeviceExtension->AdapterObject)
677 {
678 /* From nonpaged pool if there is no DMA */
679 CommonBuffer = ExAllocatePool(NonPagedPool, CommonBufferLength);
680 }
681 else
682 {
683 /* Perform a full request since we have a DMA adapter*/
684 UNIMPLEMENTED;
685 CommonBuffer = NULL;
686 }
687
688 /* Fail in case of error */
689 if (!CommonBuffer)
690 return STATUS_INSUFFICIENT_RESOURCES;
691
692 /* Zero it */
693 RtlZeroMemory(CommonBuffer, CommonBufferLength);
694
695 /* Store its size in Device Extension */
696 DeviceExtension->CommonBufferLength = CommonBufferLength;
697
698 /* SrbExtension buffer is located at the beginning of the buffer */
699 DeviceExtension->SrbExtensionBuffer = CommonBuffer;
700
701 /* Non-cached extension buffer is located at the end of
702 the common buffer */
703 if (NonCachedSize)
704 {
705 CommonBufferLength -= NonCachedSize;
706 DeviceExtension->NonCachedExtension = (PUCHAR)CommonBuffer + CommonBufferLength;
707 }
708 else
709 {
710 DeviceExtension->NonCachedExtension = NULL;
711 }
712
713 return STATUS_SUCCESS;
714 }
715
716 PVOID
717 NTAPI
718 ScsiPortGetUncachedExtension(
719 IN PVOID HwDeviceExtension,
720 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
721 IN ULONG NumberOfBytes)
722 {
723 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
724 DEVICE_DESCRIPTION DeviceDescription;
725 ULONG MapRegistersCount;
726 NTSTATUS Status;
727
728 TRACE("ScsiPortGetUncachedExtension(%p %p %lu)\n",
729 HwDeviceExtension, ConfigInfo, NumberOfBytes);
730
731 DeviceExtension = ((PSCSI_PORT_DEVICE_EXTENSION)HwDeviceExtension) - 1;
732
733 /* Check for allocated common DMA buffer */
734 if (DeviceExtension->SrbExtensionBuffer != NULL)
735 {
736 return NULL;
737 }
738
739 /* Check for DMA adapter object */
740 if (DeviceExtension->AdapterObject == NULL)
741 {
742 /* Initialize DMA adapter description */
743 RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
744
745 DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
746 DeviceDescription.Master = ConfigInfo->Master;
747 DeviceDescription.ScatterGather = ConfigInfo->ScatterGather;
748 DeviceDescription.DemandMode = ConfigInfo->DemandMode;
749 DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
750 DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
751 DeviceDescription.DmaChannel = ConfigInfo->DmaChannel;
752 DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
753 DeviceDescription.DmaWidth = ConfigInfo->DmaWidth;
754 DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
755 DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
756 DeviceDescription.DmaPort = ConfigInfo->DmaPort;
757
758 /* Get a DMA adapter object */
759 #if 0
760 DeviceExtension->AdapterObject =
761 HalGetAdapter(&DeviceDescription, &MapRegistersCount);
762
763 /* Fail in case of error */
764 if (DeviceExtension->AdapterObject == NULL)
765 {
766 return NULL;
767 }
768 #else
769 MapRegistersCount = 0;
770 #endif
771
772 /* Set number of physical breaks */
773 if (ConfigInfo->NumberOfPhysicalBreaks != 0 &&
774 MapRegistersCount > ConfigInfo->NumberOfPhysicalBreaks)
775 {
776 DeviceExtension->PortCapabilities.MaximumPhysicalPages =
777 ConfigInfo->NumberOfPhysicalBreaks;
778 }
779 else
780 {
781 DeviceExtension->PortCapabilities.MaximumPhysicalPages = MapRegistersCount;
782 }
783 }
784
785 /* Update Srb extension size */
786 if (DeviceExtension->SrbExtensionSize != ConfigInfo->SrbExtensionSize)
787 DeviceExtension->SrbExtensionSize = ConfigInfo->SrbExtensionSize;
788
789 /* Allocate a common DMA buffer */
790 Status = SpiAllocateCommonBuffer(DeviceExtension, NumberOfBytes);
791
792 if (!NT_SUCCESS(Status))
793 {
794 TRACE("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status);
795 return NULL;
796 }
797
798 return DeviceExtension->NonCachedExtension;
799 }
800
801 PVOID
802 NTAPI
803 ScsiPortGetVirtualAddress(
804 IN PVOID HwDeviceExtension,
805 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
806 {
807 // FIXME
808 UNIMPLEMENTED;
809 return NULL;
810 }
811
812 static
813 VOID
814 SpiScanDevice(
815 IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
816 IN PCHAR ArcName,
817 IN ULONG ScsiBus,
818 IN ULONG TargetId,
819 IN ULONG Lun)
820 {
821 ULONG FileId, i;
822 ARC_STATUS Status;
823 NTSTATUS ret;
824 struct _DRIVE_LAYOUT_INFORMATION *PartitionBuffer;
825 CHAR PartitionName[64];
826
827 /* Register device with partition(0) suffix */
828 RtlStringCbPrintfA(PartitionName, sizeof(PartitionName), "%spartition(0)", ArcName);
829 FsRegisterDevice(PartitionName, &DiskVtbl);
830
831 /* Read device partition table */
832 Status = ArcOpen(PartitionName, OpenReadOnly, &FileId);
833 if (Status == ESUCCESS)
834 {
835 ret = HALDISPATCH->HalIoReadPartitionTable((PDEVICE_OBJECT)FileId, 512, FALSE, &PartitionBuffer);
836 if (NT_SUCCESS(ret))
837 {
838 for (i = 0; i < PartitionBuffer->PartitionCount; i++)
839 {
840 if (PartitionBuffer->PartitionEntry[i].PartitionType != PARTITION_ENTRY_UNUSED)
841 {
842 RtlStringCbPrintfA(PartitionName,
843 sizeof(PartitionName),
844 "%spartition(%lu)",
845 ArcName,
846 PartitionBuffer->PartitionEntry[i].PartitionNumber);
847 FsRegisterDevice(PartitionName, &DiskVtbl);
848 }
849 }
850 ExFreePool(PartitionBuffer);
851 }
852 ArcClose(FileId);
853 }
854 }
855
856 static
857 VOID
858 SpiScanAdapter(
859 IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
860 IN ULONG ScsiBus,
861 IN UCHAR PathId)
862 {
863 CHAR ArcName[64];
864 PSCSI_REQUEST_BLOCK Srb;
865 PCDB Cdb;
866 INQUIRYDATA InquiryBuffer;
867 UCHAR TargetId;
868 UCHAR Lun;
869
870 if (!DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, PathId))
871 {
872 return;
873 }
874
875 /* Remember the extension */
876 ScsiDeviceExtensions[ScsiBus] = DeviceExtension;
877
878 for (TargetId = 0; TargetId < DeviceExtension->MaxTargedIds; TargetId++)
879 {
880 Lun = 0;
881 do
882 {
883 TRACE("Scanning SCSI device %d.%d.%d\n",
884 ScsiBus, TargetId, Lun);
885
886 Srb = ExAllocatePool(PagedPool, sizeof(SCSI_REQUEST_BLOCK));
887 if (!Srb)
888 break;
889 RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
890 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
891 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
892 Srb->PathId = PathId;
893 Srb->TargetId = TargetId;
894 Srb->Lun = Lun;
895 Srb->CdbLength = 6;
896 Srb->SrbFlags = SRB_FLAGS_DATA_IN;
897 Srb->DataTransferLength = INQUIRYDATABUFFERSIZE;
898 Srb->TimeOutValue = 5; /* in seconds */
899 Srb->DataBuffer = &InquiryBuffer;
900 Cdb = (PCDB)Srb->Cdb;
901 Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
902 Cdb->CDB6INQUIRY.LogicalUnitNumber = Srb->Lun;
903 Cdb->CDB6INQUIRY.AllocationLength = (UCHAR)Srb->DataTransferLength;
904 if (!SpiSendSynchronousSrb(DeviceExtension, Srb))
905 {
906 /* Don't check next LUNs */
907 break;
908 }
909
910 /* Device exists, create its ARC name */
911 if (InquiryBuffer.RemovableMedia)
912 {
913 sprintf(ArcName, "scsi(%ld)cdrom(%d)fdisk(%d)",
914 ScsiBus, TargetId, Lun);
915 FsRegisterDevice(ArcName, &DiskVtbl);
916 }
917 else
918 {
919 sprintf(ArcName, "scsi(%ld)disk(%d)rdisk(%d)",
920 ScsiBus, TargetId, Lun);
921 /* Now, check if it has partitions */
922 SpiScanDevice(DeviceExtension, ArcName, PathId, TargetId, Lun);
923 }
924
925 /* Check next LUN */
926 Lun++;
927 } while (Lun < SCSI_MAXIMUM_LOGICAL_UNITS);
928 }
929 }
930
931 static
932 VOID
933 SpiResourceToConfig(
934 IN PHW_INITIALIZATION_DATA HwInitializationData,
935 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
936 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig)
937 {
938 PACCESS_RANGE AccessRange;
939 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData;
940 ULONG RangeNumber;
941 ULONG Index;
942
943 RangeNumber = 0;
944
945 /* Loop through all entries */
946 for (Index = 0; Index < ResourceDescriptor->PartialResourceList.Count; Index++)
947 {
948 PartialData = &ResourceDescriptor->PartialResourceList.PartialDescriptors[Index];
949
950 switch (PartialData->Type)
951 {
952 case CmResourceTypePort:
953 /* Copy access ranges */
954 if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
955 {
956 TRACE("Got port at 0x%I64x, len 0x%x\n",
957 PartialData->u.Port.Start.QuadPart, PartialData->u.Port.Length);
958 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
959
960 AccessRange->RangeStart = PartialData->u.Port.Start;
961 AccessRange->RangeLength = PartialData->u.Port.Length;
962
963 AccessRange->RangeInMemory = FALSE;
964 RangeNumber++;
965 }
966 break;
967
968 case CmResourceTypeMemory:
969 /* Copy access ranges */
970 if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
971 {
972 TRACE("Got memory at 0x%I64x, len 0x%x\n",
973 PartialData->u.Memory.Start.QuadPart, PartialData->u.Memory.Length);
974 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
975
976 AccessRange->RangeStart = PartialData->u.Memory.Start;
977 AccessRange->RangeLength = PartialData->u.Memory.Length;
978
979 AccessRange->RangeInMemory = TRUE;
980 RangeNumber++;
981 }
982 break;
983
984 case CmResourceTypeInterrupt:
985 /* Copy interrupt data */
986 TRACE("Got interrupt level %d, vector %d\n",
987 PartialData->u.Interrupt.Level, PartialData->u.Interrupt.Vector);
988 PortConfig->BusInterruptLevel = PartialData->u.Interrupt.Level;
989 PortConfig->BusInterruptVector = PartialData->u.Interrupt.Vector;
990
991 /* Set interrupt mode accordingly to the resource */
992 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
993 {
994 PortConfig->InterruptMode = Latched;
995 }
996 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
997 {
998 PortConfig->InterruptMode = LevelSensitive;
999 }
1000 break;
1001
1002 case CmResourceTypeDma:
1003 TRACE("Got DMA channel %d, port %d\n",
1004 PartialData->u.Dma.Channel, PartialData->u.Dma.Port);
1005 PortConfig->DmaChannel = PartialData->u.Dma.Channel;
1006 PortConfig->DmaPort = PartialData->u.Dma.Port;
1007 break;
1008 }
1009 }
1010 }
1011
1012 static
1013 BOOLEAN
1014 SpiGetPciConfigData(
1015 IN PHW_INITIALIZATION_DATA HwInitializationData,
1016 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
1017 IN ULONG BusNumber,
1018 IN OUT PPCI_SLOT_NUMBER NextSlotNumber)
1019 {
1020 PCI_COMMON_CONFIG PciConfig;
1021 PCI_SLOT_NUMBER SlotNumber;
1022 ULONG DataSize;
1023 ULONG DeviceNumber;
1024 ULONG FunctionNumber;
1025 CHAR VendorIdString[8];
1026 CHAR DeviceIdString[8];
1027 PCM_RESOURCE_LIST ResourceList = NULL;
1028 NTSTATUS Status;
1029
1030 SlotNumber.u.AsULONG = 0;
1031
1032 /* Loop through all devices */
1033 for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
1034 {
1035 SlotNumber.u.bits.DeviceNumber = DeviceNumber;
1036
1037 /* Loop through all functions */
1038 for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
1039 {
1040 SlotNumber.u.bits.FunctionNumber = FunctionNumber;
1041
1042 /* Get PCI config bytes */
1043 DataSize = HalGetBusDataByOffset(
1044 PCIConfiguration,
1045 BusNumber,
1046 SlotNumber.u.AsULONG,
1047 &PciConfig,
1048 0,
1049 sizeof(ULONG));
1050
1051 /* If result of HalGetBusData is 0, then the bus is wrong */
1052 if (DataSize == 0)
1053 return FALSE;
1054
1055 /* If result is PCI_INVALID_VENDORID, then this device has no more
1056 "Functions" */
1057 if (PciConfig.VendorID == PCI_INVALID_VENDORID)
1058 break;
1059
1060 sprintf(VendorIdString, "%04hx", PciConfig.VendorID);
1061 sprintf(DeviceIdString, "%04hx", PciConfig.DeviceID);
1062
1063 if (_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) ||
1064 _strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength))
1065 {
1066 /* It is not our device */
1067 continue;
1068 }
1069
1070 TRACE( "Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
1071 PciConfig.VendorID, PciConfig.DeviceID,
1072 BusNumber,
1073 SlotNumber.u.bits.DeviceNumber, SlotNumber.u.bits.FunctionNumber);
1074
1075 Status = HalAssignSlotResources(NULL,
1076 NULL,
1077 NULL,
1078 NULL,
1079 PCIBus,
1080 BusNumber,
1081 SlotNumber.u.AsULONG,
1082 &ResourceList);
1083
1084 if (!NT_SUCCESS(Status))
1085 break;
1086
1087 /* Create configuration information */
1088 SpiResourceToConfig(HwInitializationData,
1089 ResourceList->List,
1090 PortConfig);
1091
1092 /* Free the resource list */
1093 ExFreePool(ResourceList);
1094
1095 /* Set dev & fn numbers */
1096 NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
1097 NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1;
1098
1099 /* Save the slot number */
1100 PortConfig->SlotNumber = SlotNumber.u.AsULONG;
1101
1102 return TRUE;
1103 }
1104 NextSlotNumber->u.bits.FunctionNumber = 0;
1105 }
1106
1107 NextSlotNumber->u.bits.DeviceNumber = 0;
1108
1109 return FALSE;
1110 }
1111
1112 ULONG
1113 NTAPI
1114 ScsiPortInitialize(
1115 IN PVOID Argument1,
1116 IN PVOID Argument2,
1117 IN PHW_INITIALIZATION_DATA HwInitializationData,
1118 IN PVOID HwContext OPTIONAL)
1119 {
1120 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1121 ULONG DeviceExtensionSize;
1122 PORT_CONFIGURATION_INFORMATION PortConfig;
1123 BOOLEAN Again;
1124 BOOLEAN FirstConfigCall = TRUE;
1125 PCI_SLOT_NUMBER SlotNumber;
1126 UCHAR ScsiBus;
1127 NTSTATUS Status;
1128
1129 if (HwInitializationData->HwInitializationDataSize != sizeof(HW_INITIALIZATION_DATA))
1130 {
1131 return STATUS_INVALID_PARAMETER;
1132 }
1133
1134 /* Check params for validity */
1135 if ((HwInitializationData->HwInitialize == NULL) ||
1136 (HwInitializationData->HwStartIo == NULL) ||
1137 (HwInitializationData->HwInterrupt == NULL) ||
1138 (HwInitializationData->HwFindAdapter == NULL) ||
1139 (HwInitializationData->HwResetBus == NULL))
1140 {
1141 return STATUS_INVALID_PARAMETER;
1142 }
1143
1144 /* Zero starting slot number */
1145 SlotNumber.u.AsULONG = 0;
1146
1147 while (TRUE)
1148 {
1149 Again = FALSE;
1150
1151 DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) + HwInitializationData->DeviceExtensionSize;
1152 DeviceExtension = FrLdrTempAlloc(DeviceExtensionSize, TAG_SCSI_DEVEXT);
1153 if (!DeviceExtension)
1154 {
1155 return STATUS_NO_MEMORY;
1156 }
1157 RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
1158 DeviceExtension->InterruptFlags = SCSI_PORT_NEXT_REQUEST_READY;
1159 DeviceExtension->HwInitialize = HwInitializationData->HwInitialize;
1160 DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
1161 DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
1162 DeviceExtension->HwResetBus = HwInitializationData->HwResetBus;
1163 DeviceExtension->MiniPortDeviceExtension = (PVOID)(DeviceExtension + 1);
1164
1165 Status = SpiCreatePortConfig(DeviceExtension,
1166 HwInitializationData,
1167 &PortConfig,
1168 FirstConfigCall);
1169 if (Status != STATUS_SUCCESS)
1170 {
1171 FrLdrTempFree(DeviceExtension, TAG_SCSI_DEVEXT);
1172 return Status;
1173 }
1174
1175 PortConfig.NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
1176 PortConfig.AccessRanges = FrLdrTempAlloc(sizeof(ACCESS_RANGE) * HwInitializationData->NumberOfAccessRanges,
1177 TAG_SCSI_ACCESS_RANGES);
1178 if (!PortConfig.AccessRanges)
1179 {
1180 FrLdrTempFree(DeviceExtension, TAG_SCSI_DEVEXT);
1181 return STATUS_NO_MEMORY;
1182 }
1183 RtlZeroMemory(PortConfig.AccessRanges, sizeof(ACCESS_RANGE) * HwInitializationData->NumberOfAccessRanges);
1184
1185 /* Search for matching PCI device */
1186 if ((HwInitializationData->AdapterInterfaceType == PCIBus) &&
1187 (HwInitializationData->VendorIdLength > 0) &&
1188 (HwInitializationData->VendorId != NULL) &&
1189 (HwInitializationData->DeviceIdLength > 0) &&
1190 (HwInitializationData->DeviceId != NULL))
1191 {
1192 PortConfig.BusInterruptLevel = 0;
1193
1194 /* Get PCI device data */
1195 TRACE("VendorId '%.*s' DeviceId '%.*s'\n",
1196 HwInitializationData->VendorIdLength,
1197 HwInitializationData->VendorId,
1198 HwInitializationData->DeviceIdLength,
1199 HwInitializationData->DeviceId);
1200
1201 if (!SpiGetPciConfigData(HwInitializationData,
1202 &PortConfig,
1203 0, /* FIXME */
1204 &SlotNumber))
1205 {
1206 /* Continue to the next bus, nothing here */
1207 FrLdrTempFree(DeviceExtension, TAG_SCSI_DEVEXT);
1208 return STATUS_INTERNAL_ERROR;
1209 }
1210
1211 if (!PortConfig.BusInterruptLevel)
1212 {
1213 /* Bypass this slot, because no interrupt was assigned */
1214 FrLdrTempFree(DeviceExtension, TAG_SCSI_DEVEXT);
1215 return STATUS_INTERNAL_ERROR;
1216 }
1217 }
1218
1219 if (HwInitializationData->HwFindAdapter(
1220 DeviceExtension->MiniPortDeviceExtension,
1221 HwContext,
1222 NULL,
1223 NULL,
1224 &PortConfig,
1225 &Again) != SP_RETURN_FOUND)
1226 {
1227 FrLdrTempFree(DeviceExtension, TAG_SCSI_DEVEXT);
1228 return STATUS_INTERNAL_ERROR;
1229 }
1230
1231 /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1232 if (PortConfig.MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS)
1233 DeviceExtension->MaxTargedIds = SCSI_MAXIMUM_TARGETS_PER_BUS;
1234 else
1235 DeviceExtension->MaxTargedIds = PortConfig.MaximumNumberOfTargets;
1236
1237 DeviceExtension->BusNum = PortConfig.SystemIoBusNumber;
1238
1239 TRACE("Adapter found: buses = %d, targets = %d\n",
1240 PortConfig.NumberOfBuses, DeviceExtension->MaxTargedIds);
1241
1242 /* Initialize adapter */
1243 if (!DeviceExtension->HwInitialize(DeviceExtension->MiniPortDeviceExtension))
1244 {
1245 FrLdrTempFree(DeviceExtension, TAG_SCSI_DEVEXT);
1246 return STATUS_INTERNAL_ERROR;
1247 }
1248
1249 /* Scan bus */
1250 for (ScsiBus = 0; ScsiBus < PortConfig.NumberOfBuses; ScsiBus++)
1251 {
1252 SpiScanAdapter(DeviceExtension, PortConfig.SystemIoBusNumber, ScsiBus);
1253 PortConfig.SystemIoBusNumber++;
1254 }
1255
1256 FirstConfigCall = FALSE;
1257 if (!Again)
1258 {
1259 break;
1260 }
1261 }
1262
1263 return STATUS_SUCCESS;
1264 }
1265
1266 VOID
1267 NTAPI
1268 ScsiPortIoMapTransfer(
1269 IN PVOID HwDeviceExtension,
1270 IN PSCSI_REQUEST_BLOCK Srb,
1271 IN PVOID LogicalAddress,
1272 IN ULONG Length)
1273 {
1274 // FIXME
1275 UNIMPLEMENTED;
1276 }
1277
1278 VOID
1279 NTAPI
1280 ScsiPortLogError(
1281 IN PVOID HwDeviceExtension,
1282 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
1283 IN UCHAR PathId,
1284 IN UCHAR TargetId,
1285 IN UCHAR Lun,
1286 IN ULONG ErrorCode,
1287 IN ULONG UniqueId)
1288 {
1289 // FIXME
1290 UNIMPLEMENTED;
1291 }
1292
1293 VOID
1294 NTAPI
1295 ScsiPortMoveMemory(
1296 IN PVOID WriteBuffer,
1297 IN PVOID ReadBuffer,
1298 IN ULONG Length)
1299 {
1300 RtlMoveMemory(WriteBuffer, ReadBuffer, Length);
1301 }
1302
1303 VOID
1304 __cdecl
1305 ScsiPortNotification(
1306 IN SCSI_NOTIFICATION_TYPE NotificationType,
1307 IN PVOID HwDeviceExtension,
1308 IN ...)
1309 {
1310 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1311 PSCSI_REQUEST_BLOCK Srb;
1312 va_list ap;
1313
1314 DeviceExtension = ((PSCSI_PORT_DEVICE_EXTENSION)HwDeviceExtension) - 1;
1315
1316 va_start(ap, HwDeviceExtension);
1317
1318 switch (NotificationType)
1319 {
1320 case RequestComplete:
1321 /* Mask the SRB as completed */
1322 Srb = va_arg(ap, PSCSI_REQUEST_BLOCK);
1323 Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
1324 break;
1325
1326 case NextRequest:
1327 /* Say that device is ready */
1328 DeviceExtension->InterruptFlags |= SCSI_PORT_NEXT_REQUEST_READY;
1329 break;
1330
1331 default:
1332 // FIXME
1333 UNIMPLEMENTED;
1334 }
1335
1336 va_end(ap);
1337 }
1338
1339 VOID
1340 NTAPI
1341 ScsiPortReadPortBufferUchar(
1342 IN PUCHAR Port,
1343 OUT PUCHAR Buffer,
1344 IN ULONG Count)
1345 {
1346 __inbytestring(H2I(Port), Buffer, Count);
1347 }
1348
1349 VOID
1350 NTAPI
1351 ScsiPortReadPortBufferUlong(
1352 IN PULONG Port,
1353 OUT PULONG Buffer,
1354 IN ULONG Count)
1355 {
1356 __indwordstring(H2I(Port), Buffer, Count);
1357 }
1358
1359 VOID
1360 NTAPI
1361 ScsiPortReadPortBufferUshort(
1362 IN PUSHORT Port,
1363 OUT PUSHORT Buffer,
1364 IN ULONG Count)
1365 {
1366 __inwordstring(H2I(Port), Buffer, Count);
1367 }
1368
1369 UCHAR
1370 NTAPI
1371 ScsiPortReadPortUchar(
1372 IN PUCHAR Port)
1373 {
1374 TRACE("ScsiPortReadPortUchar(%p)\n", Port);
1375
1376 return READ_PORT_UCHAR(Port);
1377 }
1378
1379 ULONG
1380 NTAPI
1381 ScsiPortReadPortUlong(
1382 IN PULONG Port)
1383 {
1384 return READ_PORT_ULONG(Port);
1385 }
1386
1387 USHORT
1388 NTAPI
1389 ScsiPortReadPortUshort(
1390 IN PUSHORT Port)
1391 {
1392 return READ_PORT_USHORT(Port);
1393 }
1394
1395 VOID
1396 NTAPI
1397 ScsiPortReadRegisterBufferUchar(
1398 IN PUCHAR Register,
1399 IN PUCHAR Buffer,
1400 IN ULONG Count)
1401 {
1402 // FIXME
1403 UNIMPLEMENTED;
1404 }
1405
1406 VOID
1407 NTAPI
1408 ScsiPortReadRegisterBufferUlong(
1409 IN PULONG Register,
1410 IN PULONG Buffer,
1411 IN ULONG Count)
1412 {
1413 // FIXME
1414 UNIMPLEMENTED;
1415 }
1416
1417 VOID
1418 NTAPI
1419 ScsiPortReadRegisterBufferUshort(
1420 IN PUSHORT Register,
1421 IN PUSHORT Buffer,
1422 IN ULONG Count)
1423 {
1424 // FIXME
1425 UNIMPLEMENTED;
1426 }
1427
1428 UCHAR
1429 NTAPI
1430 ScsiPortReadRegisterUchar(
1431 IN PUCHAR Register)
1432 {
1433 return READ_REGISTER_UCHAR(Register);
1434 }
1435
1436 ULONG
1437 NTAPI
1438 ScsiPortReadRegisterUlong(
1439 IN PULONG Register)
1440 {
1441 return READ_REGISTER_ULONG(Register);
1442 }
1443
1444 USHORT
1445 NTAPI
1446 ScsiPortReadRegisterUshort(
1447 IN PUSHORT Register)
1448 {
1449 return READ_REGISTER_USHORT(Register);
1450 }
1451
1452 ULONG
1453 NTAPI
1454 ScsiPortSetBusDataByOffset(
1455 IN PVOID DeviceExtension,
1456 IN ULONG BusDataType,
1457 IN ULONG SystemIoBusNumber,
1458 IN ULONG SlotNumber,
1459 IN PVOID Buffer,
1460 IN ULONG Offset,
1461 IN ULONG Length)
1462 {
1463 // FIXME
1464 UNIMPLEMENTED;
1465 return 0;
1466 }
1467
1468 VOID
1469 NTAPI
1470 ScsiPortStallExecution(
1471 IN ULONG Delay)
1472 {
1473 KeStallExecutionProcessor(Delay);
1474 }
1475
1476 BOOLEAN
1477 NTAPI
1478 ScsiPortValidateRange(
1479 IN PVOID HwDeviceExtension,
1480 IN INTERFACE_TYPE BusType,
1481 IN ULONG SystemIoBusNumber,
1482 IN SCSI_PHYSICAL_ADDRESS IoAddress,
1483 IN ULONG NumberOfBytes,
1484 IN BOOLEAN InIoSpace)
1485 {
1486 // FIXME
1487 UNIMPLEMENTED;
1488 return TRUE;
1489 }
1490
1491 #if 0
1492 // ScsiPortWmi*
1493 #endif
1494
1495
1496 VOID
1497 NTAPI
1498 ScsiPortWritePortBufferUchar(
1499 IN PUCHAR Port,
1500 IN PUCHAR Buffer,
1501 IN ULONG Count)
1502 {
1503 __outbytestring(H2I(Port), Buffer, Count);
1504 }
1505
1506 VOID
1507 NTAPI
1508 ScsiPortWritePortBufferUlong(
1509 IN PULONG Port,
1510 IN PULONG Buffer,
1511 IN ULONG Count)
1512 {
1513 __outdwordstring(H2I(Port), Buffer, Count);
1514 }
1515
1516 VOID
1517 NTAPI
1518 ScsiPortWritePortBufferUshort(
1519 IN PUSHORT Port,
1520 IN PUSHORT Buffer,
1521 IN ULONG Count)
1522 {
1523 __outwordstring(H2I(Port), Buffer, Count);
1524 }
1525
1526 VOID
1527 NTAPI
1528 ScsiPortWritePortUchar(
1529 IN PUCHAR Port,
1530 IN UCHAR Value)
1531 {
1532 WRITE_PORT_UCHAR(Port, Value);
1533 }
1534
1535 VOID
1536 NTAPI
1537 ScsiPortWritePortUlong(
1538 IN PULONG Port,
1539 IN ULONG Value)
1540 {
1541 WRITE_PORT_ULONG(Port, Value);
1542 }
1543
1544 VOID
1545 NTAPI
1546 ScsiPortWritePortUshort(
1547 IN PUSHORT Port,
1548 IN USHORT Value)
1549 {
1550 WRITE_PORT_USHORT(Port, Value);
1551 }
1552
1553 VOID
1554 NTAPI
1555 ScsiPortWriteRegisterBufferUchar(
1556 IN PUCHAR Register,
1557 IN PUCHAR Buffer,
1558 IN ULONG Count)
1559 {
1560 // FIXME
1561 UNIMPLEMENTED;
1562 }
1563
1564 VOID
1565 NTAPI
1566 ScsiPortWriteRegisterBufferUlong(
1567 IN PULONG Register,
1568 IN PULONG Buffer,
1569 IN ULONG Count)
1570 {
1571 // FIXME
1572 UNIMPLEMENTED;
1573 }
1574
1575 VOID
1576 NTAPI
1577 ScsiPortWriteRegisterBufferUshort(
1578 IN PUSHORT Register,
1579 IN PUSHORT Buffer,
1580 IN ULONG Count)
1581 {
1582 // FIXME
1583 UNIMPLEMENTED;
1584 }
1585
1586 VOID
1587 NTAPI
1588 ScsiPortWriteRegisterUchar(
1589 IN PUCHAR Register,
1590 IN UCHAR Value)
1591 {
1592 WRITE_REGISTER_UCHAR(Register, Value);
1593 }
1594
1595 VOID
1596 NTAPI
1597 ScsiPortWriteRegisterUlong(
1598 IN PULONG Register,
1599 IN ULONG Value)
1600 {
1601 WRITE_REGISTER_ULONG(Register, Value);
1602 }
1603
1604 VOID
1605 NTAPI
1606 ScsiPortWriteRegisterUshort(
1607 IN PUSHORT Register,
1608 IN USHORT Value)
1609 {
1610 WRITE_REGISTER_USHORT(Register, Value);
1611 }
1612
1613 extern char __ImageBase;
1614
1615 ULONG
1616 LoadBootDeviceDriver(VOID)
1617 {
1618 PIMAGE_NT_HEADERS NtHeaders;
1619 LIST_ENTRY ModuleListHead;
1620 PIMAGE_IMPORT_DESCRIPTOR ImportTable;
1621 ULONG ImportTableSize;
1622 PLDR_DATA_TABLE_ENTRY BootDdDTE, FreeldrDTE;
1623 CHAR NtBootDdPath[MAX_PATH];
1624 PVOID ImageBase = NULL;
1625 ULONG (NTAPI *EntryPoint)(IN PVOID DriverObject, IN PVOID RegistryPath);
1626 BOOLEAN Success;
1627
1628 // FIXME: Must be done *INSIDE* the HAL!
1629 #ifdef _M_IX86
1630 HalpInitializePciStubs();
1631 HalpInitBusHandler();
1632 #endif
1633
1634 /* Initialize the loaded module list */
1635 InitializeListHead(&ModuleListHead);
1636
1637 /* Create full ntbootdd.sys path */
1638 strcpy(NtBootDdPath, FrLdrBootPath);
1639 strcat(NtBootDdPath, "\\NTBOOTDD.SYS");
1640
1641 /* Load file */
1642 Success = WinLdrLoadImage(NtBootDdPath, LoaderBootDriver, &ImageBase);
1643 if (!Success)
1644 {
1645 /* That's OK. File simply doesn't exist */
1646 return ESUCCESS;
1647 }
1648
1649 /* Allocate a DTE for ntbootdd */
1650 Success = WinLdrAllocateDataTableEntry(&ModuleListHead, "ntbootdd.sys",
1651 "NTBOOTDD.SYS", ImageBase, &BootDdDTE);
1652 if (!Success)
1653 return EIO;
1654
1655 /* Add the PE part of freeldr.sys to the list of loaded executables, it
1656 contains ScsiPort* exports, imported by ntbootdd.sys */
1657 Success = WinLdrAllocateDataTableEntry(&ModuleListHead, "scsiport.sys",
1658 "FREELDR.SYS", &__ImageBase, &FreeldrDTE);
1659 if (!Success)
1660 {
1661 RemoveEntryList(&BootDdDTE->InLoadOrderLinks);
1662 return EIO;
1663 }
1664
1665 /* Fix imports */
1666 Success = WinLdrScanImportDescriptorTable(&ModuleListHead, "", BootDdDTE);
1667
1668 /* Now unlinkt the DTEs, they won't be valid later */
1669 RemoveEntryList(&BootDdDTE->InLoadOrderLinks);
1670 RemoveEntryList(&FreeldrDTE->InLoadOrderLinks);
1671
1672 if (!Success)
1673 return EIO;
1674
1675 /* Change imports to PA */
1676 ImportTable = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(VaToPa(BootDdDTE->DllBase),
1677 TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ImportTableSize);
1678 for (;(ImportTable->Name != 0) && (ImportTable->FirstThunk != 0);ImportTable++)
1679 {
1680 PIMAGE_THUNK_DATA ThunkData = (PIMAGE_THUNK_DATA)VaToPa(RVA(BootDdDTE->DllBase, ImportTable->FirstThunk));
1681
1682 while (((PIMAGE_THUNK_DATA)ThunkData)->u1.AddressOfData != 0)
1683 {
1684 ThunkData->u1.Function = (ULONG)VaToPa((PVOID)ThunkData->u1.Function);
1685 ThunkData++;
1686 }
1687 }
1688
1689 /* Relocate image to PA */
1690 NtHeaders = RtlImageNtHeader(VaToPa(BootDdDTE->DllBase));
1691 if (!NtHeaders)
1692 return EIO;
1693 Success = (BOOLEAN)LdrRelocateImageWithBias(VaToPa(BootDdDTE->DllBase),
1694 NtHeaders->OptionalHeader.ImageBase - (ULONG_PTR)BootDdDTE->DllBase,
1695 "FreeLdr",
1696 TRUE,
1697 TRUE, /* in case of conflict still return success */
1698 FALSE);
1699 if (!Success)
1700 return EIO;
1701
1702 /* Call the entrypoint */
1703 EntryPoint = VaToPa(BootDdDTE->EntryPoint);
1704 (*EntryPoint)(NULL, NULL);
1705
1706 return ESUCCESS;
1707 }
1708
1709 /* EOF */