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