Implemented ScsiPortGetUncachedExtension().
[reactos.git] / reactos / drivers / storage / scsiport / scsiport.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2001, 2002 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: scsiport.c,v 1.34 2003/09/05 11:48:03 ekohl Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/storage/scsiport/scsiport.c
24 * PURPOSE: SCSI port driver
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ddk/ntddk.h>
31 #include <ddk/srb.h>
32 #include <ddk/scsi.h>
33 #include <ddk/ntddscsi.h>
34
35 #define NDEBUG
36 #include <debug.h>
37
38
39 #define VERSION "0.0.1"
40
41 #include "scsiport_int.h"
42
43 /* TYPES *********************************************************************/
44
45 #define IRP_FLAG_COMPLETE 0x00000001
46 #define IRP_FLAG_NEXT 0x00000002
47
48
49 /* GLOBALS *******************************************************************/
50
51 static NTSTATUS STDCALL
52 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
53 IN PIRP Irp);
54
55 static NTSTATUS STDCALL
56 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
57 IN PIRP Irp);
58
59 static NTSTATUS STDCALL
60 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
61 IN PIRP Irp);
62
63 static VOID STDCALL
64 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
65 IN PIRP Irp);
66
67 static IO_ALLOCATION_ACTION STDCALL
68 ScsiPortAllocateController(IN PDEVICE_OBJECT DeviceObject,
69 IN PIRP Irp,
70 IN PVOID MapRegisterBase,
71 IN PVOID Context);
72
73 static BOOLEAN STDCALL
74 ScsiPortStartPacket(IN OUT PVOID Context);
75
76 static NTSTATUS
77 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
78 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
79 IN ULONG PortCount,
80 IN OUT PSCSI_PORT_DEVICE_EXTENSION *RealDeviceExtension);
81
82 static PSCSI_PORT_LUN_EXTENSION
83 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
84 IN UCHAR PathId,
85 IN UCHAR TargetId,
86 IN UCHAR Lun);
87
88 static PSCSI_PORT_LUN_EXTENSION
89 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
90 IN UCHAR PathId,
91 IN UCHAR TargetId,
92 IN UCHAR Lun);
93
94 static VOID
95 ScsiPortInquire(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
96
97 static ULONG
98 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
99 OUT PSCSI_ADAPTER_BUS_INFO AdapterBusInfo);
100
101 static BOOLEAN STDCALL
102 ScsiPortIsr(IN PKINTERRUPT Interrupt,
103 IN PVOID ServiceContext);
104
105 static VOID STDCALL
106 ScsiPortDpcForIsr(IN PKDPC Dpc,
107 IN PDEVICE_OBJECT DpcDeviceObject,
108 IN PIRP DpcIrp,
109 IN PVOID DpcContext);
110
111 static VOID STDCALL
112 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
113 PVOID Context);
114
115 static PSCSI_REQUEST_BLOCK
116 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
117 PSCSI_REQUEST_BLOCK OriginalSrb);
118
119 static NTSTATUS
120 ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
121 PUNICODE_STRING RegistryPath);
122
123
124 /* FUNCTIONS *****************************************************************/
125
126 /**********************************************************************
127 * NAME EXPORTED
128 * DriverEntry
129 *
130 * DESCRIPTION
131 * This function initializes the driver.
132 *
133 * RUN LEVEL
134 * PASSIVE_LEVEL
135 *
136 * ARGUMENTS
137 * DriverObject
138 * System allocated Driver Object for this driver.
139 *
140 * RegistryPath
141 * Name of registry driver service key.
142 *
143 * RETURN VALUE
144 * Status.
145 */
146
147 NTSTATUS STDCALL
148 DriverEntry(IN PDRIVER_OBJECT DriverObject,
149 IN PUNICODE_STRING RegistryPath)
150 {
151 DPRINT("ScsiPort Driver %s\n", VERSION);
152 return(STATUS_SUCCESS);
153 }
154
155
156 /**********************************************************************
157 * NAME EXPORTED
158 * ScsiDebugPrint
159 *
160 * DESCRIPTION
161 * Prints debugging messages.
162 *
163 * RUN LEVEL
164 * PASSIVE_LEVEL
165 *
166 * ARGUMENTS
167 * DebugPrintLevel
168 * Debug level of the given message.
169 *
170 * DebugMessage
171 * Pointer to printf()-compatible format string.
172 *
173 * ...
174 Additional output data (see printf()).
175 *
176 * RETURN VALUE
177 * None.
178 *
179 * @implemented
180 */
181
182 VOID
183 ScsiDebugPrint(IN ULONG DebugPrintLevel,
184 IN PCHAR DebugMessage,
185 ...)
186 {
187 char Buffer[256];
188 va_list ap;
189
190 #if 0
191 if (DebugPrintLevel > InternalDebugLevel)
192 return;
193 #endif
194
195 va_start(ap, DebugMessage);
196 vsprintf(Buffer, DebugMessage, ap);
197 va_end(ap);
198
199 DbgPrint(Buffer);
200 }
201
202
203 /*
204 * @unimplemented
205 */
206 VOID STDCALL
207 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
208 IN UCHAR PathId,
209 IN UCHAR TargetId,
210 IN UCHAR Lun,
211 IN UCHAR SrbStatus)
212 {
213 DPRINT("ScsiPortCompleteRequest()\n");
214 UNIMPLEMENTED;
215 }
216
217
218 /*
219 * @implemented
220 */
221 ULONG STDCALL
222 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
223 {
224 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
225 return(Address.u.LowPart);
226 }
227
228
229 /*
230 * @unimplemented
231 */
232 VOID STDCALL
233 ScsiPortFlushDma(IN PVOID HwDeviceExtension)
234 {
235 DPRINT("ScsiPortFlushDma()\n");
236 UNIMPLEMENTED;
237 }
238
239
240 /*
241 * @implemented
242 */
243 VOID STDCALL
244 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
245 IN PVOID MappedAddress)
246 {
247 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
248 PSCSI_PORT_DEVICE_BASE DeviceBase;
249 PLIST_ENTRY Entry;
250
251 DPRINT("ScsiPortFreeDeviceBase() called\n");
252
253 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
254 SCSI_PORT_DEVICE_EXTENSION,
255 MiniPortDeviceExtension);
256 if (IsListEmpty(&DeviceExtension->DeviceBaseListHead))
257 return;
258
259 Entry = DeviceExtension->DeviceBaseListHead.Flink;
260 while (Entry != &DeviceExtension->DeviceBaseListHead)
261 {
262 DeviceBase = CONTAINING_RECORD(Entry,
263 SCSI_PORT_DEVICE_BASE,
264 List);
265 if (DeviceBase->MappedAddress == MappedAddress)
266 {
267 MmUnmapIoSpace(DeviceBase->MappedAddress,
268 DeviceBase->NumberOfBytes);
269 RemoveEntryList(Entry);
270 ExFreePool(DeviceBase);
271
272 return;
273 }
274
275 Entry = Entry->Flink;
276 }
277 }
278
279
280 /*
281 * @implemented
282 */
283 ULONG STDCALL
284 ScsiPortGetBusData(IN PVOID DeviceExtension,
285 IN ULONG BusDataType,
286 IN ULONG SystemIoBusNumber,
287 IN ULONG SlotNumber,
288 IN PVOID Buffer,
289 IN ULONG Length)
290 {
291 return(HalGetBusData(BusDataType,
292 SystemIoBusNumber,
293 SlotNumber,
294 Buffer,
295 Length));
296 }
297
298
299 /*
300 * @implemented
301 */
302 PVOID STDCALL
303 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
304 IN INTERFACE_TYPE BusType,
305 IN ULONG SystemIoBusNumber,
306 IN SCSI_PHYSICAL_ADDRESS IoAddress,
307 IN ULONG NumberOfBytes,
308 IN BOOLEAN InIoSpace)
309 {
310 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
311 PHYSICAL_ADDRESS TranslatedAddress;
312 PSCSI_PORT_DEVICE_BASE DeviceBase;
313 ULONG AddressSpace;
314 PVOID MappedAddress;
315
316 DPRINT("ScsiPortGetDeviceBase() called\n");
317
318 AddressSpace = (ULONG)InIoSpace;
319 if (HalTranslateBusAddress(BusType,
320 SystemIoBusNumber,
321 IoAddress,
322 &AddressSpace,
323 &TranslatedAddress) == FALSE)
324 return NULL;
325
326 /* i/o space */
327 if (AddressSpace != 0)
328 return((PVOID)TranslatedAddress.u.LowPart);
329
330 MappedAddress = MmMapIoSpace(TranslatedAddress,
331 NumberOfBytes,
332 FALSE);
333
334 DeviceBase = ExAllocatePool(NonPagedPool,
335 sizeof(SCSI_PORT_DEVICE_BASE));
336 if (DeviceBase == NULL)
337 return(MappedAddress);
338
339 DeviceBase->MappedAddress = MappedAddress;
340 DeviceBase->NumberOfBytes = NumberOfBytes;
341 DeviceBase->IoAddress = IoAddress;
342 DeviceBase->SystemIoBusNumber = SystemIoBusNumber;
343
344 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
345 SCSI_PORT_DEVICE_EXTENSION,
346 MiniPortDeviceExtension);
347
348 InsertHeadList(&DeviceExtension->DeviceBaseListHead,
349 &DeviceBase->List);
350
351 return(MappedAddress);
352 }
353
354
355 /*
356 * @implemented
357 */
358 PVOID STDCALL
359 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
360 IN UCHAR PathId,
361 IN UCHAR TargetId,
362 IN UCHAR Lun)
363 {
364 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
365 PSCSI_PORT_LUN_EXTENSION LunExtension;
366 PLIST_ENTRY Entry;
367
368 DPRINT("ScsiPortGetLogicalUnit() called\n");
369
370 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
371 SCSI_PORT_DEVICE_EXTENSION,
372 MiniPortDeviceExtension);
373 if (IsListEmpty(&DeviceExtension->LunExtensionListHead))
374 return NULL;
375
376 Entry = DeviceExtension->LunExtensionListHead.Flink;
377 while (Entry != &DeviceExtension->LunExtensionListHead)
378 {
379 LunExtension = CONTAINING_RECORD(Entry,
380 SCSI_PORT_LUN_EXTENSION,
381 List);
382 if (LunExtension->PathId == PathId &&
383 LunExtension->TargetId == TargetId &&
384 LunExtension->Lun == Lun)
385 {
386 return (PVOID)&LunExtension->MiniportLunExtension;
387 }
388
389 Entry = Entry->Flink;
390 }
391
392 return NULL;
393 }
394
395
396 /*
397 * @unimplemented
398 */
399 SCSI_PHYSICAL_ADDRESS STDCALL
400 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
401 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
402 IN PVOID VirtualAddress,
403 OUT ULONG *Length)
404 {
405 DPRINT1("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
406 HwDeviceExtension, Srb, VirtualAddress, Length);
407 UNIMPLEMENTED;
408 }
409
410
411 /*
412 * @unimplemented
413 */
414 PSCSI_REQUEST_BLOCK STDCALL
415 ScsiPortGetSrb(IN PVOID DeviceExtension,
416 IN UCHAR PathId,
417 IN UCHAR TargetId,
418 IN UCHAR Lun,
419 IN LONG QueueTag)
420 {
421 DPRINT("ScsiPortGetSrb()\n");
422 UNIMPLEMENTED;
423 }
424
425
426 /*
427 * @implemented
428 */
429 PVOID STDCALL
430 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
431 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
432 IN ULONG NumberOfBytes)
433 {
434 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
435 DEVICE_DESCRIPTION DeviceDescription;
436
437 DPRINT1("ScsiPortGetUncachedExtension(%p %p %lu)\n",
438 HwDeviceExtension, ConfigInfo, NumberOfBytes);
439
440 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
441 SCSI_PORT_DEVICE_EXTENSION,
442 MiniPortDeviceExtension);
443
444 /* Check for allocated common DMA buffer */
445 if (DeviceExtension->VirtualAddress != NULL)
446 {
447 DPRINT1("The HBA has already got a common DMA buffer!\n");
448 return NULL;
449 }
450
451 /* Check for DMA adapter object */
452 if (DeviceExtension->AdapterObject == NULL)
453 {
454 /* Initialize DMA adapter description */
455 RtlZeroMemory(&DeviceDescription,
456 sizeof(DEVICE_DESCRIPTION));
457 DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION1;
458 DeviceDescription.Master = ConfigInfo->Master;
459 DeviceDescription.ScatterGather = ConfigInfo->ScatterGather;
460 DeviceDescription.DemandMode = ConfigInfo->DemandMode;
461 DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
462 DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
463 DeviceDescription.DmaChannel = ConfigInfo->DmaChannel;
464 DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
465 DeviceDescription.DmaWidth = ConfigInfo->DmaWidth;
466 DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
467 DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
468 DeviceDescription.DmaPort = ConfigInfo->DmaPort;
469
470 /* Get a DMA adapter object */
471 DeviceExtension->AdapterObject = HalGetAdapter(&DeviceDescription,
472 &DeviceExtension->MapRegisterCount);
473 if (DeviceExtension->AdapterObject == NULL)
474 {
475 DPRINT1("HalGetAdapter() failed\n");
476 return NULL;
477 }
478 }
479
480 /* Allocate a common DMA buffer */
481 DeviceExtension->CommonBufferLength = NumberOfBytes;
482 DeviceExtension->VirtualAddress =
483 HalAllocateCommonBuffer(DeviceExtension->AdapterObject,
484 DeviceExtension->CommonBufferLength,
485 &DeviceExtension->PhysicalAddress,
486 FALSE);
487 if (DeviceExtension->VirtualAddress == NULL)
488 {
489 DPRINT1("HalAllocateCommonBuffer() failed!\n");
490 DeviceExtension->CommonBufferLength = 0;
491 return NULL;
492 }
493
494 return DeviceExtension->VirtualAddress;
495 }
496
497
498 /*
499 * @unimplemented
500 */
501 PVOID STDCALL
502 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
503 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
504 {
505 DPRINT("ScsiPortGetVirtualAddress()\n");
506 UNIMPLEMENTED;
507 }
508
509
510 /**********************************************************************
511 * NAME EXPORTED
512 * ScsiPortInitialize
513 *
514 * DESCRIPTION
515 * Initializes SCSI port driver specific data.
516 *
517 * RUN LEVEL
518 * PASSIVE_LEVEL
519 *
520 * ARGUMENTS
521 * Argument1
522 * Pointer to the miniport driver's driver object.
523 *
524 * Argument2
525 * Pointer to the miniport driver's registry path.
526 *
527 * HwInitializationData
528 * Pointer to port driver specific configuration data.
529 *
530 * HwContext
531 Miniport driver specific context.
532 *
533 * RETURN VALUE
534 * Status.
535 *
536 * @implemented
537 */
538
539 ULONG STDCALL
540 ScsiPortInitialize(IN PVOID Argument1,
541 IN PVOID Argument2,
542 IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
543 IN PVOID HwContext)
544 {
545 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
546 PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
547 PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension;
548 PSCSI_PORT_DEVICE_EXTENSION RealDeviceExtension;
549 PCONFIGURATION_INFORMATION SystemConfig;
550 PPORT_CONFIGURATION_INFORMATION PortConfig;
551 BOOLEAN Again;
552 ULONG i;
553 ULONG Result;
554 NTSTATUS Status;
555 ULONG MaxBus;
556 PACCESS_RANGE AccessRanges;
557 ULONG ExtensionSize;
558
559 DPRINT("ScsiPortInitialize() called!\n");
560
561 if ((HwInitializationData->HwInitialize == NULL) ||
562 (HwInitializationData->HwStartIo == NULL) ||
563 (HwInitializationData->HwInterrupt == NULL) ||
564 (HwInitializationData->HwFindAdapter == NULL) ||
565 (HwInitializationData->HwResetBus == NULL))
566 return(STATUS_INVALID_PARAMETER);
567
568 DriverObject->DriverStartIo = ScsiPortStartIo;
569 DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)ScsiPortCreateClose;
570 DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)ScsiPortCreateClose;
571 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)ScsiPortDeviceControl;
572 DriverObject->MajorFunction[IRP_MJ_SCSI] = (PDRIVER_DISPATCH)ScsiPortDispatchScsi;
573
574
575 SystemConfig = IoGetConfigurationInformation();
576
577 ExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
578 HwInitializationData->DeviceExtensionSize;
579 PseudoDeviceExtension = ExAllocatePool(PagedPool,
580 ExtensionSize);
581 RtlZeroMemory(PseudoDeviceExtension,
582 ExtensionSize);
583 PseudoDeviceExtension->Length = ExtensionSize;
584 PseudoDeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
585 PseudoDeviceExtension->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize;
586 PseudoDeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
587 PseudoDeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
588
589 PortConfig = &PseudoDeviceExtension->PortConfig;
590
591 PortConfig->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
592 PortConfig->AdapterInterfaceType = HwInitializationData->AdapterInterfaceType;
593 PortConfig->InterruptMode =
594 (PortConfig->AdapterInterfaceType == PCIBus) ? LevelSensitive : Latched;
595 PortConfig->AtdiskPrimaryClaimed = SystemConfig->AtDiskPrimaryAddressClaimed;
596 PortConfig->AtdiskSecondaryClaimed = SystemConfig->AtDiskSecondaryAddressClaimed;
597 PortConfig->NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
598
599 PortConfig->AccessRanges =
600 ExAllocatePool(PagedPool,
601 sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
602
603 for (i = 0; i < SCSI_MAXIMUM_BUSES; i++)
604 PortConfig->InitiatorBusId[i] = 255;
605
606 PortConfig->SystemIoBusNumber = 0;
607 PortConfig->SlotNumber = 0;
608
609 MaxBus = (PortConfig->AdapterInterfaceType == PCIBus) ? 8 : 1;
610
611 DPRINT("MaxBus: %lu\n", MaxBus);
612
613 while (TRUE)
614 {
615 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
616
617 InitializeListHead(&PseudoDeviceExtension->DeviceBaseListHead);
618
619 // RtlZeroMemory(AccessRanges,
620 // sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
621
622 RtlZeroMemory(PseudoDeviceExtension->MiniPortDeviceExtension,
623 PseudoDeviceExtension->MiniPortExtensionSize);
624
625 /* Note: HwFindAdapter is called once for each bus */
626 Result = (HwInitializationData->HwFindAdapter)(&PseudoDeviceExtension->MiniPortDeviceExtension,
627 HwContext,
628 NULL, /* BusInformation */
629 NULL, /* ArgumentString */
630 &PseudoDeviceExtension->PortConfig,
631 &Again);
632 DPRINT("HwFindAdapter() result: %lu\n", Result);
633
634 if (Result == SP_RETURN_FOUND)
635 {
636 DPRINT("ScsiPortInitialize(): Found HBA!\n");
637
638 Status = ScsiPortCreatePortDevice(DriverObject,
639 PseudoDeviceExtension,
640 SystemConfig->ScsiPortCount,
641 &RealDeviceExtension);
642
643 if (!NT_SUCCESS(Status))
644 {
645 DbgPrint("ScsiPortCreatePortDevice() failed! (Status 0x%lX)\n", Status);
646
647 ExFreePool(PortConfig->AccessRanges);
648 ExFreePool(PseudoDeviceExtension);
649
650 return(Status);
651 }
652
653 /* Get inquiry data */
654 ScsiPortInquire(RealDeviceExtension);
655
656 /* Build the registry device map */
657 ScsiPortBuildDeviceMap(RealDeviceExtension,
658 (PUNICODE_STRING)Argument2);
659
660 /* Update the configuration info */
661 SystemConfig->AtDiskPrimaryAddressClaimed = PortConfig->AtdiskPrimaryClaimed;
662 SystemConfig->AtDiskSecondaryAddressClaimed = PortConfig->AtdiskSecondaryClaimed;
663 SystemConfig->ScsiPortCount++;
664 }
665
666 if (Again == FALSE)
667 {
668 PortConfig->SystemIoBusNumber++;
669 PortConfig->SlotNumber = 0;
670 }
671
672 DPRINT("Bus: %lu MaxBus: %lu\n", PortConfig->SystemIoBusNumber, MaxBus);
673 if (PortConfig->SystemIoBusNumber >= MaxBus)
674 {
675 DPRINT("Scanned all buses!\n");
676 break;
677 }
678 }
679
680 ExFreePool(PortConfig->AccessRanges);
681 ExFreePool(PseudoDeviceExtension);
682
683 DPRINT("ScsiPortInitialize() done!\n");
684
685 return(STATUS_SUCCESS);
686 }
687
688
689 /*
690 * @unimplemented
691 */
692 VOID STDCALL
693 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
694 IN PSCSI_REQUEST_BLOCK Srb,
695 IN ULONG LogicalAddress,
696 IN ULONG Length)
697 {
698 DPRINT("ScsiPortIoMapTransfer()\n");
699 UNIMPLEMENTED;
700 }
701
702
703 /*
704 * @unimplemented
705 */
706 VOID STDCALL
707 ScsiPortLogError(IN PVOID HwDeviceExtension,
708 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
709 IN UCHAR PathId,
710 IN UCHAR TargetId,
711 IN UCHAR Lun,
712 IN ULONG ErrorCode,
713 IN ULONG UniqueId)
714 {
715 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
716
717 DPRINT("ScsiPortLogError() called\n");
718
719 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
720 SCSI_PORT_DEVICE_EXTENSION,
721 MiniPortDeviceExtension);
722
723
724 DPRINT("ScsiPortLogError() done\n");
725 }
726
727
728 /*
729 * @implemented
730 */
731 VOID STDCALL
732 ScsiPortMoveMemory(OUT PVOID Destination,
733 IN PVOID Source,
734 IN ULONG Length)
735 {
736 RtlMoveMemory(Destination,
737 Source,
738 Length);
739 }
740
741
742 /*
743 * @implemented
744 */
745 VOID
746 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
747 IN PVOID HwDeviceExtension,
748 ...)
749 {
750 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
751
752 DPRINT("ScsiPortNotification() called\n");
753
754 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
755 SCSI_PORT_DEVICE_EXTENSION,
756 MiniPortDeviceExtension);
757
758 DPRINT("DeviceExtension %p\n", DeviceExtension);
759
760 DPRINT("Initializing = %s\n", (DeviceExtension->Initializing)?"TRUE":"FALSE");
761
762 if (DeviceExtension->Initializing == TRUE)
763 return;
764
765 switch (NotificationType)
766 {
767 case RequestComplete:
768 DPRINT("Notify: RequestComplete\n");
769 DeviceExtension->IrpFlags |= IRP_FLAG_COMPLETE;
770 break;
771
772 case NextRequest:
773 DPRINT("Notify: NextRequest\n");
774 DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
775 break;
776
777 default:
778 break;
779 }
780 }
781
782
783 /*
784 * @implemented
785 */
786 ULONG STDCALL
787 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
788 IN ULONG BusDataType,
789 IN ULONG SystemIoBusNumber,
790 IN ULONG SlotNumber,
791 IN PVOID Buffer,
792 IN ULONG Offset,
793 IN ULONG Length)
794 {
795 DPRINT("ScsiPortSetBusDataByOffset()\n");
796 return(HalSetBusDataByOffset(BusDataType,
797 SystemIoBusNumber,
798 SlotNumber,
799 Buffer,
800 Offset,
801 Length));
802 }
803
804
805 /*
806 * @implemented
807 */
808 BOOLEAN STDCALL
809 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
810 IN INTERFACE_TYPE BusType,
811 IN ULONG SystemIoBusNumber,
812 IN SCSI_PHYSICAL_ADDRESS IoAddress,
813 IN ULONG NumberOfBytes,
814 IN BOOLEAN InIoSpace)
815 {
816 DPRINT("ScsiPortValidateRange()\n");
817 return(TRUE);
818 }
819
820
821 /* INTERNAL FUNCTIONS ********************************************************/
822
823 /**********************************************************************
824 * NAME INTERNAL
825 * ScsiPortCreateClose
826 *
827 * DESCRIPTION
828 * Answer requests for Create/Close calls: a null operation.
829 *
830 * RUN LEVEL
831 * PASSIVE_LEVEL
832 *
833 * ARGUMENTS
834 * DeviceObject
835 * Pointer to a device object.
836 *
837 * Irp
838 * Pointer to an IRP.
839 *
840 * ...
841 Additional output data (see printf()).
842 *
843 * RETURN VALUE
844 * Status.
845 */
846
847 static NTSTATUS STDCALL
848 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
849 IN PIRP Irp)
850 {
851 DPRINT("ScsiPortCreateClose()\n");
852
853 Irp->IoStatus.Status = STATUS_SUCCESS;
854 Irp->IoStatus.Information = FILE_OPENED;
855
856 IoCompleteRequest(Irp, IO_NO_INCREMENT);
857
858 return(STATUS_SUCCESS);
859 }
860
861
862 /**********************************************************************
863 * NAME INTERNAL
864 * ScsiPortDispatchScsi
865 *
866 * DESCRIPTION
867 * Answer requests for SCSI calls
868 *
869 * RUN LEVEL
870 * PASSIVE_LEVEL
871 *
872 * ARGUMENTS
873 * Standard dispatch arguments
874 *
875 * RETURNS
876 * NTSTATUS
877 */
878
879 static NTSTATUS STDCALL
880 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
881 IN PIRP Irp)
882 {
883 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
884 PIO_STACK_LOCATION Stack;
885 PSCSI_REQUEST_BLOCK Srb;
886 NTSTATUS Status = STATUS_SUCCESS;
887 ULONG DataSize = 0;
888
889 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
890 DeviceObject, Irp);
891
892 DeviceExtension = DeviceObject->DeviceExtension;
893 Stack = IoGetCurrentIrpStackLocation(Irp);
894
895 Srb = Stack->Parameters.Scsi.Srb;
896 if (Srb == NULL)
897 {
898 Status = STATUS_UNSUCCESSFUL;
899
900 Irp->IoStatus.Status = Status;
901 Irp->IoStatus.Information = 0;
902
903 IoCompleteRequest(Irp, IO_NO_INCREMENT);
904
905 return(Status);
906 }
907
908 DPRINT("Srb: %p\n", Srb);
909 DPRINT("Srb->Function: %lu\n", Srb->Function);
910 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
911
912 switch (Srb->Function)
913 {
914 case SRB_FUNCTION_EXECUTE_SCSI:
915 IoStartPacket(DeviceObject, Irp, NULL, NULL);
916 return(STATUS_PENDING);
917
918 case SRB_FUNCTION_SHUTDOWN:
919 case SRB_FUNCTION_FLUSH:
920 if (DeviceExtension->PortConfig.CachesData == TRUE)
921 {
922 IoStartPacket(DeviceObject, Irp, NULL, NULL);
923 return(STATUS_PENDING);
924 }
925 break;
926
927 case SRB_FUNCTION_CLAIM_DEVICE:
928 {
929 PSCSI_PORT_LUN_EXTENSION LunExtension;
930
931 DPRINT(" SRB_FUNCTION_CLAIM_DEVICE\n");
932 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
933
934 LunExtension = SpiGetLunExtension(DeviceExtension,
935 Srb->PathId,
936 Srb->TargetId,
937 Srb->Lun);
938 if (LunExtension != NULL)
939 {
940 /* Reference device object and keep the pointer */
941 ObReferenceObject(DeviceObject);
942 LunExtension->DeviceObject = DeviceObject;
943 LunExtension->DeviceClaimed = TRUE;
944 Srb->DataBuffer = DeviceObject;
945 }
946 else
947 {
948 Srb->DataBuffer = NULL;
949 }
950 }
951 break;
952
953 case SRB_FUNCTION_RELEASE_DEVICE:
954 {
955 PSCSI_PORT_LUN_EXTENSION LunExtension;
956
957 DPRINT(" SRB_FUNCTION_RELEASE_DEVICE\n");
958 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
959
960 LunExtension = SpiGetLunExtension(DeviceExtension,
961 Srb->PathId,
962 Srb->TargetId,
963 Srb->Lun);
964 if (LunExtension != NULL)
965 {
966 /* Dereference device object */
967 ObDereferenceObject(LunExtension->DeviceObject);
968 LunExtension->DeviceObject = NULL;
969 LunExtension->DeviceClaimed = FALSE;
970 }
971 }
972 break;
973
974 default:
975 DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
976 Status = STATUS_NOT_IMPLEMENTED;
977 break;
978 }
979
980 Irp->IoStatus.Status = Status;
981 Irp->IoStatus.Information = DataSize;
982
983 IoCompleteRequest(Irp, IO_NO_INCREMENT);
984
985 return(Status);
986 }
987
988
989 /**********************************************************************
990 * NAME INTERNAL
991 * ScsiPortDeviceControl
992 *
993 * DESCRIPTION
994 * Answer requests for device control calls
995 *
996 * RUN LEVEL
997 * PASSIVE_LEVEL
998 *
999 * ARGUMENTS
1000 * Standard dispatch arguments
1001 *
1002 * RETURNS
1003 * NTSTATUS
1004 */
1005
1006 static NTSTATUS STDCALL
1007 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
1008 IN PIRP Irp)
1009 {
1010 PIO_STACK_LOCATION Stack;
1011 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1012
1013 DPRINT("ScsiPortDeviceControl()\n");
1014
1015 Irp->IoStatus.Status = STATUS_SUCCESS;
1016 Irp->IoStatus.Information = 0;
1017
1018
1019 Stack = IoGetCurrentIrpStackLocation(Irp);
1020 DeviceExtension = DeviceObject->DeviceExtension;
1021
1022 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
1023 {
1024 case IOCTL_SCSI_GET_DUMP_POINTERS:
1025 {
1026 PDUMP_POINTERS DumpPointers;
1027 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
1028 DumpPointers = (PDUMP_POINTERS)Irp->AssociatedIrp.SystemBuffer;
1029 DumpPointers->DeviceObject = DeviceObject;
1030
1031 Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
1032 }
1033 break;
1034
1035 case IOCTL_SCSI_GET_CAPABILITIES:
1036 {
1037 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
1038
1039 *((PIO_SCSI_CAPABILITIES *)Irp->AssociatedIrp.SystemBuffer) =
1040 DeviceExtension->PortCapabilities;
1041
1042 Irp->IoStatus.Information = sizeof(PIO_SCSI_CAPABILITIES);
1043 }
1044 break;
1045
1046 case IOCTL_SCSI_GET_INQUIRY_DATA:
1047 {
1048 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
1049
1050 /* Copy inquiry data to the port device extension */
1051 Irp->IoStatus.Information =
1052 SpiGetInquiryData(DeviceExtension,
1053 Irp->AssociatedIrp.SystemBuffer);
1054 DPRINT("Inquiry data size: %lu\n", Irp->IoStatus.Information);
1055 }
1056 break;
1057
1058 default:
1059 DPRINT1(" unknown ioctl code: 0x%lX\n",
1060 Stack->Parameters.DeviceIoControl.IoControlCode);
1061 break;
1062 }
1063
1064 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1065
1066 return(STATUS_SUCCESS);
1067 }
1068
1069
1070 static VOID STDCALL
1071 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
1072 IN PIRP Irp)
1073 {
1074 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1075 PIO_STACK_LOCATION IrpStack;
1076 KIRQL OldIrql;
1077
1078 DPRINT("ScsiPortStartIo() called!\n");
1079
1080 DeviceExtension = DeviceObject->DeviceExtension;
1081 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1082
1083 // FIXME: implement the supported functions
1084
1085 switch (IrpStack->MajorFunction)
1086 {
1087 case IRP_MJ_SCSI:
1088 {
1089 BOOLEAN Result;
1090 PSCSI_REQUEST_BLOCK Srb;
1091 KIRQL oldIrql;
1092
1093 DPRINT("IRP_MJ_SCSI\n");
1094
1095 Srb = IrpStack->Parameters.Scsi.Srb;
1096
1097 DPRINT("DeviceExtension %p\n", DeviceExtension);
1098
1099 Irp->IoStatus.Status = STATUS_SUCCESS;
1100 Irp->IoStatus.Information = Srb->DataTransferLength;
1101
1102 DeviceExtension->CurrentIrp = Irp;
1103
1104 if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
1105 ScsiPortStartPacket,
1106 DeviceExtension))
1107 {
1108 DPRINT("Synchronization failed!\n");
1109
1110 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
1111 Irp->IoStatus.Information = 0;
1112 IoCompleteRequest(Irp,
1113 IO_NO_INCREMENT);
1114 IoStartNextPacket(DeviceObject,
1115 FALSE);
1116 }
1117 KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql);
1118 if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
1119 {
1120 DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
1121 IoCompleteRequest(Irp,
1122 IO_NO_INCREMENT);
1123 }
1124
1125 if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
1126 {
1127 DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
1128 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1129 IoStartNextPacket(DeviceObject,
1130 FALSE);
1131 }
1132 else
1133 {
1134 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1135 }
1136 }
1137 break;
1138
1139 default:
1140 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1141 Irp->IoStatus.Information = 0;
1142 IoCompleteRequest(Irp,
1143 IO_NO_INCREMENT);
1144 IoStartNextPacket(DeviceObject,
1145 FALSE);
1146 break;
1147 }
1148 DPRINT("ScsiPortStartIo() done\n");
1149 }
1150
1151
1152 static BOOLEAN STDCALL
1153 ScsiPortStartPacket(IN OUT PVOID Context)
1154 {
1155 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1156 PIO_STACK_LOCATION IrpStack;
1157 PSCSI_REQUEST_BLOCK Srb;
1158
1159 DPRINT("ScsiPortStartPacket() called\n");
1160
1161 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)Context;
1162
1163 IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
1164 Srb = IrpStack->Parameters.Scsi.Srb;
1165
1166 return(DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
1167 Srb));
1168 }
1169
1170
1171 /**********************************************************************
1172 * NAME INTERNAL
1173 * ScsiPortCreatePortDevice
1174 *
1175 * DESCRIPTION
1176 * Creates and initializes a SCSI port device object.
1177 *
1178 * RUN LEVEL
1179 * PASSIVE_LEVEL
1180 *
1181 * ARGUMENTS
1182 * DriverObject
1183 * ...
1184 *
1185 * PseudoDeviceExtension
1186 * ...
1187 *
1188 * PortNumber
1189 * ...
1190 *
1191 * RETURNS
1192 * NTSTATUS
1193 */
1194
1195 static NTSTATUS
1196 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
1197 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
1198 IN ULONG PortNumber,
1199 IN OUT PSCSI_PORT_DEVICE_EXTENSION *RealDeviceExtension)
1200 {
1201 PSCSI_PORT_DEVICE_EXTENSION PortDeviceExtension;
1202 PIO_SCSI_CAPABILITIES PortCapabilities;
1203 PDEVICE_OBJECT PortDeviceObject;
1204 WCHAR NameBuffer[80];
1205 UNICODE_STRING DeviceName;
1206 WCHAR DosNameBuffer[80];
1207 UNICODE_STRING DosDeviceName;
1208 NTSTATUS Status;
1209 ULONG AccessRangeSize;
1210 ULONG MappedIrq;
1211 KIRQL Dirql;
1212 KAFFINITY Affinity;
1213
1214 DPRINT("ScsiPortCreatePortDevice() called\n");
1215
1216 *RealDeviceExtension = NULL;
1217
1218 MappedIrq = HalGetInterruptVector(PseudoDeviceExtension->PortConfig.AdapterInterfaceType,
1219 PseudoDeviceExtension->PortConfig.SystemIoBusNumber,
1220 PseudoDeviceExtension->PortConfig.BusInterruptLevel,
1221 PseudoDeviceExtension->PortConfig.BusInterruptVector,
1222 &Dirql,
1223 &Affinity);
1224
1225 /* Create a unicode device name */
1226 swprintf(NameBuffer,
1227 L"\\Device\\ScsiPort%lu",
1228 PortNumber);
1229 RtlInitUnicodeString(&DeviceName,
1230 NameBuffer);
1231
1232 DPRINT("Creating device: %wZ\n", &DeviceName);
1233
1234 /* Create the port device */
1235 Status = IoCreateDevice(DriverObject,
1236 PseudoDeviceExtension->Length,
1237 &DeviceName,
1238 FILE_DEVICE_CONTROLLER,
1239 0,
1240 FALSE,
1241 &PortDeviceObject);
1242 if (!NT_SUCCESS(Status))
1243 {
1244 DbgPrint("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
1245 return(Status);
1246 }
1247
1248 DPRINT("Created device: %wZ\n", &DeviceName);
1249
1250 /* Set the buffering strategy here... */
1251 PortDeviceObject->Flags |= DO_DIRECT_IO;
1252 PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
1253
1254 PortDeviceExtension = PortDeviceObject->DeviceExtension;
1255
1256 /* Copy pseudo device extension into the real device extension */
1257 memcpy(PortDeviceExtension,
1258 PseudoDeviceExtension,
1259 PseudoDeviceExtension->Length);
1260
1261 /* Copy access ranges */
1262 AccessRangeSize =
1263 sizeof(ACCESS_RANGE) * PseudoDeviceExtension->PortConfig.NumberOfAccessRanges;
1264 PortDeviceExtension->PortConfig.AccessRanges = ExAllocatePool(NonPagedPool,
1265 AccessRangeSize);
1266 memcpy(PortDeviceExtension->PortConfig.AccessRanges,
1267 PseudoDeviceExtension->PortConfig.AccessRanges,
1268 AccessRangeSize);
1269
1270 /* Copy device base list */
1271 if (IsListEmpty(&PseudoDeviceExtension->DeviceBaseListHead))
1272 {
1273 InitializeListHead(&PortDeviceExtension->DeviceBaseListHead);
1274 }
1275 else
1276 {
1277 PseudoDeviceExtension->DeviceBaseListHead.Flink =
1278 PortDeviceExtension->DeviceBaseListHead.Flink;
1279 PseudoDeviceExtension->DeviceBaseListHead.Blink =
1280 PortDeviceExtension->DeviceBaseListHead.Blink;
1281 PortDeviceExtension->DeviceBaseListHead.Blink->Flink =
1282 &PortDeviceExtension->DeviceBaseListHead;
1283 PortDeviceExtension->DeviceBaseListHead.Flink->Blink =
1284 &PortDeviceExtension->DeviceBaseListHead;
1285 }
1286
1287 PortDeviceExtension->DeviceObject = PortDeviceObject;
1288 PortDeviceExtension->PortNumber = PortNumber;
1289
1290 /* Initialize the spin lock in the controller extension */
1291 KeInitializeSpinLock(&PortDeviceExtension->IrpLock);
1292 KeInitializeSpinLock(&PortDeviceExtension->SpinLock);
1293
1294 /* Register an interrupt handler for this device */
1295 Status = IoConnectInterrupt(&PortDeviceExtension->Interrupt,
1296 ScsiPortIsr,
1297 PortDeviceExtension,
1298 &PortDeviceExtension->SpinLock,
1299 MappedIrq,
1300 Dirql,
1301 Dirql,
1302 PortDeviceExtension->PortConfig.InterruptMode,
1303 TRUE,
1304 Affinity,
1305 FALSE);
1306 if (!NT_SUCCESS(Status))
1307 {
1308 DbgPrint("Could not Connect Interrupt %d\n",
1309 PortDeviceExtension->PortConfig.BusInterruptVector);
1310 IoDeleteDevice(PortDeviceObject);
1311 return(Status);
1312 }
1313
1314 /* Initialize the DPC object */
1315 IoInitializeDpcRequest(PortDeviceExtension->DeviceObject,
1316 ScsiPortDpcForIsr);
1317
1318 /* Initialize the device timer */
1319 PortDeviceExtension->TimerState = IDETimerIdle;
1320 PortDeviceExtension->TimerCount = 0;
1321 IoInitializeTimer(PortDeviceExtension->DeviceObject,
1322 ScsiPortIoTimer,
1323 PortDeviceExtension);
1324
1325 /* Initialize port capabilities */
1326 PortCapabilities = ExAllocatePool(NonPagedPool,
1327 sizeof(IO_SCSI_CAPABILITIES));
1328 PortDeviceExtension->PortCapabilities = PortCapabilities;
1329 PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
1330 PortCapabilities->MaximumTransferLength =
1331 PortDeviceExtension->PortConfig.MaximumTransferLength;
1332 PortCapabilities->MaximumPhysicalPages =
1333 PortCapabilities->MaximumTransferLength / PAGE_SIZE;
1334 PortCapabilities->SupportedAsynchronousEvents = 0; /* FIXME */
1335 PortCapabilities->AlignmentMask =
1336 PortDeviceExtension->PortConfig.AlignmentMask;
1337 PortCapabilities->TaggedQueuing =
1338 PortDeviceExtension->PortConfig.TaggedQueuing;
1339 PortCapabilities->AdapterScansDown =
1340 PortDeviceExtension->PortConfig.AdapterScansDown;
1341 PortCapabilities->AdapterUsesPio = TRUE; /* FIXME */
1342
1343 /* Initialize LUN-Extension list */
1344 InitializeListHead(&PortDeviceExtension->LunExtensionListHead);
1345
1346 DPRINT("DeviceExtension %p\n", PortDeviceExtension);
1347
1348 /* FIXME: Copy more configuration data? */
1349
1350
1351 /* Create the dos device link */
1352 swprintf(DosNameBuffer,
1353 L"\\??\\Scsi%lu:",
1354 PortNumber);
1355 RtlInitUnicodeString(&DosDeviceName,
1356 DosNameBuffer);
1357
1358 IoCreateSymbolicLink(&DosDeviceName,
1359 &DeviceName);
1360
1361 *RealDeviceExtension = PortDeviceExtension;
1362
1363 DPRINT("ScsiPortCreatePortDevice() done\n");
1364
1365 return(STATUS_SUCCESS);
1366 }
1367
1368
1369 static PSCSI_PORT_LUN_EXTENSION
1370 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1371 IN UCHAR PathId,
1372 IN UCHAR TargetId,
1373 IN UCHAR Lun)
1374 {
1375 PSCSI_PORT_LUN_EXTENSION LunExtension;
1376 ULONG LunExtensionSize;
1377
1378 DPRINT("SpiAllocateLunExtension (%p %u %u %u)\n",
1379 DeviceExtension, PathId, TargetId, Lun);
1380
1381 LunExtensionSize =
1382 sizeof(SCSI_PORT_LUN_EXTENSION) + DeviceExtension->LunExtensionSize;
1383 DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
1384
1385 LunExtension = ExAllocatePool(NonPagedPool,
1386 LunExtensionSize);
1387 if (LunExtension == NULL)
1388 {
1389 return NULL;
1390 }
1391
1392 RtlZeroMemory(LunExtension,
1393 LunExtensionSize);
1394
1395 InsertTailList(&DeviceExtension->LunExtensionListHead,
1396 &LunExtension->List);
1397
1398 LunExtension->PathId = PathId;
1399 LunExtension->TargetId = TargetId;
1400 LunExtension->Lun = Lun;
1401
1402 return LunExtension;
1403 }
1404
1405
1406 static PSCSI_PORT_LUN_EXTENSION
1407 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1408 IN UCHAR PathId,
1409 IN UCHAR TargetId,
1410 IN UCHAR Lun)
1411 {
1412 PSCSI_PORT_LUN_EXTENSION LunExtension;
1413 PLIST_ENTRY Entry;
1414
1415 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
1416 DeviceExtension, PathId, TargetId, Lun);
1417
1418 if (IsListEmpty(&DeviceExtension->LunExtensionListHead))
1419 return NULL;
1420
1421 Entry = DeviceExtension->LunExtensionListHead.Flink;
1422 while (Entry != &DeviceExtension->LunExtensionListHead)
1423 {
1424 LunExtension = CONTAINING_RECORD(Entry,
1425 SCSI_PORT_LUN_EXTENSION,
1426 List);
1427 if (LunExtension->PathId == PathId &&
1428 LunExtension->TargetId == TargetId &&
1429 LunExtension->Lun == Lun)
1430 {
1431 return LunExtension;
1432 }
1433
1434 Entry = Entry->Flink;
1435 }
1436
1437 return NULL;
1438 }
1439
1440
1441 static VOID
1442 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1443 {
1444 PSCSI_PORT_LUN_EXTENSION LunExtension;
1445 SCSI_REQUEST_BLOCK Srb;
1446 ULONG Bus;
1447 ULONG Target;
1448 ULONG Lun;
1449 BOOLEAN Result;
1450
1451 DPRINT("ScsiPortInquire() called\n");
1452
1453 DeviceExtension->Initializing = TRUE;
1454
1455 RtlZeroMemory(&Srb,
1456 sizeof(SCSI_REQUEST_BLOCK));
1457 Srb.DataBuffer = ExAllocatePool(NonPagedPool, 256);
1458 Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
1459 Srb.DataTransferLength = 256;
1460 Srb.Cdb[0] = SCSIOP_INQUIRY;
1461
1462 for (Bus = 0; Bus < DeviceExtension->PortConfig.NumberOfBuses; Bus++)
1463 {
1464 Srb.PathId = Bus;
1465
1466 for (Target = 0; Target < DeviceExtension->PortConfig.MaximumNumberOfTargets; Target++)
1467 {
1468 Srb.TargetId = Target;
1469
1470 for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
1471 {
1472 Srb.Lun = Lun;
1473 Srb.SrbStatus = SRB_STATUS_SUCCESS;
1474
1475 Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
1476 &Srb);
1477 DPRINT("Result: %s Srb.SrbStatus %lx\n", (Result)?"True":"False", Srb.SrbStatus);
1478
1479 if (Result == TRUE && Srb.SrbStatus == SRB_STATUS_SUCCESS)
1480 {
1481 LunExtension = SpiAllocateLunExtension(DeviceExtension,
1482 Bus,
1483 Target,
1484 Lun);
1485 if (LunExtension != NULL)
1486 {
1487 /* Copy inquiry data */
1488 memcpy(&LunExtension->InquiryData,
1489 Srb.DataBuffer,
1490 sizeof(INQUIRYDATA));
1491 }
1492 }
1493 }
1494 }
1495 }
1496
1497 ExFreePool(Srb.DataBuffer);
1498
1499 DeviceExtension->Initializing = FALSE;
1500
1501 DPRINT("ScsiPortInquire() done\n");
1502 }
1503
1504
1505 static ULONG
1506 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1507 OUT PSCSI_ADAPTER_BUS_INFO AdapterBusInfo)
1508 {
1509 PSCSI_PORT_LUN_EXTENSION LunExtension;
1510 PSCSI_INQUIRY_DATA UnitInfo, PrevUnit;
1511 ULONG Bus;
1512 ULONG Target;
1513 ULONG Lun;
1514 ULONG UnitCount;
1515
1516 DPRINT("SpiGetInquiryData() called\n");
1517
1518 /* Copy inquiry data to the port device extension */
1519 AdapterBusInfo->NumberOfBuses = DeviceExtension->PortConfig.NumberOfBuses;
1520
1521 UnitInfo = (PSCSI_INQUIRY_DATA)
1522 ((PUCHAR)AdapterBusInfo + sizeof(SCSI_ADAPTER_BUS_INFO) +
1523 (sizeof(SCSI_BUS_DATA) * (AdapterBusInfo->NumberOfBuses - 1)));
1524
1525 for (Bus = 0; Bus < AdapterBusInfo->NumberOfBuses; Bus++)
1526 {
1527 AdapterBusInfo->BusData[Bus].InitiatorBusId =
1528 DeviceExtension->PortConfig.InitiatorBusId[Bus];
1529 AdapterBusInfo->BusData[Bus].InquiryDataOffset =
1530 (ULONG)((PUCHAR)UnitInfo - (PUCHAR)AdapterBusInfo);
1531
1532 PrevUnit = NULL;
1533 UnitCount = 0;
1534
1535 for (Target = 0; Target < DeviceExtension->PortConfig.MaximumNumberOfTargets; Target++)
1536 {
1537 for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
1538 {
1539 LunExtension = SpiGetLunExtension(DeviceExtension,
1540 Bus,
1541 Target,
1542 Lun);
1543 if (LunExtension != NULL)
1544 {
1545 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
1546 Bus, Target, Lun);
1547
1548 UnitInfo->PathId = Bus;
1549 UnitInfo->TargetId = Target;
1550 UnitInfo->Lun = Lun;
1551 UnitInfo->InquiryDataLength = INQUIRYDATABUFFERSIZE;
1552 memcpy(&UnitInfo->InquiryData,
1553 &LunExtension->InquiryData,
1554 INQUIRYDATABUFFERSIZE);
1555 if (PrevUnit != NULL)
1556 PrevUnit->NextInquiryDataOffset = (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterBusInfo);
1557 PrevUnit = UnitInfo;
1558 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)UnitInfo + sizeof(SCSI_INQUIRY_DATA)+INQUIRYDATABUFFERSIZE-1);
1559 UnitCount++;
1560 }
1561 }
1562 }
1563 DPRINT("UnitCount: %lu\n", UnitCount);
1564 AdapterBusInfo->BusData[Bus].NumberOfLogicalUnits = UnitCount;
1565 if (UnitCount == 0)
1566 AdapterBusInfo->BusData[Bus].InquiryDataOffset = 0;
1567 }
1568
1569 DPRINT("Data size: %lu\n", (ULONG)UnitInfo - (ULONG)AdapterBusInfo);
1570
1571 return (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterBusInfo);
1572 }
1573
1574
1575 static BOOLEAN STDCALL
1576 ScsiPortIsr(IN PKINTERRUPT Interrupt,
1577 IN PVOID ServiceContext)
1578 {
1579 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1580 BOOLEAN Result;
1581
1582 DPRINT("ScsiPortIsr() called!\n");
1583
1584 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
1585
1586 Result = DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension);
1587 if (Result == FALSE)
1588 {
1589 return(FALSE);
1590 }
1591
1592 if (DeviceExtension->IrpFlags)
1593 {
1594 IoRequestDpc(DeviceExtension->DeviceObject,
1595 DeviceExtension->CurrentIrp,
1596 DeviceExtension);
1597 }
1598
1599 return(TRUE);
1600 }
1601
1602
1603 // ScsiPortDpcForIsr
1604 // DESCRIPTION:
1605 //
1606 // RUN LEVEL:
1607 //
1608 // ARGUMENTS:
1609 // IN PKDPC Dpc
1610 // IN PDEVICE_OBJECT DpcDeviceObject
1611 // IN PIRP DpcIrp
1612 // IN PVOID DpcContext
1613 //
1614 static VOID STDCALL
1615 ScsiPortDpcForIsr(IN PKDPC Dpc,
1616 IN PDEVICE_OBJECT DpcDeviceObject,
1617 IN PIRP DpcIrp,
1618 IN PVOID DpcContext)
1619 {
1620 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1621 PIO_STACK_LOCATION IrpStack;
1622 PSCSI_REQUEST_BLOCK Srb;
1623 KIRQL oldIrql;
1624
1625 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
1626 Dpc, DpcDeviceObject, DpcIrp, DpcContext);
1627
1628 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DpcContext;
1629
1630 KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql);
1631 if (DeviceExtension->IrpFlags)
1632 {
1633 IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
1634 Srb = IrpStack->Parameters.Scsi.Srb;
1635
1636 if (DeviceExtension->OriginalSrb != NULL)
1637 {
1638 DPRINT("Got sense data!\n");
1639
1640 DPRINT("Valid: %x\n", DeviceExtension->InternalSenseData.Valid);
1641 DPRINT("ErrorCode: %x\n", DeviceExtension->InternalSenseData.ErrorCode);
1642 DPRINT("SenseKey: %x\n", DeviceExtension->InternalSenseData.SenseKey);
1643 DPRINT("SenseCode: %x\n", DeviceExtension->InternalSenseData.AdditionalSenseCode);
1644
1645 /* Copy sense data */
1646 if (DeviceExtension->OriginalSrb->SenseInfoBufferLength != 0)
1647 {
1648 RtlCopyMemory(DeviceExtension->OriginalSrb->SenseInfoBuffer,
1649 &DeviceExtension->InternalSenseData,
1650 sizeof(SENSE_DATA));
1651 DeviceExtension->OriginalSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
1652 }
1653
1654 /* Clear current sense data */
1655 RtlZeroMemory(&DeviceExtension->InternalSenseData, sizeof(SENSE_DATA));
1656
1657 IrpStack->Parameters.Scsi.Srb = DeviceExtension->OriginalSrb;
1658 DeviceExtension->OriginalSrb = NULL;
1659 }
1660 else if ((SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) &&
1661 (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION))
1662 {
1663 DPRINT("SCSIOP_REQUEST_SENSE required!\n");
1664
1665 DeviceExtension->OriginalSrb = Srb;
1666 IrpStack->Parameters.Scsi.Srb = ScsiPortInitSenseRequestSrb(DeviceExtension,
1667 Srb);
1668 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1669 if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
1670 ScsiPortStartPacket,
1671 DeviceExtension))
1672 {
1673 DPRINT1("Synchronization failed!\n");
1674
1675 DpcIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
1676 DpcIrp->IoStatus.Information = 0;
1677 IoCompleteRequest(DpcIrp,
1678 IO_NO_INCREMENT);
1679 IoStartNextPacket(DpcDeviceObject,
1680 FALSE);
1681 }
1682
1683 return;
1684 }
1685
1686 DeviceExtension->CurrentIrp = NULL;
1687
1688
1689 // DpcIrp->IoStatus.Information = 0;
1690 // DpcIrp->IoStatus.Status = STATUS_SUCCESS;
1691
1692 if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
1693 {
1694 DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
1695 IoCompleteRequest(DpcIrp, IO_NO_INCREMENT);
1696 }
1697
1698 if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
1699 {
1700 DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
1701 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1702 IoStartNextPacket(DpcDeviceObject, FALSE);
1703 }
1704 else
1705 {
1706 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1707 }
1708 }
1709 else
1710 {
1711 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1712 }
1713
1714 DPRINT("ScsiPortDpcForIsr() done\n");
1715 }
1716
1717
1718 // ScsiPortIoTimer
1719 // DESCRIPTION:
1720 // This function handles timeouts and other time delayed processing
1721 //
1722 // RUN LEVEL:
1723 //
1724 // ARGUMENTS:
1725 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
1726 // IN PVOID Context the Controller extension for the
1727 // controller the device is on
1728 //
1729 static VOID STDCALL
1730 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
1731 PVOID Context)
1732 {
1733 DPRINT1("ScsiPortIoTimer()\n");
1734 }
1735
1736
1737 static PSCSI_REQUEST_BLOCK
1738 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1739 PSCSI_REQUEST_BLOCK OriginalSrb)
1740 {
1741 PSCSI_REQUEST_BLOCK Srb;
1742 PCDB Cdb;
1743
1744 Srb = &DeviceExtension->InternalSrb;
1745
1746 RtlZeroMemory(Srb,
1747 sizeof(SCSI_REQUEST_BLOCK));
1748
1749 Srb->PathId = OriginalSrb->PathId;
1750 Srb->TargetId = OriginalSrb->TargetId;
1751 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1752 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
1753 Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
1754
1755 Srb->TimeOutValue = 4;
1756
1757 Srb->CdbLength = 6;
1758 Srb->DataBuffer = &DeviceExtension->InternalSenseData;
1759 Srb->DataTransferLength = sizeof(SENSE_DATA);
1760
1761 Cdb = (PCDB)Srb->Cdb;
1762 Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
1763 Cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA);
1764
1765 return(Srb);
1766 }
1767
1768
1769 static VOID
1770 ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1771 {
1772 DeviceExtension->OriginalSrb = NULL;
1773 }
1774
1775
1776 /**********************************************************************
1777 * NAME INTERNAL
1778 * ScsiPortBuildDeviceMap
1779 *
1780 * DESCRIPTION
1781 * Builds the registry device map of all device which are attached
1782 * to the given SCSI HBA port. The device map is located at:
1783 * \Registry\Machine\DeviceMap\Scsi
1784 *
1785 * RUN LEVEL
1786 * PASSIVE_LEVEL
1787 *
1788 * ARGUMENTS
1789 * DeviceExtension
1790 * ...
1791 *
1792 * RegistryPath
1793 * Name of registry driver service key.
1794 *
1795 * RETURNS
1796 * NTSTATUS
1797 */
1798
1799 static NTSTATUS
1800 ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1801 PUNICODE_STRING RegistryPath)
1802 {
1803 PSCSI_PORT_LUN_EXTENSION LunExtension;
1804 OBJECT_ATTRIBUTES ObjectAttributes;
1805 UNICODE_STRING KeyName;
1806 UNICODE_STRING ValueName;
1807 WCHAR NameBuffer[64];
1808 ULONG Disposition;
1809 HANDLE ScsiKey;
1810 HANDLE ScsiPortKey;
1811 HANDLE ScsiBusKey;
1812 HANDLE ScsiInitiatorKey;
1813 HANDLE ScsiTargetKey;
1814 HANDLE ScsiLunKey;
1815 ULONG BusNumber;
1816 ULONG Target;
1817 ULONG CurrentTarget;
1818 ULONG Lun;
1819 PWCHAR DriverName;
1820 ULONG UlongData;
1821 PWCHAR TypeName;
1822 NTSTATUS Status;
1823
1824 DPRINT("ScsiPortBuildDeviceMap() called\n");
1825
1826 if (DeviceExtension == NULL || RegistryPath == NULL)
1827 {
1828 DPRINT1("Invalid parameter\n");
1829 return(STATUS_INVALID_PARAMETER);
1830 }
1831
1832 /* Open or create the 'Scsi' subkey */
1833 RtlInitUnicodeStringFromLiteral(&KeyName,
1834 L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
1835 InitializeObjectAttributes(&ObjectAttributes,
1836 &KeyName,
1837 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
1838 0,
1839 NULL);
1840 Status = ZwCreateKey(&ScsiKey,
1841 KEY_ALL_ACCESS,
1842 &ObjectAttributes,
1843 0,
1844 NULL,
1845 REG_OPTION_VOLATILE,
1846 &Disposition);
1847 if (!NT_SUCCESS(Status))
1848 {
1849 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1850 return(Status);
1851 }
1852
1853 /* Create new 'Scsi Port X' subkey */
1854 DPRINT("Scsi Port %lu\n",
1855 DeviceExtension->PortNumber);
1856
1857 swprintf(NameBuffer,
1858 L"Scsi Port %lu",
1859 DeviceExtension->PortNumber);
1860 RtlInitUnicodeString(&KeyName,
1861 NameBuffer);
1862 InitializeObjectAttributes(&ObjectAttributes,
1863 &KeyName,
1864 0,
1865 ScsiKey,
1866 NULL);
1867 Status = ZwCreateKey(&ScsiPortKey,
1868 KEY_ALL_ACCESS,
1869 &ObjectAttributes,
1870 0,
1871 NULL,
1872 REG_OPTION_VOLATILE,
1873 &Disposition);
1874 ZwClose(ScsiKey);
1875 if (!NT_SUCCESS(Status))
1876 {
1877 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1878 return(Status);
1879 }
1880
1881 /*
1882 * Create port-specific values
1883 */
1884
1885 /* Set 'DMA Enabled' (REG_DWORD) value */
1886 UlongData = (ULONG)!DeviceExtension->PortCapabilities->AdapterUsesPio;
1887 DPRINT(" DMA Enabled = %s\n", (UlongData) ? "TRUE" : "FALSE");
1888 RtlInitUnicodeString(&ValueName,
1889 L"DMA Enabled");
1890 Status = ZwSetValueKey(ScsiPortKey,
1891 &ValueName,
1892 0,
1893 REG_DWORD,
1894 &UlongData,
1895 sizeof(ULONG));
1896 if (!NT_SUCCESS(Status))
1897 {
1898 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status);
1899 ZwClose(ScsiPortKey);
1900 return(Status);
1901 }
1902
1903 /* Set 'Driver' (REG_SZ) value */
1904 DriverName = wcsrchr(RegistryPath->Buffer, L'\\') + 1;
1905 RtlInitUnicodeString(&ValueName,
1906 L"Driver");
1907 Status = ZwSetValueKey(ScsiPortKey,
1908 &ValueName,
1909 0,
1910 REG_SZ,
1911 DriverName,
1912 (wcslen(DriverName) + 1) * sizeof(WCHAR));
1913 if (!NT_SUCCESS(Status))
1914 {
1915 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status);
1916 ZwClose(ScsiPortKey);
1917 return(Status);
1918 }
1919
1920 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
1921 UlongData = (ULONG)DeviceExtension->PortConfig.BusInterruptLevel;
1922 DPRINT(" Interrupt = %lu\n", UlongData);
1923 RtlInitUnicodeString(&ValueName,
1924 L"Interrupt");
1925 Status = ZwSetValueKey(ScsiPortKey,
1926 &ValueName,
1927 0,
1928 REG_DWORD,
1929 &UlongData,
1930 sizeof(ULONG));
1931 if (!NT_SUCCESS(Status))
1932 {
1933 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status);
1934 ZwClose(ScsiPortKey);
1935 return(Status);
1936 }
1937
1938 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
1939 UlongData = ScsiPortConvertPhysicalAddressToUlong(DeviceExtension->PortConfig.AccessRanges[0].RangeStart);
1940 DPRINT(" IOAddress = %lx\n", UlongData);
1941 RtlInitUnicodeString(&ValueName,
1942 L"IOAddress");
1943 Status = ZwSetValueKey(ScsiPortKey,
1944 &ValueName,
1945 0,
1946 REG_DWORD,
1947 &UlongData,
1948 sizeof(ULONG));
1949 if (!NT_SUCCESS(Status))
1950 {
1951 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status);
1952 ZwClose(ScsiPortKey);
1953 return(Status);
1954 }
1955
1956 /* Enumerate buses */
1957 for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig.NumberOfBuses; BusNumber++)
1958 {
1959 /* Create 'Scsi Bus X' key */
1960 DPRINT(" Scsi Bus %lu\n", BusNumber);
1961 swprintf(NameBuffer,
1962 L"Scsi Bus %lu",
1963 BusNumber);
1964 RtlInitUnicodeString(&KeyName,
1965 NameBuffer);
1966 InitializeObjectAttributes(&ObjectAttributes,
1967 &KeyName,
1968 0,
1969 ScsiPortKey,
1970 NULL);
1971 Status = ZwCreateKey(&ScsiBusKey,
1972 KEY_ALL_ACCESS,
1973 &ObjectAttributes,
1974 0,
1975 NULL,
1976 REG_OPTION_VOLATILE,
1977 &Disposition);
1978 if (!NT_SUCCESS(Status))
1979 {
1980 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1981 ZwClose(ScsiPortKey);
1982 return(Status);
1983 }
1984
1985 /* Create 'Initiator Id X' key */
1986 DPRINT(" Initiator Id %u\n",
1987 DeviceExtension->PortConfig.InitiatorBusId[BusNumber]);
1988 swprintf(NameBuffer,
1989 L"Initiator Id %u",
1990 DeviceExtension->PortConfig.InitiatorBusId[BusNumber]);
1991 RtlInitUnicodeString(&KeyName,
1992 NameBuffer);
1993 InitializeObjectAttributes(&ObjectAttributes,
1994 &KeyName,
1995 0,
1996 ScsiBusKey,
1997 NULL);
1998 Status = ZwCreateKey(&ScsiInitiatorKey,
1999 KEY_ALL_ACCESS,
2000 &ObjectAttributes,
2001 0,
2002 NULL,
2003 REG_OPTION_VOLATILE,
2004 &Disposition);
2005 if (!NT_SUCCESS(Status))
2006 {
2007 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
2008 ZwClose(ScsiBusKey);
2009 ZwClose(ScsiPortKey);
2010 return(Status);
2011 }
2012
2013 /* FIXME: Are there any initiator values (??) */
2014
2015 ZwClose(ScsiInitiatorKey);
2016
2017
2018 /* Enumerate targets */
2019 CurrentTarget = (ULONG)-1;
2020 ScsiTargetKey = NULL;
2021 for (Target = 0; Target < DeviceExtension->PortConfig.MaximumNumberOfTargets; Target++)
2022 {
2023 for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
2024 {
2025 LunExtension = SpiGetLunExtension(DeviceExtension,
2026 BusNumber,
2027 Target,
2028 Lun);
2029 if (LunExtension != NULL)
2030 {
2031 if (Target != CurrentTarget)
2032 {
2033 /* Close old target key */
2034 if (ScsiTargetKey != NULL)
2035 {
2036 ZwClose(ScsiTargetKey);
2037 ScsiTargetKey = NULL;
2038 }
2039
2040 /* Create 'Target Id X' key */
2041 DPRINT(" Target Id %lu\n", Target);
2042 swprintf(NameBuffer,
2043 L"Target Id %lu",
2044 Target);
2045 RtlInitUnicodeString(&KeyName,
2046 NameBuffer);
2047 InitializeObjectAttributes(&ObjectAttributes,
2048 &KeyName,
2049 0,
2050 ScsiBusKey,
2051 NULL);
2052 Status = ZwCreateKey(&ScsiTargetKey,
2053 KEY_ALL_ACCESS,
2054 &ObjectAttributes,
2055 0,
2056 NULL,
2057 REG_OPTION_VOLATILE,
2058 &Disposition);
2059 if (!NT_SUCCESS(Status))
2060 {
2061 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
2062 ZwClose(ScsiBusKey);
2063 ZwClose(ScsiPortKey);
2064 return(Status);
2065 }
2066
2067 CurrentTarget = Target;
2068 }
2069
2070 /* Create 'Logical Unit Id X' key */
2071 DPRINT(" Logical Unit Id %lu\n", Lun);
2072 swprintf(NameBuffer,
2073 L"Logical Unit Id %lu",
2074 Lun);
2075 RtlInitUnicodeString(&KeyName,
2076 NameBuffer);
2077 InitializeObjectAttributes(&ObjectAttributes,
2078 &KeyName,
2079 0,
2080 ScsiTargetKey,
2081 NULL);
2082 Status = ZwCreateKey(&ScsiLunKey,
2083 KEY_ALL_ACCESS,
2084 &ObjectAttributes,
2085 0,
2086 NULL,
2087 REG_OPTION_VOLATILE,
2088 &Disposition);
2089 if (!NT_SUCCESS(Status))
2090 {
2091 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
2092 ZwClose(ScsiTargetKey);
2093 ZwClose(ScsiBusKey);
2094 ZwClose(ScsiPortKey);
2095 return(Status);
2096 }
2097
2098 /* Set 'Identifier' (REG_SZ) value */
2099 swprintf(NameBuffer,
2100 L"%.8S%.16S%.4S",
2101 LunExtension->InquiryData.VendorId,
2102 LunExtension->InquiryData.ProductId,
2103 LunExtension->InquiryData.ProductRevisionLevel);
2104 DPRINT(" Identifier = '%S'\n", NameBuffer);
2105 RtlInitUnicodeString(&ValueName,
2106 L"Identifier");
2107 Status = ZwSetValueKey(ScsiLunKey,
2108 &ValueName,
2109 0,
2110 REG_SZ,
2111 NameBuffer,
2112 (wcslen(NameBuffer) + 1) * sizeof(WCHAR));
2113 if (!NT_SUCCESS(Status))
2114 {
2115 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status);
2116 ZwClose(ScsiLunKey);
2117 ZwClose(ScsiTargetKey);
2118 ZwClose(ScsiBusKey);
2119 ZwClose(ScsiPortKey);
2120 return(Status);
2121 }
2122
2123 /* Set 'Type' (REG_SZ) value */
2124 switch (LunExtension->InquiryData.DeviceType)
2125 {
2126 case 0:
2127 TypeName = L"DiskPeripheral";
2128 break;
2129 case 1:
2130 TypeName = L"TapePeripheral";
2131 break;
2132 case 2:
2133 TypeName = L"PrinterPeripheral";
2134 break;
2135 case 4:
2136 TypeName = L"WormPeripheral";
2137 break;
2138 case 5:
2139 TypeName = L"CdRomPeripheral";
2140 break;
2141 case 6:
2142 TypeName = L"ScannerPeripheral";
2143 break;
2144 case 7:
2145 TypeName = L"OpticalDiskPeripheral";
2146 break;
2147 case 8:
2148 TypeName = L"MediumChangerPeripheral";
2149 break;
2150 case 9:
2151 TypeName = L"CommunicationPeripheral";
2152 break;
2153 default:
2154 TypeName = L"OtherPeripheral";
2155 break;
2156 }
2157 DPRINT(" Type = '%S'\n", TypeName);
2158 RtlInitUnicodeString(&ValueName,
2159 L"Type");
2160 Status = ZwSetValueKey(ScsiLunKey,
2161 &ValueName,
2162 0,
2163 REG_SZ,
2164 TypeName,
2165 (wcslen(TypeName) + 1) * sizeof(WCHAR));
2166 if (!NT_SUCCESS(Status))
2167 {
2168 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status);
2169 ZwClose(ScsiLunKey);
2170 ZwClose(ScsiTargetKey);
2171 ZwClose(ScsiBusKey);
2172 ZwClose(ScsiPortKey);
2173 return(Status);
2174 }
2175
2176 ZwClose(ScsiLunKey);
2177 }
2178 }
2179
2180 /* Close old target key */
2181 if (ScsiTargetKey != NULL)
2182 {
2183 ZwClose(ScsiTargetKey);
2184 ScsiTargetKey = NULL;
2185 }
2186 }
2187
2188 ZwClose(ScsiBusKey);
2189 }
2190
2191 ZwClose(ScsiPortKey);
2192
2193 DPRINT("ScsiPortBuildDeviceMap() done\n");
2194
2195 return(Status);
2196 }
2197
2198 /* EOF */