Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

657 lines
16 KiB

  1. /*++
  2. Copyright (c) 2002 Microsoft Corporation
  3. Module Name:
  4. Abstract:
  5. The format of the SCSI (port driver) device map is as follows:
  6. Scsi Port 0 - KEY
  7. Driver - REG_SZ specifying the drive name, e.g., aha154x.
  8. Interrupt - REG_DWORD specifying the interrupt vector that the HBA
  9. uses. For example, 58.
  10. IOAddress - REG_DWORD specifying the IO address the HBA uses;
  11. for example, 0xd800.
  12. Dma64BidAddresses - REG_DWORD specifying whether the HBA is using
  13. 64 bit addresses or not. Should always be 1 if present.
  14. PCCARD - REG_DWORD specifying whether this is a PCCARD bus or not.
  15. The value will always be 1 if present.
  16. SCSI Bus 0 - KEY
  17. Initiator Id 7 - KEY
  18. Target Id 0 - KEY
  19. Logical Unit ID 0 - KEY
  20. Identifier - REG_SZ specifying the SCSI Vendor ID from
  21. the LUNs inquiry data.
  22. InquiryData - REG_BINARY specifies the SCSI Inquiry Data
  23. for the LUN.
  24. SerialNumber - REG_SZ specifies the SCSI Serial Number
  25. for the LUN if present.
  26. Type - REG_SZ specifies the SCSI device type for the LUN.
  27. Usage:
  28. The module exports the following functions:
  29. PortOpenMapKey - Opens a handle to the root of the SCSI device map.
  30. PortBuildAdapterEntry - Creates an entry for the specified adapter
  31. in the SCSI device map.
  32. PortBuildBusEntry - Creates an entry for the specified bus in the
  33. SCSI device map.
  34. PortBuildTargetEntry - Creates an entry for the specified target in
  35. the SCSI device map.
  36. PortBuildLunEntry - Creates an entry for the specified LUN in the
  37. SCSI device map.
  38. Author:
  39. Matthew D Hendel (math) 18-July-2002
  40. Revision History:
  41. --*/
  42. #include "precomp.h"
  43. #include <wdmguid.h>
  44. //
  45. // Defines
  46. //
  47. #define SCSI_DEVMAP_KEY_NAME \
  48. (L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi")
  49. #define SCSI_LUN_KEY_NAME\
  50. (L"%s\\Scsi Port %d\\SCSI Bus %d\\Target Id %d\\Logical Unit Id %d")
  51. //
  52. // Implementation
  53. //
  54. NTSTATUS
  55. PortOpenMapKey(
  56. OUT PHANDLE DeviceMapKey
  57. )
  58. /*++
  59. Routine Description:
  60. Open a handle to the root of the SCSI Device Map.
  61. The handle must be closed with ZwClose.
  62. Arguments:
  63. DeviceMapKey - Supplies a buffer where the device map handle should
  64. be stored on success.
  65. Return Value:
  66. NTSTATUS code.
  67. --*/
  68. {
  69. UNICODE_STRING name;
  70. OBJECT_ATTRIBUTES objectAttributes;
  71. HANDLE mapKey;
  72. ULONG disposition;
  73. NTSTATUS status;
  74. ASSERT (DeviceMapKey != NULL);
  75. PAGED_CODE();
  76. //
  77. // Open the SCSI key in the device map.
  78. //
  79. RtlInitUnicodeString(&name, SCSI_DEVMAP_KEY_NAME);
  80. InitializeObjectAttributes(&objectAttributes,
  81. &name,
  82. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  83. NULL,
  84. (PSECURITY_DESCRIPTOR) NULL);
  85. //
  86. // Create or open the key.
  87. //
  88. status = ZwCreateKey(&mapKey,
  89. KEY_READ | KEY_WRITE,
  90. &objectAttributes,
  91. 0,
  92. (PUNICODE_STRING) NULL,
  93. REG_OPTION_VOLATILE,
  94. &disposition);
  95. if(NT_SUCCESS(status)) {
  96. *DeviceMapKey = mapKey;
  97. } else {
  98. *DeviceMapKey = NULL;
  99. }
  100. return status;
  101. }
  102. NTSTATUS
  103. PortMapBuildAdapterEntry(
  104. IN HANDLE DeviceMapKey,
  105. IN ULONG PortNumber,
  106. IN ULONG InterruptLevel, OPTIONAL
  107. IN ULONG IoAddress, OPTIONAL
  108. IN ULONG Dma64BitAddresses,
  109. IN PUNICODE_STRING DriverName,
  110. IN PGUID BusType, OPTIONAL
  111. OUT PHANDLE AdapterKeyBuffer OPTIONAL
  112. )
  113. /*++
  114. Routine Description:
  115. Create a device map entry for the SCSI HBA. We also include device
  116. map entries for each of the Busses attached to the HBA, and the initiator
  117. for each bus.
  118. Arguments:
  119. DeviceMapKey - Supplies the handle to the device map key.
  120. PortNumber - Supplies the port number that this HBA represents.
  121. InterruptLevel - Supplies the interrupt level, or 0 for none.
  122. IoAddress - Supplies the IoAddress or 0 for none.
  123. Dma64BitAddress -
  124. DriverName - NULL terminated unicode string that is the driver name.
  125. BusType - Bus type that this HBA is on.
  126. AdapterKeyBuffer -
  127. Return Value:
  128. NTSTATUS code.
  129. --*/
  130. {
  131. NTSTATUS Status;
  132. ULONG Temp;
  133. HANDLE AdapterKey;
  134. PAGED_CODE();
  135. //
  136. // String must be NULL terminated.
  137. //
  138. ASSERT (DriverName->Buffer [DriverName->Length / sizeof (WCHAR)] == UNICODE_NULL);
  139. Status = PortCreateKeyEx (DeviceMapKey,
  140. REG_OPTION_VOLATILE,
  141. &AdapterKey,
  142. L"Scsi Port %d",
  143. PortNumber);
  144. if (!NT_SUCCESS (Status)) {
  145. return Status;
  146. }
  147. //
  148. // Add interrupt level if non-zero.
  149. //
  150. if (InterruptLevel) {
  151. Status = PortSetValueKey (AdapterKey,
  152. L"Interrupt",
  153. REG_DWORD,
  154. &InterruptLevel,
  155. sizeof (ULONG));
  156. }
  157. //
  158. // Add IoAddress if non-zero.
  159. //
  160. if (IoAddress) {
  161. Status = PortSetValueKey (AdapterKey,
  162. L"IOAddress",
  163. REG_DWORD,
  164. &IoAddress,
  165. sizeof (ULONG));
  166. }
  167. //
  168. // Add Dma64BitAddresses if non-zero.
  169. //
  170. if (Dma64BitAddresses) {
  171. Temp = 1;
  172. Status = PortSetValueKey (AdapterKey,
  173. L"Dma64BitAddresses",
  174. REG_DWORD,
  175. &Temp,
  176. sizeof (ULONG));
  177. }
  178. //
  179. // Add the driver name.
  180. //
  181. Status = PortSetValueKey (AdapterKey,
  182. L"Driver",
  183. REG_SZ,
  184. DriverName->Buffer,
  185. DriverName->Length + sizeof (WCHAR));
  186. //
  187. // If this is a PCMCIA card, set the PCCARD flag.
  188. //
  189. if (BusType != NULL &&
  190. IsEqualGUID (BusType, &GUID_BUS_TYPE_PCMCIA)) {
  191. Temp = 1;
  192. Status = PortSetValueKey (AdapterKey,
  193. L"PCCARD",
  194. REG_DWORD,
  195. &Temp,
  196. sizeof (ULONG));
  197. }
  198. if (AdapterKeyBuffer != NULL) {
  199. *AdapterKeyBuffer = AdapterKey;
  200. } else {
  201. ZwClose (AdapterKey);
  202. }
  203. return STATUS_SUCCESS;
  204. }
  205. NTSTATUS
  206. PortMapBuildBusEntry(
  207. IN HANDLE AdapterKey,
  208. IN ULONG BusId,
  209. IN ULONG InitiatorId,
  210. OUT PHANDLE BusKeyBuffer OPTIONAL
  211. )
  212. /*++
  213. Routine Description:
  214. Build the BusId device map entry under the adapters device map entry. The
  215. bus entry is populated with an entry for the initiator ID only.
  216. Arguments:
  217. AdapterKey - Handle to the adapter's device map entry.
  218. BusId - Supplies the ID of this bus.
  219. InitiatorId - Supplies the initiator target ID.
  220. BusKeyBuffer _ Supplies an optional pointer to a buffer to receive the
  221. opened bus key.
  222. Return Value:
  223. NTSTATUS code.
  224. --*/
  225. {
  226. NTSTATUS Status;
  227. HANDLE BusKey;
  228. ASSERT (BusId <= 255);
  229. ASSERT (InitiatorId <= 255);
  230. PAGED_CODE();
  231. Status = PortCreateKeyEx (AdapterKey,
  232. REG_OPTION_VOLATILE,
  233. &BusKey,
  234. L"SCSI Bus %d",
  235. BusId);
  236. if (!NT_SUCCESS (Status)) {
  237. return Status;
  238. }
  239. PortCreateKeyEx (BusKey,
  240. REG_OPTION_VOLATILE,
  241. NULL,
  242. L"Initiator Id %d",
  243. InitiatorId);
  244. if (BusKeyBuffer) {
  245. *BusKeyBuffer = BusKey;
  246. } else {
  247. ZwClose (BusKey);
  248. }
  249. return STATUS_SUCCESS;
  250. }
  251. NTSTATUS
  252. PortMapBuildTargetEntry(
  253. IN HANDLE BusKey,
  254. IN ULONG TargetId,
  255. OUT PHANDLE TargetKey OPTIONAL
  256. )
  257. {
  258. NTSTATUS Status;
  259. ASSERT (TargetId <= 255);
  260. PAGED_CODE();
  261. Status = PortCreateKeyEx (BusKey,
  262. REG_OPTION_VOLATILE,
  263. TargetKey,
  264. L"Target Id %d",
  265. TargetId);
  266. return Status;
  267. }
  268. NTSTATUS
  269. PortMapBuildLunEntry(
  270. IN HANDLE TargetKey,
  271. IN ULONG Lun,
  272. IN PINQUIRYDATA InquiryData,
  273. IN PANSI_STRING SerialNumber, OPTIONAL
  274. PVOID DeviceId,
  275. IN ULONG DeviceIdLength,
  276. OUT PHANDLE LunKeyBuffer OPTIONAL
  277. )
  278. /*++
  279. Routine Description:
  280. Create and populate the Logical Unit Device Map Entry with the following
  281. information:
  282. Identifier - REG_SZ specifying the SCSI Vendor Id from the inquriy
  283. data.
  284. InquiryData - REG_BINARY specifying the SCSI InquiryData.
  285. SerialNumber - REG_SZ specifying the serial number (page 80 of Inquriy
  286. VPD).
  287. Type - REG_SZ specifying the SCSI device type.
  288. DeviceIdentifierPage - REG_BINARY specifying the binary device
  289. identifier data (page 83 of VPD).
  290. Arguments:
  291. TargetKey - Specifies the Target's previously opened key.
  292. Lun - Specifies the Logical Unit ID for this LUN.
  293. InquiryData - Specifies the binary inquriy data for this LUN. NOTE: Only
  294. the first INQUIRYDATABUFFERSIZE bytes of the Inquiry data are used.
  295. SerialNumber - Specifies the ANSI Serial Number (page 80) for the LUN. May
  296. be NULL if there is no serial number.
  297. DeviceId - Specifies the device identifier page (page 83) for the LUN. May
  298. be NULL if the device does not support page 83.
  299. DeviceIdLength - Specifies the length of the DeviceId parameter. Not used
  300. when DeviceId is NULL.
  301. LunKeyReturn - Specifies the buffer for key for the logical unit to
  302. be copied to. May be NULL if not necessary.
  303. Return Value:
  304. NTSTATUS code.
  305. --*/
  306. {
  307. NTSTATUS Status;
  308. HANDLE LunKey;
  309. PCSCSI_DEVICE_TYPE DeviceEntry;
  310. ULONG Length;
  311. ASSERT (Lun <= 255);
  312. ASSERT (InquiryData != NULL);
  313. PAGED_CODE();
  314. Status = PortCreateKeyEx (TargetKey,
  315. REG_OPTION_VOLATILE,
  316. &LunKey,
  317. L"Logical Unit Id %d",
  318. Lun);
  319. if (!NT_SUCCESS (Status)) {
  320. return Status;
  321. }
  322. //
  323. // Write out the INQUIRY DATA in binary form.
  324. //
  325. PortSetValueKey (LunKey,
  326. L"InquiryData",
  327. REG_BINARY,
  328. InquiryData,
  329. INQUIRYDATABUFFERSIZE);
  330. //
  331. // Write out the SERIAL NUMBER as a string.
  332. //
  333. if (SerialNumber->Length != 0) {
  334. PortSetValueKey (LunKey,
  335. L"SerialNumber",
  336. PORT_REG_ANSI_STRING,
  337. SerialNumber->Buffer,
  338. SerialNumber->Length);
  339. }
  340. //
  341. // Write the SCSI VendorId.
  342. //
  343. PortSetValueKey (LunKey,
  344. L"Identifier",
  345. PORT_REG_ANSI_STRING,
  346. InquiryData->VendorId,
  347. sizeof (InquiryData->VendorId));
  348. //
  349. // Add the DeviceType entry as a string.
  350. //
  351. DeviceEntry = PortGetDeviceType (InquiryData->DeviceType);
  352. Length = wcslen (DeviceEntry->DeviceMap);
  353. PortSetValueKey (LunKey,
  354. L"DeviceType",
  355. REG_SZ,
  356. (PVOID)DeviceEntry->DeviceMap,
  357. (Length + 1) * sizeof (WCHAR));
  358. //
  359. // Write out the DeviceIdentifierPage if it was given.
  360. //
  361. if (DeviceId != NULL) {
  362. PortSetValueKey (LunKey,
  363. L"DeviceIdentifierPage",
  364. REG_BINARY,
  365. DeviceId,
  366. DeviceIdLength);
  367. }
  368. if (LunKeyBuffer) {
  369. *LunKeyBuffer = LunKey;
  370. }
  371. return STATUS_SUCCESS;
  372. }
  373. NTSTATUS
  374. PortMapDeleteAdapterEntry(
  375. IN ULONG PortId
  376. )
  377. /*++
  378. Routine Description:
  379. Delete the Adapter's SCSI DeviceMap entry from the registry.
  380. Arguments:
  381. PortId - PortId associated with the adapter.
  382. Return Value:
  383. NTSTATUS code.
  384. --*/
  385. {
  386. HANDLE AdapterKey;
  387. NTSTATUS Status;
  388. OBJECT_ATTRIBUTES ObjectAttributes;
  389. UNICODE_STRING KeyName;
  390. WCHAR KeyNameBuffer[256];
  391. PAGED_CODE();
  392. swprintf (KeyNameBuffer,
  393. L"%s\\Scsi Port %d",
  394. SCSI_DEVMAP_KEY_NAME,
  395. PortId);
  396. RtlInitUnicodeString (&KeyName, KeyNameBuffer);
  397. InitializeObjectAttributes (&ObjectAttributes,
  398. &KeyName,
  399. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  400. NULL,
  401. NULL);
  402. Status = ZwOpenKey (&AdapterKey,
  403. KEY_ALL_ACCESS,
  404. &ObjectAttributes);
  405. if (!NT_SUCCESS (Status)) {
  406. return Status;
  407. }
  408. ZwDeleteKey (AdapterKey);
  409. ZwClose (AdapterKey);
  410. return Status;
  411. }
  412. NTSTATUS
  413. PortMapDeleteLunEntry(
  414. IN ULONG PortId,
  415. IN ULONG BusId,
  416. IN ULONG TargetId,
  417. IN ULONG Lun
  418. )
  419. /*++
  420. Routine Description:
  421. Delete the logical unit's SCSI DeviceMap entry from the registry.
  422. Arguments:
  423. PortId - Port ID associaed with the adapter.
  424. BusId - Bus ID / PathId that this logical unit is on.
  425. TargetId - Target that this logical unit is on.
  426. Lun - Logical unit ID for this LUN.
  427. Return Value:
  428. NTSTATUS code.
  429. --*/
  430. {
  431. HANDLE LunKey;
  432. NTSTATUS Status;
  433. OBJECT_ATTRIBUTES ObjectAttributes;
  434. UNICODE_STRING KeyName;
  435. WCHAR KeyNameBuffer[256];
  436. PAGED_CODE();
  437. swprintf (KeyNameBuffer,
  438. SCSI_LUN_KEY_NAME,
  439. SCSI_DEVMAP_KEY_NAME,
  440. PortId,
  441. BusId,
  442. TargetId,
  443. Lun);
  444. RtlInitUnicodeString (&KeyName, KeyNameBuffer);
  445. InitializeObjectAttributes (&ObjectAttributes,
  446. &KeyName,
  447. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  448. NULL,
  449. NULL);
  450. Status = ZwOpenKey (&LunKey,
  451. KEY_ALL_ACCESS,
  452. &ObjectAttributes);
  453. if (!NT_SUCCESS (Status)) {
  454. return Status;
  455. }
  456. ZwDeleteKey (LunKey);
  457. ZwClose (LunKey);
  458. return Status;
  459. }