1 /*
2  * PROJECT:     ReactOS Storage Stack / SCSIPORT storage port library
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Registry operations
5  * COPYRIGHT:   Eric Kohl (eric.kohl@reactos.org)
6  *              Aleksey Bragin (aleksey@reactos.org)
7  *              2020 Victor Perevertkin (victor.perevertkin@reactos.org)
8  */
9 
10 #include "scsiport.h"
11 #include "scsitypes.h"
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 
17 VOID
18 SpiInitOpenKeys(
19     _Inout_ PCONFIGURATION_INFO ConfigInfo,
20     _In_ PSCSI_PORT_DRIVER_EXTENSION DriverExtension)
21 {
22     OBJECT_ATTRIBUTES ObjectAttributes;
23     UNICODE_STRING KeyName;
24     NTSTATUS Status;
25     HANDLE parametersKey;
26 
27     DriverExtension->IsLegacyDriver = TRUE;
28 
29     /* Open the service key */
30     InitializeObjectAttributes(&ObjectAttributes,
31                                &DriverExtension->RegistryPath,
32                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
33                                NULL,
34                                NULL);
35 
36     Status = ZwOpenKey(&ConfigInfo->ServiceKey, KEY_READ, &ObjectAttributes);
37 
38     if (!NT_SUCCESS(Status))
39     {
40         DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n",
41                DriverExtension->RegistryPath, Status);
42         ConfigInfo->ServiceKey = NULL;
43     }
44 
45     /* If we could open driver's service key, then proceed to the Parameters key */
46     if (ConfigInfo->ServiceKey != NULL)
47     {
48         RtlInitUnicodeString(&KeyName, L"Parameters");
49         InitializeObjectAttributes(&ObjectAttributes,
50                                    &KeyName,
51                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
52                                    ConfigInfo->ServiceKey,
53                                    NULL);
54 
55         /* Try to open it */
56         Status = ZwOpenKey(&ConfigInfo->DeviceKey, KEY_READ, &ObjectAttributes);
57 
58         if (NT_SUCCESS(Status))
59         {
60             /* Yes, Parameters key exist, and it must be used instead of
61                the Service key */
62             ZwClose(ConfigInfo->ServiceKey);
63             ConfigInfo->ServiceKey = ConfigInfo->DeviceKey;
64             ConfigInfo->DeviceKey = NULL;
65         }
66     }
67 
68     if (ConfigInfo->ServiceKey != NULL)
69     {
70         /* Open the Device key */
71         RtlInitUnicodeString(&KeyName, L"Device");
72         InitializeObjectAttributes(&ObjectAttributes,
73                                    &KeyName,
74                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
75                                    ConfigInfo->ServiceKey,
76                                    NULL);
77 
78         /* We don't check for failure here - not needed */
79         ZwOpenKey(&ConfigInfo->DeviceKey, KEY_READ, &ObjectAttributes);
80 
81         // Detect the driver PnP capabilities via its Parameters\PnpInterface key
82         // for example: HKLM\SYSTEM\CurrentControlSet\Services\UNIATA\Parameters\PnpInterface
83 
84         RtlInitUnicodeString(&KeyName, L"PnpInterface");
85         InitializeObjectAttributes(&ObjectAttributes,
86                                    &KeyName,
87                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
88                                    ConfigInfo->ServiceKey,
89                                    NULL);
90 
91         Status = ZwOpenKey(&parametersKey, KEY_READ, &ObjectAttributes);
92 
93         if (NT_SUCCESS(Status))
94         {
95             // if the key exists, it's enough for us for now
96             // (the proper check should iterate over INTERFACE_TYPE values)
97             DriverExtension->IsLegacyDriver = FALSE;
98             ZwClose(parametersKey);
99         }
100     }
101 }
102 
103 /**********************************************************************
104  * NAME                         INTERNAL
105  *  SpiBuildDeviceMap
106  *
107  * DESCRIPTION
108  *  Builds the registry device map of all device which are attached
109  *  to the given SCSI HBA port. The device map is located at:
110  *    \Registry\Machine\DeviceMap\Scsi
111  *
112  * RUN LEVEL
113  *  PASSIVE_LEVEL
114  *
115  * ARGUMENTS
116  *  DeviceExtension
117  *      ...
118  *
119  *  RegistryPath
120  *      Name of registry driver service key.
121  *
122  * RETURNS
123  *  NTSTATUS
124  */
125 
126 NTSTATUS
127 RegistryInitAdapterKey(
128     _Inout_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
129 {
130     OBJECT_ATTRIBUTES ObjectAttributes;
131     UNICODE_STRING KeyName;
132     UNICODE_STRING ValueName;
133     WCHAR NameBuffer[64];
134     HANDLE ScsiKey;
135     HANDLE ScsiPortKey = NULL;
136     HANDLE ScsiBusKey = NULL;
137     HANDLE ScsiInitiatorKey = NULL;
138     ULONG BusNumber;
139     ULONG UlongData;
140     NTSTATUS Status;
141 
142     DPRINT("SpiBuildDeviceMap() called\n");
143 
144     if (DeviceExtension == NULL)
145     {
146         DPRINT1("Invalid parameter\n");
147         return STATUS_INVALID_PARAMETER;
148     }
149 
150     /* Open or create the 'Scsi' subkey */
151     RtlInitUnicodeString(&KeyName,
152                          L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
153     InitializeObjectAttributes(&ObjectAttributes,
154                                &KeyName,
155                                OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE,
156                                0,
157                                NULL);
158     Status = ZwCreateKey(&ScsiKey,
159                          KEY_ALL_ACCESS,
160                          &ObjectAttributes,
161                          0,
162                          NULL,
163                          REG_OPTION_VOLATILE,
164                          NULL);
165     if (!NT_SUCCESS(Status))
166     {
167         DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
168         return Status;
169     }
170 
171     /* Create new 'Scsi Port X' subkey */
172     DPRINT("Scsi Port %lu\n", DeviceExtension->PortNumber);
173 
174     swprintf(NameBuffer,
175              L"Scsi Port %lu",
176              DeviceExtension->PortNumber);
177     RtlInitUnicodeString(&KeyName, NameBuffer);
178     InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_KERNEL_HANDLE, ScsiKey, NULL);
179     Status = ZwCreateKey(&ScsiPortKey,
180                          KEY_ALL_ACCESS,
181                          &ObjectAttributes,
182                          0,
183                          NULL,
184                          REG_OPTION_VOLATILE,
185                          NULL);
186     ZwClose(ScsiKey);
187     if (!NT_SUCCESS(Status))
188     {
189         DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
190         return Status;
191     }
192 
193     /*
194      * Create port-specific values
195      */
196 
197     /* Set 'DMA Enabled' (REG_DWORD) value */
198     UlongData = (ULONG)!DeviceExtension->PortCapabilities.AdapterUsesPio;
199     DPRINT("  DMA Enabled = %s\n", UlongData ? "TRUE" : "FALSE");
200     RtlInitUnicodeString(&ValueName, L"DMA Enabled");
201     Status = ZwSetValueKey(ScsiPortKey,
202                            &ValueName,
203                            0,
204                            REG_DWORD,
205                            &UlongData,
206                            sizeof(UlongData));
207     if (!NT_SUCCESS(Status))
208     {
209         DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status);
210         ZwClose(ScsiPortKey);
211         return Status;
212     }
213 
214     /* Set 'Driver' (REG_SZ) value */
215     PUNICODE_STRING driverNameU = &DeviceExtension->Common.DeviceObject->DriverObject
216                                   ->DriverExtension->ServiceKeyName;
217 
218     PWCHAR driverName = ExAllocatePoolWithTag(PagedPool,
219                                               driverNameU->Length + sizeof(UNICODE_NULL),
220                                               TAG_SCSIPORT);
221     if (!driverName)
222     {
223         DPRINT("Failed to allocate driverName!\n");
224         ZwClose(ScsiPortKey);
225         return STATUS_INSUFFICIENT_RESOURCES;
226     }
227 
228     RtlCopyMemory(driverName, driverNameU->Buffer, driverNameU->Length);
229     driverName[driverNameU->Length / sizeof(WCHAR)] = UNICODE_NULL;
230 
231     RtlInitUnicodeString(&ValueName, L"Driver");
232     Status = ZwSetValueKey(ScsiPortKey,
233                            &ValueName,
234                            0,
235                            REG_SZ,
236                            driverName,
237                            driverNameU->Length + sizeof(UNICODE_NULL));
238 
239     ExFreePoolWithTag(driverName, TAG_SCSIPORT);
240 
241     if (!NT_SUCCESS(Status))
242     {
243         DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status);
244         ZwClose(ScsiPortKey);
245         return Status;
246     }
247 
248     /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
249     UlongData = (ULONG)DeviceExtension->PortConfig->BusInterruptLevel;
250     DPRINT("  Interrupt = %lu\n", UlongData);
251     RtlInitUnicodeString(&ValueName, L"Interrupt");
252     Status = ZwSetValueKey(ScsiPortKey,
253                            &ValueName,
254                            0,
255                            REG_DWORD,
256                            &UlongData,
257                            sizeof(UlongData));
258     if (!NT_SUCCESS(Status))
259     {
260         DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status);
261         ZwClose(ScsiPortKey);
262         return Status;
263     }
264 
265     /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
266     UlongData = ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension->PortConfig->AccessRanges)[0].RangeStart);
267     DPRINT("  IOAddress = %lx\n", UlongData);
268     RtlInitUnicodeString(&ValueName, L"IOAddress");
269     Status = ZwSetValueKey(ScsiPortKey,
270                            &ValueName,
271                            0,
272                            REG_DWORD,
273                            &UlongData,
274                            sizeof(UlongData));
275     if (!NT_SUCCESS(Status))
276     {
277         DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status);
278         ZwClose(ScsiPortKey);
279         return Status;
280     }
281 
282     /* Enumerate buses */
283     for (BusNumber = 0; BusNumber < DeviceExtension->NumberOfBuses; BusNumber++)
284     {
285         /* Create 'Scsi Bus X' key */
286         DPRINT("    Scsi Bus %lu\n", BusNumber);
287         swprintf(NameBuffer,
288                  L"Scsi Bus %lu",
289                  BusNumber);
290         RtlInitUnicodeString(&KeyName, NameBuffer);
291         InitializeObjectAttributes(&ObjectAttributes,
292                                    &KeyName,
293                                    OBJ_KERNEL_HANDLE,
294                                    ScsiPortKey,
295                                    NULL);
296         Status = ZwCreateKey(&ScsiBusKey,
297                              KEY_ALL_ACCESS,
298                              &ObjectAttributes,
299                              0,
300                              NULL,
301                              REG_OPTION_VOLATILE,
302                              NULL);
303         if (!NT_SUCCESS(Status))
304         {
305             DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
306             goto ByeBye;
307         }
308 
309         /* Create 'Initiator Id X' key */
310         DPRINT("      Initiator Id %lu\n",
311                DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
312         swprintf(NameBuffer,
313                  L"Initiator Id %lu",
314                  (ULONG)(UCHAR)DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
315         RtlInitUnicodeString(&KeyName, NameBuffer);
316         InitializeObjectAttributes(&ObjectAttributes,
317                                    &KeyName,
318                                    OBJ_KERNEL_HANDLE,
319                                    ScsiBusKey,
320                                    NULL);
321         Status = ZwCreateKey(&ScsiInitiatorKey,
322                              KEY_ALL_ACCESS,
323                              &ObjectAttributes,
324                              0,
325                              NULL,
326                              REG_OPTION_VOLATILE,
327                              NULL);
328         if (!NT_SUCCESS(Status))
329         {
330             DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
331             goto ByeBye;
332         }
333 
334         /* FIXME: Are there any initiator values (??) */
335 
336         ZwClose(ScsiInitiatorKey);
337         ScsiInitiatorKey = NULL;
338 
339         DeviceExtension->Buses[BusNumber].RegistryMapKey = ScsiBusKey;
340         ScsiBusKey = NULL;
341     }
342 
343 ByeBye:
344     if (ScsiInitiatorKey != NULL)
345         ZwClose(ScsiInitiatorKey);
346 
347     if (ScsiBusKey != NULL)
348         ZwClose(ScsiBusKey);
349 
350     if (ScsiPortKey != NULL)
351         ZwClose(ScsiPortKey);
352 
353     DPRINT("SpiBuildDeviceMap() done\n");
354 
355     return Status;
356 }
357 
358 NTSTATUS
359 RegistryInitLunKey(
360     _Inout_ PSCSI_PORT_LUN_EXTENSION LunExtension)
361 {
362     WCHAR nameBuffer[64];
363     UNICODE_STRING keyName;
364     UNICODE_STRING valueName;
365     OBJECT_ATTRIBUTES objectAttributes;
366     HANDLE targetKey;
367     NTSTATUS status;
368 
369     // get the LUN's bus key
370     PSCSI_PORT_DEVICE_EXTENSION portExt = LunExtension->Common.LowerDevice->DeviceExtension;
371     HANDLE busKey = portExt->Buses[LunExtension->PathId].RegistryMapKey;
372 
373     // create/open 'Target Id X' key
374     swprintf(nameBuffer, L"Target Id %lu", LunExtension->TargetId);
375     RtlInitUnicodeString(&keyName, nameBuffer);
376     InitializeObjectAttributes(&objectAttributes, &keyName, OBJ_KERNEL_HANDLE, busKey, NULL);
377     status = ZwCreateKey(&targetKey,
378                          KEY_ALL_ACCESS,
379                          &objectAttributes,
380                          0,
381                          NULL,
382                          REG_OPTION_VOLATILE,
383                          NULL);
384     if (!NT_SUCCESS(status))
385     {
386         DPRINT("ZwCreateKey() failed (Status %lx)\n", status);
387         return status;
388     }
389 
390     // Create 'Logical Unit Id X' key
391     swprintf(nameBuffer, L"Logical Unit Id %lu", LunExtension->Lun);
392     RtlInitUnicodeString(&keyName, nameBuffer);
393     InitializeObjectAttributes(&objectAttributes, &keyName, OBJ_KERNEL_HANDLE, targetKey, NULL);
394     status = ZwCreateKey(&LunExtension->RegistryMapKey,
395                          KEY_ALL_ACCESS,
396                          &objectAttributes,
397                          0,
398                          NULL,
399                          REG_OPTION_VOLATILE,
400                          NULL);
401     if (!NT_SUCCESS(status))
402     {
403         DPRINT("ZwCreateKey() failed (Status %lx)\n", status);
404         goto ByeBye;
405     }
406 
407     // Set 'Identifier' (REG_SZ) value
408     swprintf(nameBuffer,
409              L"%.8S%.16S%.4S",
410              LunExtension->InquiryData.VendorId,
411              LunExtension->InquiryData.ProductId,
412              LunExtension->InquiryData.ProductRevisionLevel);
413     RtlInitUnicodeString(&valueName, L"Identifier");
414     status = ZwSetValueKey(LunExtension->RegistryMapKey,
415                            &valueName,
416                            0,
417                            REG_SZ,
418                            nameBuffer,
419                            (wcslen(nameBuffer) + 1) * sizeof(WCHAR));
420     if (!NT_SUCCESS(status))
421     {
422         DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", status);
423         goto ByeBye;
424     }
425 
426     // Set 'Type' (REG_SZ) value
427     PWCHAR typeName = (PWCHAR)GetPeripheralTypeW(&LunExtension->InquiryData);
428     DPRINT("          Type = '%S'\n", typeName);
429     RtlInitUnicodeString(&valueName, L"Type");
430     status = ZwSetValueKey(LunExtension->RegistryMapKey,
431                            &valueName,
432                            0,
433                            REG_SZ,
434                            typeName,
435                            (wcslen(typeName) + 1) * sizeof(WCHAR));
436     if (!NT_SUCCESS(status))
437     {
438         DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", status);
439         goto ByeBye;
440     }
441 
442     // Set 'InquiryData' (REG_BINARY) value
443     RtlInitUnicodeString(&valueName, L"InquiryData");
444     status = ZwSetValueKey(LunExtension->RegistryMapKey,
445                            &valueName,
446                            0,
447                            REG_BINARY,
448                            &LunExtension->InquiryData,
449                            INQUIRYDATABUFFERSIZE);
450     if (!NT_SUCCESS(status))
451     {
452         DPRINT("ZwSetValueKey('InquiryData') failed (Status %lx)\n", status);
453         goto ByeBye;
454     }
455 
456 ByeBye:
457     ZwClose(targetKey);
458     // TODO: maybe we will need it in future
459     ZwClose(LunExtension->RegistryMapKey);
460 
461     return status;
462 }
463