@@ -130,6 +130,229 @@ VOID WppCleanupRoutine(PVOID arg1)
130130}
131131#endif
132132
133+ USHORT CopyBufferToAnsiString (void * _pDest , const void * _pSrc , const char delimiter , size_t _maxlength )
134+ {
135+ PCHAR dst = (PCHAR )_pDest ;
136+ PCHAR src = (PCHAR )_pSrc ;
137+ USHORT _length = _maxlength ;
138+
139+ while (_length && (* src != delimiter ))
140+ {
141+ * dst ++ = * src ++ ;
142+ -- _length ;
143+ };
144+ * dst = '\0' ;
145+ return _length ;
146+ }
147+
148+ BOOLEAN VioStorReadRegistryParameter (IN PVOID DeviceExtension , IN PUCHAR ValueName , IN LONG offset )
149+ {
150+ BOOLEAN bReadResult = FALSE;
151+ BOOLEAN bUseAltPerHbaRegRead = FALSE;
152+ ULONG pBufferLength = sizeof (ULONG );
153+ UCHAR * pBuffer = NULL ;
154+ PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION )DeviceExtension ;
155+ ULONG spgspn_rc , i , j ;
156+ STOR_ADDRESS HwAddress = {0 };
157+ PSTOR_ADDRESS pHwAddress = & HwAddress ;
158+ CHAR valname_as_str [64 ] = {0 };
159+ CHAR hba_id_as_str [4 ] = {0 };
160+ USHORT shAdapterId = (USHORT )adaptExt -> slot_number - 1 ;
161+ ULONG value_as_ulong ;
162+
163+ /* Get a clean buffer to store the registry value... */
164+ pBuffer = StorPortAllocateRegistryBuffer (DeviceExtension , & pBufferLength );
165+ if (pBuffer == NULL )
166+ {
167+ RhelDbgPrint (TRACE_LEVEL_WARNING , " StorPortAllocateRegistryBuffer failed to allocate buffer\n" );
168+ return FALSE;
169+ }
170+ memset (pBuffer , 0 , sizeof (ULONG ));
171+
172+ /* Check if we can get a System PortNumber to access the \Parameters\Device(d) subkey to get a per HBA value.
173+ * FIXME NOTE
174+ *
175+ * Regarding StorPortGetSystemPortNumber():
176+ *
177+ * StorPort always reports STOR_STATUS_INVALID_DEVICE_STATE and does not update pHwAddress->Port.
178+ * Calls to StorPortRegistryRead() and StorPortRegistryWrite() only read or write to \Parameters\Device-1,
179+ * which appears to be an uninitialized value. Therefore, the alternate per HBA read technique will always be used.
180+ *
181+ * Please refer to PR #1216 for more details.
182+ *
183+ * FIXME NOTE END
184+ */
185+ pHwAddress -> Type = STOR_ADDRESS_TYPE_BTL8 ;
186+ pHwAddress -> AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH ;
187+ RhelDbgPrint (TRACE_REGISTRY ,
188+ " Checking whether the HBA system port number and HBA specific registry are available for reading... "
189+ "\n" );
190+ spgspn_rc = StorPortGetSystemPortNumber (DeviceExtension , pHwAddress );
191+ if (spgspn_rc == STOR_STATUS_INVALID_DEVICE_STATE )
192+ {
193+ RhelDbgPrint (TRACE_REGISTRY ,
194+ " WARNING : !!!...HBA Port not ready yet...!!! Returns : 0x%x (STOR_STATUS_INVALID_DEVICE_STATE) "
195+ "\n" ,
196+ spgspn_rc );
197+ /*
198+ * When we are unable to get a valid system PortNumber, we need to
199+ * use an alternate per HBA registry read technique. The technique
200+ * implemented here uses per HBA registry value names based on the
201+ * Storport provided slot_number minus one, padded to hundreds,
202+ * e.g. \Parameters\Device\Valuename_123.
203+ *
204+ * This permits up to 999 HBAs. That ought to be enough... c( O.O )ɔ
205+ */
206+ bUseAltPerHbaRegRead = TRUE;
207+ RhelDbgPrint (TRACE_REGISTRY ,
208+ " Using alternate per HBA registry read technique [\\Parameters\\Device\\Value_(ddd)]. \n" );
209+
210+ /* Grab the first 60 characters of the target Registry Value.
211+ * Value name limit is 16,383 characters, so this is important.
212+ * We leave the last 4 characters for the hba_id_as_str values.
213+ * NULL terminator wraps things up. Also used in TRACING.
214+ */
215+ CopyBufferToAnsiString (& valname_as_str , ValueName , '\0' , 60 );
216+ CopyBufferToAnsiString (& hba_id_as_str , & shAdapterId , '\0' , 4 );
217+
218+ /* Convert from integer to padded ASCII numbers. */
219+ if (shAdapterId / 100 )
220+ {
221+ j = 0 ;
222+ hba_id_as_str [j ] = (UCHAR )(shAdapterId / 100 ) + 48 ;
223+ }
224+ else
225+ {
226+ hba_id_as_str [0 ] = 48 ;
227+ if (shAdapterId / 10 )
228+ {
229+ j = 1 ;
230+ hba_id_as_str [j ] = (UCHAR )(shAdapterId / 10 ) + 48 ;
231+ }
232+ else
233+ {
234+ hba_id_as_str [1 ] = 48 ;
235+ j = 2 ;
236+ hba_id_as_str [j ] = (UCHAR )shAdapterId + 48 ;
237+ }
238+ }
239+ if ((j < 1 ) && (shAdapterId / 10 ))
240+ {
241+ j = 1 ;
242+ hba_id_as_str [j ] = (UCHAR )(((shAdapterId - ((shAdapterId / 100 ) * 100 )) / 10 ) + 48 );
243+ }
244+ else if ((j < 2 ) && (shAdapterId > 9 ))
245+ {
246+ j = 2 ;
247+ hba_id_as_str [j ] = (UCHAR )((shAdapterId - ((shAdapterId / 10 ) * 10 )) + 48 );
248+ }
249+ else
250+ {
251+ j = 1 ;
252+ hba_id_as_str [j ] = 48 ;
253+ }
254+ if ((j < 2 ) && (shAdapterId > 0 ))
255+ {
256+ j = 2 ;
257+ hba_id_as_str [j ] = (UCHAR )((shAdapterId - ((shAdapterId / 10 ) * 10 )) + 48 );
258+ }
259+ else if (j < 2 )
260+ {
261+ j = 2 ;
262+ hba_id_as_str [j ] = 48 ;
263+ }
264+ /* NULL-terminate the string. */
265+ hba_id_as_str [3 ] = '\0' ;
266+ /* Skip the exisitng ValueName. */
267+ for (i = 0 ; valname_as_str [i ] != '\0' ; ++ i )
268+ {
269+ }
270+ /* Append an underscore. */
271+ valname_as_str [i ] = '\x5F' ;
272+ /* Append the padded HBA ID and NULL terminator. */
273+ for (j = 0 ; j < 4 ; ++ j )
274+ {
275+ valname_as_str [i + j + 1 ] = hba_id_as_str [j ];
276+ }
277+
278+ PUCHAR ValueNamePerHba = (UCHAR * )& valname_as_str ;
279+ bReadResult = StorPortRegistryRead (DeviceExtension ,
280+ ValueNamePerHba ,
281+ 1 ,
282+ MINIPORT_REG_DWORD ,
283+ pBuffer ,
284+ & pBufferLength );
285+ }
286+ else
287+ {
288+ RhelDbgPrint (TRACE_REGISTRY , " HBA Port : %u | Returns : 0x%x \n" , pHwAddress -> Port , spgspn_rc );
289+ RhelDbgPrint (TRACE_REGISTRY , " Using StorPort-based per HBA registry read [\\Parameters\\Device(d)]. \n" );
290+ /* FIXME : THIS DOES NOT WORK. IT WILL NOT READ \Parameters\Device(d) subkeys...
291+ * NOTE : Only MINIPORT_REG_DWORD values are supported.
292+ */
293+ bReadResult = StorPortRegistryRead (DeviceExtension , ValueName , 0 , MINIPORT_REG_DWORD , pBuffer , & pBufferLength );
294+ /* Grab the first 64 characters of the target Registry Value.
295+ * Value name limit is 16,383 characters, so this is important.
296+ * NULL terminator wraps things up. Used in TRACING.
297+ */
298+ CopyBufferToAnsiString (& valname_as_str , ValueName , '\0' , 64 );
299+ }
300+
301+ if ((bReadResult == FALSE) || (pBufferLength == 0 ))
302+ {
303+ RhelDbgPrint (TRACE_REGISTRY ,
304+ " StorPortRegistryRead was unable to find a per HBA value %s. Attempting to find a global "
305+ "value... \n" ,
306+ (bUseAltPerHbaRegRead ) ? "using \\Parameters\\Device\\Value_(ddd) value names"
307+ : "at the \\Parameters\\Device(d) subkey" );
308+ bReadResult = FALSE;
309+ pBufferLength = sizeof (ULONG );
310+ memset (pBuffer , 0 , sizeof (ULONG ));
311+
312+ /* Do a "Global" read of the Parameters\Device subkey...
313+ * NOTE : Only MINIPORT_REG_DWORD values are supported.
314+ */
315+ bReadResult = StorPortRegistryRead (DeviceExtension , ValueName , 1 , MINIPORT_REG_DWORD , pBuffer , & pBufferLength );
316+ /* Grab the first 64 characters of the target Registry Value.
317+ * Value name limit is 16,383 characters, so this is important.
318+ * NULL terminator wraps things up. Used in TRACING.
319+ */
320+ CopyBufferToAnsiString (& valname_as_str , ValueName , '\0' , 64 );
321+ }
322+ /* Give me the DWORD Registry Value as a ULONG from the pointer.
323+ * Used in TRACING.
324+ */
325+ memcpy (& value_as_ulong , pBuffer , sizeof (ULONG ));
326+
327+ if ((bReadResult == FALSE) || (pBufferLength == 0 ))
328+ {
329+ RhelDbgPrint (TRACE_REGISTRY ,
330+ " StorPortRegistryRead of %s returned NOT FOUND or EMPTY, pBufferLength = %d, Possible "
331+ "pBufferLength Hint = 0x%x (%lu) \n" ,
332+ valname_as_str ,
333+ pBufferLength ,
334+ value_as_ulong ,
335+ value_as_ulong );
336+ StorPortFreeRegistryBuffer (DeviceExtension , pBuffer );
337+ return FALSE;
338+ }
339+ else
340+ {
341+ RhelDbgPrint (TRACE_REGISTRY ,
342+ " StorPortRegistryRead of %s returned SUCCESS, pBufferLength = %d, Value = 0x%x (%lu) \n" ,
343+ valname_as_str ,
344+ pBufferLength ,
345+ value_as_ulong ,
346+ value_as_ulong );
347+
348+ StorPortCopyMemory ((PVOID )((UINT_PTR )adaptExt + offset ), (PVOID )pBuffer , sizeof (ULONG ));
349+
350+ StorPortFreeRegistryBuffer (DeviceExtension , pBuffer );
351+
352+ return TRUE;
353+ }
354+ }
355+
133356ULONG
134357DriverEntry (IN PVOID DriverObject , IN PVOID RegistryPath )
135358{
0 commit comments