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