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