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