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