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