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