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