kvm-guest-drivers-windows
655 строк · 24.6 Кб
1/*
2* This file contains various virtio queue related routines.
3*
4* Copyright (c) 2012-2017 Red Hat, Inc.
5*
6* Author(s):
7* Vadim Rozenfeld <vrozenfe@redhat.com>
8*
9* Redistribution and use in source and binary forms, with or without
10* modification, are permitted provided that the following conditions
11* are met :
12* 1. Redistributions of source code must retain the above copyright
13* notice, this list of conditions and the following disclaimer.
14* 2. Redistributions in binary form must reproduce the above copyright
15* notice, this list of conditions and the following disclaimer in the
16* documentation and / or other materials provided with the distribution.
17* 3. Neither the names of the copyright holders nor the names of their contributors
18* may be used to endorse or promote products derived from this software
19* without specific prior written permission.
20* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23* ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30* SUCH DAMAGE.
31*/
32#include "trace.h"
33#include "helper.h"
34
35#if defined(EVENT_TRACING)
36#include "helper.tmh"
37#endif
38
39#define SET_VA_PA() { ULONG len; va = adaptExt->indirect ? srbExt->pdesc : NULL; \
40pa = va ? StorPortGetPhysicalAddress(DeviceExtension, NULL, va, &len).QuadPart : 0; \
41}
42
43VOID
44SendSRB(
45IN PVOID DeviceExtension,
46IN PSRB_TYPE Srb
47)
48{
49PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
50PSRB_EXTENSION srbExt = NULL;
51PVOID va = NULL;
52ULONGLONG pa = 0;
53ULONG QueueNumber = VIRTIO_SCSI_REQUEST_QUEUE_0;
54STOR_LOCK_HANDLE LockHandle = { 0 };
55ULONG status = STOR_STATUS_SUCCESS;
56UCHAR ScsiStatus = SCSISTAT_GOOD;
57ULONG MessageID;
58int res = 0;
59PREQUEST_LIST element;
60ULONG index;
61ENTER_FN_SRB();
62
63if (!Srb)
64return;
65
66if (adaptExt->bRemoved) {
67SRB_SET_SRB_STATUS(Srb, SRB_STATUS_NO_DEVICE);
68CompleteRequest(DeviceExtension, Srb);
69return;
70}
71
72LOG_SRB_INFO();
73
74if (adaptExt->num_queues > 1) {
75STARTIO_PERFORMANCE_PARAMETERS param;
76param.Size = sizeof(STARTIO_PERFORMANCE_PARAMETERS);
77status = StorPortGetStartIoPerfParams(DeviceExtension, (PSCSI_REQUEST_BLOCK)Srb, ¶m);
78if (status == STOR_STATUS_SUCCESS && param.MessageNumber != 0) {
79QueueNumber = MESSAGE_TO_QUEUE(param.MessageNumber);
80if (QueueNumber >= adaptExt->num_queues + VIRTIO_SCSI_REQUEST_QUEUE_0) {
81QueueNumber %= adaptExt->num_queues;
82}
83} else {
84RhelDbgPrint(TRACE_LEVEL_ERROR, " StorPortGetStartIoPerfParams failed srb 0x%p status 0x%x MessageNumber %d.\n", Srb, status, param.MessageNumber);
85}
86}
87
88srbExt = SRB_EXTENSION(Srb);
89
90if (!srbExt) {
91RhelDbgPrint(TRACE_LEVEL_INFORMATION, " No SRB Extenstion for SRB 0x%p \n", Srb);
92return;
93}
94
95MessageID = QUEUE_TO_MESSAGE(QueueNumber);
96index = QueueNumber - VIRTIO_SCSI_REQUEST_QUEUE_0;
97
98if (adaptExt->reset_in_progress) {
99RhelDbgPrint(TRACE_LEVEL_FATAL, " Reset is in progress, completing SRB 0x%p with SRB_STATUS_BUS_RESET.\n", Srb);
100SRB_SET_SRB_STATUS(Srb, SRB_STATUS_BUS_RESET);
101CompleteRequest(DeviceExtension, Srb);
102return;
103}
104
105VioScsiVQLock(DeviceExtension, MessageID, &LockHandle, FALSE);
106SET_VA_PA();
107res = virtqueue_add_buf(adaptExt->vq[QueueNumber],
108srbExt->psgl,
109srbExt->out, srbExt->in,
110&srbExt->cmd, va, pa);
111
112if (res >= 0) {
113element = &adaptExt->processing_srbs[index];
114InsertTailList(&element->srb_list, &srbExt->list_entry);
115element->srb_cnt++;
116}
117VioScsiVQUnlock(DeviceExtension, MessageID, &LockHandle, FALSE);
118if ( res >= 0){
119if (virtqueue_kick_prepare(adaptExt->vq[QueueNumber])) {
120virtqueue_notify(adaptExt->vq[QueueNumber]);
121}
122} else {
123virtqueue_notify(adaptExt->vq[QueueNumber]);
124ScsiStatus = SCSISTAT_QUEUE_FULL;
125SRB_SET_SRB_STATUS(Srb, SRB_STATUS_BUSY);
126SRB_SET_SCSI_STATUS(Srb, ScsiStatus);
127StorPortBusy(DeviceExtension, 10);
128CompleteRequest(DeviceExtension, Srb);
129RhelDbgPrint(TRACE_LEVEL_FATAL, " Could not put an SRB into a VQ, so complete it with SRB_STATUS_BUSY. QueueNumber = %d, SRB = 0x%p, Lun = %d, TimeOut = %d.\n", QueueNumber, srbExt->Srb, SRB_LUN(Srb), Srb->TimeOutValue);
130}
131
132EXIT_FN_SRB();
133}
134
135BOOLEAN
136SynchronizedTMFRoutine(
137IN PVOID DeviceExtension,
138IN PVOID Context
139)
140{
141PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
142PSCSI_REQUEST_BLOCK Srb = (PSCSI_REQUEST_BLOCK) Context;
143PSRB_EXTENSION srbExt = SRB_EXTENSION(Srb);
144PVOID va;
145ULONGLONG pa;
146
147ENTER_FN();
148SET_VA_PA();
149if (virtqueue_add_buf(adaptExt->vq[VIRTIO_SCSI_CONTROL_QUEUE],
150srbExt->psgl,
151srbExt->out, srbExt->in,
152&srbExt->cmd, va, pa) >= 0){
153virtqueue_kick(adaptExt->vq[VIRTIO_SCSI_CONTROL_QUEUE]);
154EXIT_FN();
155return TRUE;
156}
157SRB_SET_SRB_STATUS(Srb, SRB_STATUS_BUSY);
158StorPortBusy(DeviceExtension, adaptExt->queue_depth);
159EXIT_ERR();
160return FALSE;
161}
162
163BOOLEAN
164SendTMF(
165IN PVOID DeviceExtension,
166IN PSCSI_REQUEST_BLOCK Srb
167)
168{
169ENTER_FN();
170return StorPortSynchronizeAccess(DeviceExtension, SynchronizedTMFRoutine, (PVOID)Srb);
171EXIT_FN();
172}
173
174BOOLEAN
175DeviceReset(
176IN PVOID DeviceExtension
177)
178{
179PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
180PSCSI_REQUEST_BLOCK Srb = &adaptExt->tmf_cmd.Srb;
181PSRB_EXTENSION srbExt = adaptExt->tmf_cmd.SrbExtension;
182VirtIOSCSICmd *cmd = &srbExt->cmd;
183ULONG fragLen;
184ULONG sgElement;
185
186ENTER_FN();
187if (adaptExt->dump_mode) {
188return TRUE;
189}
190ASSERT(adaptExt->tmf_infly == FALSE);
191Srb->SrbExtension = srbExt;
192RtlZeroMemory((PVOID)cmd, sizeof(VirtIOSCSICmd));
193cmd->srb = (PVOID)Srb;
194cmd->req.tmf.lun[0] = 1;
195cmd->req.tmf.lun[1] = 0;
196cmd->req.tmf.lun[2] = 0;
197cmd->req.tmf.lun[3] = 0;
198cmd->req.tmf.type = VIRTIO_SCSI_T_TMF;
199cmd->req.tmf.subtype = VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET;
200
201srbExt->psgl = srbExt->vio_sg;
202srbExt->pdesc = srbExt->desc_alias;
203sgElement = 0;
204srbExt->psgl[sgElement].physAddr = StorPortGetPhysicalAddress(DeviceExtension, NULL, &cmd->req.tmf, &fragLen);
205srbExt->psgl[sgElement].length = sizeof(cmd->req.tmf);
206sgElement++;
207srbExt->out = sgElement;
208srbExt->psgl[sgElement].physAddr = StorPortGetPhysicalAddress(DeviceExtension, NULL, &cmd->resp.tmf, &fragLen);
209srbExt->psgl[sgElement].length = sizeof(cmd->resp.tmf);
210sgElement++;
211srbExt->in = sgElement - srbExt->out;
212StorPortPause(DeviceExtension, 60);
213if (!SendTMF(DeviceExtension, Srb)) {
214StorPortResume(DeviceExtension);
215return FALSE;
216}
217adaptExt->tmf_infly = TRUE;
218return TRUE;
219}
220
221VOID
222ShutDown(
223IN PVOID DeviceExtension
224)
225{
226ULONG index;
227PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
228ENTER_FN();
229virtio_device_reset(&adaptExt->vdev);
230virtio_delete_queues(&adaptExt->vdev);
231for (index = VIRTIO_SCSI_CONTROL_QUEUE; index < adaptExt->num_queues + VIRTIO_SCSI_REQUEST_QUEUE_0; ++index) {
232adaptExt->vq[index] = NULL;
233}
234
235virtio_device_shutdown(&adaptExt->vdev);
236EXIT_FN();
237}
238
239VOID
240GetScsiConfig(
241IN PVOID DeviceExtension
242)
243{
244PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
245ENTER_FN();
246
247adaptExt->features = virtio_get_features(&adaptExt->vdev);
248adaptExt->indirect = CHECKBIT(adaptExt->features, VIRTIO_RING_F_INDIRECT_DESC);
249
250virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, seg_max),
251&adaptExt->scsi_config.seg_max, sizeof(adaptExt->scsi_config.seg_max));
252RhelDbgPrint(TRACE_LEVEL_INFORMATION, " seg_max %lu\n", adaptExt->scsi_config.seg_max);
253
254virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, num_queues),
255&adaptExt->scsi_config.num_queues, sizeof(adaptExt->scsi_config.num_queues));
256RhelDbgPrint(TRACE_LEVEL_INFORMATION, " num_queues %lu\n", adaptExt->scsi_config.num_queues);
257
258virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, max_sectors),
259&adaptExt->scsi_config.max_sectors, sizeof(adaptExt->scsi_config.max_sectors));
260RhelDbgPrint(TRACE_LEVEL_INFORMATION, " max_sectors %lu\n", adaptExt->scsi_config.max_sectors);
261
262virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, cmd_per_lun),
263&adaptExt->scsi_config.cmd_per_lun, sizeof(adaptExt->scsi_config.cmd_per_lun));
264RhelDbgPrint(TRACE_LEVEL_INFORMATION, " cmd_per_lun %lu\n", adaptExt->scsi_config.cmd_per_lun);
265
266virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, event_info_size),
267&adaptExt->scsi_config.event_info_size, sizeof(adaptExt->scsi_config.event_info_size));
268RhelDbgPrint(TRACE_LEVEL_INFORMATION, " event_info_size %lu\n", adaptExt->scsi_config.event_info_size);
269
270virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, sense_size),
271&adaptExt->scsi_config.sense_size, sizeof(adaptExt->scsi_config.sense_size));
272RhelDbgPrint(TRACE_LEVEL_INFORMATION, " sense_size %lu\n", adaptExt->scsi_config.sense_size);
273
274virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, cdb_size),
275&adaptExt->scsi_config.cdb_size, sizeof(adaptExt->scsi_config.cdb_size));
276RhelDbgPrint(TRACE_LEVEL_INFORMATION, " cdb_size %lu\n", adaptExt->scsi_config.cdb_size);
277
278virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, max_channel),
279&adaptExt->scsi_config.max_channel, sizeof(adaptExt->scsi_config.max_channel));
280RhelDbgPrint(TRACE_LEVEL_INFORMATION, " max_channel %u\n", adaptExt->scsi_config.max_channel);
281
282virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, max_target),
283&adaptExt->scsi_config.max_target, sizeof(adaptExt->scsi_config.max_target));
284RhelDbgPrint(TRACE_LEVEL_INFORMATION, " max_target %u\n", adaptExt->scsi_config.max_target);
285
286virtio_get_config(&adaptExt->vdev, FIELD_OFFSET(VirtIOSCSIConfig, max_lun),
287&adaptExt->scsi_config.max_lun, sizeof(adaptExt->scsi_config.max_lun));
288RhelDbgPrint(TRACE_LEVEL_INFORMATION, " max_lun %lu\n", adaptExt->scsi_config.max_lun);
289
290EXIT_FN();
291}
292
293
294VOID
295SetGuestFeatures(
296IN PVOID DeviceExtension
297)
298{
299ULONGLONG guestFeatures = 0;
300PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
301ENTER_FN();
302
303if (CHECKBIT(adaptExt->features, VIRTIO_F_VERSION_1)) {
304guestFeatures |= (1ULL << VIRTIO_F_VERSION_1);
305if (CHECKBIT(adaptExt->features, VIRTIO_F_RING_PACKED)) {
306guestFeatures |= (1ULL << VIRTIO_F_RING_PACKED);
307}
308}
309if (CHECKBIT(adaptExt->features, VIRTIO_F_ANY_LAYOUT)) {
310guestFeatures |= (1ULL << VIRTIO_F_ANY_LAYOUT);
311}
312if (CHECKBIT(adaptExt->features, VIRTIO_F_ACCESS_PLATFORM)) {
313guestFeatures |= (1ULL << VIRTIO_F_ACCESS_PLATFORM);
314}
315if (CHECKBIT(adaptExt->features, VIRTIO_RING_F_EVENT_IDX)) {
316guestFeatures |= (1ULL << VIRTIO_RING_F_EVENT_IDX);
317}
318if (CHECKBIT(adaptExt->features, VIRTIO_RING_F_INDIRECT_DESC)) {
319guestFeatures |= (1ULL << VIRTIO_RING_F_INDIRECT_DESC);
320}
321if (CHECKBIT(adaptExt->features, VIRTIO_SCSI_F_CHANGE)) {
322guestFeatures |= (1ULL << VIRTIO_SCSI_F_CHANGE);
323}
324if (CHECKBIT(adaptExt->features, VIRTIO_SCSI_F_HOTPLUG)) {
325guestFeatures |= (1ULL << VIRTIO_SCSI_F_HOTPLUG);
326}
327if (!NT_SUCCESS(virtio_set_features(&adaptExt->vdev, guestFeatures))) {
328RhelDbgPrint(TRACE_LEVEL_FATAL, " virtio_set_features failed\n");
329}
330
331EXIT_FN();
332}
333
334
335BOOLEAN
336InitVirtIODevice(
337IN PVOID DeviceExtension
338)
339{
340PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
341NTSTATUS status;
342
343status = virtio_device_initialize(
344&adaptExt->vdev,
345&VioScsiSystemOps,
346adaptExt,
347adaptExt->msix_enabled);
348if (!NT_SUCCESS(status)) {
349LogError(adaptExt,
350SP_INTERNAL_ADAPTER_ERROR,
351__LINE__);
352RhelDbgPrint(TRACE_LEVEL_FATAL, " Failed to initialize virtio device, error %x\n", status);
353return FALSE;
354}
355return TRUE;
356}
357
358BOOLEAN
359InitHW(
360IN PVOID DeviceExtension,
361IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
362)
363{
364PACCESS_RANGE accessRange;
365PADAPTER_EXTENSION adaptExt;
366ULONG pci_cfg_len, i;
367
368ENTER_FN();
369adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
370adaptExt->system_io_bus_number = ConfigInfo->SystemIoBusNumber;
371adaptExt->slot_number = ConfigInfo->SlotNumber;
372
373/* read PCI config space */
374pci_cfg_len = StorPortGetBusData(
375DeviceExtension,
376PCIConfiguration,
377ConfigInfo->SystemIoBusNumber,
378(ULONG)ConfigInfo->SlotNumber,
379(PVOID)&adaptExt->pci_config_buf,
380sizeof(adaptExt->pci_config_buf));
381
382if (pci_cfg_len != sizeof(adaptExt->pci_config_buf)) {
383LogError(DeviceExtension,
384SP_INTERNAL_ADAPTER_ERROR,
385__LINE__);
386RhelDbgPrint(TRACE_LEVEL_FATAL, " CANNOT READ PCI CONFIGURATION SPACE %d\n", pci_cfg_len);
387return FALSE;
388}
389
390{
391UCHAR CapOffset;
392PPCI_MSIX_CAPABILITY pMsixCapOffset;
393PPCI_COMMON_HEADER pPciComHeader;
394pPciComHeader = &adaptExt->pci_config;
395if ((pPciComHeader->Status & PCI_STATUS_CAPABILITIES_LIST) == 0)
396{
397RhelDbgPrint(TRACE_LEVEL_INFORMATION, " NO CAPABILITIES_LIST\n");
398}
399else
400{
401if ((pPciComHeader->HeaderType & (~PCI_MULTIFUNCTION)) == PCI_DEVICE_TYPE)
402{
403CapOffset = pPciComHeader->u.type0.CapabilitiesPtr;
404while (CapOffset != 0)
405{
406pMsixCapOffset = (PPCI_MSIX_CAPABILITY)&adaptExt->pci_config_buf[CapOffset];
407if (pMsixCapOffset->Header.CapabilityID == PCI_CAPABILITY_ID_MSIX)
408{
409RhelDbgPrint(TRACE_LEVEL_INFORMATION, "MessageControl.TableSize = %d\n", pMsixCapOffset->MessageControl.TableSize);
410RhelDbgPrint(TRACE_LEVEL_INFORMATION, "MessageControl.FunctionMask = %d\n", pMsixCapOffset->MessageControl.FunctionMask);
411RhelDbgPrint(TRACE_LEVEL_INFORMATION, "MessageControl.MSIXEnable = %d\n", pMsixCapOffset->MessageControl.MSIXEnable);
412
413RhelDbgPrint(TRACE_LEVEL_INFORMATION, " MessageTable = %lu\n", pMsixCapOffset->MessageTable.TableOffset);
414RhelDbgPrint(TRACE_LEVEL_INFORMATION, " PBATable = %lu\n", pMsixCapOffset->PBATable.TableOffset);
415adaptExt->msix_enabled = (pMsixCapOffset->MessageControl.MSIXEnable == 1);
416} else
417{
418RhelDbgPrint(TRACE_LEVEL_INFORMATION, " CapabilityID = %x, Next CapOffset = %x\n", pMsixCapOffset->Header.CapabilityID, CapOffset);
419}
420CapOffset = pMsixCapOffset->Header.Next;
421}
422RhelDbgPrint(TRACE_LEVEL_INFORMATION, " msix_enabled = %d\n", adaptExt->msix_enabled);
423} else
424{
425RhelDbgPrint(TRACE_LEVEL_FATAL, " NOT A PCI_DEVICE_TYPE\n");
426}
427}
428}
429
430/* initialize the pci_bars array */
431for (i = 0; i < ConfigInfo->NumberOfAccessRanges; i++) {
432accessRange = *ConfigInfo->AccessRanges + i;
433if (accessRange->RangeLength != 0) {
434int iBar = virtio_get_bar_index(&adaptExt->pci_config, accessRange->RangeStart);
435if (iBar == -1) {
436RhelDbgPrint(TRACE_LEVEL_FATAL,
437" Cannot get index for BAR %I64d\n", accessRange->RangeStart.QuadPart);
438return FALSE;
439}
440adaptExt->pci_bars[iBar].BasePA = accessRange->RangeStart;
441adaptExt->pci_bars[iBar].uLength = accessRange->RangeLength;
442adaptExt->pci_bars[iBar].bPortSpace = !accessRange->RangeInMemory;
443}
444}
445
446/* initialize the virtual device */
447if (!InitVirtIODevice(DeviceExtension)) {
448return FALSE;
449}
450
451EXIT_FN();
452return TRUE;
453}
454
455BOOLEAN
456SynchronizedKickEventRoutine(
457IN PVOID DeviceExtension,
458IN PVOID Context
459)
460{
461PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
462PVirtIOSCSIEventNode eventNode = (PVirtIOSCSIEventNode) Context;
463PVOID va = NULL;
464ULONGLONG pa = 0;
465
466ENTER_FN();
467if (virtqueue_add_buf(adaptExt->vq[VIRTIO_SCSI_EVENTS_QUEUE],
468&eventNode->sg,
4690, 1,
470eventNode, va, pa) >= 0){
471virtqueue_kick(adaptExt->vq[VIRTIO_SCSI_EVENTS_QUEUE]);
472EXIT_FN();
473return TRUE;
474}
475EXIT_ERR();
476return FALSE;
477}
478
479
480BOOLEAN
481KickEvent(
482IN PVOID DeviceExtension,
483IN PVirtIOSCSIEventNode EventNode
484)
485{
486PADAPTER_EXTENSION adaptExt;
487ULONG fragLen;
488
489ENTER_FN();
490adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
491RtlZeroMemory((PVOID)EventNode, sizeof(VirtIOSCSIEventNode));
492EventNode->sg.physAddr = StorPortGetPhysicalAddress(DeviceExtension, NULL, &EventNode->event, &fragLen);
493EventNode->sg.length = sizeof(VirtIOSCSIEvent);
494return SynchronizedKickEventRoutine(DeviceExtension, (PVOID)EventNode);
495EXIT_FN();
496}
497
498VOID
499//FORCEINLINE
500VioScsiVQLock(
501IN PVOID DeviceExtension,
502IN ULONG MessageID,
503IN OUT PSTOR_LOCK_HANDLE LockHandle,
504IN BOOLEAN isr
505)
506{
507PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
508ULONG QueueNumber = MESSAGE_TO_QUEUE(MessageID);
509ENTER_FN();
510
511if (!isr) {
512if (adaptExt->msix_enabled) {
513// Queue numbers start at 0, message ids at 1.
514NT_ASSERT(MessageID > VIRTIO_SCSI_REQUEST_QUEUE_0);
515if (QueueNumber >= (adaptExt->num_queues + VIRTIO_SCSI_REQUEST_QUEUE_0)) {
516QueueNumber %= adaptExt->num_queues;
517}
518StorPortAcquireSpinLock(DeviceExtension, DpcLock, &adaptExt->dpc[QueueNumber - VIRTIO_SCSI_REQUEST_QUEUE_0], LockHandle);
519}
520else {
521StorPortAcquireSpinLock(DeviceExtension, InterruptLock, NULL, LockHandle);
522}
523}
524EXIT_FN();
525}
526
527VOID
528//FORCEINLINE
529VioScsiVQUnlock(
530IN PVOID DeviceExtension,
531IN ULONG MessageID,
532IN PSTOR_LOCK_HANDLE LockHandle,
533IN BOOLEAN isr
534)
535{
536ENTER_FN();
537if (!isr) {
538StorPortReleaseSpinLock(DeviceExtension, LockHandle);
539}
540EXIT_FN();
541}
542
543VOID FirmwareRequest(
544IN PVOID DeviceExtension,
545IN PSRB_TYPE Srb
546)
547{
548PADAPTER_EXTENSION adaptExt;
549PSRB_EXTENSION srbExt = NULL;
550ULONG dataLen = 0;
551PSRB_IO_CONTROL srbControl = NULL;
552PFIRMWARE_REQUEST_BLOCK firmwareRequest = NULL;
553ENTER_FN();
554adaptExt = (PADAPTER_EXTENSION)DeviceExtension;
555srbExt = SRB_EXTENSION(Srb);
556srbControl = (PSRB_IO_CONTROL)SRB_DATA_BUFFER(Srb);
557dataLen = SRB_DATA_TRANSFER_LENGTH(Srb);
558if (dataLen < (sizeof(SRB_IO_CONTROL) + sizeof(FIRMWARE_REQUEST_BLOCK))) {
559srbControl->ReturnCode = FIRMWARE_STATUS_INVALID_PARAMETER;
560SRB_SET_SRB_STATUS(Srb, SRB_STATUS_BAD_SRB_BLOCK_LENGTH);
561RhelDbgPrint(TRACE_LEVEL_ERROR,
562" FirmwareRequest Bad Block Length %ul\n", dataLen);
563return;
564}
565
566firmwareRequest = (PFIRMWARE_REQUEST_BLOCK)(srbControl + 1);
567switch (firmwareRequest->Function) {
568
569case FIRMWARE_FUNCTION_GET_INFO: {
570PSTORAGE_FIRMWARE_INFO_V2 firmwareInfo;
571firmwareInfo = (PSTORAGE_FIRMWARE_INFO_V2)((PUCHAR)srbControl + firmwareRequest->DataBufferOffset);
572RhelDbgPrint(TRACE_LEVEL_INFORMATION,
573" FIRMWARE_FUNCTION_GET_INFO \n");
574if ((firmwareInfo->Version >= STORAGE_FIRMWARE_INFO_STRUCTURE_VERSION_V2) ||
575(firmwareInfo->Size >= sizeof(STORAGE_FIRMWARE_INFO_V2))) {
576firmwareInfo->Version = STORAGE_FIRMWARE_INFO_STRUCTURE_VERSION_V2;
577firmwareInfo->Size = sizeof(STORAGE_FIRMWARE_INFO_V2);
578
579firmwareInfo->UpgradeSupport = TRUE;
580
581firmwareInfo->SlotCount = 1;
582firmwareInfo->ActiveSlot = 0;
583firmwareInfo->PendingActivateSlot = STORAGE_FIRMWARE_INFO_INVALID_SLOT;
584firmwareInfo->FirmwareShared = FALSE;
585firmwareInfo->ImagePayloadAlignment = PAGE_SIZE;
586firmwareInfo->ImagePayloadMaxSize = PAGE_SIZE;
587
588if (firmwareRequest->DataBufferLength >= (sizeof(STORAGE_FIRMWARE_INFO_V2) + sizeof(STORAGE_FIRMWARE_SLOT_INFO_V2))) {
589firmwareInfo->Slot[0].SlotNumber = 0;
590firmwareInfo->Slot[0].ReadOnly = FALSE;
591StorPortCopyMemory(&firmwareInfo->Slot[0].Revision, &adaptExt->fw_ver, sizeof (adaptExt->fw_ver));
592srbControl->ReturnCode = FIRMWARE_STATUS_SUCCESS;
593} else {
594firmwareRequest->DataBufferLength = sizeof(STORAGE_FIRMWARE_INFO_V2) + sizeof(STORAGE_FIRMWARE_SLOT_INFO_V2);
595srbControl->ReturnCode = FIRMWARE_STATUS_OUTPUT_BUFFER_TOO_SMALL;
596}
597SRB_SET_SRB_STATUS(Srb, SRB_STATUS_SUCCESS);
598}
599else {
600RhelDbgPrint(TRACE_LEVEL_ERROR,
601" Wrong Version %ul or Size %ul\n", firmwareInfo->Version, firmwareInfo->Size);
602srbControl->ReturnCode = FIRMWARE_STATUS_INVALID_PARAMETER;
603SRB_SET_SRB_STATUS(Srb, SRB_STATUS_BAD_SRB_BLOCK_LENGTH);
604}
605}
606break;
607case FIRMWARE_FUNCTION_DOWNLOAD: {
608PSTORAGE_FIRMWARE_DOWNLOAD_V2 firmwareDwnld;
609firmwareDwnld = (PSTORAGE_FIRMWARE_DOWNLOAD_V2)((PUCHAR)srbControl + firmwareRequest->DataBufferOffset);
610RhelDbgPrint(TRACE_LEVEL_INFORMATION,
611" FIRMWARE_FUNCTION_DOWNLOAD \n");
612if ((firmwareDwnld->Version >= STORAGE_FIRMWARE_DOWNLOAD_STRUCTURE_VERSION_V2) ||
613(firmwareDwnld->Size >= sizeof(STORAGE_FIRMWARE_DOWNLOAD_V2))) {
614firmwareDwnld->Version = STORAGE_FIRMWARE_DOWNLOAD_STRUCTURE_VERSION_V2;
615firmwareDwnld->Size = sizeof(STORAGE_FIRMWARE_DOWNLOAD_V2);
616adaptExt->fw_ver++;
617srbControl->ReturnCode = FIRMWARE_STATUS_SUCCESS;
618SRB_SET_SRB_STATUS(Srb, SRB_STATUS_SUCCESS);
619}
620else {
621RhelDbgPrint(TRACE_LEVEL_ERROR,
622" Wrong Version %ul or Size %ul\n", firmwareDwnld->Version, firmwareDwnld->Size);
623srbControl->ReturnCode = FIRMWARE_STATUS_INVALID_PARAMETER;
624SRB_SET_SRB_STATUS(Srb, SRB_STATUS_BAD_SRB_BLOCK_LENGTH);
625}
626}
627break;
628case FIRMWARE_FUNCTION_ACTIVATE: {
629PSTORAGE_FIRMWARE_ACTIVATE firmwareActivate;
630firmwareActivate = (PSTORAGE_FIRMWARE_ACTIVATE)((PUCHAR)srbControl + firmwareRequest->DataBufferOffset);
631if ((firmwareActivate->Version == STORAGE_FIRMWARE_ACTIVATE_STRUCTURE_VERSION) ||
632(firmwareActivate->Size >= sizeof(STORAGE_FIRMWARE_ACTIVATE))) {
633firmwareActivate->Version = STORAGE_FIRMWARE_ACTIVATE_STRUCTURE_VERSION;
634firmwareActivate->Size = sizeof(STORAGE_FIRMWARE_ACTIVATE);
635srbControl->ReturnCode = FIRMWARE_STATUS_SUCCESS;
636SRB_SET_SRB_STATUS(Srb, SRB_STATUS_SUCCESS);
637}
638else {
639RhelDbgPrint(TRACE_LEVEL_ERROR,
640" Wrong Version %ul or Size %ul\n", firmwareActivate->Version, firmwareActivate->Size);
641srbControl->ReturnCode = FIRMWARE_STATUS_INVALID_PARAMETER;
642SRB_SET_SRB_STATUS(Srb, SRB_STATUS_BAD_SRB_BLOCK_LENGTH);
643}
644RhelDbgPrint(TRACE_LEVEL_VERBOSE,
645" FIRMWARE_FUNCTION_ACTIVATE \n");
646}
647break;
648default:
649RhelDbgPrint(TRACE_LEVEL_INFORMATION,
650" Unsupported Function %ul\n", firmwareRequest->Function);
651SRB_SET_SRB_STATUS(Srb, SRB_STATUS_INVALID_REQUEST);
652break;
653}
654EXIT_FN();
655}
656