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